初始提交

This commit is contained in:
2025-09-04 16:35:14 +08:00
commit 5cd52c4d2c
735 changed files with 155784 additions and 0 deletions

View File

@ -0,0 +1,172 @@
<template>
<div>
<TopNav navTitle="处警记录" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Search placeholder="请输入上报人员姓名" v-model="kwd" :isSx="true" @update:sx="showPopup = !showPopup"
@update:modelValue="onSearch"></Search>
</div>
</van-sticky>
<SxPopup :showPopup="showPopup" :list="cjxx.sxList" :showTime='false' :p_top="110" @update:close="showPopup = false"
@update:onConfirm="onConfirm" />
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list v-model:loading="loading" :finished="finished" finished-text=" " @load="onLoad" offset="1"
:immediate-check="false">
<List v-for="(item, index) in cjxx.list" :key="index" :item="item" :dict="{ D_QW_CJSBLX }" />
<van-empty description="暂无信息" image="default" v-if="cjxx.list.length <= 0 && showEmpty" />
</van-list>
</van-pull-refresh>
</div>
</template>
<script setup>
import { getRypcList, getRypcCount } from "../../../api/common.js";
import TopNav from "../../../components/topNav.vue";
import Search from "../../../components/search.vue";
import Tabs from "../../../components/tabs.vue";
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/cjbsList.vue";
import { setTimeQuantum } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, reactive, onMounted, watch } from "vue";
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
const showEmpty = ref(false);
const { D_QW_CJSBLX } = getDictList(
"D_QW_CJSBLX"
); //字典信息
watch(D_QW_CJSBLX, (newValue) => {
for (let i = 0; i < newValue.length; i++) {
newValue[i].name = newValue[i].text;
newValue[i].key = newValue[i].dm;
newValue[i].isCheck = false;
}
cjxx.sxList = [
{
title: "警情类型",
isCheckBox: true,
array: newValue,
},
];
//时间段选项
// cjxx.sxList[1] = setTimeQuantum();
});
const tabsIndex = ref(1);
const total = ref(0);
const tabs = ref([
{
name: "全部",
count: 0,
pclx: "",
},
{
name: "盘查",
count: 0,
pclx: "9",
},
{
name: "移交",
count: 0,
pclx: "2",
},
{
name: "放行",
count: 0,
pclx: "1",
},
]);
const cjxx = reactive({
pageNum: 1,
pageSize: 10,
yjJb: "",
yjLx: "",
startTime: "",
endTime: "",
yjLx: "",
sxList: [], //筛选条件数据
list: [], //预警列表数据
});
const kwd = ref("");
const finished = ref(false);
const loading = ref(false);
const loadingPull = ref(false);
const showPopup = ref(false); //筛选弹窗
onMounted(() => {
getList();
});
//下拉刷新
function onRefresh() {
cjxx.list = [];
cjxx.pageNum = 1;
kwd.value = "";
tabsIndex.value++;
getList();
}
// 获取警情信息
function getList() {
loading.value = true;
qcckGet({
pageCurrent: cjxx.pageNum,
pageSize: cjxx.pageSize,
cjsbRyXm: kwd.value,
cjsbLx: cjxx.cjsbLx
}, "/mosty-qwzx/tbQwCjbs/selectPage")
.then((res) => {
loading.value = false;
loadingPull.value = false;
if (!res.records || res.records.length <= 0) showEmpty.value = true;
if (cjxx.pageNum == 1) {
cjxx.list = res.records;
} else {
res.records.forEach((item) => {
cjxx.list.push(item);
});
}
total.value = res.pages;
})
.catch((err) => {
loading.value = false;
showEmpty.value = true;
});
}
/**
* 关键字搜索
* @param {Object} val
*/
function onSearch(val) {
cjxx.pageNum = 1;
getList();
}
// 弹框盒子
function onConfirm(val) {
cjxx.startTime = val.startTime;
cjxx.endTime = val.endTime;
let arr = [];
if (val.list) {
val.list[0].array.forEach((item) => {
if (item.isCheck) {
arr.push(item.value);
}
});
cjxx.cjsbLx = arr.join(",");
}
cjxx.pageNum = 1;
getList();
showPopup.value = false;
}
function onLoad() {
if (cjxx.pageNum >= total.value) {
finished.value = true;
return;
}
cjxx.pageNum += 1;
getList();
}
</script>
<style lang="scss" scoped>
.sticky_box {
margin-top: 13vw;
}
</style>

View File

@ -0,0 +1,131 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="处警报送" :showRight="isSeeInfo ? true : false" :showLeft="true" @clickRight="onClickRight" />
<div class="main_box">
<van-form @submit="onSubmit" class="form" :disabled="isSeeInfo ? false : true">
<van-field name="radio" label="警情类型">
<template #input>
<van-radio-group v-model="params.cjsbLx" direction="horizontal" :disabled="isSeeInfo ? false : true">
<van-radio :name="item.dm" v-for="item in D_QW_CJSBLX" :key="item">{{ item.zdmc }}</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field v-model="params.cjsbQk" name="cjsbQk" type="textarea" label="处警情况" placeholder="请输入处警情况"
:rules="[{ required: true, message: '请输入处警情况' }]" />
<van-field name="uploader" label="图片">
<template #input>
<van-uploader :disabled="isSeeInfo ? false : true" v-model="wpTpIdList" multiple :after-read="upLoadImg" />
</template>
</van-field>
<div style="margin: 16px" v-show="isSeeInfo">
<van-button round block type="primary" native-type="submit" :loading="isLoading" loading-type="spinner"
loading-text="提交中...">提交</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import { qcckGet, qcckPost } from "../../../api/qcckApi.js";
import ImageCompressor from "image-compressor.js";
import {
timeValidate
} from "../../../utils/tools.js";
import { ImagePreview } from "vant";
import { getMybbTodayNew } from "../../../api/common";
import { useRoute } from "vue-router";
import { onMounted, ref } from 'vue';
import { upImage } from "@/api/common";
import { hintToast } from "@/utils/tools";
import router from "@/router";
import { getDictList, setDict } from "../../../utils/dict";
const { D_QW_CJSBLX } = getDictList(
"D_QW_CJSBLX"
);
const route = useRoute();
const wpTpIdList = ref([]);
const isSeeInfo = ref(true);
const fileList = ref([])
const params = ref({
cjsbTpid: '',//图片
})
const baseUrl = ref("");
const workTips = ref();
// 上传图片
async function upLoadImg(file) {
file.message = "上传中...";
let fileBlob = await _compressImage(file.file);
let fileData = new File([fileBlob], fileBlob.name, { type: fileBlob.type });
const data = new FormData();
data.append("file", fileData);
upImage(data).then((res) => {
console.log(res, 'res');
file.status = "done";
file.message = "上传成功";
if (!fileList.value.includes(res)) fileList.value.push(res);
});
}
//压缩图片
const _compressImage = (file) => {
return new Promise((resolve, reject) => {
new ImageCompressor(file, {
quality: 0.6, //压缩质量
success(res) {
resolve(res);
},
error(e) {
reject(e);
},
});
});
};
const onSubmit = () => {
if (fileList.value.length > 0) params.value.cjsbTpid = fileList.value.join(',');
qcckPost(params.value, "/mosty-qwzx/tbQwCjbs/save").then(res => {
hintToast('添加成功')
router.back()
})
}
const onClickRight = () => {
router.push('/cjbsList')
}
const getImageUrl = (item) => {
return new Promise((ok) => {
qcckGet({}, `/mosty-base/minio/file/download/${item}`).then(res => {
ok(res.url);
})
});
}
onMounted(async () => {
if (route.query.item) {
isSeeInfo.value = false;
params.value = JSON.parse(route.query.item);
let imgId = params.value.cjsbTpid.split(',');
for (let i = 0; i < imgId.length; i++) {
const el = imgId[i];
wpTpIdList.value.push({ url: await getImageUrl(el) });
console.log(wpTpIdList.value, 'wpTpIdList.value');
}
}
})
</script>
<style lang="scss" scoped>
.main_box {
padding: 10px;
box-sizing: border-box;
}
::v-deep .van-radio {
margin-bottom: 4px;
}
::v-deep .van-radio__label--disabled{
color: #000!important;
}
::v-deep .van-field__label{
color: #000!important;
}
</style>

View File

@ -0,0 +1,132 @@
<template>
<div>
<TopNav navTitle="打卡记录" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Search placeholder="请输入人员姓名" v-model="kwd" :isSx="false" @update:sx="showPopup = !showPopup"
@update:modelValue="onSearch"></Search>
</div>
</van-sticky>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list v-model:loading="loading" :finished="finished" finished-text=" " @load="onLoad" offset="1"
:immediate-check="false">
<List v-for="(item, index) in yjxx.list" :key="index" :item="item" />
<van-empty description="暂无信息" image="default" v-if="yjxx.list.length <= 0 && showEmpty" />
</van-list>
</van-pull-refresh>
</div>
</template>
<script setup>
import { getRypcList, getRypcCount } from "../../../api/common.js";
import TopNav from "../../../components/topNav.vue";
import Search from "../../../components/search.vue";
import Tabs from "../../../components/tabs.vue";
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/clockList.vue";
import { setTimeQuantum } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, reactive, onMounted, watch } from "vue";
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
const showEmpty = ref(false);
const tabsIndex = ref(1);
const total = ref(0);
const tabs = ref([
{
name: "全部",
count: 0,
pclx: "",
},
{
name: "盘查",
count: 0,
pclx: "9",
},
{
name: "移交",
count: 0,
pclx: "2",
},
{
name: "放行",
count: 0,
pclx: "1",
},
]);
const yjxx = reactive({
pageNum: 1,
pageSize: 10,
yjJb: "",
yjLx: "",
startTime: "",
endTime: "",
yjLx: "",
sxList: [], //筛选条件数据
list: [], //预警列表数据
});
const kwd = ref("");
const finished = ref(false);
const loading = ref(false);
const loadingPull = ref(false);
const showPopup = ref(false); //筛选弹窗
onMounted(() => {
getList();
});
//下拉刷新
function onRefresh() {
yjxx.list = [];
yjxx.pageNum = 1;
kwd.value = "";
tabsIndex.value++;
getList();
}
// 获取警情信息
function getList() {
loading.value = true;
qcckPost({
pageCurrent: yjxx.pageNum,
pageSize: yjxx.pageSize,
dkrxm: kwd.value,
}, "/mosty-qwzx/tbQwXfbb/selectXfbbDkPage")
.then((res) => {
loading.value = false;
loadingPull.value = false;
if (!res.records || res.records.length <= 0) showEmpty.value = true;
if (yjxx.pageNum == 1) {
yjxx.list = res.records;
} else {
res.records.forEach((item) => {
yjxx.list.push(item);
});
}
total.value = res.pages;
})
.catch((err) => {
loading.value = false;
showEmpty.value = true;
});
}
/**
* 关键字搜索
* @param {Object} val
*/
function onSearch(val) {
yjxx.pageNum = 1;
getList();
}
function onLoad() {
if (yjxx.pageNum >= total.value) {
finished.value = true;
return;
}
yjxx.pageNum += 1;
getList();
}
</script>
<style lang="scss" scoped>
.sticky_box {
margin-top: 13vw;
}
</style>

View File

@ -0,0 +1,325 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="打卡" :showRight="true" :showLeft="true" @clickRight="onClickRight" />
<div class="main_box">
<!-- <div class="top_box">
<div class="left_top">
<div class="top_text">上班09:00:00</div>
<div class="tip_text">未打卡</div>
</div>
<div class="left_top">
<div class="top_text">下班09:00:00</div>
<div class="tip_text">未打卡</div>
</div>
</div> -->
<div class="upload_box">
<div class="image_box" v-if="baseUrl">
<van-icon name="close" class="close_icon" @click="clearImage" color="#000" size="24px" />
<van-image :src="baseUrl" @click="onClickImg(baseUrl)" style="flex: 1">
<template v-slot:loading>
<van-loading type="spinner" size="20" />
</template>
</van-image>
</div>
<div class="upload_icon_box" v-else>
<van-icon @click="photoFn" name="plus" />
</div>
<!-- <van-uploader v-model="clockList" :max-count="1" :after-read="afterRead" capture="camera"
:before-read="beforeRead" accept="image/*" /> -->
<div class="upload_tip"><span style="color: red;">*</span>须拍摄实景图才可进行打卡</div>
</div>
<div class="dk_box">
<div class="circle_box" @click="workFn">
{{ workTips ? workTips : '打卡' }}
</div>
<!-- <div class="dk_tip" v-show="rangeShow"><van-icon name="checked" color="#08B353" />已进入考勤范围德阳市某某某</div>
<div class="dk_tip" v-show="!rangeShow"><van-icon name="clear" color="red" />未进入考勤范围德阳市某某某</div> -->
</div>
<!-- <div class="bzt_box">
<div style="color: #75787F;">时间轴</div>
<van-steps direction="vertical" :active="-1" active-color="#1DB1FF">
<van-step>
<div style="color:#000">上班打卡</div>
<img src="@/assets/images/menu-dk.png" alt="">
</van-step>
<van-step style="color:#000">
<div>下班打卡</div>
<img src="@/assets/images/menu-dk.png" alt="">
</van-step>
</van-steps>
</div> -->
<div class="choose_dw">
<van-button type="primary" block @click="chooseDwFn">{{ workTips ? workTips : '点位选择' }}</van-button>
<van-popup v-model:show="showPicker" position="bottom">
<van-picker :columns="columns" @confirm="onConfirm" @cancel="showPicker = false" />
</van-popup>
</div>
</div>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import { qcckGet, qcckPost } from "../../../api/qcckApi.js";
import ImageCompressor from "image-compressor.js";
import {
timeValidate
} from "../../../utils/tools.js";
import { ImagePreview } from "vant";
import { getMybbTodayNew } from "../../../api/common";
import { onMounted, ref } from 'vue';
import { upImage } from "@/api/common";
import { hintToast } from "@/utils/tools";
import router from "@/router";
const clockList = ref();
const rangeShow = ref(true);
const showPicker = ref(false);
const columns = ref([
]);
const params = ref({
bbid: "",//报备id,
bxdid: "",//必巡id
tpid: '',//附件
})
const baseUrl = ref("");
const workTips = ref()
const Loadtion = ref({
jd: "暂无",
wd: "暂无",
radius: 5000
});
// 文件预览
async function afterRead(file) {
file.message = "上传中...";
let fileBlob = await _compressImage(file.file);
let fileData = new File([fileBlob], fileBlob.name, { type: fileBlob.type });
const data = new FormData();
data.append("file", fileData);
file.status = "uploading";
upImage(data).then((res) => {
console.log(res, 'res');
file.status = "done";
file.message = "上传成功";
params.value.tpid = res;
});
}
const beforeRead = (file) => {
// 判断相册里面的照片是不是最新拍摄的照片
let timestamp = file.lastModified;
let newTime = new Date().getTime() - 5 * 60 * 1000;
if (timestamp < newTime) {
hintToast('请重新拍摄最新时间的拍照')
return true
} else {
return true
}
}
const photoFn = () => {
try {
bridge.pZ("photo");
} catch (err) {
console.log(err, 'err');
}
}
//预览图片
function onClickImg(url) {
ImagePreview([url]);
}
// 删除图片
const clearImage = () => {
baseUrl.value = ""
}
//压缩图片
const _compressImage = (file) => {
return new Promise((resolve, reject) => {
new ImageCompressor(file, {
quality: 0.6, //压缩质量
success(res) {
resolve(res);
},
error(e) {
reject(e);
},
});
});
};
//获取当前位置信息
function _getUserLocation(sfdw) {
let { lng, lat, zbly } = getLocation();
if (lng && lat) {
Loadtion.value.jd = lng;
Loadtion.value.wd = lat;
getBxList()
} else {
hintToast("暂无坐标信息");
}
}
const chooseDwFn = () => {
showPicker.value = true;
}
const onConfirm = (e) => {
workTips.value = e.text;
params.value.bxdid = e.value;
showPicker.value = false;
}
// 上班打卡
const workFn = () => {
if (params.value.tpid == '') {
hintToast('请拍照再打卡');
return
}
qcckPost(params.value, "/mosty-qwzx/tbQwXfbb/addXfbbDk").then(res => {
hintToast('打卡成功');
router.back()
})
}
const onClickRight = () => {
router.push('/clockList')
}
// 获取报备id
const getBbInfo = () => {
getMybbTodayNew().then(res => {
params.value.bbid = res ? res.id : '';
})
}
// 获取必训点
const getBxList = () => {
qcckGet(Loadtion.value, "/mosty-jcgl/tbJcglBxd/selectNearbyList").then(res => {
console.log(res, 'res');
columns.value = res.map((item) => {
return { text: item.bxdMc, value: item.id }
})
})
}
function setimage_base64(pzid, base64) {
console.log(base64, 'base64');
baseUrl.value = `data:image/jpeg;base64,${base64}`;
qcckPost({base64:base64}, "/mosty-base/minio/image/upload/base64").then(res => {
params.value.tpid = res;
})
}
function btof(data, fileName) {
const dataArr = data.split(',')
const byteString = atob(dataArr[1])
const options = {
type: 'image/jpeg',
endings: 'native'
}
const u8Arr = new Uint8Array(byteString.length)
for (let i = 0; i < byteString.length; i++) {
u8Arr[i] = byteString.charCodeAt(i)
}
return new File([u8Arr], fileName + '.jpg', options)
}
onMounted(() => {
getBbInfo();
_getUserLocation(true); //获取当前位置
setInterval(() => {
// _getUserLocation(false); //获取当前位置
}, 5000);
window.setimagebase64 = setimage_base64;
})
</script>
<style lang="scss" scoped>
.main_box {
padding: 10px;
box-sizing: border-box;
}
.top_box {
display: flex;
justify-content: space-between;
margin-bottom: 10px;
.left_top {
width: 48%;
height: 80px;
padding: 10px;
box-sizing: border-box;
top: 61px;
left: 10px;
gap: 0px;
border-radius: 10px;
opacity: 0px;
background-color: #EDEDED;
.tip_text {
color: #75787F;
margin-top: 6px;
}
}
}
.upload_box {
display: flex;
.upload_tip {
color: #75787F;
font-size: 13px;
}
.image_box {
position: relative;
width: 160px;
height: 100px;
.close_icon {
position: absolute;
right: 0;
top: 0;
z-index: 20;
}
::v-deep .van-image {
width: 100%;
}
}
.upload_icon_box {
border: 1px solid #ccc;
text-align: center;
width: 160px;
height: 100px;
line-height: 100px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
}
}
.dk_box {
text-align: center;
.dk_tip {
color: #707070;
margin-top: 6px;
}
}
.circle_box {
width: 160px;
height: 160px;
line-height: 160px;
margin: 0 auto;
margin-top: 40%;
border-radius: 50%;
color: #fff;
font-size: 20px;
text-align: center;
background: linear-gradient(to bottom, #1DB1FF, #007DE9);
}
.choose_dw {
position: absolute;
bottom: 0;
width: 100%;
left: 0;
}
</style>

View File

@ -0,0 +1,107 @@
<template>
<ul class="box-rank">
<li class="item">
<div class="text title">日期</div>
<div class="text title">执勤时间</div>
<div class="text title">执勤状态</div>
</li>
<li class="item" v-for="(item, index) in data" :key="index" @click="routePush(item)">
<div class="text title">{{ item.time }}</div>
<div class="text title">{{ item.zqsj }}</div>
<div class="text title" :class="item.zqzt == '请假' ? 'red' : item.zqzt == '未执勤' ? '' : 'green'
">
{{ item.zqzt }}
</div>
</li>
<van-empty description="暂无信息" image="default" v-if="data.length <= 0 && !loading" />
</ul>
</template>
<script setup>
import { ref, defineExpose, watch, onMounted } from "vue";
import { useRouter } from "vue-router";
const router = useRouter();
const props = defineProps({
listData: { type: Array },
});
watch(
() => props.listData,
() => {
data.value = props.listData;
},
{ deep: true }
);
function routePush(row) {
const timeDay = new Date()
let y = timeDay.getFullYear()
let m = timeDay.getMonth() + 1 < 10 ? '0' + (timeDay.getMonth() + 1) : timeDay.getMonth() + 1
let d = timeDay.getDate() < 10 ? '0' + timeDay.getDate() : timeDay.getDate()
const dtime = y + '-' + m + '-' + d
if (row.zt === "04") {
return false;
} else {
router.push({
path: "/xfbbInfo",
query: {
zt: row.zt,
pbid: row.zt === '01' ? row.id : null,
bbid: row.zt === '01' ? null : row.id,
isDay: dtime === row.time ? 1 : 0
},
});
}
}
const loading = ref(false);
const data = ref([]);
onMounted(() => {
data.value = props.listData;
})
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.box-rank {
width: 100%;
height: 100%;
.item {
display: flex;
align-items: center;
justify-content: center;
height: 8vw;
@include font_size($font_medium_s);
@include font_color($font-color-theme);
.text {
flex: 1;
text-align: center;
}
.mc {
color: #3e6ee8;
}
}
.item:nth-child(2n + 1) {
@include table_item_color($table-item-theme);
}
.item:nth-child(1) {
background: #3e6ee8 !important;
color: #fff;
}
.red {
color: red !important;
}
.green {
color: #88e9af;
}
.blue {
color: #3e6ee8;
}
}
</style>

View File

@ -0,0 +1,107 @@
<template>
<ul class="box-rank">
<li class="item">
<div class="text title">日期</div>
<div class="text title">执勤时间</div>
<div class="text title">执勤状态</div>
</li>
<li class="item" v-for="(item, index) in data" :key="index" @click="routePush(item)">
<div class="text title">{{ item.time }}</div>
<div class="text title">{{ item.zqsj }}</div>
<div class="text title" :class="item.zqzt == '请假' ? 'red' : item.zqzt == '未值班' ? '' : 'green'
">
{{ item.zqzt }}
</div>
</li>
<van-empty description="暂无信息" image="default" v-if="data.length <= 0 && !loading" />
</ul>
</template>
<script setup>
import { ref, defineExpose, watch, onMounted } from "vue";
import { useRouter } from "vue-router";
const router = useRouter();
const props = defineProps({
listData: { type: Array },
});
watch(
() => props.listData,
() => {
data.value = props.listData;
},
{ deep: true }
);
function routePush(row) {
const timeDay = new Date()
let y = timeDay.getFullYear()
let m = timeDay.getMonth() + 1 < 10 ? '0' + (timeDay.getMonth() + 1) : timeDay.getMonth() + 1
let d = timeDay.getDate() < 10 ? '0' + timeDay.getDate() : timeDay.getDate()
const dtime = y + '-' + m + '-' + d
if (row.zt === "04") {
return false;
} else {
router.push({
path: "/yyzx/views/addZbbbInfo",
query: {
zt: row.zt,
id: row.id,
flag: dtime === row.time ? 1 : 0,
text: row.zqzt
},
});
}
}
const loading = ref(false);
const data = ref([]);
onMounted(() => {
data.value = props.listData;
})
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.box-rank {
width: 100%;
height: 100%;
.item {
display: flex;
align-items: center;
justify-content: center;
height: 8vw;
@include font_size($font_medium_s);
@include font_color($font-color-theme);
.text {
flex: 1;
text-align: center;
}
.mc {
color: #3e6ee8;
}
}
.item:nth-child(2n + 1) {
@include table_item_color($table-item-theme);
}
.item:nth-child(1) {
background: #3e6ee8 !important;
color: #fff;
}
.red {
color: red !important;
}
.green {
color: #88e9af;
}
.blue {
color: #3e6ee8;
}
}
</style>

View File

@ -0,0 +1,446 @@
<template>
<div class="container">
<van-form>
<div class="title_tab">值班班次</div>
<van-cell title="值班日期" @click="calShow = true">
<template #value>
<span>{{ chooseTime }}</span>
</template>
</van-cell>
<van-calendar v-model:show="calShow" @confirm="onConfirm" :min-date="minDate" :max-date="maxDate"
color="#3e6ee8"></van-calendar>
<van-field v-model="normalForm.bcmc" name="班次" is-link readonly label="班次" placeholder="请选择班次" input-align="right"
@click="showDialogfn('qwbc')" />
<van-field readonly v-if="normalForm.bcsc" v-model="normalForm.bcsc" input-align="right" label="班次时段" />
<div class="title_tab">值班人员</div>
<van-field v-model="normalForm.zbld" name="值班领导" required input-align="right" label="值班领导" is-link readonly
placeholder="请值班领导" :rules="[{ required: true, message: '请选择值班领导' }]" @click="showDialogfn('zbld')" />
<van-field v-model="normalForm.zhz" readonly input-align="right" name="picker" label="指挥长" placeholder="请选择指挥长"
@click="showDialogfn('zhz')" is-link />
<van-field v-model="normalForm.zzzhz" readonly input-align="right" name="picker" label="专职指挥长"
placeholder="请选择专职指挥长" @click="showDialogfn('zzzhz')" is-link />
<van-field v-model="normalForm.fz" readonly input-align="right" name="picker" label="法制" placeholder="请选择法制"
@click="showDialogfn('fz')" is-link />
<van-cell class="mulSelect" title="值班民警" color="#1989fa">
<template #right-icon>
<van-icon @click.stop="showDialogfn('mj')" name="add-o" color="#1989fa" size="22" />
</template>
<template #default>
<div class="selected-box">
<div class="check-item-tag" v-for="(item, index) in list.mj" :key="index">
<van-tag color="#7232dd" closeable @close="deleteCheckTag(item, index, 'mj')" plain>{{ item.jlxm
}}</van-tag>
</div>
</div>
</template>
</van-cell>
<van-cell class="mulSelect" title="值班辅警" color="#1989fa">
<template #right-icon>
<van-icon @click.stop="showDialogfn('fj')" name="add-o" color="#1989fa" size="22" />
</template>
<template #default>
<div class="selected-box">
<div class="check-item-tag" v-for="(item, index) in list.fj" :key="index">
<van-tag closeable @close="deleteCheckTag(item, index, 'fj')" color="#7232dd" plain>{{ item.jlxm
}}</van-tag>
</div>
</div>
</template>
</van-cell>
<div class="title_tab">联系方式</div>
<van-field v-model="normalForm.zbdh" name="值班电话" label="值班电话" type="tel" placeholder="请选择值班电话"
input-align="right" />
<van-field v-model="normalForm.hh" name="呼号" label="呼号" type="digit" placeholder="请输入呼号" input-align="right" />
<div style="margin: 16px 0; padding: 0 5vw">
<van-button style="margin: 16px 0" round @click="editFn()" block type="success" v-if="list.bbInfo">
结束报备
</van-button>
<van-button round @click="_submitZbbbData" block type="primary" v-else>
开始报备
</van-button>
</div>
</van-form>
<!-- 负责人 -->
<Select bclx="01" :checked="r_checked" :selectType="selectType" :show="showSelect" :checkedList="list.checkedList"
@update:cancel="showSelect = false" @update:confirm="onComfirm" :key="selectIndex" />
</div>
</template>
<script setup>
import { Dialog, Toast } from "vant";
import { dateFormat, timeValidate, hintToast } from "../../../utils/tools.js";
import { computed, ref, reactive, onMounted, watch, defineEmits } from "vue";
import { useRouter, useRoute } from "vue-router";
import Select from "../../../components/Select.vue";
import {
getMyZbbbData,
getMyZbpbData,
submitZbbbData,
startAndEndZbbbData,
endTaskStatus,
} from "../../../api/yyzxApi.js";
import { getBcList, getXfqList, getKfdList } from "../../../api/xfbbAndZbbb.js";
const router = useRouter();
const route = useRoute();
const emit = defineEmits(["setTitle"]);
//表单数据
const normalForm = reactive({
bcmc: "",
bcsc: "",
zbld: "",
zhz: "",
zzzhz: "",
fz: "",
hh: "",
bcsc: "",
zbdh: "",
});
//选择数据
const list = reactive({
mj: [], //选中的民警数据
fj: [], //选中的辅警数据
bcList: [], //班次信息
bpInfo: { zbmj: [], zbfj: [], jlList: [], zbpbId: "", zbrq: "", qwbcid: "" }, //无报备的排班信息
bbInfo: null, //报备信息
checkedList: [], //默认选中的民辅警数据
});
const showSelect = ref(false);
const r_checked = ref(""); //单选框默认选中
const selectIndex = ref(1); //选择器组件KEY
const selectType = ref(""); //选择的类型
// 巡防日期
const minDate = new Date(2000, 0, 1);
const maxDate = new Date(2050, 0, 1);
const calShow = ref(false);
const chooseTime = ref(timeValidate(new Date(), "ymd"));
const titleTime = ref();
function onConfirm(val) {
calShow.value = false;
chooseTime.value = timeValidate(val, "ymd");
titleTime.value = timeValidate(val, "ymd");
}
onMounted(() => {
_getBcData();
_getMyZbbbData();
});
//确认选择
function onComfirm(val) {
if (val.length <= 0) return;
switch (selectType.value) {
case "qwbc":
r_checked.value = val[0].key;
onbcConfirm(val[0]);
break;
case "zbld":
case "zhz":
case "zzzhz":
case "fz":
if (r_checked.value == val[0].key) {
r_checked.value = "";
if (selectType.value == "zbld") normalForm.zbld = "";
if (selectType.value == "zhz") normalForm.zhz = "";
if (selectType.value == "zzzhz") normalForm.zzzhz = "";
if (selectType.value == "fz") normalForm.fz = "";
} else {
r_checked.value = val[0].key;
onfzrConfirm(val[0]);
}
break;
case "mj":
// list.mj = [];
val.forEach((item) => {
list.checkedList.push(item.key);
toggle(item);
});
break;
case "fj":
// list.fj = [];
val.forEach((item) => {
list.checkedList.push(item.key);
toggle(item);
});
break;
}
}
//打开选择框
function showDialogfn(val) {
if (selectType.value !== val) r_checked.value = "";
selectType.value = val;
showSelect.value = true;
selectIndex.value++;
}
//开始报备
function _submitZbbbData() {
Reflect.deleteProperty(list.bpInfo, "zbmj");
Reflect.deleteProperty(list.bpInfo, "zbfj");
list.bpInfo.jlList = [...list.fj, ...list.mj];
if (!list.bpInfo.id) {
hintToast("没有排班信息");
return;
}
list.bpInfo.zbpbId = list.bpInfo.id; //排班ID
list.bpInfo.zbrq = dateFormat();
submitZbbbData(list.bpInfo).then((res) => {
hintToast("成功");
_startZbbbData(res, 0);
_endTaskStatus("04", list.bpInfo.mrjlid, 2);
});
}
//结束任务
function _endTaskStatus(rwxl, ywid, rwzt) {
let data = { rwxl, ywid, rwzt };
try {
let location = JSON.parse(bridge.getLocation());
data.jd = location.app_x;
data.wd = location.app_y;
} catch (error) { }
endTaskStatus(data).then((res) => { });
}
//结束报备
function editFn() {
Dialog.confirm({
title: "提示",
message: "是否确认结束报备!",
confirmButtonColor: "#3e6ee8",
}).then((res) => {
_startZbbbData(list.bbInfo.id, 1);
});
}
//提交开始||结束报备
function _startZbbbData(id, bbzt) {
startAndEndZbbbData({ id, bbzt }).then((res) => {
list.bpInfo = null;
router.go(-1);
});
}
//获取我的值班报备信息
function _getMyZbbbData() {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
getMyZbbbData()
.then((res) => {
if (res) {
list.bbInfo = res;
emit("setTitle", "值班报备信息");
_setHxData(res);
Toast.clear();
} else {
//没有报备信息调用
_getMyZbpbData();
}
})
.catch((err) => {
Toast.clear();
});
}
//获取我的值班排班信息
function _getMyZbpbData() {
getMyZbpbData().then((res) => {
//回显班次数据
emit("setTitle", "值班排班信息");
if (res) {
_setHxData(res);
list.bpInfo = res;
} else {
hintToast("没有值班和排班信息");
}
Toast.clear();
});
}
//设置页面回显
function _setHxData(res) {
let info = list.bcList.find((item) => {
return item.id == res.qwbcid;
});
if (info) onbcConfirm(info);
//值班人
normalForm.zbld = `${res.zbldXm ? res.zbldXm : ""} ${res.zbldDh ? res.zbldDh : ""
}`;
normalForm.zbdh = res.zbldDh ? res.zbldDh : "";
normalForm.zhz = `${res.zbzhzXm ? res.zbzhzXm : ""} ${res.zbzhzDh ? res.zbzhzDh : ""
}`;
normalForm.zzzhz = `${res.zzzhzXm ? res.zzzhzXm : ""} ${res.zzzhzDh ? res.zzzhzDh : ""
}`;
normalForm.fz = `${res.fzzbXm ? res.fzzbXm : ""} ${res.fzzbDh ? res.fzzbDh : ""
}`;
//呼号
normalForm.hh = res.hh;
//民辅警
list.mj = JSON.parse(res.zbmj);
list.fj = JSON.parse(res.zbfj);
}
//选中的班次数据
function onbcConfirm(val) {
list.bpInfo.qwbcid = val.id;
normalForm.bcmc = val.bcmc;
normalForm.bcsc = `${val.kssj} - ${val.jssj}`;
}
//获取班次数据
function _getBcData() {
return new Promise((ok) => {
let data = {
type: 2,
keyword: "",
bclx: "01",
};
getBcList(data).then((res) => {
if (res) {
for (let i = 0; i < res.length; i++) {
res[i].value = `${res[i].ssbm}-${res[i].bcmc}`;
res[i].key = res[i].id;
}
list.bcList = res;
}
ok();
});
});
}
//选中领导数据
function onfzrConfirm(val) {
switch (selectType.value) {
case "zbld":
normalForm.zbld = `${val.xm} ${val.lxdh}`;
normalForm.zbdh = val.lxdh;
break;
case "zhz":
normalForm.zhz = `${val.xm} ${val.lxdh}`;
break;
case "zzzhz":
normalForm.zzzhz = `${val.xm} ${val.lxdh}`;
break;
case "fz":
normalForm.fz = `${val.xm} ${val.lxdh}`;
break;
}
}
//删除选中的民辅警数据
function deleteCheckTag(item, index, val) {
switch (val) {
case "mj":
list.mj.splice(index, 1);
break;
case "fj":
list.fj.splice(index, 1);
break;
}
}
//选中民辅警数据
const toggle = (item) => {
switch (selectType.value) {
case "mj":
list.mj.push({
jh: item.jh,
jllx: item.fl,
jlxm: item.xm,
sfzh: item.sfzh,
xm: item.xm,
lxdh: item.lxdh,
xbdm: item.xbdm,
id: item.ryid,
qwjzId: "",
jlId: item.ryid,
});
break;
case "fj":
list.fj.push({
jh: item.jh,
jllx: item.fl,
jlxm: item.xm,
id: item.id,
sfzh: item.sfzh,
xm: item.xm,
lxdh: item.lxdh,
xbdm: item.xbdm,
qwjzId: "",
jlId: item.id,
});
break;
}
};
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.popupTitle {
text-align: center;
background-color: rgb(11, 137, 247);
height: 6vh;
line-height: 6vh;
}
.popbtn-box {
width: 100%;
display: flex;
justify-content: space-around;
}
.check-item-tag {
display: inline-block;
margin: 0 6px;
}
.check-data-box {
height: 25vh;
overflow: auto;
}
.time-box {
display: flex;
}
::v-deep .mulSelect .van-cell__title,
.van-cell__value {
flex: unset;
}
::v-deep .mulSelect .van-cell__value {
flex: 1;
}
.title_tab {
@include font_color($font-color-theme);
padding-left: 7vw;
position: relative;
margin: 2vw 0;
letter-spacing: 2px;
}
.title_tab::after {
content: "";
position: absolute;
top: 0;
left: 5vw;
bottom: 0;
width: 4px;
background: #3b6be7;
border-radius: 2px;
}
.van-cell:after {
display: none;
}
.van-cell {
@include table_item_color($table-item-theme);
box-sizing: border-box;
border-radius: 4px;
padding: 6px;
margin: 8px 5%;
width: 90%;
overflow: hidden;
color: var(--van-cell-text-color);
font-size: var(--van-cell-font-size);
line-height: var(--van-cell-line-height);
}
.popupTitle {
color: #fff;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,462 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="部门巡防报备清单" :showLeft="true" />
<div class="calenderBox">
<div class="calender-head">
<div class="btn" @click="last">
<van-icon name="arrow-left" color="#fff" />
</div>
<div class="text">{{ Year }}{{ month }}</div>
<div class="btn" @click="next">
<van-icon name="arrow" color="#fff" />
</div>
</div>
<!-- 日历 -->
<div class="list">
<ul class="week">
<li class="days" v-for="(item, index) in week" :key="index">
{{ item }}
</li>
</ul>
<div class="wrap">
<div @click="checkDay(Year + '-' + month + '-' + item.value)" class="item"
v-for="(item, index) in calendarList" :key="index">
<div class="num" :class="calendarActive == Year + '-' + month + '-' + item.value ? 'active' : ''">
{{ item.value }}<span v-show="item.value"></span>
</div>
<div class="status" v-show="item.value">
<div v-for="item2 in item.list" :key="item2.id">
<span @click="itemClick(item)" v-show="item.value" :style="{ background: item.color }">{{ item2.fzrXm }}
{{ item2.kssj.split(":")[0] + ":" + item2.kssj.split(":")[1] }}
{{ item2.jssj.split(":")[0] + ":" + item2.jssj.split(":")[1] }}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-for="item in zbInfo.list" :key="item.id" class="list-item item_box">
<div class="title">部门巡防报备详情</div>
<div>
<div class="num-text">负责人{{ item.fzrXm }}</div>
<div class="num-text">
巡防民警{{ checkJSON(item.pbmj, 'jlxm') }}
</div>
<div class="num-text">
巡防辅警{{ checkJSON(item.pbfj, 'jlxm') }}
</div>
<div class="num-text">
巡防车辆{{ checkJSON(item.pbcl, 'jdchphm') }}
</div>
<div class="num-text">负责人电话{{ item.fzrLxdh }}</div>
<div class="num-text">巡防时间{{ item.kssj }} - {{ item.jssj }}</div>
</div>
</div>
<div v-if="zbInfo.list.length === 0" style="text-align: center; padding: 12px 0; color: #828282">
暂无今日报备
</div>
</div>
</template>
<script setup>
import { getXfbbByMonth } from "../../../api/calender";
import TopNav from "../../../components/topNav.vue";
import { onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
import { Toast } from "vant";
const zbInfo = ref({
list: [],
});
const router = useRouter();
const week = ref(["周日", "周一", "周二", "周三", "周四", "周五", "周六"]);
const Year = ref(new Date().getFullYear()); //日历上的年份
const month = ref(new Date().getMonth() + 1); //日历上的月份
const Day = ref(new Date().getDate()); //日历上的天份
const nowYear = ref(new Date().getFullYear());
const nowmonth = ref(new Date().getMonth() + 1);
const nowDay = ref(new Date().getDate());
//日历选中高亮
const calendarActive = ref("");
const starttime = ref("");
const endtime = ref("");
const nowtime = ref("");
const calendarList = ref([]);
onMounted(() => {
Draw(nowYear.value, nowmonth.value);
let time_month = nowmonth.value; //现在的月份
let time_day = nowDay.value; //现在的天数
if (nowmonth.value < 10) {
time_month = 0 + "" + nowmonth.value;
}
if (nowDay.value < 10) {
time_day = 0 + "" + nowDay.value;
}
nowtime.value = nowYear.value + "-" + time_month + "-" + time_day;
calendarActive.value =
nowYear.value + "-" + nowmonth.value + "-" + nowDay.value;
starttime.value = nowtime.value;
endtime.value = nowtime.value;
});
//处理JSON数据
function checkJSON(row, key) {
var data = []
try {
data = JSON.parse(row)
} catch (error) {
data = []
}
var str = ''
try {
str = data.map(item => item[key]).join(',')
} catch (error) {
}
return !str ? '暂无' : str
}
function itemClick(e) {
zbInfo.value = e;
}
//状态字典
const ztDict = [
{
label: "无报备",
value: "00",
color: "#7b7b7b",
},
{
label: "有报备",
value: "01",
color: "#51fb06",
},
{
label: "今日报备",
value: "02",
color: "#51fb06",
},
{
label: "今日排班",
value: "03",
color: "#7b7b7b",
},
{
label: "无",
value: "04",
color: "#7b7b7b",
},
{
label: "有排班",
value: "05",
color: "#7b7b7b",
},
{
label: "无排班",
value: "06",
color: "#7b7b7b",
},
];
//状态数据处理
function checkZt(list = []) {
var zt = [];
if (list.length > 0) {
zt = list.map((item) => {
return {
text: ztDict.filter((item2) => item2.value === item.zt)[0].label,
color: ztDict.filter((item2) => item2.value === item.zt)[0].color,
id: item.id,
zt: item.zt,
};
});
}
return zt;
}
const isToday = ref(true);
function Draw(Year, Month) {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
getXfbbByMonth({ time: Year + "-" + Month })
.then((res) => {
const copyRes = JSON.parse(JSON.stringify(res)).map((c) => {
var ccc = [];
if (!c.list) {
ccc = [];
} else {
ccc = c.list.map((ci) => {
return {
...ci,
zt: c.type,
};
});
}
return {
...c,
label: ztDict.filter((item2) => item2.value === c.type)[0].label,
color: ztDict.filter((item2) => item2.value === c.type)[0].color,
list: ccc,
};
});
calendarList.value = copyRes.map((item, index) => {
return {
value: index + 1,
kssj: "20:00", //假数据
jssj: "23:59",
status: checkZt(item.list), //假的状态
count: Year + "-" + Month + "-" + item.day,
...item,
};
});
if (isToday.value) {
var toTime = new Date();
var m =
toTime.getMonth() < 9
? "0" + (toTime.getMonth() + 1)
: toTime.getMonth() + 1;
var d = toTime.getDay() < 10 ? "0" + toTime.getDay() : toTime.getDay();
var toDay = toTime.getFullYear() + "-" + m + "-" + d;
calendarList.value.forEach((v) => {
if (v.time === toDay) {
zbInfo.value = v;
isToday.value = false;
}
});
}
for (
var i = 1, firstDay = new Date(Year, Month - 1, 1).getDay();
i <= firstDay;
i++
) {
calendarList.value.unshift("");
}
Toast.clear();
})
.catch((err) => {
Toast.clear();
});
}
function checkDay(val) {
calendarActive.value = val;
}
// 上个月
function last() {
month.value--;
if (month.value == 0) {
month.value = 12;
Year.value--;
}
Draw(Year.value, month.value);
}
// 下个月
function next() {
month.value++;
if (month.value == 13) {
month.value = 1;
Year.value++;
}
Draw(Year.value, month.value);
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.calenderBox {
width: 100%;
padding: 1vw;
box-sizing: border-box;
.calender-head {
width: 100%;
height: 15vw;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-weight: bold;
line-height: 40px;
position: relative;
.change {
position: absolute;
right: 1vw;
bottom: 2vw;
cursor: pointer;
color: #3e6ee8;
@include font_size($font_medium_s);
}
.btn {
width: 7vw;
height: 7vw;
line-height: 7vw;
text-align: center;
border-radius: 1vw;
background: #3e6ee8;
color: #fff;
}
.text {
margin: 0 4vw;
@include font_color($font-color-theme);
}
}
.week {
width: 100%;
display: flex;
flex-wrap: nowrap;
text-align: center;
height: 10vw;
line-height: 10vw;
background: #164acc;
color: #fff;
.days {
flex: 1;
}
}
.wrap {
width: 100%;
display: flex;
flex-wrap: wrap;
.item {
width: calc((100% / 7) - 1.3px);
border: 1px solid #3e6ee8;
border-top: none;
font-size: 10px;
min-height: 15vw;
.num {
text-align: right;
padding-right: 1vw;
box-sizing: border-box;
@include font_color($font-color-theme);
}
.num.active {
color: #1adb10;
}
.status {
text-align: center;
margin: 1vw 0;
span {
background: #3e6ee8;
padding: 1px 1vw;
display: block;
width: 10vw;
color: #fff;
border-radius: 1vw;
margin: 6px auto;
}
.green {
background: #1adb10;
}
.gray {
background: #83868f;
}
}
.time {
font-size: 10px;
// height: 5vw;
// line-height: 7vw;
color: #3e6ee8;
text-align: center;
}
.greenColor {
color: #1adb10;
}
.grayColr {
color: #83868f;
}
.BlueColor {
color: #3e6ee8;
}
}
.item:nth-child(7n + 2) {
border-left: none;
}
.item:nth-child(7n + 3) {
border-left: none;
}
.item:nth-child(7n + 4) {
border-left: none;
}
.item:nth-child(7n + 5) {
border-left: none;
}
.item:nth-child(7n + 6) {
border-left: none;
}
.item:nth-child(7n + 7) {
border-left: none;
}
}
}
.list {
// max-height: calc(100vh - 35vw);
// overflow: hidden;
// overflow-y: auto;
}
.list-item {
padding: 3vw;
margin: 2vh 5vw;
border-radius: 2vw;
.phone-icon {
position: absolute;
right: 5vw;
}
.address-box {
display: flex;
justify-content: space-between;
.adress-left {
color: #3e6ee8;
}
}
.name-text {
@include font_size($font_medium);
color: #3e6ee8;
margin-bottom: 1vh;
font-weight: bold;
display: flex;
justify-content: flex-start;
align-items: center;
}
.title {
@include font_size($font_medium);
font-weight: 550;
}
.num-text {
@include font_size($font_medium_s);
color: #2b2b2b;
padding: 4px 0;
}
}
</style>

View File

@ -0,0 +1,461 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="部门值班报备清单" :showLeft="true" />
<div class="calenderBox">
<div class="calender-head">
<div class="btn" @click="last">
<van-icon name="arrow-left" color="#fff" />
</div>
<div class="text">{{ Year }}{{ month }}</div>
<div class="btn" @click="next">
<van-icon name="arrow" color="#fff" />
</div>
</div>
<!-- 日历 -->
<div class="list">
<ul class="week">
<li class="days" v-for="(item, index) in week" :key="index">
{{ item }}
</li>
</ul>
<div class="wrap">
<div @click="checkDay(Year + '-' + month + '-' + item.value)" class="item"
v-for="(item, index) in calendarList" :key="index">
<div class="num" :class="calendarActive == Year + '-' + month + '-' + item.value
? 'active'
: ''
">
{{ item.value }}<span v-show="item.value"></span>
</div>
<div class="status" v-show="item.value">
<div v-for="item2 in item.list" :key="item2.id">
<span @click="itemClick(item)" v-show="item.value" :style="{ background: item.color }">{{ item2.zbldXm
}}
{{
item2.kssj.split(":")[0] + ":" + item2.kssj.split(":")[1]
}}
{{
item2.jssj.split(":")[0] + ":" + item2.jssj.split(":")[1]
}}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="list-item item_box">
<div class="title">部门值班报备详情</div>
<div v-for="item in zbInfo.list" :key="item.id">
<div class="num-text">值班领导{{ item.zbldXm }}</div>
<div class="num-text" v-if="item.zbmj && item.zbmj.length > 0">
值班民警{{
JSON.parse(item.zbmj)
.map((jl) => jl.jlxm)
.join("、") || "暂无"
}}
</div>
<div class="num-text" v-if="item.zbfj && item.zbfj.length > 0">
值班辅警{{
JSON.parse(item.zbfj)
.map((jl) => jl.jlxm)
.join("、") || "暂无"
}}
</div>
<div class="num-text">值班电话{{ item.zbldDh }}</div>
<div class="num-text">值班时间{{ item.kssj }} - {{ item.jssj }}</div>
</div>
</div>
<div v-if="zbInfo.list.length === 0" style="text-align: center; padding: 12px 0; color: #828282">
无今日值班
</div>
</div>
</template>
<script setup>
import { getDeptByMonth } from "../../../api/calender";
import TopNav from "../../../components/topNav.vue";
import { onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
import { Toast } from "vant";
const zbInfo = ref({
list: [],
});
//日历选中高亮
const calendarActive = ref("");
const router = useRouter();
const week = ref(["周日", "周一", "周二", "周三", "周四", "周五", "周六"]);
const Year = ref(new Date().getFullYear()); //日历上的年份
const month = ref(new Date().getMonth() + 1); //日历上的月份
const Day = ref(new Date().getDate()); //日历上的天份
const nowYear = ref(new Date().getFullYear());
const nowmonth = ref(new Date().getMonth() + 1);
const nowDay = ref(new Date().getDate());
const starttime = ref("");
const endtime = ref("");
const nowtime = ref("");
const calendarList = ref([]);
onMounted(() => {
Draw(nowYear.value, nowmonth.value);
let time_month = nowmonth.value; //现在的月份
let time_day = nowDay.value; //现在的天数
if (nowmonth.value < 10) {
time_month = 0 + "" + nowmonth.value;
}
if (nowDay.value < 10) {
time_day = 0 + "" + nowDay.value;
}
nowtime.value = nowYear.value + "-" + time_month + "-" + time_day;
calendarActive.value =
nowYear.value + "-" + nowmonth.value + "-" + nowDay.value;
starttime.value = nowtime.value;
endtime.value = nowtime.value;
});
function itemClick(e) {
zbInfo.value = e;
}
function checkDay(val) {
calendarActive.value = val;
}
//状态字典
const ztDict = [
{
label: "无报备",
value: "00",
color: "#7b7b7b",
},
{
label: "有报备",
value: "01",
color: "#51fb06",
},
{
label: "今日报备",
value: "02",
color: "#51fb06",
},
{
label: "今日排班",
value: "03",
color: "#7b7b7b",
},
{
label: "无",
value: "04",
color: "#7b7b7b",
},
{
label: "有排班",
value: "05",
color: "#7b7b7b",
},
{
label: "无排班",
value: "06",
color: "#7b7b7b",
},
];
//状态数据处理
function checkZt(list = []) {
var zt = [];
if (list.length > 0) {
zt = list.map((item) => {
return {
text: ztDict.filter((item2) => item2.value === item.zt)[0].label,
color: ztDict.filter((item2) => item2.value === item.zt)[0].color,
id: item.id,
zt: item.zt,
};
});
}
return zt;
}
const isToday = ref(true);
function Draw(Year, Month) {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
getDeptByMonth({ time: Year + "-" + Month })
.then((res) => {
const copyRes = JSON.parse(JSON.stringify(res)).map((c) => {
var ccc = [];
if (!c.list) {
ccc = [];
} else {
ccc = c.list.map((ci) => {
return {
...ci,
zt: c.type,
};
});
}
return {
...c,
label: ztDict.filter((item2) => item2.value === c.type)[0].label,
color: ztDict.filter((item2) => item2.value === c.type)[0].color,
list: ccc,
};
});
calendarList.value = copyRes.map((item, index) => {
return {
value: index + 1,
kssj: "20:00", //假数据
jssj: "23:59",
status: checkZt(item.list), //假的状态
count: Year + "-" + Month + "-" + item.day,
...item,
};
});
if (isToday.value) {
var toTime = new Date();
var m =
toTime.getMonth() < 9
? "0" + (toTime.getMonth() + 1)
: toTime.getMonth() + 1;
var d =
toTime.getDate() < 10 ? "0" + toTime.getDate() : toTime.getDate();
var toDay = toTime.getFullYear() + "-" + m + "-" + d;
calendarList.value.forEach((v) => {
if (v.time === toDay) {
zbInfo.value = v;
isToday.value = false;
}
});
}
for (
var i = 1, firstDay = new Date(Year, Month - 1, 1).getDate();
i <= firstDay;
i++
) {
calendarList.value.unshift("");
}
Toast.clear();
})
.catch((err) => {
Toast.clear();
});
}
// 上个月
function last() {
month.value--;
if (month.value == 0) {
month.value = 12;
Year.value--;
}
Draw(Year.value, month.value);
}
// 下个月
function next() {
month.value++;
if (month.value == 13) {
month.value = 1;
Year.value++;
}
Draw(Year.value, month.value);
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.calenderBox {
width: 100%;
padding: 1vw;
box-sizing: border-box;
.calender-head {
width: 100%;
height: 15vw;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-weight: bold;
line-height: 40px;
position: relative;
.change {
position: absolute;
right: 1vw;
bottom: 2vw;
cursor: pointer;
color: #3e6ee8;
@include font_size($font_medium_s);
}
.btn {
width: 7vw;
height: 7vw;
line-height: 7vw;
text-align: center;
border-radius: 1vw;
background: #3e6ee8;
color: #fff;
}
.text {
margin: 0 4vw;
@include font_color($font-color-theme);
}
}
.week {
width: 100%;
display: flex;
flex-wrap: nowrap;
text-align: center;
height: 10vw;
line-height: 10vw;
background: #164acc;
color: #fff;
.days {
flex: 1;
}
}
.wrap {
width: 100%;
display: flex;
flex-wrap: wrap;
.item {
width: calc((100% / 7) - 1.3px);
border: 1px solid #3e6ee8;
border-top: none;
font-size: 10px;
min-height: 15vw;
.num {
text-align: right;
padding-right: 1vw;
box-sizing: border-box;
@include font_color($font-color-theme);
}
.num.active {
color: #1adb10;
}
.status {
text-align: center;
margin: 1vw 0;
span {
background: #3e6ee8;
padding: 1px 1vw;
display: block;
width: 10vw;
color: #fff;
border-radius: 1vw;
margin: 6px auto;
}
.green {
background: #1adb10;
}
.gray {
background: #83868f;
}
}
.time {
font-size: 10px;
// height: 5vw;
// line-height: 7vw;
color: #3e6ee8;
text-align: center;
}
.greenColor {
color: #1adb10;
}
.grayColr {
color: #83868f;
}
.BlueColor {
color: #3e6ee8;
}
}
.item:nth-child(7n + 2) {
border-left: none;
}
.item:nth-child(7n + 3) {
border-left: none;
}
.item:nth-child(7n + 4) {
border-left: none;
}
.item:nth-child(7n + 5) {
border-left: none;
}
.item:nth-child(7n + 6) {
border-left: none;
}
.item:nth-child(7n + 7) {
border-left: none;
}
}
}
.list {
max-height: calc(100vh - 35vw);
// overflow: hidden;
// overflow-y: auto;
}
.list-item {
padding: 3vw;
margin: 2vh 5vw;
border-radius: 2vw;
.phone-icon {
position: absolute;
right: 5vw;
}
.address-box {
display: flex;
justify-content: space-between;
.adress-left {
color: #3e6ee8;
}
}
.name-text {
@include font_size($font_medium);
color: #3e6ee8;
margin-bottom: 1vh;
font-weight: bold;
display: flex;
justify-content: flex-start;
align-items: center;
}
.title {
@include font_size($font_medium);
font-weight: 550;
}
.num-text {
@include font_size($font_medium_s);
color: #2b2b2b;
padding: 4px 0;
}
}
</style>

View File

@ -0,0 +1,131 @@
<template>
<div class="container" style="padding-top: 13vw">
<TopNav :navTitle="'盘查人员信息'" />
<van-form>
<div class="title_tab other_type_title">人员信息</div>
<div
@click="routerPush(item)"
class="info_box item_box"
v-for="(item, i) in userInfo"
:key="i"
>
<div class="item">
<span class="name">姓名</span>
<span class="text">
<span class="info">{{ item.xm ? item.xm : "未知" }}</span>
</span>
</div>
<div class="item">
<span class="name">权重</span>
<span class="text">
<span class="info">{{ item.qz }}</span>
</span>
</div>
<div class="item">
<span class="name">身份证号</span>
<span class="text">
<span class="info">{{ item.zjhm }}</span>
</span>
</div>
</div>
</van-form>
<van-empty
description="暂无数据"
image="default"
v-if="userInfo.length <= 0"
/>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import TopNav from "../../../components/topNav";
import { useRoute, useRouter } from "vue-router";
import { hintToast } from "../../../utils/tools.js";
import { Toast ,showLoadingToast} from "vant";
import { editYyzxApi } from "../../../api/yyzxApi.js";
const router = useRouter();
const route = useRoute();
const userInfo = ref([]);
const TOASTT = ref()
onMounted(() => {
if (route.query.dhhm) {
_getUserInfo(route.query.dhhm);
}
});
// 电话
function _getUserInfo(val) {
TOASTT.value = Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
editYyzxApi(`/mosty-hczx/tbHcBpcry/getRyListBySjhm/${val}`, {})
.then((res) => {
TOASTT.value.clear();
if (res.length > 0) userInfo.value = res;
})
.catch((err) => {
TOASTT.value.clear();
});
}
function routerPush(row) {
router.push({
path: "/quarantinePersonnel",
query: { sfzh: row.zjhm, pcsrlx: "6", dhpc: route.query.dhhm },
});
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.popupTitle {
text-align: center;
background-color: rgb(11, 137, 247);
height: 6vh;
line-height: 6vh;
}
.title_tab {
margin: 2vw 0 2vw 6vw;
}
.info_box {
margin: 2vw 4vw;
padding: 2vw;
box-sizing: border-box;
@include font_color($font-color-theme);
@include font_size($font_medium_s);
.item {
display: flex;
justify-content: space-between;
background-color: #e8eeff;
margin-bottom: 2vw;
padding: 2vw;
box-sizing: border-box;
.name {
display: inline-block;
width: 14vw;
text-align-last: justify;
}
.text {
display: inline-block;
width: calc(100% - 15vw);
.info {
float: right;
}
}
}
}
.rycard {
display: flex;
img {
margin-right: 2.5vw;
}
.item_ry {
line-height: 1.5em;
}
}
</style>

254
src/pages/yyzx/index.vue Normal file
View File

@ -0,0 +1,254 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="应用中心" :showRight="false" :showLeft="false" />
<YyzxItem title="置顶" :list="zdList.list" />
<!-- <YyzxItem title="勤务中心" :list="qwzxList.list" />
<YyzxItem title="预警中心" :list="yjzxList.list" />
<YyzxItem title="指令中心" :list="zlzxList.list" /> -->
<!-- <YyzxItem title="警情中心" :list="wqList.list" /> -->
<!-- <YyzxItem title="核查中心" :list="hcList.list" /> -->
<!-- <YyzxItem title="任务中心" :list="rwzxList.list" /> -->
<!-- <YyzxItem title="公共应用" :list="ggyyList.list" /> -->
<!-- 底部tas -->
<BottomTabs type="yyzx" />
<!-- 盘人 -->
<checkedPeople ref="peo" :key="zdgzKey + 'pr'" />
<!-- 盘车 -->
<checkedCar ref="car" :key="zdgzKey + 'pc'" />
<PcModel ref="dhcr" :key="zdgzKey + 'dhcr'"></PcModel>
<div style="height: 14.8666vw"></div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, onUnmounted, onActivated } from "vue";
import checkedCar from "../spsHome/components/checkCar.vue";
import checkedPeople from "../spsHome/components/checkPeople.vue";
import YyzxItem from "../../components/yyzxItem.vue";
import BottomTabs from "../../components/bottomTabs.vue";
import TopNav from "../../components/topNav.vue";
import PcModel from "../../components/pcModel.vue";
import emitter from "../../utils/eventBus.js";
import { onBeforeRouteLeave } from "vue-router";
const peo = ref(); //盘查人员组件对象
const car = ref(); //盘查车辆组件对象
const dhcr = ref(); //电话查人组件对象
const zdgzKey = ref(1);
const hcList = reactive({
list: [
{
name: "人员盘查",
imgUrl: require("../../assets/images/menu-yyhc.png"),
path: "pr",
},
{
name: "车辆盘查",
imgUrl: require("../../assets/images/menu-clhc.png"),
path: "pc",
},
{
name: "人员盘查列表",
imgUrl: require("../../assets/images/rypclb.png"),
path: "/yyzx/views/pcry",
},
{
name: "车辆盘查列表",
imgUrl: require("../../assets/images/clpclb.png"),
path: "/yyzx/views/clpc",
},
{
name: "巡访管理",
imgUrl: require("../../assets/images/11.png"),
path: "/Declaration",
},
],
});
const wqList = reactive({
list: [
{
name: "警情统计",
imgUrl: require("../../assets/images/menu-yjzl.png"),
path: "/jqfx",
},
{
name: "警情列表",
imgUrl: require("../../assets/images/menu-yjzl.png"),
path: "/yyzx/jqxx/index",
},
],
});
const rwzxList = reactive({
list: [
{
name: "任务统计",
imgUrl: require("../../assets/images/rwtj.png"),
path: "/yyzx/rwzx",
},
{
name: "任务列表",
imgUrl: require("../../assets/images/rwtj.png"),
path: "/rwlist",
},
],
});
const zlzxList = reactive({
list: [
{
name: "指令统计",
imgUrl: require("../../assets/images/menu-zlzx.png"),
path: "/yyzx/zlzx/zlTotal",
},
{
name: "指令列表",
imgUrl: require("../../assets/images/menu-zlzx.png"),
path: "/yyzx/zlzx/zlzxIndex",
},
],
});
const yjzxList = reactive({
list: [
{
name: "预警统计",
imgUrl: require("../../assets/images/yjtj.png"),
path: "/yyzx/yjxx/yjTotal",
},
{
name: "预警列表",
imgUrl: require("../../assets/images/menu-yjzx.png"),
path: "/yyzx/yjxx/index",
},
],
});
const qwzxList = reactive({
list: [
{
name: "今日勤务",
imgUrl: require("../../assets/images/qwtj.png"),
path: "/qwCenter",
},
// 存在问题
// {
// name: "历史勤务",
// imgUrl: require("../../assets/images/qwtj.png"),
// path: "/hisQwCenter",
// },
{
name: "巡防报备",
imgUrl: require("../../assets/images/menu-rwzx.png"),
path: "/yyzx/xfbb/addXfbb",
},
{
name: "临时勤务报备",
imgUrl: require("../../assets/images/menu-rwzx.png"),
path: "/yyzx/xfbb/addtsXfbb",
},
{
name: "值班报备",
imgUrl: require("../../assets/images/zbbb.png"),
path: "/yyzx/views/addZbbb",
},
{
name: "我的巡防",
imgUrl: require("../../assets/images/xfbbqd.png"),
path: "/calendar",
},
{
name: "我的值班",
imgUrl: require("../../assets/images/zbbb.png"),
path: "/zbbbCalendar",
},
{
name: "临时勤务列表",
imgUrl: require("../../assets/images/menu-rwzx.png"),
path: "/yyzx/xfbb/tsXfbbList",
},
{
name: "部门值班",
imgUrl: require("../../assets/images/zbbb.png"),
path: "/deptzbbbCalendar",
},
{
name: "部门巡防",
imgUrl: require("../../assets/images/xfbbqd.png"),
path: "/deptxfbbCalendar",
},
{
name: "人员休假",
imgUrl: require("../../assets/images/xfbbqd.png"),
path: "/deptryxjCalendar",
},
],
});
//置顶
const zdList = reactive({
list: [
{
name: "人员盘查",
imgUrl: require("../../assets/images/menu-yyhc.png"),
path: "pr",
},
{
name: "车辆盘查",
imgUrl: require("../../assets/images/menu-clhc.png"),
path: "pc",
},
{
name: "打卡",
imgUrl: require("../../assets/images/menu-dk.png"),
path: "/clock",
},
],
});
//公共应用
const ggyyList = reactive({
list: [
{
name: "意见反馈",
imgUrl: require("../../assets/yyzx/yjsj.png"),
path: "/yjsj",
},
{
name: "意见反馈统计",
imgUrl: require("../../assets/images/yjfktj.png"),
path: "/xttj",
},
],
});
onActivated(() => {
zdgzKey.value++;
});
onMounted(() => {
zdgzKey.value++;
//点击盘查功能
emitter.on("onClickPc", (res) => {
if (res == "pr") {
checkPeople();
} else if (res == "/dhcr") {
checkDhcr();
} else {
checkCar();
}
});
});
onUnmounted(() => {
emitter.off("onClickPc");
localStorage.removeItem('XF_Active')
});
//点击盘人
function checkPeople() {
peo.value.handleOpen();
}
//点击盘车
function checkCar() {
car.value.handleOpen();
}
// 点击电弧查人
function checkDhcr() {
dhcr.value.peoplePopupShow = true;
}
</script>
<style lang="scss" scoped>
</style>

View File

@ -0,0 +1,32 @@
<template>
<!-- 关联警情 -->
<div style="padding-top:13vw">
<TopNav navTitle="关联警情" :showRight="false" :showLeft="true" />
<List
v-for="(item, index) in list"
:key="index"
:item="item"
/>
</div>
</template>
<script setup>
import List from "../../../components/JqList.vue";
import TopNav from "../../../components/topNav.vue";
import { onMounted, ref } from "vue";
import { getGljq } from "../../../api/jqxx";
import { useRoute } from "vue-router";
const route = useRoute()
const list = ref([]);
function getList() {
getGljq({ jjdbh:route.query.jjdbh }).then((res) => {
list.value = res;
});
}
onMounted(() => {
getList();
});
</script>
<style>
</style>

View File

@ -0,0 +1,218 @@
<template>
<div>
<TopNav navTitle="警情列表" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Tabs
:list="tabs"
@onYjjb="onSelect"
:type="'car'"
:key="tabsIndex"
></Tabs>
<Search
placeholder="请输入关键字"
v-model="kwd"
:isSx="true"
@update:sx="showPopup = !showPopup"
@update:modelValue="onSearch"
></Search>
</div>
</van-sticky>
<SxPopup
:showPopup="showPopup"
:list="yjxx.sxList"
:p_top="145"
@update:close="showPopup = false"
@update:onConfirm="onConfirm"
:kssj="dateFormat()"
:jssj="dateFormat()"
/>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text=" "
@load="onLoad"
offset="1"
:immediate-check="false"
>
<List
v-for="(item, index) in yjxx.list"
:key="index"
:item="item"
path="/yyzx/jqxx/jqDetail"
/>
<van-empty
description="没有警情信息"
image="default"
v-if="yjxx.list.length <= 0 && showEmpty"
/>
</van-list>
</van-pull-refresh>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import Search from "../../../components/search.vue";
import Tabs from "../../../components/tabs.vue";
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/JqList.vue";
import { setTimeQuantum, dateFormat } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, reactive, onMounted, watch } from "vue";
import { getJqList, getStatistics } from "../../../api/jqxx";
const tabs = ref([
{
name: "全部警情",
value: null,
count: 0,
},
{
name: "刑事警情",
value: 1,
count: 0,
},
{
name: "行政警情",
value: 2,
count: 0,
},
{
name: "交通警情",
value: 3,
count: 0,
},
{
name: "其他",
value: 4,
count: 0,
},
]);
const sx = ref([setTimeQuantum()]);
sx.value[0].array[0].isCheck = true;
const yjxx = reactive({
sxList: sx.value, //筛选条件数据
list: [], //预警列表数据,
total: 0,
});
const params = ref({
pageNum: 1,
pageSize: 10,
bjnr: "",
bjlb: "",
endTime: dateFormat(),
startTime: dateFormat(),
});
const tabsIndex = ref(1);
const kwd = ref("");
const finished = ref(false);
const loading = ref(false);
const loadingPull = ref(false);
const showEmpty = ref(false);
const showPopup = ref(false); //筛选弹窗
//下拉刷新
function onRefresh() {
tabsIndex.value++;
yjxx.list = [];
params.value.pageNum = 1;
params.value.bjnr = "";
params.value.bjlb = "";
params.value.endTime = "";
params.value.startTime = "";
getList();
getJqtj();
}
//获取警情列表
function getList() {
loading.value = false;
getJqList(params.value)
.then((res) => {
loading.value = false;
loadingPull.value = false;
if (res.records && res.records.length > 0) {
yjxx.list.push(...res.records);
} else {
showEmpty.value = true;
}
yjxx.total = res.total;
})
.catch((err) => {
loading.value = false;
showEmpty.value = true;
});
}
function onLoad() {
if (yjxx.list >= yjxx.total) {
finished.value = true;
return;
}
params.value.pageNum++;
getList();
}
//获取警情统计数据
function getJqtj() {
const data = {
endTime: params.value.endTime,
startTime: params.value.startTime,
bjnr: params.value.bjnr,
};
getStatistics(data).then((res) => {
tabs.value[0].count = res.jtCount + res.qtCount + res.xsCount + res.xzCount;
tabs.value[1].count = res.xsCount;
tabs.value[2].count = res.xzCount;
tabs.value[3].count = res.jtCount;
tabs.value[4].count = res.qtCount;
});
}
onMounted(() => {
getList();
getJqtj();
});
/**
* tab选择
* @param {Object} val
*/
function onSelect(val) {
// loading.value = true;
finished.value = false;
yjxx.list = [];
params.value.bjnr = "";
params.value = {
pageNum: 1,
pageSize: 10,
endTime: params.value.endTime,
startTime: params.value.startTime,
bjlb: !val ? null : val,
};
getList();
}
/**
* 关键字搜索
* @param {Object} val
*/
function onSearch(val) {
yjxx.list = [];
params.value.bjnr = val;
params.value = {
pageNum: 1,
pageSize: 20,
endTime: "",
startTime: "",
bjlb: !val ? null : val,
};
getList();
getJqtj();
}
function onConfirm(val) {
yjxx.list = [];
params.value.startTime = val.startTime;
params.value.endTime = val.endTime;
getList();
getJqtj();
showPopup.value = false;
}
</script>
<style>
</style>

View File

@ -0,0 +1,91 @@
<template>
<div style="padding-top: 14vw">
<TopNav navTitle="警情详情" :showRight="false" :showLeft="true" />
<div class="ry_info">
<List :item="jqDetail" path="/yyzx/jqxx/jqDetail" />
</div>
<!-- <Steps :data="stepsData">
<template v-slot:default="{ scope }">
<div class="content">
<div class="cont_l">
<div class="text title">{{ scope.title }}</div>
<div class="text">执行人:{{ scope.zxr }}</div>
<div class="text">执行部门:{{ scope.zxbm }}</div>
</div>
</div>
</template>
</Steps> -->
<div class="mapPattern">
<van-button round block type="primary" @click="routerPush('/yyzx/jqxx/gljqList')"> 关联警情 </van-button>
</div>
</div>
</template>
<script setup>
import List from "../../../components/JqList.vue";
import TopNav from "../../../components/topNav.vue";
import Steps from "../../../components/Steps.vue";
import { getJqInfo } from "../../../api/jqxx";
import { onMounted, ref } from "vue";
import { useRoute } from "vue-router";
import router from "../../../router";
const route = useRoute()
const jqDetail = ref({});
const stepsData = ref([
{
title: "接到警情",
zxr: "张三",
zxbm: "高新区派出所",
time: "2022-10-27 20:11:26",
},
{
title: "接到警情",
zxr: "张三",
zxbm: "高新区派出所",
time: "2022-10-27 20:11:26",
},
{
title: "接到警情",
zxr: "张三",
zxbm: "高新区派出所",
time: "2022-10-27 20:11:26",
}
]);
//获取详情
function getInfo(){
getJqInfo(route.query.id).then(res=>{
jqDetail.value = res
})
}
function routerPush(path){
router.push({
path:path,
query:{jjdbh:jqDetail.value.jjdbh}
})
}
onMounted(()=>{
getInfo()
})
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.ry_info {
margin: 2vw 3vw;
border-radius: 2vw;
@include jrtz_fill_color($jrtz-fill-color-theme);
}
.content {
display: flex;
padding-bottom: 20px;
.cont_l {
margin-right: 16px;
.text{
line-height: 5.5vw;
}
.title{
@include font_size($font_medium);
font-weight: 550;
}
}
}
</style>

View File

@ -0,0 +1,329 @@
<template>
<div class="mryq_box">
<div class="title red">
<span></span>
<span></span>
<span></span>
<span></span>
</div>
<div class="dw_rq d_bottom">
<span>单位巡警大队 </span>
<span> 2022年11月8日 </span>
</div>
<div class="dw_rq">
<span>审核领导邱文宇 </span>
<span> 撰稿人胡云建 </span>
</div>
<div class="text_box">
<span class="twxc_title"> 1发案情况</span><br />
&emsp;&emsp;街面实发警情共8件相对昨日减少6件其中盗窃三车警情3件相对昨日减少3件扒窃警情5件相对昨日增加2件车财警情0件相对昨日减少5件<br />
<span class="twxc_title"> 2今日发案分布</span><br />
<div class="table_box">
<div class="fafb_table_header header">
<div>单位</div>
<div>芳草</div>
<div>桂溪</div>
<div>合作</div>
<div>和平</div>
<div>石羊</div>
<div>西园</div>
<div>肖家</div>
<div>新川</div>
<div>会展</div>
<div>益州</div>
<div>中和</div>
<div>合计</div>
</div>
<div class="data_box">
<div class="table_box">
<div
class="fafb_table_header right"
v-for="item in mryq.fafb"
:key="item"
>
<div>{{ Object.keys(item)[0] }}</div>
<div v-for="_item in item[Object.keys(item)[0]]" :key="_item">
{{ _item }}
</div>
</div>
</div>
</div>
</div>
<span class="twxc_title"> 3热点区域图</span><br />
<span class="twxc_title"> 4巡大天网巡查情况</span><br />
<div class="twxc_box">
<div v-for="item in mryq.twxc" :key="item" class="twxc_item">
<div class="twxc_title">{{ item.ssbm }}</div>
<div>重点区域{{ item.zdqu }}</div>
<div>巡控时段{{ item.xksd }}</div>
<div>必巡线必巡点{{ item.bxxBxd }}</div>
<div>天网杆号{{ item.twgh }}</div>
<div>巡查时间{{ item.xcsj }}</div>
<div>巡查原因{{ item.xcyy }}</div>
<div>巡逻质效{{ item.xlzx }}</div>
</div>
</div>
<span class="twxc_title"> 5警情图巡情况</span><br />
<div class="twxc_box">
<div v-for="item in mryq.jqtx" :key="item" class="twxc_item">
<div class="twxc_title">{{ item.ssbm }}</div>
<div>图巡时段{{ item.txsd }}</div>
<div>点位地址{{ item.dwdz }}</div>
<div>天网号{{ item.twh }}</div>
<div>巡查情况{{ item.xcqk }}</div>
<div>巡查原因{{ item.xcyy }}</div>
<div>巡逻质效{{ item.xlzx }}</div>
<div>存在问题{{ item.czwt }}</div>
<div>整改措施{{ item.zgcs }}</div>
</div>
</div>
<span class="twxc_title"> 6移动巡逻盘查数据</span><br />
<div class="table_box">
<div class="fafb_table_header header" style="width: 30%">
<div></div>
<div>卡点与街面巡防</div>
<div>芳草</div>
<div>桂溪</div>
<div>合作</div>
<div>和平</div>
<div>石羊</div>
<div>西园</div>
<div>肖家</div>
<div>新川</div>
<div>会展</div>
<div>益州</div>
<div>中和</div>
</div>
<div class="data_box" style="width: 70%">
<div class="table_box">
<div
class="fafb_table_header right"
v-for="item in mryq.ydxlpc"
:key="item"
:style="Object.keys(item)[0] == '盘查合计数' ? 'width:18%' : ''"
>
<div>{{ Object.keys(item)[0] }}</div>
<div class="two_table">
<div
v-for="_item in item[Object.keys(item)[0]]"
:key="_item"
:style="_item.title == '人员、车辆' ? 'width:100%' : ''"
>
{{ _item.title }}
</div>
</div>
<template style="display: flex">
<div
class="total_item_sum"
v-for="_item in item[Object.keys(item)[0]]"
:key="_item"
:style="_item.title == '人员、车辆' ? 'width:100%' : ''"
>
<div v-for="_it in _item.arr" :key="_it">
{{ _it }}
</div>
</div>
</template>
</div>
</div>
</div>
</div>
<span class="twxc_title">7质效评估</span><br />
&emsp;&emsp;今日和平三个警情相比昨日上升一个于上月环比上升1件桂溪西园合作肖家所有街面实发六类侵财警情巡逻防控未取得质效其余各所无街面实发六类侵财警情巡逻防控取得质效<br />
<span class="twxc_title">8工作指令</span><br />
&emsp;&emsp;今日街面实发警情8件分布于***地方巡大各所根据发案时段发案区域合理部署警力在街面警情热点区域开展巡逻防控和逢疑必查工作
</div>
</div>
</template>
<script setup>
import { reactive } from "vue";
const mryq = reactive({
fafb: [
{ 两抢: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ 汽盗: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ 车财: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ 三车: [0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 3] },
{ 扒窃: [0, 0, 1, 1, 0, 2, 1, 0, 0, 0, 0, 4] },
{ 六类汇总: [0, 1, 3, 1, 0, 2, 1, 0, 0, 0, 0, 8] },
],
twxc: [
{
ssbm: "桂溪",
zdqu: "名都路沿线周边",
xksd: "00:00-04:00",
bxxBxd: "名都路沿线",
twgh: "D-09030939",
xcsj: "11月7日 01:00-02:00",
xcyy: "车财易发案区域",
xlzx: "巡查时段无警力巡逻,无街面发案",
},
{
ssbm: "合作",
zdqu: "龙湖时代天街周边",
xksd: "18:00-21:00",
bxxBxd: "龙湖时代天街周边道路沿线",
twgh: "Y-09055102",
xcsj: "11月6日 19:00-20:00",
xcyy: "扒窃易发案区域",
xlzx: "巡查时段无警力巡逻,无街面发案",
},
{
ssbm: "石羊",
zdqu: "复城国际周边",
xksd: "19:00-22:00",
bxxBxd: "盛华南路沿线",
twgh: "D-09040960",
xcsj: "11月7日 20:00-21:00",
xcyy: "三车易发案区域",
xlzx: "巡查时段有警车巡逻,无街面发案",
},
],
jqtx: [
{
ssbm: "中和所",
txsd: "11月7日 01:00-02:00",
dwdz: "紫竹广场",
twh: "09025301",
xcqk: "巡查时段无警力巡逻,无街面发案",
xcyy: "车财易发案区域",
xlzx: "无街面发案",
czwt: "1、巡查时段街面三车随意停放无人员管理。",
zgcs: "加强巡逻遥控,规范停车",
},
{
ssbm: "合作所",
txsd: "11月7日 01:00-02:00",
dwdz: "紫竹广场",
twh: "09025301",
xcqk: "巡查时段无警力巡逻,无街面发案",
xcyy: "车财易发案区域",
xlzx: "无街面发案",
czwt: "1、巡查时段街面三车随意停放无人员管理。",
zgcs: "加强巡逻遥控,规范停车",
},
],
ydxlpc: [
{
盘车人员: [
{ title: "移交人员数", arr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ title: "人员合计数", arr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
],
},
{
盘查车辆: [
{ title: "移交车辆数", arr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ title: "车辆合计数", arr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
],
},
{
盘查物品: [
{ title: "人员物品数", arr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
{ title: "车辆物品数", arr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
],
},
{
盘查合计数: [
{ title: "人员、车辆", arr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] },
],
},
],
});
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.mryq_box {
padding: 0 3vw 5vw 3vw;
@include font_color($font-color-theme);
@include font_size($font_medium_s);
.title {
font-size: 10vw;
text-align: center;
padding: 5vw 15vw 2vw 15vw;
display: flex;
justify-content: space-between;
align-items: center;
// letter-spacing: 40px;
}
.dw_rq {
display: flex;
justify-content: space-between;
@include font_size($font_medium);
font-weight: 600;
padding: 1vw;
}
.d_bottom {
border-bottom: 3px solid red;
}
.text_box {
line-height: 5.5vw;
.table_box {
display: flex;
.header {
width: 15%;
text-align: center;
& > div {
height: 5vw;
}
}
.header:nth-child(1) {
border-left: 1px solid #999;
}
.data_box {
width: 85%;
overflow-x: scroll;
.table_box {
display: flex;
width: 230%;
}
.right {
width: 28%;
& > div {
height: 5vw;
}
}
}
}
.twxc_box {
.twxc_item {
border-bottom: 1px solid #eff0f5;
padding: 2vw 0;
}
}
.twxc_title {
display: inline-block;
@include font_size($font_medium);
font-weight: 600;
margin: 2vw 0;
}
}
}
.two_table {
display: flex;
& > div {
width: 50%;
}
}
.total_item_sum {
width: 50%;
text-align: center;
& > div {
border-top: 1px solid #999;
border-right: 1px solid #999;
height: 5vw;
}
& > div:last-child {
border-bottom: 1px solid #999;
}
}
.fafb_table_header {
& > div {
text-align: center;
border-top: 1px solid #999;
border-right: 1px solid #999;
}
& > div:last-child {
border-bottom: 1px solid #999;
}
}
</style>

View File

@ -0,0 +1,223 @@
<template>
<div :id="echid" class="gfChart"></div>
</template>
<script>
import * as echarts from "echarts";
export default {
props: ["list"],
watch: {
list: {
handler(val) {
this.hamdlegfChart();
},
immediate: true,
deep: true,
},
},
data() {
return {
echid: "",
themeType: getStorage("themeSetting"),
};
},
created() {
this.echid = "echi_et" + new Date().getTime();
},
mounted() {
this.hamdlegfChart();
},
methods: {
hamdlegfChart() {
if (document.getElementById(this.echid)) {
let myChart = echarts.init(document.getElementById(this.echid));
var option = {
grid: {
left: "0",
right: "0",
bottom: "48",
top: "10",
containLabel: true,
},
legend: {
left: "center",
bottom: 0, //具体
textStyle: {
color: this.themeType == "light" ? "#333" : "#fff",
},
},
tooltip: {},
dataset: {
source: this.list,
},
xAxis: {
type: "category",
axisLabel: {
color: this.themeType == "light" ? "#333" : "#fff",
},
},
yAxis: {
splitLine: { show: false },
axisLabel: {
color: this.themeType == "light" ? "#333" : "#fff",
},
},
series: [
{
type: "bar",
barWidth: 9,
itemStyle: {
normal: {
// barBorderRadius: [5, 5, 5, 5],
},
},
color: [
{
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#1eabff",
},
{
offset: 1,
color: "#4760ff",
},
],
},
],
},
{
type: "bar",
barWidth: 9,
itemStyle: {
normal: {
// barBorderRadius: [5, 5, 5, 5],
},
},
color: [
{
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#88f2b9",
},
{
offset: 1,
color: "#0dda72",
},
],
},
],
},
{
type: "bar",
barWidth: 9,
itemStyle: {
normal: {
// barBorderRadius: [5, 5, 5, 5],
},
},
color: [
{
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#ffd91b",
},
{
offset: 1,
color: "#ff8e43",
},
],
},
],
},
{
type: "bar",
barWidth: 9,
itemStyle: {
normal: {
// barBorderRadius: [5, 5, 5, 5],
},
},
color: [
{
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#f87373",
},
{
offset: 1,
color: "#e81b1b",
},
],
},
],
},
{
type: "bar",
barWidth: 9,
itemStyle: {
normal: {
// barBorderRadius: [5, 5, 5, 5],
},
},
color: [
{
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#f9906f",
},
{
offset: 1,
color: "#f05654",
},
],
},
],
},
],
};
option && myChart.setOption(option);
}
},
},
};
</script>
<style scoped>
.gfChart {
margin-top: 1vw;
height: 100%;
width: 100%;
margin: 0 auto;
}
</style>

View File

@ -0,0 +1,109 @@
<template>
<ul class="box-rank">
<li class="item">
<div class="text title">名次</div>
<div class="text title" v-if="active == 1">名称</div>
<div class="text title">完成数</div>
<div class="text title">未完成</div>
<div class="text title">完成</div>
<div class="text title dep" style="text-align: center">部门</div>
</li>
<li class="item" v-for="(item, index) in data" :key="index">
<div class="text title mc" v-if="index == 0">
<van-image
width="5vw"
height="5vw"
fit="contain"
:src="require('../../../../assets/gxapp/j.png')"
/>
</div>
<div class="text title mc" v-else-if="index == 1">
<van-image
width="5vw"
height="5vw"
fit="contain"
:src="require('../../../../assets/gxapp/y.png')"
/>
</div>
<div class="text title mc" v-else-if="index == 2">
<van-image
width="5vw"
height="5vw"
fit="contain"
:src="require('../../../../assets/gxapp/t.png')"
/>
</div>
<div class="text title mc" v-else>{{ index + 1 }}</div>
<div class="text title" v-if="active == 1">{{ item.jsrmc }}</div>
<div class="text title">{{ item.ys }}</div>
<div class="text title">{{ item.ns }}</div>
<div class="text title">{{ (item.rate * 100).toFixed(0) }}%</div>
<div class="text title dep">{{ item.ssbm }}</div>
</li>
<van-empty description="暂无信息" image="default" v-if="data.length <= 0" />
</ul>
</template>
<script setup>
import { ref, onMounted } from "vue";
import { getGrphbData,getBmpm } from "../../../../api/rwzx.js";
const props = defineProps({
active: Number, //选中的排行榜 0部门 1 个人
});
//个人排行榜数据
const data = ref([]);
if (props.active == 1) {
_getGrphbData();
} else {
_getBmpm()
}
//获取个人排行榜数据
function _getGrphbData() {
getGrphbData({}).then((res) => {
if (res.length > 0) data.value = res;
});
}
//获取部门排名数据
function _getBmpm(){
getBmpm({}).then(res => {
if (res.length > 0) data.value = res;
})
}
</script>
<style lang="scss" scoped>
@import "../../../../assets/styles/mixin.scss";
.box-rank {
width: 100%;
height: 100%;
.item {
display: flex;
align-items: center;
justify-content: center;
@include font_size($font_medium_s);
height: 8vw;
.text {
flex: 2;
text-align: center;
}
.mc {
color: #3e6ee8;
}
.dep {
flex: 3;
display: inline-block;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: left;
}
}
.item:nth-child(2n + 1) {
@include table_item_color($table-item-theme);
}
.item:nth-child(1) {
background: #3e6ee8 !important;
color: #fff;
}
}
</style>

View File

@ -0,0 +1,344 @@
<template>
<div :id="echid" class="gfChart"></div>
</template>
<script>
import * as echarts from "echarts";
export default {
props: ["datas"],
watch: {
datas: {
handler(val) {
this.hamdlegfChart();
},
immediate: true,
deep: true,
},
},
data() {
return {
echid: "",
themeType: getStorage("themeSetting"),
};
},
created() {
this.echid = "ech_rw" + new Date().getTime();
},
mounted() {
this.hamdlegfChart();
},
methods: {
hamdlegfChart() {
if (document.getElementById(this.echid)) {
let myChart = echarts.init(document.getElementById(this.echid));
var option = {
grid: {
left: "0",
right: "0",
bottom: "0",
top: "0",
containLabel: true,
},
tooltip: {
trigger: "item",
},
legend: {
bottom: "5",
left: "center",
textStyle: {
color: this.themeType == "light" ? "#333" : "#fff",
},
},
graphic: {
type: "text",
left: 133,
top: 107,
style: {
text: "任务类型",
textAlign: "center",
fill: "#377aff",
fontSize: 14,
fontWeight: 600,
},
},
series: [{
name: "Access From",
type: "pie",
radius: ["30%", "50%"],
center: ["50%", "40%"],
avoidLabelOverlap: false,
label: {
alignTo: "edge",
edgeDistance: 10,
textStyle: {
fontSize: 13,
// color: "#000",
lineHeight: 30,
},
formatter: function(data) {
//自定义,加个判断 渲染不同样式 配🍱
if (data.name == "已完成") {
return (
"{name|" +
data.name +
"}" +
"{value|" +
data.value +
" }" +
" \n" +
"{num1|" +
data.percent +
"%" +
"}"
);
}
if (data.name == "超期完成") {
return (
"{name|" +
data.name +
"}" +
"{value|" +
data.value +
" }" +
" \n" +
"{num2|" +
data.percent +
"%" +
"}"
);
}
if (data.name == "超期进行中") {
return (
"{name|" +
data.name +
"}" +
"{value|" +
data.value +
" }" +
" \n" +
"{num3|" +
data.percent +
"%" +
"}"
);
}
if (data.name == "进行中") {
return (
"{name|" +
data.name +
"}" +
"{value|" +
data.value +
" }" +
" \n" +
"{num4|" +
data.percent +
"%" +
"}"
);
}
if (data.name == "超期未完成") {
return (
"{name|" +
data.name +
"}" +
"{value|" +
data.value +
" }" +
" \n" +
"{num5|" +
data.percent +
"%" +
"}"
);
}
},
rich: {
num1: {
fontSize: 16,
fontWeight: 600,
color: "#1bb0ff",
},
num2: {
fontSize: 16,
fontWeight: 600,
color: "#ffde19",
},
num3: {
fontSize: 16,
fontWeight: 600,
color: "#f87373",
},
num4: {
fontSize: 16,
fontWeight: 600,
color: "#88f2b9",
},
num5: {
fontSize: 16,
fontWeight: 600,
color: "#f05654",
},
},
},
labelLine: {
length: 8,
length2: 20,
maxSurfaceAngle: 80,
},
labelLayout: function(params) {
const isLeft = params.labelRect.x < myChart.getWidth() / 2;
const points = params.labelLinePoints;
points[2][0] = isLeft ?
params.labelRect.x :
params.labelRect.x + params.labelRect.width;
return {
labelLinePoints: points,
};
},
emphasis: {
label: {
show: true,
fontSize: "20",
fontWeight: "bold",
},
},
data: [{
value: this.datas.ywc,
name: "已完成",
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(
1,
0,
1,
1, //(上-下 渐变)
[{
offset: 1,
color: "#4760ff"
},
{
offset: 0.5,
color: "#1bb0ff"
},
]
),
},
},
},
{
value: this.datas.jxz,
name: "进行中",
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(
1,
0,
1,
1, //(左上-右下 渐变)
[{
offset: 0,
color: "#88f2b9",
},
{
offset: 1,
color: "#0dda72",
},
],
),
},
},
},
{
value: this.datas.cqwc,
name: "超期完成",
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(
1,
0,
1,
1, //(左上-右下 渐变)
[{
offset: 1,
color: "#ff8747"
},
{
offset: 0.5,
color: "#ffde19"
},
]
),
},
},
},
{
value: this.datas.cqjxz,
name: "超期进行中",
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(
1,
0,
1,
1, //(左上-右下 渐变)
[{
offset: 1,
color: "#ea2121"
},
{
offset: 0.5,
color: "#f87373"
},
]
),
},
},
},
{
value: this.datas.cqwwc,
name: "超期未完成",
itemStyle: {
normal: {
//颜色渐变
color: new echarts.graphic.LinearGradient(
1,
0,
1,
1, //(左上-右下 渐变)
[{
offset: 1,
color: "#f05654"
},
{
offset: 0.5,
color: "#f9906f"
},
]
),
},
},
},
],
}, ],
};
option && myChart.setOption(option);
}
},
},
};
</script>
<style scoped>
.gfChart {
margin-top: 1vw;
height: 100%;
width: 100%;
margin: 0 auto;
}
</style>

View File

@ -0,0 +1,87 @@
<template>
<ul class="statics-rwzx">
<li class="item item_box">
<div class="title">任务总数</div>
<div class="number numb">{{ rwCount.all }}</div>
</li>
<li class="item item_box">
<div class="title">超期进行中</div>
<div class="number numb">{{ rwCount.cqjxz }}</div>
</li>
<li class="item item_box">
<div class="title">超期完成</div>
<div class="number numb">{{ rwCount.cqwc }}</div>
</li>
<li class="item item_box">
<div class="title">进行中</div>
<div class="number numb">{{ rwCount.jxz }}</div>
</li>
<li class="item item_box">
<div class="title">已完成</div>
<div class="number numb">{{ rwCount.ywc }}</div>
</li>
<li class="item item_box">
<div class="title">超期未完成</div>
<div class="number numb">{{ rwCount.cqwwc }}</div>
</li>
</ul>
</template>
<script setup>
import { getRwCount } from "../../../../api/rwzx.js";
import { reactive, ref, onMounted } from "vue";
//任务统计数据
const rwCount = ref({
all: 0,
cqjxz: 0,
cqwc: 0,
jxz: 0,
ywc: 0,
cqwwc: 0,
});
onMounted(() => {
_getRwCount();
});
//获取统计数量
function _getRwCount() {
getRwCount({}).then((res) => {
if (res) rwCount.value = res;
});
}
</script>
<style lang="scss" scoped>
@import "../../../../assets/styles/mixin.scss";
.statics-rwzx {
width: 100%;
height: 100%;
min-height: 26vw;
padding-top: 4vw;
box-sizing: border-box;
overflow: hidden;
.item {
float: left;
width: 31%;
border-radius: 2vw;
overflow: hidden;
margin-bottom: 4vw;
.title {
height: 7vw;
text-align: center;
line-height: 7vw;
@include font_size($font_medium_s);
background: #3e6ee8;
color: #fff;
}
.number {
height: 10vw;
text-align: center;
line-height: 10vw;
}
}
li:nth-child(3n + 2) {
margin-left: 3%;
margin-right: 3%;
}
}
</style>

View File

@ -0,0 +1,317 @@
<template>
<van-config-provider :theme-vars="themeVars">
<div style="padding-top: 13vw">
<TopNav navTitle="任务中心" :showRight="false" :showLeft="true" />
<div style="padding: 0 4vw; box-sizing: border-box">
<!-- 数据统计 -->
<div class="mainBox">
<Statics></Statics>
</div>
<!-- 任务类型统计 -->
<div class="item_box">
<div class="container">
<div class="strip_box">
<span class="strip"></span>
<span class="total_title">任务类型统计</span>
</div>
<div class="title-right">
<span v-if="rwTypeTime == 1"> 今日</span>
<span v-if="rwTypeTime == 2"> 近7日</span>
<span v-if="rwTypeTime == 3"> 近30日</span>
<img
src="../../../assets/images/xiala.png"
width
class="img"
alt=""
@click="isShowDataCount1 = true"
/>
<van-action-sheet v-model:show="isShowDataCount1">
<van-picker
:columns="timeList"
@confirm="change_data_count"
@cancel="isShowDataCount1 = false"
/>
</van-action-sheet>
</div>
</div>
<div class="coulum">
<barChart :list="rwTypeList.list"></barChart>
</div>
</div>
<!-- 任务完成情况 -->
<div class="item_box">
<div class="container">
<div class="strip_box">
<span class="strip"></span>
<span class="total_title">任务完成情况</span>
</div>
<div class="title-right">
<span v-if="rwWcTime == 1"> 今日</span>
<span v-if="rwWcTime == 2"> 近7日</span>
<span v-if="rwWcTime == 3"> 近30日</span>
<img
src="../../../assets/images/xiala.png"
width
class="img"
alt=""
@click="isShowDataCount2 = true"
/>
<van-action-sheet v-model:show="isShowDataCount2">
<van-picker
:columns="timeList"
@confirm="change_data_count2"
@cancel="isShowDataCount2 = false"
/>
</van-action-sheet>
</div>
</div>
<div class="coulumBar">
<SircleChart
:datas="reWcCountDtaa"
v-if="reWcCountDtaa"
></SircleChart>
</div>
</div>
<!-- 排行榜 -->
<div class="rankBox">
<van-tabs
title-active-color="#3e6ee8"
color="#3e6ee8"
:background="themeType == 'light' ? '#fff' : '#041634'"
:title-inactive-color="themeType == 'light' ? '#333' : '#fff'"
v-model:active="active"
@change="onActive"
>
<van-tab
:title="item"
v-for="(item, index) in rankingList"
:key="index"
>
</van-tab>
</van-tabs>
<div class="item_box ranking">
<Ranking :active="active" :key="activeIndex"></Ranking>
</div>
</div>
</div>
</div>
</van-config-provider>
</template>
<script setup>
import { ref, onMounted, reactive } from "vue";
import TopNav from "../../../components/topNav.vue";
import Statics from "./components/statics.vue";
import barChart from "./components/barChart.vue";
import SircleChart from "./components/sircleChart.vue";
import Ranking from "./components/ranking.vue";
import { getRwTypeCount, getRwCount } from "../../../api/rwzx.js";
import { Toast } from "vant";
//时间段选择数据
const timeList = ref(["今日", "近7日", "近30天"]);
const rankingList = ref(["部门排行榜", "个人排行榜"]);
const active = ref(0); //选中排行榜
const rwTypeTime = ref(1); //任务类型统计默认时间
const rwWcTime = ref(1); //任务完成统计默认时间
const isShowDataCount1 = ref(false); //任务类型统计时间弹窗
const isShowDataCount2 = ref(false); //任务完成统计时间弹窗
const reWcCountDtaa = ref(null); //任务完成统计数据
const activeIndex = ref(1);
const rwTypeList = reactive({
list: [],
}); //任务类型统计数据
const themeType = ref(getStorage("themeSetting"));
onMounted(() => {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
Promise.all([_getRwTypeCount(), _getRwCount()])
.then((res) => {
Toast.clear();
})
.catch((err) => {
Toast.clear();
});
});
//切换排行版
function onActive(e) {
activeIndex.value++;
}
//获取任务成统计数据
function _getRwCount() {
getRwCount({
dateType: rwWcTime.value,
}).then((res) => {
if (res) reWcCountDtaa.value = res;
});
}
//获取任务类型统计数据
function _getRwTypeCount() {
getRwTypeCount({
dateType: rwTypeTime.value,
}).then((res) => {
let arr = [
["product", "已完成", "进行中", "超期完成", "超期进行中", "超期未完成"],
];
for (let i = 0; i < res.length; i++) {
switch (res[i].dm) {
case "01":
arr[1] = _setRwTypeData(res[i]);
break;
case "02":
arr[2] = _setRwTypeData(res[i]);
break;
case "03":
arr[3] = _setRwTypeData(res[i]);
break;
case "04":
arr[4] = _setRwTypeData(res[i]);
break;
case "05":
arr[5] = _setRwTypeData(res[i]);
break;
}
}
rwTypeList.list = arr;
});
}
//设置任务类型图标数据
function _setRwTypeData(item) {
let arr = [];
for (let it in item) {
if (it == "ct") item[it] = item[it].replace("任务", "");
switch (it) {
case "ct":
arr[0] = item[it];
break;
case "ywc":
arr[1] = item[it];
break;
case "jxz":
arr[2] = item[it];
break;
case "cqwc":
arr[3] = item[it];
break;
case "cqjxz":
arr[4] = item[it];
break;
case "cqwwc":
arr[5] = item[it];
break;
}
}
return arr;
}
//确认选中的时间
function change_data_count(val) {
switch (val) {
case "今日":
rwTypeTime.value = 1;
break;
case "近7日":
rwTypeTime.value = 2;
break;
case "近30天":
rwTypeTime.value = 3;
break;
}
isShowDataCount1.value = false;
_getRwTypeCount();
}
//选中的任务完成的查询时间
function change_data_count2(val) {
switch (val) {
case "今日":
rwWcTime.value = 1;
break;
case "近7日":
rwWcTime.value = 2;
break;
case "近30天":
rwWcTime.value = 3;
break;
}
isShowDataCount2.value = false;
_getRwCount();
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.mainBox {
box-sizing: border-box;
.dataCount {
height: 40vw;
}
}
.item_box {
@include font_size($font_medium_s);
padding: 3vw;
box-sizing: border-box;
margin-bottom: 4vw;
.container {
margin: 3vw;
border-radius: 5px;
display: flex;
justify-content: space-between;
align-items: center;
.strip_box {
display: flex;
align-items: center;
.strip {
display: inline-block;
width: 4px;
height: 14px;
background-color: #1989fa;
margin-right: 2vw;
}
.total_title {
@include font_size($font_medium);
}
}
.title-right {
background: #3e6ee8;
color: #fff;
padding: 0.5vw 2vw;
border-radius: 1vw;
}
}
.coulum {
width: 100%;
height: 54vw;
}
.coulumBar {
width: 100%;
height: 75vw;
}
}
.rankBox {
// margin-top: 8vw;
.ranking {
margin-top: 4vw;
}
::v-deep .van-tab__text--ellipsis {
font-size: 4vw;
font-weight: 600;
}
}
</style>

View File

@ -0,0 +1,280 @@
<template>
<div>
<TopNav :navTitle="title" :showRight="false" :showLeft="true" />
<div class="concent">
<van-form @submit="onSubmit">
<van-field
v-model="form.sqrXm"
name="sqrXm"
label="申请人"
readonly
label-width="70px"
/>
<van-field
v-model="form.sqbm"
name="sqbm"
label="申请人部门"
readonly
label-width="70px"
/>
<van-field
v-model="form.qjlxmc"
name="qjlxmc"
label="请假类型"
is-link
label-width="70px"
required
:rules="[{ required: true, message: '请假类型' }]"
@click="chooseQJLX"
/>
<van-field
v-model="form.kssj"
name="kssj"
label="开始时间"
readonly
is-link
label-width="70px"
required
:rules="[{ required: true, message: '请选择开始时间' }]"
@click="chooseTime('kssj')"
/>
<van-field
v-model="form.jssj"
name="jssj"
readonly
label="结束时间"
is-link
label-width="70px"
required
:rules="[{ required: true, message: '请选择结束时间' }]"
@click="chooseTime('jssj')"
/>
<van-field
v-model="form.bz"
name="bz"
label="备注"
type="textarea"
label-width="70px"
/>
<div style="margin: 16px 0; padding: 0 5vw">
<van-button
:loading="loading"
round
native-type="submit"
block
type="primary"
>
提交</van-button
>
</div>
</van-form>
</div>
<!-- 时间选择 -->
<van-popup v-model:show="showksPicker" position="bottom">
<van-datetime-picker
v-model="time"
type="date"
title="请选择时间"
:min-hour="minTime"
:min-date="minDate"
:formatter="formatter"
@confirm="onksConfirm"
@change="ksChange"
@cancel="showksPicker = false"
/>
</van-popup>
<!-- 请假类型 -->
<van-dialog
:show="showSetting"
title="请选择请假类型"
show-cancel-button
@confirm="onConfirm"
@cancel="showSetting = false"
confirmButtonColor="#3e6ee8"
>
<van-radio-group v-model="isActive">
<van-radio v-for="item in D_BZ_QXJLX" :key="item.dm" :name="item.dm">{{
item.zdmc
}}</van-radio>
</van-radio-group>
</van-dialog>
</div>
</template>
<script setup>
import router from "../../../../router/index.js";
import { getDictList, setDict } from "../../../../utils/dict";
import {
ryqjListById,
ryqjListEdit,
ryqjListAdd,
} from "../../../../api/qwzx.js";
import TopNav from "../../../../components/topNav.vue";
import { timeValidate, hintToast } from "../../../../utils/tools.js";
import {
ref,
reactive,
onMounted,
getCurrentInstance,
watch,
computed,
} from "vue";
import { useRoute } from "vue-router";
const { D_BZ_QXJLX } = getDictList("D_BZ_QXJLX"); //字典信息请假类型
const { proxy } = getCurrentInstance();
const route = useRoute();
const user = ref(JSON.parse(window.localStorage.getItem("userInfo")));
const form = ref({
sqrXm: user.value.userName,
sqbm: user.value.deptName,
sqbmid: user.value.deptList[0].deptId,
qjlx: "",
qjlxmc: "",
kssj: "",
jssj: "",
bz: "",
sqrlx: "01",
sqrId: user.value.id,
});
const minDate = computed({
get: () => {
if (!form.value.kssj) {
return new Date();
} else if (timeType.value === "jssj") {
return new Date(form.value.kssj);
} else {
return new Date();
}
},
});
const title = ref("");
const time = ref("");
const minTime = timeValidate(new Date(), "ymd");
const isActive = ref(null);
const timeType = ref(null);
const showSetting = ref(false);
const showksPicker = ref(false);
watch(
() => D_BZ_QXJLX,
(newValue) => {
if (newValue._object.D_BZ_QXJLX.length > 0) init();
},
{ deep: true }
);
onMounted(() => {
// init()
});
// 初始化
function init() {
if (route.query.type == "add") {
title.value = "新增人员请假";
} else {
title.value = "修改人员请假";
getInfoByID(route.query.id);
}
}
// 根据id查询时间
function getInfoByID(id) {
ryqjListById(id).then((res) => {
form.value = res;
let obj = D_BZ_QXJLX.value.find((v) => {
return v.dm == form.value.qjlx;
});
if (obj) {
form.value.qjlxmc = obj.zdmc;
}
});
}
// 编辑 - 新增请假类型
function onSubmit(e) {
if (route.query.id && route.query.type == "edit") {
let { qjlxmc, ...params } = form.value;
ryqjListEdit(params).then((res) => {
router.go(-1);
hintToast("编辑成功");
});
}
if (route.query.type == "add") {
let { qjlxmc, ...params } = form.value;
ryqjListAdd(params).then((res) => {
hintToast("新增成功");
router.go(-1);
});
}
}
// 请假类型
function chooseQJLX() {
showSetting.value = true;
}
//确认用户的选择请假类型
function onConfirm() {
showSetting.value = false;
form.value.qjlx = isActive.value;
let obj = D_BZ_QXJLX.value.find((v) => {
return v.dm == isActive.value;
});
form.value.qjlxmc = obj.zdmc;
}
// 时间点击
function chooseTime(val) {
timeType.value = val;
showksPicker.value = true;
}
// 时间选择
function onksConfirm(val) {
showksPicker.value = false;
switch (timeType.value) {
case "kssj":
form.value.kssj = timeValidate(val, "ymd");
form.value.jssj = form.value.kssj;
break;
case "jssj":
form.value.jssj = timeValidate(val, "ymd");
break;
}
timeType.value = null;
}
function ksChange(val) {
switch (timeType.value) {
case "kssj":
form.value.kssj = timeValidate(val, "ymd");
break;
case "jssj":
form.value.jssj = timeValidate(val, "ymd");
break;
}
}
</script>
<style lang="scss" scoped>
@import "../../../../assets/styles/mixin.scss";
.concent {
margin-top: 16vw;
}
::v-deep .van-radio-group {
padding: 5vw;
}
::v-deep .van-radio {
padding: 2vw 0;
}
.van-cell {
@include table_item_color($table-item-theme);
box-sizing: border-box;
border-radius: 4px;
padding: 6px;
margin: 8px 4%;
width: 92%;
overflow: hidden;
color: var(--van-cell-text-color);
font-size: var(--van-cell-font-size);
line-height: var(--van-cell-line-height);
}
</style>

View File

@ -0,0 +1,158 @@
<template>
<div>
<TopNav
navTitle="人员休假"
:showRight="true"
:showLeft="true"
rightIcon="add-o"
@clickRight="onClickRight('','add')"
/>
</div>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text=" "
@load="onLoad"
offset="30"
:immediate-check="false"
>
<ul class="rest">
<li class="rest-item" v-for="(item,index) in datalist.list" :key="index">
<div class="title">
<span class="bt">{{item.sqrXm}}的提交请假</span>
<span class="time">{{item.xtCjsj}}</span>
</div>
<div class="item">请假类型{{setDict(item.qjlx, D_BZ_QXJLX)}}</div>
<div class="item">开始时间{{item.kssj}}</div>
<div class="item">结束时间{{item.jssj}}</div>
<div class="item-bottom">
<span class="pass"></span>
<span class="edit" @click="onClickRight(item.id,'edit')">修改</span>
</div>
</li>
<van-empty
v-if="datalist.list.length<=0"
description="暂无请假记录"
image="default"/>
</ul>
</van-list>
</van-pull-refresh>
</template>
<script setup>
import { ryqjList } from "../../../api/qwzx.js";
import TopNav from "../../../components/topNav.vue";
import router from "../../../router/index.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, reactive, onMounted,getCurrentInstance} from "vue";
const { D_BZ_QXJLX } = getDictList("D_BZ_QXJLX"); //字典信息请假类型
const { proxy } = getCurrentInstance();
const user = ref(JSON.parse(window.localStorage.getItem("userInfo")));
const datalist = reactive({
list:[]
})
const finished = ref(false)
const loading = ref(false)
const loadingPull = ref(false);
const pageCurrent = ref(1)
const pageSize = ref(10)
const total = ref(0)
onMounted(() => {
getDataList()
});
// 查询列表
function getDataList(){
let params = {
pageCurrent:pageCurrent.value,
pageSize:pageSize.value,
}
loading.value = true
ryqjList(params).then((res)=>{
if(pageCurrent.value == 1){
datalist.list = res.records
}else{
datalist.list = datalist.list.concat(res.records)
}
loadingPull.value = false;
loading.value = false
pageCurrent.value = res.pages
pageSize.value = res.size
total.value = res.total
}).catch(()=>{
loading.value = false
})
}
//触底加载
function onLoad() {
if (datalist.list.length == total.value) {
finished.value = true;
return;
}
pageCurrent.value += 1;
getDataList();
}
//下拉刷新
function onRefresh() {
pageCurrent.value = 1;
finished.value = false
getDataList();
}
//跳转添加页面
function onClickRight(id,type) {
router.push({path:"/deptryxjCalendar/addEdit",query:{id,type}});
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.van-pull-refresh {
margin-top: 16vw;
.rest{
width: 100%;
height: 100%;
padding: 0 4vw;
box-sizing: border-box;
.rest-item{
border-bottom: 1px solid #e9e9e9;
padding: 1vw 0;
box-sizing: border-box;
.title{
display: flex;
justify-content: space-between;
align-items: center;
height: 6vw;
.bt{
font-weight: 600;
@include font_size($font_medium_s);
}
.time{
color: #cccccc;
@include font_size($font_medium_s);
}
}
.item{
line-height: 5vw;
@include font_size($font_medium_s);
}
.item-bottom{
@include font_size($font_medium_s);
display: flex;
justify-content: space-between;
align-items: center;
height: 6vw;
.pass{
color: #06ae56;
}
.edit{
color: #10aeff;
}
}
}
}
}
</style>

View File

@ -0,0 +1,351 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="我的巡防清单" :showLeft="true" />
<div class="calenderBox">
<div class="calender-head">
<div class="btn" @click="last">
<van-icon name="arrow-left" color="#fff" />
</div>
<div class="text">{{ Year }}{{ month }}</div>
<div class="btn" @click="next">
<van-icon name="arrow" color="#fff" />
</div>
<div class="change" @click="isChange = !isChange">
<van-icon name="exchange" size="16" color="#3e6ee8" />
{{ isChange ? "切换表格" : "切换列表" }}
</div>
</div>
<!-- 日历列表 -->
<div v-if="!isChange" class="list">
<ul class="week">
<li class="days" v-for="(item, index) in week" :key="index">
{{ item }}
</li>
</ul>
<div class="wrap">
<div class="item" v-for="(item, index) in calendarList" :key="index">
<div class="num">
{{ item.value }}<span v-show="item.value"></span>
</div>
<div class="status" v-show="item.value">
<span
@click="routePush(evn, item)"
v-for="(evn, index) in item.status"
:key="index + 'evn'"
v-show="item.value"
:style="{ background: evn.color }"
>{{ evn.text }}</span
>
</div>
<div
class="time"
:class="
item.status == '请假'
? 'greenColor'
: item.status == '未报备'
? 'grayColr'
: ''
"
v-show="item.value"
></div>
</div>
</div>
</div>
<!-- 日历列表 -->
<div v-else class="list">
<CalendarList :listData="listData"></CalendarList>
</div>
</div>
</div>
</template>
<script setup>
import { getPbbbByMonth } from "../../../api/calender";
import TopNav from "../../../components/topNav.vue";
import CalendarList from "../components/calendarList.vue";
import { onMounted, reactive, ref } from "vue";
import { useRouter } from "vue-router";
import { Toast } from "vant";
const router = useRouter();
const isChange = ref(false);
const week = ref(["周日", "周一", "周二", "周三", "周四", "周五", "周六"]);
const Year = ref(new Date().getFullYear()); //日历上的年份
const month = ref(new Date().getMonth() + 1); //日历上的月份
const Day = ref(new Date().getDate()); //日历上的天份
const listData = ref([]);
const nowYear = ref(new Date().getFullYear());
const nowmonth = ref(new Date().getMonth() + 1);
const nowDay = ref(new Date().getDate());
const starttime = ref("");
const endtime = ref("");
const nowtime = ref("");
const calendarList = ref([]);
onMounted(() => {
Draw(nowYear.value, nowmonth.value);
let time_month = nowmonth.value; //现在的月份
let time_day = nowDay.value; //现在的天数
if (nowmonth.value < 10) {
time_month = 0 + "" + nowmonth.value;
}
if (nowDay.value < 10) {
time_day = 0 + "" + nowDay.value;
}
nowtime.value = nowYear.value + "-" + time_month + "-" + time_day;
starttime.value = nowtime.value;
endtime.value = nowtime.value;
});
function routePush(e, t) {
const timeDay = new Date();
let y = timeDay.getFullYear();
let m =
timeDay.getMonth() + 1 < 10
? "0" + (timeDay.getMonth() + 1)
: timeDay.getMonth() + 1;
let d = timeDay.getDate() < 10 ? "0" + timeDay.getDate() : timeDay.getDate();
const dtime = y + "-" + m + "-" + d;
if (e.zt === "04") {
return false;
} else {
router.push({
path: "/xfbbInfo",
query: {
zt: e.zt,
pbid: e.zt === "01" ? e.id : null,
bbid: e.zt === "01" ? null : e.id,
isDay: dtime === t.count ? 1 : 0,
},
});
}
}
//状态字典
const ztDict = [
{
label: "未执勤",
value: "01",
color: "#7b7b7b",
},
{
label: "执勤中",
value: "02",
color: "#51fb06",
},
{
label: "已执勤",
value: "03",
color: "#0084ff",
},
{
label: "请假",
value: "04",
color: "#f00",
},
];
//状态数据处理
function checkZt(list = []) {
var zt = [];
if (list.length > 0) {
zt = list.map((item) => {
return {
text: ztDict.filter((item2) => item2.value === item.zt)[0].label,
color: ztDict.filter((item2) => item2.value === item.zt)[0].color,
id: item.id,
zt: item.zt,
};
});
}
return zt;
}
function Draw(Year, Month) {
getPbbbByMonth({ time: Year + "-" + Month })
.then((res) => {
listData.value = [];
res.map((item) => {
if (item.list.length === 0) {
listData.value.push({
time: Year + "-" + Month + "-" + item.day,
zqsj: "--",
zqzt: "--",
zt: "04",
});
} else {
item.list.map((env) => {
listData.value.push({
time: Year + "-" + Month + "-" + item.day,
zqsj: env.time,
zqzt: ztDict.filter((item2) => item2.value === env.zt)[0].label,
zt: env.zt,
id: env.id,
});
});
}
});
calendarList.value = res.map((item, index) => {
return {
value: index + 1,
kssj: "20:00", //假数据
jssj: "23:59",
status: checkZt(item.list), //假的状态
count: Year + "-" + Month + "-" + item.day,
};
});
for (
var i = 1, firstDay = new Date(Year, Month - 1, 1).getDay();
i <= firstDay;
i++
) {
calendarList.value.unshift("");
}
})
.catch((err) => {});
}
// 上个月
function last() {
month.value--;
if (month.value == 0) {
month.value = 12;
Year.value--;
}
Draw(Year.value, month.value);
}
// 下个月
function next() {
month.value++;
if (month.value == 13) {
month.value = 1;
Year.value++;
}
Draw(Year.value, month.value);
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.calenderBox {
width: 100%;
padding: 1vw;
box-sizing: border-box;
.calender-head {
width: 100%;
height: 15vw;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-weight: bold;
line-height: 40px;
position: relative;
.change {
position: absolute;
right: 1vw;
bottom: 2vw;
cursor: pointer;
color: #3e6ee8;
@include font_size($font_medium_s);
}
.btn {
width: 7vw;
height: 7vw;
line-height: 7vw;
text-align: center;
border-radius: 1vw;
background: #3e6ee8;
color: #fff;
}
.text {
margin: 0 4vw;
@include font_color($font-color-theme);
}
}
.week {
width: 100%;
display: flex;
flex-wrap: nowrap;
text-align: center;
height: 10vw;
line-height: 10vw;
background: #164acc;
color: #fff;
.days {
flex: 1;
}
}
.wrap {
width: 100%;
display: flex;
flex-wrap: wrap;
.item {
width: calc((100% / 7) - 1.3px);
border: 1px solid #3e6ee8;
border-top: none;
font-size: 10px;
min-height: 15vw;
.num {
text-align: right;
padding-right: 1vw;
box-sizing: border-box;
@include font_color($font-color-theme);
}
.status {
text-align: center;
margin: 1vw 0;
span {
background: #3e6ee8;
padding: 1px 1vw;
display: block;
width: 10vw;
color: #fff;
border-radius: 1vw;
margin: 6px auto;
}
.green {
background: #1adb10;
}
.gray {
background: #83868f;
}
}
.time {
font-size: 10px;
// height: 5vw;
// line-height: 7vw;
color: #3e6ee8;
text-align: center;
}
.greenColor {
color: #1adb10;
}
.grayColr {
color: #83868f;
}
.BlueColor {
color: #3e6ee8;
}
}
.item:nth-child(7n + 2) {
border-left: none;
}
.item:nth-child(7n + 3) {
border-left: none;
}
.item:nth-child(7n + 4) {
border-left: none;
}
.item:nth-child(7n + 5) {
border-left: none;
}
.item:nth-child(7n + 6) {
border-left: none;
}
.item:nth-child(7n + 7) {
border-left: none;
}
}
}
.list {
max-height: calc(100vh - 35vw);
// overflow: hidden;
// overflow-y: auto;
}
</style>

View File

@ -0,0 +1,262 @@
<template>
<div>
<TopNav navTitle="盘查车辆" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Tabs
:list="tabs"
@onYjjb="onSelect"
:type="'car'"
:key="tabsIndex"
></Tabs>
<Search
placeholder="请输入关键字"
v-model="infoValue"
:isSx="true"
@update:sx="showPopup = !showPopup"
@update:modelValue="onSearch"
></Search>
</div>
</van-sticky>
<SxPopup
:showPopup="showPopup"
:list="pccl.sxList"
:p_top="145"
@update:close="showPopup = false"
@update:onConfirm="onConfirm"
/>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list
:finished="finished"
finished-text=" "
@load="onLoad"
offset="1"
:immediate-check="false"
>
<List
v-for="(item, index) in pccl.list"
:key="index"
:item="item"
:dict="{ D_BZ_HPZL }"
/>
<van-empty
description="暂无信息"
image="default"
v-if="pccl.list.length <= 0 && showEmpty"
/>
</van-list>
<van-loading style="text-align: center" v-if="loading"
>加载中...</van-loading
>
</van-pull-refresh>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import TopNav from "../../../components/topNav.vue";
import Search from "../../../components/search.vue";
import Tabs from "../../../components/tabs.vue";
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/pcclList.vue";
import { setTimeQuantum } from "../../../utils/tools.js";
import { getClpcPcList, getClpcCount } from "../../../api/common.js";
import { getDictList, setDict } from "../../../utils/dict";
const { D_BZ_YJLX, D_BZ_TYJB, D_BZ_PCCLJG, D_BZ_HPZL } = getDictList(
"D_BZ_YJLX",
"D_BZ_TYJB",
"D_BZ_PCCLJG",
"D_BZ_HPZL"
); //字典信息
const showEmpty = ref(false);
const loading = ref(false);
const loadingPull = ref(false);
const finished = ref(false);
const infoValue = ref("");
const showPopup = ref(false); //筛选弹窗
const pccljg = ref("");
const tabsIndex = ref(1);
const pccl = reactive({
page: 1,
kssj: "",
jssj: "",
total: 0,
sxList: [{}, setTimeQuantum()], //筛选条件数据
list: [],
});
const tabs = ref([
{
name: "全部",
count: 0,
},
{
name: "放行",
count: 0,
},
{
name: "移交",
count: 0,
},
{
name: "盘查",
count: 0,
},
]);
onMounted(() => {
// getCount("1");
// getCount("2");
// getCount("9");
getCount();
getData();
});
// 切换tabs
function onSelect(val) {
pccl.page = 1;
switch (val) {
case 0:
pccljg.value = "";
break;
case 1:
pccljg.value = "1";
break;
case 2:
pccljg.value = "2";
break;
case 3:
pccljg.value = "9";
break;
}
getData();
}
// 时间筛选
function onConfirm(val) {
pccl.list = [];
pccl.page = 1;
pccl.kssj = val.startTime;
pccl.jssj = val.endTime;
getData();
getCount();
}
// 滚动加载
function onLoad() {
if (pccl.page >= pccl.total) {
finished.value = true;
return;
}
pccl.page += 1;
getData();
}
// 搜索
function onSearch(val) {
pccl.list = [];
pccl.page = 1;
pccljg.value = "";
pccl.jssj = "";
pccl.kssj = "";
infoValue.value = val;
getData();
getCount();
}
// 统计
function getCount(val) {
let params = {
// pcclJg: val,
// pageCurrent: 1,
// pageSize: 10,
hphm: infoValue.value,
kssj: pccl.kssj,
jssj: pccl.jssj,
};
getClpcCount(params).then((res) => {
tabs.value[1].count = res.fx;
tabs.value[2].count = res.yj;
tabs.value[3].count = res.pc;
tabs.value[0].count = res.All;
// switch (val) {
// case "1":
// tabs.value[1].count = res.total;
// break;
// case "2":
// tabs.value[2].count = res.total;
// break;
// case "9":
// tabs.value[3].count = res.total;
// break;
// case "":
// tabs.value[0].count = res.total;
// break;
// }
});
}
//下拉刷新
function onRefresh() {
pccl.list = [];
pccl.page = 1;
// pccljg.value = "";
pccl.jssj = "";
pccl.kssj = "";
infoValue.value = "";
tabsIndex.value++;
// getCount("1");
// getCount("2");
// getCount("9");
// getCount("");
getData();
}
// 获取列表
function getData(val) {
loading.value = true;
let params = {
pcclJg: pccljg.value,
kssj: pccl.kssj,
jssj: pccl.jssj,
pageCurrent: pccl.page,
pageSize: 10,
hphm: infoValue.value,
};
// loading.value = true
getClpcPcList(params)
.then((res) => {
loading.value = false;
loadingPull.value = false;
let arr = res.records ? res.records : [];
if (!res.records || res.records.length <= 0) showEmpty.value = true;
if (pccl.page == 1) {
pccl.list = arr;
} else {
pccl.list = pccl.list.concat(arr);
}
switch (val) {
case "1":
tabs.value[1].count = res.total;
break;
case "2":
tabs.value[2].count = res.total;
break;
case "9":
tabs.value[3].count = res.total;
break;
case "":
tabs.value[0].count = res.total;
break;
}
pccl.total = res.total;
})
.catch(() => {
loading.value = false;
showEmpty.value = true;
});
}
</script>
<style lang="scss" scoped>
.van-list {
height: calc(100vh - 38vw);
overflow: hidden;
overflow-y: auto;
}
</style>

View File

@ -0,0 +1,303 @@
<template>
<div class="">
<TopNav navTitle="预警指令反馈" />
<div class="contentBox">
<div class="item_box item">
<van-field
v-model="formData.time"
placeholder="请选择处置时间"
rows="2"
label="处置时间"
label-width="60px"
input-align="right"
right-icon="arrow-down"
@click="show = true" />
<van-popup
v-model:show="show"
position="bottom"
:style="{height:'30%'}">
<van-datetime-picker
v-model="time"
type="datatime"
title="选择时间"
@confirm="chooseTime"
@cancel="show = false"
/>
</van-popup>
</div>
<div class="item_box item">
<van-field
v-model="fknrCnt"
label="处置地点"
autosize type="textarea"
label-width="60px"
placeholder="请输入处置地点"/>
</div>
<div class="item_box item">
<van-field
v-model="formData.czcs"
placeholder="请选择处置措施"
rows="2" label="处置措施" label-width="60px" input-align="right"
right-icon="arrow-down" @click="isShowType = true" />
<van-action-sheet v-model:show="isShowType">
<van-picker
:columns="diposalMeasure"
@confirm="chooseCzcs"
@cancel="isShowType = false"
/>
</van-action-sheet>
</div>
<div class="item_box item">
<van-field
v-model="formData.czjg"
rows="2"
label="处置结果"
placeholder="请选择处置结果"
label-width="60px" input-align="right"
right-icon="arrow-down" @click="isShow = true" />
<van-action-sheet v-model:show="isShow">
<van-picker
:columns="disposalResults"
@confirm="chooseCzjg"
@cancel="isShow = false"
/>
</van-action-sheet>
</div>
<div class="item_box item itemTextArea">
<van-field
v-model="formData.czjgms"
rows="2"
label="处置经过描述"
autosize
type="textarea"
label-width="100px"
maxlength="200"
placeholder="请输入处置经过描述"
show-word-limit/>
</div>
<div class="item_box item">
<div class="flex-item">
<van-field
v-model="formData.czmj"
label="处置民警"
autosize
type="textarea"
label-width="60px"
placeholder="请输入处置民警"/>
<div class="czBtn" @click="addMj">按钮</div>
</div>
<div class="policeCardWrap">
<div class="policeCardCon" v-for="(item,index) in mjList" :key="index">
<div class="policeCard">{{item}}</div>
<span class="close" @click="deleteMj(index)">
<van-icon name="close"></van-icon>
</span>
</div>
</div>
</div>
<div class="info_box item_box">
<div class="title">文件上传</div>
<van-uploader :after-read="afterRead" v-model="fileList" />
</div>
</div>
<div @click="formSubmit()" class="btnWrap">
<van-button :loading="loading" round block type="primary">提交</van-button>
</div>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import router from "../../../router";
import { ref, onMounted } from "vue";
const time = ref(new Date())
const loading = ref(false)
const show = ref(false)
const isShow = ref(false)
const isShowType = ref(false)
const formData = ref({
time: '', //时间
czcs:'',//处置措施
czjg:'',//处置结果
disposalArea: '',
diposalMeasure: '1',
disposalResults: '1',
czjgms: '',
czmj: '',
imageUrl: []
})
const index1 = ref('')
const index2 = ref(0)
const diposalMeasure = ref(['抓捕', '管控'])
const disposalResults = ref(['抓获', '未抓获'])
const mjList = ref(['张三'])
const upImgGroup = ref([])
const fileList = ref([]);
// 选择时间
function chooseTime(val){
formData.value.time = dateFormat(val)
show.value = false
}
// 选择处置措施
function chooseCzcs(val){
formData.value.czcs = val
isShowType.value = false
}
// 选择处置结果
function chooseCzjg(val){
formData.value.czjg = val
isShow.value = false
}
function formSubmit(e) {
let that = this
router.push("/yjzl");
// uni.showModal({
// content: '是否提交反馈信息',
// confirmText: '确认',
// showCancel: false,
// success(res) {
// if (res.confirm) {
// that.$post('/dispatchWarning/yjzl/doDeal', {
// 'czsj': that.date,
// 'czddxz': that.formData.disposalArea,
// 'czcs': that.formData.diposalMeasure,
// 'czjg': that.formData.disposalResults,
// 'czjgms': that.formData.czjgms,
// 'czmj': that.mjList.join(','),
// 'yjzlId': that.xqId,
// 'fileids': that.imgs.join(',')
// }).then(res => {
// uni.navigateBack({
// delta: 2
// })
// }).catch(err =>{
// uni.showToast({
// title:err
// })
// })
// }
// }
// })
}
// 删除民警
function deleteMj(index) {
mjList.value.splice(index, 1)
}
// 新增民警
function addMj() {
mjList.value.push(formData.value.czmj)
formData.value.czmj = ''
}
// 时间处理
function dateFormat(time) {
let date = new Date(time);
let year = date.getFullYear();
let month = date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1;
let day = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
let hours = date.getHours() < 10 ? "0" + date.getHours() : date.getHours();
let minutes = date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes();
let seconds = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
return year + "-" + month + "-" + day + ' ' + hours + ':' + minutes + ':' + seconds;
}
function getDate(type) {
const date = new Date();
let year = date.getFullYear();
let month = date.getMonth() + 1;
let day = date.getDate();
if (type === 'start') {
year = year - 60;
} else if (type === 'end') {
year = year + 2;
}
month = month > 9 ? month : '0' + month;
day = day > 9 ? day : '0' + day;
return `${year}-${month}-${day}`;
}
function afterRead(file) {
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.contentBox{
margin-top: 14vw;
padding: 3vw 2vw;
box-sizing: border-box;
.item{
margin-bottom: 4vw;
.flex-item{
position: relative;
.czBtn{
width: 10vw;
position: absolute;
top: 4vw;
right: 4vw;
color: rgb(66, 136, 231);
@include font_size($font_medium_s);
}
}
.policeCardWrap {
padding: 1vw;
box-sizing: border-box;
display: flex;
flex-wrap: wrap;
.policeCardCon {
position: relative;
@include font_size($font_medium_s);
background-color: #092C5D;
margin-right: 2vw;
text-align: center;
margin-bottom: 2vw;
border-radius: 1vw;
color: #fff;
.policeCard {
padding: 1vw 5vw;
box-sizing: border-box;
}
.close{
position: absolute;
right: 0vw;
top: 0vw;
}
}
}
}
.info_box{
padding: 4vw;
box-sizing: border-box;
.title {
@include font_size($font_medium);
margin-bottom: 4vw;
}
}
.itemTextArea{
::v-deep .van-field__control{
height: 200px !important;
}
}
}
.btnWrap {
padding: 2vw 4vw;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,219 @@
<template>
<div>
<TopNav navTitle="盘查人员" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Tabs :list="tabs" @onYjjb="onSelect" :type="'car'" :key="tabsIndex"></Tabs>
<Search placeholder="请输入人员姓名" v-model="kwd" :isSx="true" @update:sx="showPopup = !showPopup"
@update:modelValue="onSearch"></Search>
</div>
</van-sticky>
<SxPopup :showPopup="showPopup" :list="yjxx.sxList" :p_top="145" @update:close="showPopup = false"
@update:onConfirm="onConfirm" />
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list v-model:loading="loading" :finished="finished" finished-text=" " @load="onLoad" offset="1"
:immediate-check="false">
<List v-for="(item, index) in yjxx.list" :key="index" :item="item"
:dict="{ D_BZ_YJLX, D_BZ_TYJB, D_BZ_PCCLJG }" />
<van-empty description="暂无信息" image="default" v-if="yjxx.list.length <= 0 && showEmpty" />
</van-list>
</van-pull-refresh>
</div>
</template>
<script setup>
import { getYjxxTj, getPageList } from "../../../api/yjxx.js";
import { getRypcList, getRypcCount } from "../../../api/common.js";
import TopNav from "../../../components/topNav.vue";
import Search from "../../../components/search.vue";
import Tabs from "../../../components/tabs.vue";
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/PcList.vue";
import { setTimeQuantum } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, reactive, onMounted, watch } from "vue";
const showEmpty = ref(false);
const { D_BZ_YJLX, D_BZ_TYJB, D_BZ_PCCLJG } = getDictList(
"D_BZ_YJLX",
"D_BZ_TYJB",
"D_BZ_PCCLJG"
); //字典信息
watch(D_BZ_PCCLJG, (newValue) => {
for (let i = 0; i < newValue.length; i++) {
newValue[i].name = newValue[i].text;
newValue[i].key = newValue[i].dm;
newValue[i].isCheck = false;
}
yjxx.sxList = [
{
title: "盘查处理结果",
isCheckBox: true,
array: newValue,
},
];
//时间段选项
yjxx.sxList[1] = setTimeQuantum();
});
const tabsIndex = ref(1);
const total = ref(0);
const tabs = ref([
{
name: "全部",
count: 0,
pclx: "",
},
{
name: "盘查",
count: 0,
pclx: "9",
},
{
name: "移交",
count: 0,
pclx: "2",
},
{
name: "放行",
count: 0,
pclx: "1",
},
]);
const yjxx = reactive({
pageNum: 1,
pageSize: 10,
yjJb: "",
yjLx: "",
startTime: "",
endTime: "",
yjLx: "",
sxList: [], //筛选条件数据
list: [], //预警列表数据
});
const kwd = ref("");
const finished = ref(false);
const loading = ref(false);
const loadingPull = ref(false);
const showPopup = ref(false); //筛选弹窗
onMounted(() => {
getList();
tj();
// tj(9);
// tj(2);
// tj(1);
});
//下拉刷新
function onRefresh() {
yjxx.list = [];
yjxx.pageNum = 1;
kwd.value = "";
yjxx.startTime = "";
yjxx.endTime = "";
yjxx.yjLx = "";
tabsIndex.value++;
getList();
// tj();
// tj(9);
// tj(2);
// tj(1);
}
// 获取警情信息
function getList() {
loading.value = true;
getRypcList({
pageCurrent: yjxx.pageNum,
pageSize: yjxx.pageSize,
xm: kwd.value,
kssj: yjxx.startTime,
jssj: yjxx.endTime,
pcclJg: yjxx.yjLx,
})
.then((res) => {
loading.value = false;
loadingPull.value = false;
if (!res.records || res.records.length <= 0) showEmpty.value = true;
if (yjxx.pageNum == 1) {
yjxx.list = res.records;
} else {
res.records.forEach((item) => {
yjxx.list.push(item);
});
}
total.value = res.pages;
})
.catch((err) => {
loading.value = false;
showEmpty.value = true;
});
}
function tj(val) {
getRypcCount({
// pageCurrent: yjxx.pageNum,
// pageSize: yjxx.pageSize,
xm: kwd.value,
kssj: yjxx.startTime,
jssj: yjxx.endTime,
// pcclJg: val,
}).then((res) => {
tabs.value[1].count = res.pc;
tabs.value[2].count = res.yj;
tabs.value[3].count = res.fx;
tabs.value[0].count = res.All;
// if (val == 9) {
// tabs.value[1].count = res.total;
// } else if (val == 2) {
// tabs.value[2].count = res.total;
// } else if (val == 1) {
// tabs.value[3].count = res.total;
// } else {
// tabs.value[0].count = res.total;
// }
});
}
/**
* tab选择
* @param {Object} val
*/
function onSelect(val) {
yjxx.pageNum = 1;
yjxx.yjLx = tabs.value[val].pclx;
getList();
// tj();
}
/**
* 关键字搜索
* @param {Object} val
*/
function onSearch(val) {
yjxx.pageNum = 1;
getList();
tj();
}
// 弹框盒子
function onConfirm(val) {
yjxx.startTime = val.startTime;
yjxx.endTime = val.endTime;
let arr = [];
val.list[0].array.forEach((item) => {
if (item.isCheck) {
arr.push(item.value);
}
});
yjxx.yjLx = arr.join(",");
yjxx.pageNum = 1;
getList();
tj();
showPopup.value = false;
}
function onLoad() {
if (yjxx.pageNum >= total.value) {
finished.value = true;
return;
}
yjxx.pageNum += 1;
getList();
}
</script>
<style scoped></style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,341 @@
<template>
<div class="tjyj-box">
<TopNav navTitle="添加意见" />
<div class="info_box">
<div class="yjlx-box info_box item_box">
<div class="title">意见类型</div>
<van-radio-group v-model="isActive" direction="horizontal" @change="chooseRadio">
<van-radio :disabled="status" v-for="(item, index) in radioList" :key="index" :name="item.val">{{ item.name
}}</van-radio>
</van-radio-group>
</div>
<div class="item_box">
<van-field v-model="seleatDate" rows="2" :disabled="status" label="系统来源" label-width="60px" input-align="right"
right-icon="arrow-down" @click="isShowType = true" />
<van-action-sheet v-model:show="isShowType">
<van-picker :columns="xtlyList" @confirm="groupChange" @cancel="isShowType = false" />
</van-action-sheet>
</div>
<div class="item_box">
<van-field :disabled="status" v-model="sugesstName" rows="2" label="意见名称" label-width="60px"
input-align="right" />
</div>
<div class="item_box">
<van-field v-model="fknrCnt" :disabled="status" rows="2" label="意见描述" autosize type="textarea" label-width="60px"
:count="!status ? true : false" maxlength="200" placeholder="请输入内容" show-word-limit />
</div>
<div class="info_box item_box">
<div class="title">文件上传</div>
<van-uploader :after-read="afterRead" :disabled="status" v-model="fileList" />
</div>
</div>
<div class="submit_but" v-if="status">
<van-button round @click="status = 0" block type="primary">编辑</van-button>
<van-button round :loading="loading" block @click="handleDelete" type="danger">删除</van-button>
</div>
<div class="submit_but" v-else>
<van-button :loading="loading" round @click="submit" block type="primary">提交</van-button>
</div>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import {
editYyzxApi,
deleteYyzxApi,
addYyzxApi,
uploadImg,
} from "../../../api/yyzxApi.js";
import { baseUrl2 } from "../../../utils/request";
import { ref, onMounted, reactive } from "vue";
import { useRouter } from "vue-router";
import { Toast } from "vant";
import { hintToast } from "../../../utils/tools";
let userInfo = JSON.parse(getStorage("userInfo")); //用户信息
const router = useRouter();
const editInfo = ref({});
const yjlxValue = ref(1);
const isActive = ref(1);
const loading = ref(false);
const seleatDate = ref("请选择");
const selectDm = ref("");
const slectType = ref("系统问题");
const sugesstName = ref("系统问题-");
const radioList = ref([
{
name: "系统问题",
val: 1,
},
{
name: "功能改进",
val: 2,
},
{
name: "新需求",
val: 3,
},
]);
const fknrCnt = ref("");
const radioValue = ref("系统问题");
const isShowType = ref(false);
const XTFK_LIST = ref([
{
zdmc: "智慧云览",
zddm: "01",
},
{
zdmc: "智慧云踪",
zddm: "02",
},
{
zdmc: "智慧云搜",
zddm: "03",
},
{
zdmc: "智慧云基",
zddm: "04",
},
{
zdmc: "智慧云侦",
zddm: "05",
},
{
zdmc: "智慧云法",
zddm: "06",
},
{
zdmc: "智慧云指",
zddm: "07",
},
{
zdmc: "智慧云眸",
zddm: "08",
},
{
zdmc: "智慧云控",
zddm: "09",
},
{
zdmc: "智慧云防",
zddm: "10",
},
{
zdmc: "智慧云管",
zddm: "11",
},
{
zdmc: "智慧云舆",
zddm: "12",
},
]);
const xtlyList = ref([
"智慧云览",
"智慧云踪",
"智慧云搜",
"智慧云基",
"智慧云侦",
"智慧云法",
"智慧云指",
"智慧云眸",
"智慧云控",
"智慧云防",
"智慧云管",
"智慧云舆",
]);
const fileList = ref([]);
const status = ref(0);
onMounted(() => {
if (router.currentRoute.value.query.info) {
let obj = JSON.parse(router.currentRoute.value.query.info);
editInfo.value = obj;
status.value = 1;
fknrCnt.value = obj.fknr;
let arr = obj.fkfj ? obj.fkfj.split(",") : [];
let brr = [];
arr.forEach((item) => {
let urlImg = baseUrl2 + "/mosty-api/mosty-base/minio/image/download/" + item;
let obj = {
url: urlImg,
codeId: item,
isImage: true,
status: "done",
message: "上传成功",
};
brr.push(obj);
});
fileList.value = brr;
radioList.value.forEach((item) => {
if (obj.fklx == item.val) {
isActive.value = item.val;
slectType.value = item.name;
sugesstName.value = item.name + "-" + seleatDate.value;
}
});
XTFK_LIST.value.forEach((item) => {
if (obj.fkxt == item.zddm) {
seleatDate.value = item.zdmc;
selectDm.value = item.zddm;
sugesstName.value = slectType.value + "-" + seleatDate.value;
}
});
} else {
status.value = 0;
}
});
function afterRead(file) {
const data = new FormData();
data.append("file", file.file);
file.status = "uploading";
file.message = "上传中...";
uploadImg(data)
.then((res) => {
file.status = "done";
file.message = "上传成功";
file.codeId = res;
})
.catch(() => {
file.status = "failed";
file.message = "上传失败";
});
}
function chooseRadio(val) {
if (!status.value) {
radioList.value.forEach((item) => {
if (item.val == val) {
yjlxValue.value = val;
slectType.value = item.name;
sugesstName.value = item.name + "-" + seleatDate.value;
}
});
}
}
// 系统来源提交
function groupChange(val) {
XTFK_LIST.value.forEach((item) => {
if (val == item.zdmc) {
seleatDate.value = item.zdmc;
selectDm.value = item.zddm;
sugesstName.value = slectType.value + "-" + seleatDate.value;
}
});
isShowType.value = false;
}
// 删除
function handleDelete() {
loading.value = true;
// deleteYyzxApi('http://80.35.14.110:8011/mosty-rzzx/tbRzXtfk/delEntity?id=' + editInfo.value.id).then(res => {
deleteYyzxApi("/mosty-rzzx/tbRzXtfk/delEntity?id=" + editInfo.value.id)
.then((res) => {
Toast.success("删除成功");
router.push("/yjsj");
loading.value = false;
})
.catch(() => {
Toast.fail("删除失败");
loading.value = false;
});
}
// 提交
function submit() {
let imgArr = [];
fileList.value.forEach((item) => {
imgArr.push(item.codeId);
});
loading.value = true;
if (editInfo.value.id) {
editInfo.value.fklx = yjlxValue.value;
editInfo.value.fkxt = selectDm.value;
editInfo.value.fknr = fknrCnt.value;
editInfo.value.fkfj = imgArr.join(",");
let params = { ...editInfo.value };
editYyzxApi("/mosty-rzzx//tbRzXtfk/updateById", params)
.then((res) => {
loading.value = false
if (res) {
hintToast("提交成功");
setTimeout(()=>{ router.go(-1); },2e3)
} else {
hintToast("提交失败");
}
})
.catch(() => {
loading.value = false
hintToast("提交失败");
});
} else {
let prams = {
fklx: yjlxValue.value, //1-系统问题2-功能改进建议3-新需求
fkxt: selectDm.value,
fknr: fknrCnt.value,
fkfj: imgArr.join(","),
ssbmdm: userInfo.deptList[0].deptId,
};
addYyzxApi("/mosty-rzzx/tbRzXtfk/addEntity", prams).then((res) => {
loading.value = false
if (res) {
hintToast("提交成功");
setTimeout(()=>{
router.go(-1);
},2e3)
} else {
hintToast("提交失败");
}
})
.catch(() => {
loading.value = false
hintToast("提交失败");
});
}
}
function suceessInfo(info) {
this.$refs.uToast.show({
type: "success",
title: "",
icon: false,
message: info,
});
this.loading = false;
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.tjyj-box {
padding-top: 13vw;
@include font_color($font-color-theme);
@include font_size($font_medium_s);
}
.info_box {
padding: 4vw;
}
.item_box {
margin-bottom: 4vw;
}
.title {
margin-bottom: 4vw;
}
::v-deep #van-field-3-input {
height: 200px !important;
}
.submit_but {
padding: 2vw 4vw;
display: flex;
}
</style>

View File

@ -0,0 +1,740 @@
<template>
<div class="containerBox" style="padding-top: 13vw">
<TopNav navTitle="位置中心" />
<div class="main">
<!-- 位置统计 -->
<div class="contant">
<div class="header">
<span>
<van-icon name="friends" size="20px" color="#3e6ee8"></van-icon>
<span class="title">实时巡组</span>
</span>
</div>
<ItemList title="今日" :list="dayList" />
<ItemList title="近一周" :list="weekList" />
<ItemList title="近一月" :list="monthList" />
</div>
<!-- 实时巡组 -->
<div class="contant">
<div class="header">
<span>
<van-icon name="friends" size="20px" color="#3e6ee8"></van-icon>
<span class="title">实时巡组</span>
</span>
<div class="callAll" style="font-size: 10px">全部呼叫</div>
</div>
<div class="select_box">
<div>
<van-checkbox-group
v-model="checked"
direction="horizontal"
@change="onChangeXfzt"
>
<van-checkbox
icon-size="16"
shape="square"
:name="item.name"
v-for="(item, index) in checkList"
:key="index"
>
<span
class="dian"
:class="
item.name == 0 ? 'online' : item.name == 1 ? 'busy' : ''
"
></span>
{{ item.label }}({{ item.value }})
</van-checkbox>
</van-checkbox-group>
</div>
</div>
<div class="group item_box">
<ul class="groupList positionList" ref="xzScroll">
<li
v-for="item in xzList.list"
:key="item.id"
@click="handelClick(item)"
>
<div class="top">
<div class="top-cnt">
<span
class="dian online"
title="巡逻中"
v-if="item.xfzt == 0"
></span>
<span
class="dian busy"
title="处警中"
v-if="item.xfzt == 1"
></span>
<span class="dian" title="离线" v-if="item.xfzt == 2"></span>
<span class="name">{{ item.jzMc ? item.jzMc:item.fzrXm+'巡组' }}</span
><br />
<span class="other"
>负责人{{ item.fzrXm }} ({{ item.fzrLxdh }})</span
>
</div>
<div class="imgBtn">
<van-icon name="phone-circle-o" color="#25b882" size="30" />
</div>
</div>
<div class="address">
<van-icon
name="location"
size="15px"
color="#3e6ee8"
></van-icon>
<span>{{ item.dqwz }}</span>
</div>
</li>
<van-loading
type="spinner"
v-if="xzLoading"
style="padding-top: 50vw; text-align: center"
/>
<van-empty
image="default"
description="无列表数据"
v-if="xzList.list.length <= 0 && !xzLoading"
/>
</ul>
</div>
</div>
<!-- 人员实时位置 -->
<div class="contant">
<div class="header">
<span>
<van-icon name="manager" size="20px" color="#3e6ee8"></van-icon>
<span class="title">人员实时位置</span>
</span>
</div>
<div class="group item_box">
<Search
v-model="localVal"
placeholder="请输入相关信息"
@update:modelValue="SeachLocation"
></Search>
<ul class="groupList positionList" ref="ryScroll">
<li
v-for="item in wzList.list"
:key="item.id"
@click="handelClick(item)"
style="border-bottom:1px solid #eff0f5"
>
<div class="top">
<div class="top-cnt">
<span class="other">负责人{{ item.yh_xm }}</span>
<div class="text">
{{ item.dwrq }}
{{ item.kssj ? item.kssj.slice(11, 16) : "00:00" }}
{{ item.jssj ? item.jssj.slice(11, 16) : "00:00" }}
</div>
</div>
<div class="imgBtn">
<van-icon name="phone-circle-o" color="#25b882" size="30" />
</div>
</div>
<div class="address" v-if="item.dqwz">
<van-icon
name="location"
size="15px"
color="#3e6ee8"
></van-icon>
<span>{{ item.dqwz }}</span>
</div>
</li>
<van-loading
type="spinner"
v-if="renLoading"
style="padding-top: 4vw; text-align: center"
/>
<van-empty
image="default"
description="无列表数据"
v-if="wzList.list.length <= 0 && !renLoading"
/>
</ul>
</div>
</div>
</div>
</div>
</template>
<script setup>
import {
locationLCS,
locationXZWZS,
locationWZRS,
locationRYSSWZ,
getSelectDeckList,
} from "../../../api/yyzxApi.js";
import ItemList from "../../../components/component/itemList.vue";
import TopNav from "../../../components/topNav.vue";
import { timeValidate, getRecentDay } from "../../../utils/tools.js";
import { ref, reactive, onMounted, defineEmits } from "vue";
import Search from "../../../components/search.vue";
import { Toast } from "vant";
const xzLoading = ref(false);
const xzScroll = ref(null);
const renLoading = ref(false);
const ryScroll = ref(null);
//状态数据
const Searvalue = ref([]); // 巡组搜索关键字
const checked = ref([0, 1, 2]); //巡组复选框
const checkList = reactive([
{
name: 0,
label: "巡逻中",
value: 0,
},
{
name: 1,
value: 0,
label: "处警中",
},
{
name: 2,
value: 0,
label: "离线",
},
]);
const today = ref(timeValidate(new Date(), "ymd")); //今天
const week = ref(getRecentDay(-6, "ymd")); //近7天
const month = ref(getRecentDay(-29, "ymd"));
//今日统计数据
const dayList = ref([
{
name: "坐标总数",
count: 0,
},
{
name: "里程数",
count: 0,
isShowKm: true,
},
{
name: "巡组位置数",
count: 0,
},
]);
//周统计
const weekList = ref([
{
name: "坐标总数",
count: 0,
},
{
name: "里程数",
count: 0,
isShowKm: true,
},
{
name: "巡组位置数",
count: 0,
},
]);
//月统计
const monthList = ref([
{
name: "坐标总数",
count: 0,
},
{
name: "里程数",
count: 0,
isShowKm: true,
},
{
name: "巡组位置数",
count: 0,
},
]);
let pageCurrent = ref(1);
let xzTotal = ref(0);
let xzList = reactive({
list: [],
}); //巡组数据
let wzList = reactive({
list: [],
}); //人员实时位置
const wzTotal = ref(0);
const wzPageNum = ref(1);
const localVal = ref("");
onMounted(() => {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
// <!-- 位置统计 -->
// //里程数 今天 -近七天 -近30天 )
// getLcs(today.value, today.value, "day");
// getLcs(week.value, today.value, "week");
// getLcs(month.value, today.value, "month");
// // //位置人数(坐标总数) 今天 -近七天 -近30天
// getWzrs(today.value, today.value, "day");
// getWzrs(week.value, today.value, "week");
// getWzrs(month.value, today.value, "month");
// // //巡组位置巡数 今天 -近七天 -近30天
// getXzwzs(today.value, today.value, "day");
// getXzwzs(week.value, today.value, "week");
// getXzwzs(month.value, today.value, "month");
// // 实时巡组
// SelectDeckList(0);
// SelectDeckList(1);
// SelectDeckList(2);
// onChangeXfzt();
// // 人员实时位置
// getDataList();
// scroll("xz");
// scroll("ry");
Promise.all([
getLcs(today.value, today.value, "day"),
getLcs(week.value, today.value, "week"),
getLcs(month.value, today.value, "month"),
getWzrs(today.value, today.value, "day"),
getWzrs(week.value, today.value, "week"),
getWzrs(month.value, today.value, "month"),
getXzwzs(today.value, today.value, "day"),
getXzwzs(week.value, today.value, "week"),
getXzwzs(month.value, today.value, "month"),
SelectDeckList(0),
SelectDeckList(1),
SelectDeckList(2),
onChangeXfzt(),
getDataList(),
scroll("xz"),
scroll("ry"),
])
.then((res) => {
Toast.clear();
})
.catch((err) => {
Toast.clear();
});
});
// 里程数
function getLcs(start, end, type) {
let params = {
ksrq: start + " 00:00:00",
jsrq: end + " 23:59:59",
};
locationLCS("/mosty-wzzx/wztj/tj/jrlcs", params).then((res) => {
if (type == "day") {
dayList.value[1].count = (res[0].lcs / 1000).toFixed(0);
}
if (type == "week") {
weekList.value[1].count = (res[0].lcs / 1000).toFixed(0);
}
if (type == "month") {
monthList.value[1].count = (res[0].lcs / 1000).toFixed(0);
}
});
}
// 获取位置人数 / 坐标总数
function getWzrs(start, end, type) {
let params = {
ksrq: start + " 00:00:00",
jsrq: end + " 23:59:59",
};
locationWZRS(params).then((res) => {
if (type == "day") {
dayList.value[0].count = res[0].sl;
}
if (type == "week") {
weekList.value[0].count = res[0].sl;
}
if (type == "month") {
monthList.value[0].count = res[0].sl;
}
});
}
// 获取巡组位置巡数
function getXzwzs(start, end, type, status) {
let params = {
ksrq: start + " 00:00:00",
jsrq: end + " 23:59:59",
};
locationXZWZS("/mosty-wzzx/wztj/tj/jrxzwzs", params).then((res) => {
if (type == "day") {
dayList.value[2].count = res[0].wzs;
}
if (type == "week") {
weekList.value[2].count = res[0].wzs;
}
if (type == "month") {
monthList.value[2].count = res[0].wzs;
}
});
}
//选择巡防状态
function onChangeXfzt() {
let status = checked.value.join(",");
pageCurrent.value = 1;
xzList.list = [];
SelectDeckList(status);
}
//巡组列表
function SelectDeckList(xfzt) {
let data = {
xfzt,
pageSize: 10,
pageCurrent: pageCurrent.value,
};
xzLoading.value = true;
getSelectDeckList("/mosty-qwzx/tbQwXfbb/selectDeckList", data)
.then((res) => {
xzLoading.value = false;
if (res.records.length > 0) {
if (pageCurrent.value == 1) {
xzList.list = res.records;
} else {
xzList.list = xzList.list.concat(res.records);
}
}
xzTotal.value = res.total;
if (xfzt == 0) {
checkList[0].value = res.total;
}
if (xfzt == 1) {
checkList[0].value = res.total;
}
if (xfzt == 2) {
checkList[2].value = res.total;
}
})
.catch(() => {
xzLoading.value = false;
});
}
// 清除搜索
function clearDataSearch() {
wzPageNum.value = 1;
getDataList();
}
// 人员事实位置搜索
function SeachLocation() {
wzPageNum.value = 1;
getDataList();
}
// 人员实时获取数据列表
function getDataList() {
let params = {
yhxm: localVal.value,
pageCurrent: wzPageNum.value,
pageSize: 10,
};
renLoading.value = true;
locationRYSSWZ("/mosty-wzzx/wztj/wz/rywzlb", params)
.then((res) => {
renLoading.value = false;
if (wzPageNum.value == 1) {
wzList.list = res.records ? res.records : [];
} else {
let arr = res.records ? res.records : [];
wzList.list = wzList.list.concat(arr);
}
wzTotal.value = res.total;
})
.catch(() => {
renLoading.value = false;
});
}
//触底加载
function scroll(type) {
let scrollTargetBox = "";
if (type == "xz") {
scrollTargetBox = xzScroll.value;
} else {
scrollTargetBox = ryScroll.value;
}
scrollTargetBox.onscroll = (e) => {
var scrollHeight = scrollTargetBox.scrollHeight;
var scrollTop = scrollTargetBox.scrollTop;
var clientHeight = scrollTargetBox.clientHeight;
if (scrollHeight - clientHeight == scrollTop) {
//滚动条滚到最底部
if (type == "xz") {
if (xzList.list.length < xzTotal.value) {
pageCurrent++;
}
} else {
if (wzList.list.length < wzTotal.value) {
wzPageNum.value++;
getDataList();
}
}
}
};
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.main {
// padding: 0 4vw;
box-sizing: border-box;
height: calc(100vh - 100px);
overflow: hidden;
overflow-y: auto;
.contant {
margin: 2vw 0;
.header {
height: 10vw;
display: flex;
align-items: center;
justify-content: space-between;
margin: 0 3.5vw;
// padding: 2vw 0;
.icon {
display: inline-block;
width: 6vw;
height: 6vw;
border: 1px solid #e5e5e5;
margin-right: 2vw;
}
.title {
font-size: 4vw;
font-weight: 600;
margin-left: 1vw;
@include font_color($font-color-theme);
}
}
.select_box {
padding-top: 8px;
overflow: hidden;
display: flex;
align-items: center;
justify-content: space-between;
padding: 3.5vw;
@include font_size($font_medium_s);
}
// 位置统计
.position {
min-height: 40vh;
.position-item {
height: 24vw;
margin-bottom: 2vw;
display: flex;
border-radius: 2vw;
overflow: hidden;
box-shadow: 0 0 4px 4px #e5e5e5;
.item-left {
display: flex;
align-items: center;
justify-content: center;
width: 10vw;
height: 24vw;
background: #1e4eca;
font-size: 4vw;
color: #fff;
padding: 0 2vw;
box-sizing: border-box;
text-align: center;
}
.item-right {
flex: 1;
display: flex;
justify-content: space-around;
align-items: center;
.item {
text-align: center;
.title {
text-align: center;
font-size: 4vw;
}
.numb {
font-size: 6vw;
font-weight: bold;
line-height: 9vw;
}
.num2 {
color: #e36356;
}
.num3 {
color: #205bf3;
}
.proportion {
text-align: center;
width: 100%;
font-size: 3vw;
img {
margin: 0 2px 0 4px;
}
.up-color {
color: #2bf242;
}
.down-color {
color: #e64a4a;
}
}
}
}
}
}
// 实时巡组
.callAll {
padding: 2px 5px;
background: linear-gradient(#00befb, #0b66d8);
border-radius: 1vw;
color: #fff;
margin-right: 1vw;
}
.group {
// box-shadow: 0 0 10px #ccc;
// padding: 4vw 2vw;
box-sizing: border-box;
margin: 0 3.5vw;
.search {
display: flex;
height: 8vw;
// ::v-deep .van-search__content {
// height: 8vw;
// }
.setchBtn {
margin-left: 1vw;
background: #2c5ff1;
padding: 1vw 4vw;
border-radius: 2vw;
color: #fff;
line-height: 6.5vw;
@include font_size($font_medium_s);
}
}
ul.groupList {
min-height: 10vh;
margin-top: 2vw;
overflow: hidden;
li {
padding-bottom: 2vw;
border-radius: 2vw;
margin-top: 2vw;
position: relative;
// background: #f7f7f7;
&:first-child {
margin-top: 0px;
}
.top {
display: flex;
justify-content: space-between;
padding: 0 3vw;
padding-top: 3vw;
line-height: 7vw;
padding-bottom: 1vw;
.top-cnt {
width: 80%;
@include font_size($font_medium_s);
}
.dian {
width: 2vw;
height: 2vw;
border-radius: 50%;
background: #999;
display: inline-block;
vertical-align: middle;
margin-right: 2vw;
&.online {
background: #1fd038;
}
&.busy {
background: #ed0000;
}
}
.name {
font-size: 4vw;
color: #5471f3;
vertical-align: middle;
}
.other {
font-size: 3vw;
}
.imgBtn {
padding-top: 10px;
margin-left: 2px;
img {
margin-right: 2vw;
width: 6vw;
height: 6vw;
border: 1px solid #e5e5e5;
&:last-child {
margin-right: 0;
}
}
}
}
li.active {
border: 1px solid #108fe7;
.checkBox {
display: block;
}
}
}
}
ul.positionList {
max-height: 60vh;
overflow: hidden;
overflow-y: auto;
}
// 地址
.address {
margin: 0 2vw;
@include bottm_tab_top_color($bottom-border-top-clore-theme);
height: 6vw;
line-height: 6vw;
font-size: 3vw;
padding: 2vw 0;
img,
span {
vertical-align: middle;
}
img {
margin-right: 2vw;
width: 4vw;
height: 4vw;
border: 1px solid #e5e5e5;
}
}
}
::v-deep .van-checkbox__label {
@include font_color($font-color-theme);
font-size: 3vw;
.dian {
width: 2vw;
height: 2vw;
border-radius: 50%;
background: #999;
display: inline-block;
vertical-align: middle;
margin-right: 1vw;
&.online {
background: #1fd038;
}
&.busy {
background: #ed0000;
}
&.blue {
background: #229bf0;
}
}
}
}
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,325 @@
<template>
<div class="xttj_box">
<TopNav navTitle="系统统计" />
<div class="item_box">
<div class="strip_box">
<span class="strip"></span>
<span class="total_title">数据总揽</span>
</div>
<div class="total_box">
<div class="total_item">
<span class="numb all">{{ dataForm.total }}</span>
<div>全部</div>
</div>
<div class="total_item">
<span class="numb xtwt">{{ dataForm.xtwt }}</span>
<div>系统问题</div>
</div>
<div class="total_item">
<span class="numb gngj">{{ dataForm.gngj }}</span>
<div>功能改进</div>
</div>
<div class="total_item">
<span class="numb xxq">{{ dataForm.xxq }}</span>
<div>新需求</div>
</div>
</div>
</div>
<div class="item_box">
<div class="strip_box">
<span class="strip"></span>
<span class="total_title">数据统计</span>
</div>
<Count :datas="dataCount"></Count>
</div>
<div class="item_box">
<div class="strip_box">
<span class="strip"></span>
<span class="total_title">部门数据分布</span>
</div>
<BarEcharts :datas="dataList"></BarEcharts>
</div>
</div>
</template>
<script setup>
import Count from "../../../components/echarts/pieChart.vue";
import BarEcharts from "../../../components/echarts/pileUpColumn.vue";
import TopNav from "../../../components/topNav.vue";
import { getYyzxApi } from "../../../api/yyzxApi.js";
import { ref, reactive, onMounted } from "vue";
import { Toast } from "vant";
const dataCount = ref([]);
const XTFK_LIST = ref([
{
zdmc: "智慧云览",
zddm: "01",
},
{
zdmc: "智慧云踪",
zddm: "02",
},
{
zdmc: "智慧云搜",
zddm: "03",
},
{
zdmc: "智慧云基",
zddm: "04",
},
{
zdmc: "智慧云侦",
zddm: "05",
},
{
zdmc: "智慧云法",
zddm: "06",
},
{
zdmc: "智慧云指",
zddm: "07",
},
{
zdmc: "智慧云眸",
zddm: "08",
},
{
zdmc: "智慧云控",
zddm: "09",
},
{
zdmc: "智慧云防",
zddm: "10",
},
{
zdmc: "智慧云管",
zddm: "11",
},
{
zdmc: "智慧云舆",
zddm: "12",
},
]);
const dataForm = ref({
xtwt: 0,
gngj: 0,
xxq: 0,
total: 0,
});
const organizationList = ref([]);
const dataList = ref({
Xlist: [],
xtwtList: [],
gngjList: [],
xxqList: [],
// treeList: []
});
onMounted(() => {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
Promise.all([getZzjg(), getDateCount(), getCount()])
.then((res) => {
Toast.clear();
})
.catch((err) => {
Toast.clear();
});
});
// 数据总揽
function getDateCount() {
//1 系统问题 2 功能改进建议 3 新需求
getYyzxApi("/mosty-rzzx/yjsj/tjfx/glfktj", {}).then((res) => {
if (res && res.length > 0) {
res.forEach((v) => {
if (v.fklx == 1) {
dataForm.value.xtwt = v.sl;
}
if (v.fklx == 2) {
dataForm.value.gngj = v.sl;
}
if (v.fklx == 3) {
dataForm.value.xxq = v.sl;
}
dataForm.value.total += v.sl;
});
}
});
}
// 数据统计
function getCount() {
getYyzxApi("/mosty-rzzx/yjsj/tjfx/gxtfktj", {}).then((res) => {
if (res && res.length > 0) {
let arr = [];
XTFK_LIST.value.forEach((item) => {
res.forEach((v) => {
let obj = {};
obj.name = v.ssbmdm;
obj.value = v.sl;
if (item.zddm == v.fkxt) {
obj.name = item.zdmc;
obj.value = v.sl;
arr.push(obj);
}
});
});
dataCount.value = arr;
}
});
}
// 查询组织机构
function getZzjg() {
getYyzxApi("/mosty-sjzx/xtzd/zzjg", {}).then((res) => {
organizationList.value = res;
getDepartment();
});
}
function getDepartment() {
getYyzxApi("/mosty-rzzx/yjsj/tjfx/xjfktj", {}).then((res) => {
if (res && res.length > 0) {
let data = res;
let brr = unquire(data, "ssbmdm");
let crr = [];
brr.temp.forEach((item) => {
let obj = {
ssbmdm: "",
fklx1: "1",
sl1: 0,
fklx2: "2",
sl2: 0,
fklx3: "3",
sl3: 0,
};
item.forEach((v) => {
obj.ssbmdm = v.ssbmdm;
if (v.fklx == "1") {
obj.sl1 = v.sl;
}
if (v.fklx == "2") {
obj.sl2 = v.sl;
}
if (v.fklx == "3") {
obj.sl3 = v.sl;
}
});
crr.push(obj);
});
let xtwt = [];
let gngjjy = [];
let xqx = [];
let name = [];
crr.forEach((it) => {
xtwt.push(it.sl1);
gngjjy.push(it.sl2);
xqx.push(it.sl3);
});
brr.nameList.forEach((t) => {
organizationList.value.forEach((v) => {
if (t == v.id) {
name.push(v.org_short_name);
}
});
});
dataList.value.xtwtList = xtwt;
dataList.value.gngjList = gngjjy;
dataList.value.xxqList = xqx;
dataList.value.Xlist = name;
}
});
}
// 处理数据
function unquire(arr, key) {
let temp = []; //分组数组
let nameList = []; //横坐标
let obj = {};
let newArr = arr.reduce((item, next) => {
obj[next.ssbmdm] ? "" : (obj[next.ssbmdm] = true && item.push(next));
return item;
}, []); //去重
for (let i = 0; i < newArr.length; i++) {
nameList.push(newArr[i].ssbmdm); //组织结构
let brr = [];
for (let j = 0; j < arr.length; j++) {
if (newArr[i][key] == arr[j][key]) {
brr.push(arr[j]);
}
}
temp.push(brr);
}
let data = {
nameList: nameList,
temp: temp,
};
return data;
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.xttj_box {
padding-top: 13vw;
}
.item_box {
margin: 3vw;
border-radius: 5px;
padding: 3vw;
.strip_box {
display: flex;
align-items: center;
.strip {
display: inline-block;
width: 4px;
height: 14px;
background-color: #1989fa;
margin-right: 2vw;
}
.total_title {
@include font_size($font_medium);
}
}
.total_box {
display: flex;
justify-content: space-between;
margin-top: 7vw;
.total_item {
width: 33.3%;
text-align: center;
@include font_size($font_medium_s);
> div {
margin-top: 2vw;
}
.numb {
font-size: 8vw;
}
}
}
}
.all {
color: #34acfc;
}
.xtwt {
color: #e58c1b;
}
.gngj {
color: #d91d1b;
}
.xxq {
color: #449f87;
}
</style>

View File

@ -0,0 +1,270 @@
<template>
<div class="yjsj_box">
<TopNav navTitle="意见收集" rightIcon="add-o" showRight="true" @clickRight="onClickRight" />
<div class="info_box">
<div class="info-item item_box" v-for="(item, index) in dataList" :key="index">
<div class="item-top">
<div class="icon">
<img class="iconImg" src="../../../assets/images/time@2x.png" alt="" />
</div>
<div class="time">{{ item.xt_cjsj }}</div>
</div>
<div class="item" @click="handleEdit(item)">
<div class="title">
<span class="title-name">意见名称</span>
<span>{{ item.fklxmc }}-{{ item.fkxtmc }}</span>
</div>
<div class="info">
<span class="title-name">意见描述</span>
<span>{{ item.fknr }}</span>
</div>
<div class="photo">
<div class="list" v-for="(v, i) in item.imgArr" :key="i">
<van-image width="80px" height="80px" :src="v" @click.stop="onClickImg(v)"></van-image>
<!-- <img class="img" :src="v" alt="" /> -->
</div>
</div>
</div>
</div>
</div>
<van-loading type="spinner" style="padding-top: 50vw; text-align: center" v-if="loading" />
<van-empty description="无列表数据" image="default" v-if="dataList.length <= 0 && showEmpty" />
</div>
</template>
<script>
import TopNav from "../../../components/topNav.vue";
import { getYyzxApi, downLoadImg } from "../../../api/yyzxApi.js";
import { baseUrl2 } from "../../../utils/request.js";
import { ImagePreview, Toast } from "vant";
export default {
components: {
TopNav,
},
data() {
return {
loading: true,
showEmpty: false,
Page: 1,
total: 0,
dataList: [],
radioList: [
{
zdmc: "系统问题",
zddm: 1,
},
{
zdmc: "功能改进",
zddm: 2,
},
{
zdmc: "新需求",
zddm: 3,
},
],
XTFK_LIST: [
{
zdmc: "智慧云览",
zddm: "01",
},
{
zdmc: "智慧云踪",
zddm: "02",
},
{
zdmc: "智慧云搜",
zddm: "03",
},
{
zdmc: "智慧云基",
zddm: "04",
},
{
zdmc: "智慧云侦",
zddm: "05",
},
{
zdmc: "智慧云法",
zddm: "06",
},
{
zdmc: "智慧云指",
zddm: "07",
},
{
zdmc: "智慧云眸",
zddm: "08",
},
{
zdmc: "智慧云控",
zddm: "09",
},
{
zdmc: "智慧云防",
zddm: "10",
},
{
zdmc: "智慧云管",
zddm: "11",
},
{
zdmc: "智慧云舆",
zddm: "12",
},
],
};
},
created() {
this.getList();
},
methods: {
//预览图片
onClickImg(url) {
ImagePreview([url]);
},
//添加意见
onClickRight() {
this.$router.push("/tjyj");
},
// 获取列表
getList() {
let parsms = {
pageNum: this.Page,
pageSize: 20,
};
getYyzxApi("/mosty-rzzx/yjsj/lbcx", parsms)
.then((res) => {
if (res.records && res.records.length > 0) {
this.loading = false;
this.dataList = res.records;
this.dataList.forEach((item) => {
item.fklxmc = "";
item.fkxtmc = "";
let arr = item.fkfj ? item.fkfj.split(",") : [];
let brr = [];
arr.forEach((item) => {
let url =
baseUrl2 +
"/mosty-api/mosty-base/minio/image/download/" +
item;
brr.push(url);
});
item.imgArr = brr;
this.radioList.forEach((v) => {
if (item.fklx == v.zddm) {
item.fklxmc = v.zdmc;
}
});
this.XTFK_LIST.forEach((v) => {
if (item.fkxt == v.zddm) {
item.fkxtmc = v.zdmc;
}
});
// item.imgArr = arr
});
this.total = res.total;
} else {
this.loading = false;
this.showEmpty = true;
}
})
.catch((err) => {
this.loading = false;
this.showEmpty = true;
});
},
// 处理意见
handleEdit(item) {
this.$router.push({
path: "/tjyj",
query: { info: JSON.stringify(item) },
});
},
},
};
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.yjsj_box {
/* padding: 4vw 3vw; */
padding-top: 13vw;
}
.info_box {
overflow: hidden;
overflow-y: auto;
padding: 4vw 3vw;
@include font_color($font-color-theme);
@include font_size($font_medium_s);
}
.info-item {
margin-bottom: 4vw;
padding: 3vw;
border-radius: 5px;
}
.info-item:nth-child(1) {
margin-top: 0;
}
.icon {
float: left;
margin-right: 2vw;
}
.iconImg {
width: 2.93334vw;
height: 2.93334vw;
margin-right: 1vw;
vertical-align: middle;
}
.item {
margin-top: 2vw;
}
.info {
/* span-indent: 2em; */
line-height: 6vw;
}
.title {
line-height: 8vw;
}
.photo {
width: 100%;
display: flex;
flex-wrap: wrap;
}
.list {
width: 20vw;
height: 20vw;
// border: 1px solid #0c6bcc;
margin-right: 2vw;
margin-top: 2vw;
}
.img {
width: 20vw;
height: 20vw;
}
.button {
position: fixed;
bottom: 0vw;
width: 60vw;
height: 10vw;
background: #0c6bcc;
color: #fff;
line-height: 10vw;
border-radius: 4vw;
left: 50%;
transform: translateX(-50%);
}
</style>

View File

@ -0,0 +1,555 @@
<template>
<div class="container" style="padding-top: 13vw">
<TopNav :navTitle="'值班报备'" />
<van-form @submit="onSubmit">
<div class="title_tab">值班班次</div>
<van-field
v-model="normalForm.bcmc"
required
name="班次"
is-link
readonly
label="班次"
placeholder="请选择班次"
input-align="right"
:rules="[{ required: true, message: '请选择班次' }]"
@click="showDialogfn('qwbc')"
/>
<van-field
readonly
v-if="normalForm.bcsc"
v-model="normalForm.bcsc"
input-align="right"
label="班次时段"
/>
<div class="title_tab">值班人员</div>
<van-field
v-model="normalForm.zbld"
name="值班领导"
required
input-align="right"
label="值班领导"
is-link
readonly
placeholder="请值班领导"
:rules="[{ required: true, message: '请选择值班领导' }]"
@click="showDialogfn('zbld')"
/>
<van-field
v-model="normalForm.zhz"
readonly
input-align="right"
name="picker"
label="指挥长"
placeholder="请选择指挥长"
@click="showDialogfn('zhz')"
is-link
/>
<van-field
v-model="normalForm.zzzhz"
readonly
input-align="right"
name="picker"
label="专职指挥长"
placeholder="请选择专职指挥长"
@click="showDialogfn('zzzhz')"
is-link
/>
<van-field
v-model="normalForm.fz"
readonly
input-align="right"
name="picker"
label="法制"
placeholder="请选择法制"
@click="showDialogfn('fz')"
is-link
/>
<van-cell class="mulSelect" title="值班民警" color="#1989fa">
<template #right-icon>
<van-icon
v-if="route.query.flag == 1"
@click.stop="showDialogfn('mj')"
name="add-o"
color="#1989fa"
size="22"
/>
</template>
<template #default>
<div class="selected-box">
<div
class="check-item-tag"
v-for="(item, index) in list.mj"
:key="index"
>
<van-tag
color="#7232dd"
:closeable="route.query.flag == 1"
@close="deleteCheckTag(item, index, 'mj')"
plain
>{{ item.jlxm }}</van-tag
>
</div>
</div>
</template>
</van-cell>
<van-cell class="mulSelect" title="值班辅警" color="#1989fa">
<template #right-icon>
<van-icon
v-if="route.query.flag == 1"
@click.stop="showDialogfn('fj')"
name="add-o"
color="#1989fa"
size="22"
/>
</template>
<template #default>
<div class="selected-box">
<div
class="check-item-tag"
v-for="(item, index) in list.fj"
:key="index"
>
<van-tag
:closeable="route.query.flag == 1"
@close="deleteCheckTag(item, index, 'fj')"
color="#7232dd"
plain
>{{ item.jlxm }}</van-tag
>
</div>
</div>
</template>
</van-cell>
<div class="title_tab">联系方式</div>
<van-field
:readonly="route.query.flag == 1 ? false : true"
v-model="normalForm.zbdh"
name="值班电话"
label="值班电话"
placeholder="请选择值班电话"
input-align="right"
/>
<van-field
:readonly="route.query.flag == 1 ? false : true"
v-model="normalForm.hh"
name="呼号"
label="呼号"
placeholder="请输入呼号"
input-align="right"
/>
<div
style="margin: 16px 0; padding: 0 5vw"
v-show="route.query.flag == 1"
>
<van-button
:loading="loading"
round
@click="_submitZbbbData"
block
type="primary"
v-if="route.query.zt === '01'"
>
开始报备
</van-button>
<van-button
style="margin: 16px 0"
:loading="loading"
round
@click="editFn()"
block
type="success"
v-if="route.query.zt === '02'"
>
结束报备
</van-button>
</div>
</van-form>
<!-- 负责人 -->
<Select
bclx="01"
:checked="r_checked"
:selectType="selectType"
:show="showSelect"
:checkedList="list.checkedList"
@update:cancel="showSelect = false"
@update:confirm="onComfirm"
:key="selectIndex"
/>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import normalReport from "../components/normalReport";
import Select from "../../../components/Select.vue";
import { Dialog, Toast } from "vant";
import { dateFormat, hintToast } from "../../../utils/tools.js";
import { computed, ref, reactive, onMounted, watch } from "vue";
import { useRouter, useRoute } from "vue-router";
import { getBcList } from "../../../api/xfbbAndZbbb.js";
import {
submitZbbbData,
startAndEndZbbbData,
endTaskStatus,
} from "../../../api/yyzxApi.js";
import { getZbpbZqInfo, gettbQwZbbb } from "../../../api/report.js";
const active = ref("a");
const router = useRouter();
const route = useRoute();
const showSelect = ref(false);
const r_checked = ref(""); //单选框默认选中
const selectIndex = ref(1); //选择器组件KEY
const selectType = ref(""); //选择的类型
//表单数据
const normalForm = reactive({
bcmc: "",
bcsc: "",
zbld: "",
zhz: "",
zzzhz: "",
fz: "",
hh: "",
bcsc: "",
});
//选择数据
const list = reactive({
mj: [], //选中的民警数据
fj: [], //选中的辅警数据
bcList: [], //班次信息
bpInfo: { zbmj: [], zbfj: [], jlList: [], zbpbId: "", zbrq: "", qwbcid: "" }, //无报备的排班信息
bbInfo: null, //报备信息
checkedList: [], //默认选中的民辅警数据
});
onMounted(() => {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
Promise.all([_getBcData(), getZbbbxx()])
.then((res) => {
Toast.clear();
})
.catch((err) => {
Toast.clear();
});
});
//确认选择
function onComfirm(val) {
if (val.length <= 0) return;
switch (selectType.value) {
case "qwbc":
r_checked.value = val[0].key;
onbcConfirm(val[0]);
break;
case "zbld":
case "zhz":
case "zzzhz":
case "fz":
if (r_checked.value == val[0].key) {
r_checked.value = "";
if (selectType.value == "zbld") normalForm.zbld = "";
if (selectType.value == "zhz") normalForm.zhz = "";
if (selectType.value == "zzzhz") normalForm.zzzhz = "";
if (selectType.value == "fz") normalForm.fz = "";
} else {
r_checked.value = val[0].key;
onfzrConfirm(val[0]);
}
break;
case "mj":
// list.mj = [];
val.forEach((item) => {
list.checkedList.push(item.key);
toggle(item);
});
break;
case "fj":
// list.fj = [];
val.forEach((item) => {
list.checkedList.push(item.key);
toggle(item);
});
break;
}
}
//打开选择框
function showDialogfn(val) {
if (selectType.value !== val) r_checked.value = "";
selectType.value = val;
showSelect.value = true;
selectIndex.value++;
}
//开始报备
function _submitZbbbData() {
Reflect.deleteProperty(list.bpInfo, "zbmj");
Reflect.deleteProperty(list.bpInfo, "zbfj");
list.bpInfo.jlList = [...list.fj, ...list.mj];
list.bpInfo.zbpbId = list.bpInfo.id; //排班ID
list.bpInfo.zbrq = dateFormat();
Dialog.confirm({
title: "提示",
message: "确认报备信息是否正确!",
confirmButtonColor: "#3e6ee8",
}).then((res) => {
submitZbbbData(list.bpInfo).then((res) => {
hintToast("成功")
_startZbbbData(res, 0);
_endTaskStatus("04", list.bpInfo.mrjlid, 2);
});
});
}
//结束任务
function _endTaskStatus(rwxl, ywid, rwzt) {
let data = { rwxl, ywid, rwzt };
try {
let location = JSON.parse(bridge.getLocation());
data.jd = location.app_x;
data.wd = location.app_y;
} catch (error) {}
endTaskStatus(data).then((res) => {});
}
//结束报备
function editFn() {
Dialog.confirm({
title: "提示",
message: "是否确认结束报备!",
confirmButtonColor: "#3e6ee8",
}).then((res) => {
_startZbbbData(route.query.id, 1);
});
}
//提交开始||结束报备
function _startZbbbData(id, bbzt) {
startAndEndZbbbData({ id, bbzt }).then((res) => {
list.bpInfo = null;
router.go(-1);
});
}
// 根据状态查询值班报备信息
function getZbbbxx() {
const temp = route.query;
if (temp.zt === "01") {
getZbpbZqInfo(temp.id).then((res) => {
list.bpInfo = res;
_setHxData(res);
});
} else {
gettbQwZbbb(temp.id).then((res) => {
list.bpInfo = res;
_setHxData(res);
});
}
}
//设置页面回显
function _setHxData(res) {
let info = list.bcList.find((item) => {
return item.id == res.qwbcid;
});
onbcConfirm(info);
//值班人
normalForm.zbld = `${res.zbldXm ? res.zbldXm : ""} ${
res.zbldDh ? res.zbldDh : ""
}`;
normalForm.zbdh = res.zbldDh ? res.zbldDh : "";
normalForm.zhz = `${res.zbzhzXm ? res.zbzhzXm : ""} ${
res.zbzhzDh ? res.zbzhzDh : ""
}`;
normalForm.zzzhz = `${res.zzzhzXm ? res.zzzhzXm : ""} ${
res.zzzhzDh ? res.zzzhzDh : ""
}`;
normalForm.fz = `${res.fzzbXm ? res.fzzbXm : ""} ${
res.fzzbDh ? res.fzzbDh : ""
}`;
// 值班电话
//呼号
normalForm.hh = res.hh;
//民辅警
list.mj = JSON.parse(res.zbmj);
list.fj = JSON.parse(res.zbfj);
}
//选中的班次数据
function onbcConfirm(val) {
normalForm.bcmc = val.bcmc;
normalForm.bcsc = `${val.kssj} - ${val.jssj}`;
}
//获取班次数据
function _getBcData() {
let data = {
type: 2,
keyword: "",
bclx: "01",
};
getBcList(data).then((res) => {
if (res) {
for (let i = 0; i < res.length; i++) {
res[i].value = `${res[i].ssbm}-${res[i].bcmc}`;
res[i].key = res[i].id;
}
list.bcList = res;
}
});
}
//选中领导数据
function onfzrConfirm(val) {
switch (selectType.value) {
case "zbld":
normalForm.zbld = `${val.xm} ${val.lxdh}`;
normalForm.zbdh = val.lxdh;
break;
case "zhz":
normalForm.zhz = `${val.xm} ${val.lxdh}`;
break;
case "zzzhz":
normalForm.zzzhz = `${val.xm} ${val.lxdh}`;
break;
case "fz":
normalForm.fz = `${val.xm} ${val.lxdh}`;
break;
}
}
//删除选中的民辅警数据
function deleteCheckTag(item, index, val) {
switch (val) {
case "mj":
list.mj.splice(index, 1);
break;
case "fj":
list.fj.splice(index, 1);
break;
}
}
//选中民辅警数据
const toggle = (item) => {
switch (selectType.value) {
case "mj":
list.mj.push({
jh: item.jh,
jllx: item.fl,
jlxm: item.xm,
sfzh: item.sfzh,
xm: item.xm,
lxdh: item.lxdh,
xbdm: item.xbdm,
id: item.ryid,
qwjzId: "",
jlId: item.ryid,
});
break;
case "fj":
list.fj.push({
jh: item.jh,
jllx: item.fl,
jlxm: item.xm,
id: item.id,
sfzh: item.sfzh,
xm: item.xm,
lxdh: item.lxdh,
xbdm: item.xbdm,
qwjzId: "",
jlId: item.id,
});
break;
}
};
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.container {
margin-top: 2vw;
}
.nav_tab {
padding: 2vw;
display: flex;
justify-content: space-around;
.tab {
background: #a4aec8;
color: #fff;
height: 32px;
line-height: 32px;
width: 40vw;
text-align: center;
border-radius: 16px 16px 16px 0;
}
.tab.active {
background: #517cea;
}
}
.popupTitle {
text-align: center;
background-color: rgb(11, 137, 247);
height: 6vh;
line-height: 6vh;
}
.popbtn-box {
width: 100%;
display: flex;
justify-content: space-around;
}
.check-item-tag {
display: inline-block;
margin: 0 6px;
}
.check-data-box {
height: 25vh;
overflow: auto;
}
.time-box {
display: flex;
}
::v-deep .mulSelect .van-cell__title,
.van-cell__value {
flex: unset;
}
::v-deep .mulSelect .van-cell__value {
flex: 1;
}
.title_tab {
@include font_color($font-color-theme);
padding-left: 7vw;
position: relative;
margin: 2vw 0;
letter-spacing: 2px;
}
.title_tab::after {
content: "";
position: absolute;
top: 0;
left: 5vw;
bottom: 0;
width: 4px;
background: #3b6be7;
border-radius: 2px;
}
.van-cell:after {
display: none;
}
.van-cell {
@include table_item_color($table-item-theme);
box-sizing: border-box;
border-radius: 4px;
padding: 6px;
margin: 8px 5%;
width: 90%;
overflow: hidden;
color: var(--van-cell-text-color);
font-size: var(--van-cell-font-size);
line-height: var(--van-cell-line-height);
}
.popupTitle {
color: #fff;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,919 @@
<template>
<div class="container" style="padding-top: 13vw">
<TopNav navTitle="特殊勤务报备" />
<van-form @submit="onSubmit">
<div class="title_tab">人员车辆</div>
<van-field v-model="normalForm.qwlxMc" required name="勤务类型" readonly is-link label="勤务类型" placeholder="请选择勤务类型"
input-align="right" :rules="[{ required: true, message: '请选择勤务类型' }]" @click="qwlxPicker = true" />
<van-field v-model="normalForm.jzMc" name="选择警组" readonly input-align="right" label="选择警组" is-link
placeholder="请选择警组" @click="showDialogfn('jz')" />
<van-field v-model="normalForm.fzrXm" required readonly input-align="right" :clearable="true" name="picker"
label="负责人" :rules="[{ required: true, message: '请选择负责人' }]" />
<van-field v-model="normalForm.zylxmc" name="人员类型" readonly input-align="right" label="选择人员类型" is-link
placeholder="请选择人员类型" @click="rylxPicker = true" />
<van-cell class="mulSelect" title="民警" color="#1989fa">
<template #right-icon>
<van-icon @click.stop="showDialogfn('mj')" name="add-o" color="#1989fa" size="22" />
</template>
<template #default>
<div class="selected-box">
<div class="check-item-tag" v-for="(item, index) in normalForm.mjList" :key="index">
<van-tag color="#7232dd" closeable @close="deleteCheckTag(item, index, 'mj')" plain>{{ item.xm || item.jlxm
}}</van-tag>
</div>
</div>
</template>
</van-cell>
<van-cell class="mulSelect" title="辅警" color="#1989fa">
<template #right-icon>
<van-icon @click.stop="showDialogfn('fj')" name="add-o" color="#1989fa" size="22" />
</template>
<template #default>
<div class="selected-box">
<div class="check-item-tag" v-for="(item, index) in normalForm.fjList" :key="index">
<van-tag closeable @close="deleteCheckTag(item, index, 'fj')" color="#7232dd" plain>{{ item.xm || item.jlxm
}}</van-tag>
</div>
</div>
</template>
</van-cell>
<van-cell class="mulSelect" title="巡防车辆" color="#1989fa">
<template #right-icon>
<van-icon @click.stop="showDialogfn('cl')" name="add-o" color="#1989fa" size="22" />
</template>
<template #default>
<div class="selected-box">
<div class="check-item-tag" v-for="(item, index) in normalForm.clList" :key="index">
<van-tag color="#7232dd" closeable @close="deleteCheckTag(item, index, 'cl')" plain>{{ item.value ||
item.jdchphm }}</van-tag>
</div>
</div>
</template>
</van-cell>
<div class="title_tab">装备</div>
<van-cell class="mulSelect" title="智能装备" color="#1989fa">
<template #right-icon>
<van-icon @click.stop="showDialogfn('zn')" name="add-o" color="#1989fa" size="22" />
</template>
<template #default>
<div class="selected-box">
<div class="check-item-tag" v-for="(item, index) in normalForm.znzbList" :key="index">
<van-tag closeable @close="deleteCheckTag(item, index, 'zn')" color="#7232dd" plain>{{ item.value ||
item.sbmc }}</van-tag>
</div>
</div>
</template>
</van-cell>
<van-field class="change" name="checkbox" label="武器装备">
<template #input>
<van-checkbox-group v-model="normalForm.wqzbList" :disabled="disable">
<van-checkbox v-for="item in D_BZ_WQZB" :name="item.dm" :key="item.dm">{{ item.zdmc }}</van-checkbox>
</van-checkbox-group>
</template>
</van-field>
<van-cell class="mulSelect" title="警用器械" color="#1989fa">
<template #right-icon>
<van-icon @click.stop="showDialogfn('jy')" name="add-o" color="#1989fa" size="22" />
</template>
<template #default>
<div class="selected-box">
<div class="check-item-tag" v-for="(item, index) in normalForm.jyqxList" :key="index">
<van-tag closeable @close="deleteCheckTag(item, index, 'jy')" color="#7232dd" plain>{{ item.value ||
item.qxmc }} * {{ item.qxsl }}</van-tag>
</div>
</div>
</template>
</van-cell>
<div class="title_tab" v-if="normalForm.jyqxList.length > 0">警用器械数量</div>
<van-field :disabled="disableForm" v-for="item in normalForm.jyqxList" :key="item.qxid" v-model="item.qxsl"
type="digit" :label="item.qxmc">
</van-field>
<div class="title_tab">巡逻方式</div>
<van-field class="change" name="radio" label="巡逻方式">
<template #input>
<van-radio-group v-model="normalForm.xlfs" direction="horizontal" :disabled="disable">
<van-radio shape="square" checked-color="#3e6ee8" name="1">步巡</van-radio>
<van-radio shape="square" checked-color="#3e6ee8" name="0">车巡</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field class="change" name="radio" label="着装类型">
<template #input>
<van-radio-group v-model="normalForm.zzlx" direction="horizontal" :disabled="disable">
<van-radio shape="square" checked-color="#3e6ee8" name="0">制服</van-radio>
<van-radio shape="square" checked-color="#3e6ee8" name="1">便衣</van-radio>
</van-radio-group>
</template>
</van-field>
<van-field class="change" name="radio" label="武装类型">
<template #input>
<van-radio-group v-model="normalForm.wzlx" direction="horizontal" :disabled="disable">
<van-radio shape="square" checked-color="#3e6ee8" name="0">武装</van-radio>
<van-radio shape="square" checked-color="#3e6ee8" name="1">非武装</van-radio>
</van-radio-group>
</template>
</van-field>
<van-row>
<van-col span="24">
<van-field rows="3" :required="normalForm.qwlx == '03' ? true : false"
:rules="[{ required: normalForm.qwlx == '03' ? true : false, message: '请输入勤务原因' }]" type="textarea"
v-model="normalForm.bz" name="备注" placeholder="备注信息" />
</van-col>
</van-row>
<div style="padding: 0 5vw" v-if="obj.bbInfo">
<van-button style="margin: 16px 0" :loading="loading" round @click="editFn(0)" block type="success">
下班打卡
</van-button>
</div>
<div style="margin: 16px 0; padding: 0 5vw" v-else>
<van-button :loading="loading" round native-type="submit" block type="primary">
开始报备
</van-button>
</div>
</van-form>
<!-- 负责人 -->
<Select bclx="02" :dwlx="dwlx" :checked="r_checked" :selectType="selectType" :show="showSelect"
:checkedList="hasCheckedList" @update:cancel="showSelect = false" @update:confirm="onComfirm" :key="selectIndex" />
<!-- 勤务类型 -->
<van-popup v-model:show="qwlxPicker" round position="bottom">
<van-picker :columns="D_BZ_QWLX" @cancel="qwlxPicker = false" @confirm="onQwlxConfirm" />
</van-popup>
<!-- 人员类型 -->
<van-popup v-model:show="rylxPicker" round position="bottom">
<van-picker :columns="D_BZ_RYLX" @cancel="rylxPicker = false" @confirm="onrylxConfirm" />
</van-popup>
</div>
</template>
<script setup>
import { getBcList, getXfqList, getKfdList } from "../../../api/xfbbAndZbbb.js";
import { getItem } from "../../../utils/storage";
import TopNav from "../../../components/topNav";
import Select from "../../../components/Select.vue";
import { Dialog, Toast } from "vant";
import { addXFBB } from "../../../api/report";
import { getMybbTodayNew, finishReport, getMyXfpbToday, } from "../../../api/common";
import { dateFormat, hintToast } from "../../../utils/tools.js";
import { ref, reactive, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import { getDictList, setDict } from "../../../utils/dict";
import { get } from "vant/lib/utils";
Toast.allowMultiple();
const router = useRouter();
const route = useRoute();
const { D_BZ_QWLX, D_BZ_WQZB } = getDictList("D_BZ_QWLX", "D_BZ_WQZB");
const userInfo = getItem("userInfo");
const showSelect = ref(false); //弹窗的显示和隐藏
const dwlx = ref("01"); //弹窗的单位类型
const calShow = ref(false); //是否显示巡防日期选择器
const chooseTime = ref(dateFormat("", new Date()));
const minDate = new Date(2000, 0, 1); // 巡防日期最小时间
const maxDate = new Date(2050, 0, 1);// 巡防日期最大时间
const loading = ref(false) //报备按钮的节流
const rylxPicker = ref(false)
const D_BZ_RYLX = reactive([
{ text: '组长', value: '01' },
{ text: '组员', value: '02' }
])
const disableForm = ref(false)
const normalForm = ref({
zylxmc: '组员',
zylx: '02',
qwlx: '',
qwlxMc: '',
xfrq: dateFormat(),
kssj: "",// 开始时间
jssj: "",//结束时间
xffwlx: "",//巡防类型
bbzt: "0",
xlfs: "1",
zzlx: "1",
wzlx: "2",
jzMc: "",
jzId: "",
ssbm: userInfo.deptName,
ssbmdm: userInfo.deptList[0].deptCode,
lxrsfzh: userInfo.idEntityCard,
lxrid: userInfo.id,
fzrXm: userInfo.userName,
fzrSfzh: userInfo.idEntityCard,
fzrLxdh: userInfo.mobile,
fzrInfo: userInfo.userName,
fzrId: userInfo.id,
znzbList: [],
jyqxList: [],
clList: [],
jlList: [],
bz: "",
xffwid: "",
xffwList: [],
kfdMc: "",
jczMc: "",
mjList: [],
fjList: [],
wqzbList: []
});
const selectIndex = ref(1); //选择器组件KEY
const selectType = ref(""); //弹窗选择的类型
const showkssjPicker = ref(false); //开始时间结束时间弹窗
const showjssjPicker = ref(false); //结束时间结束时间弹窗
const dataList = reactive({
bcList: [],//存班次的数据
xfqList: [],//存的巡防区域list
kfdList: [],//快返点数据
jczList: [],//快返点数据
jzList: [],//警组数据
fzrList: [],//负责人数据
mjList: [],//民警数据
fjList: [],//辅警数据
znzbList: [],//智能装备数据
clList: [],//车辆数据
jyqxList: []//警用器械
})
// 获取数据
const list = reactive({
xfqList: [], //巡防区
kfdList: [], //快返点
jczList: [], //检查站
bcList: [],//班次数据
});
// 选择勤务类型
const qwlxPicker = ref(false);
const hasCheckedList = ref([])//多选状态
const r_checked = ref(""); //单选框默认选中
const isUserDept = ref(false); //是否是用户本部门
const kwd = ref(""); //选择器关键字
const obj = reactive({ bbInfo: null, pbInfo: null });
onMounted(() => {
_getMybbTodayNew();
// Promise.all([
// _getXfqList(),
// _getKfdList(),
// _getJczList(),
// ]).then((res) => {
// });
});
// 查询巡防范围
function _getXfqList() {
return new Promise((ok) => {
let data = {
type: isUserDept.value ? 1 : 2,
keyword: kwd.value,
};
getXfqList(data).then((res) => {
for (let i = 0; i < res.length; i++) {
res[i].value = `${res[i].ssbm}-${res[i].xfqMc}`;
res[i].key = res[i].id;
}
list.xfqList = res;
ok();
});
});
}
// 选择勤务类型
function onQwlxConfirm(val) {
normalForm.value.qwlx = val.value;
normalForm.value.qwlxMc = val.text;
qwlxPicker.value = false;
}
// 选择人员类型
function onrylxConfirm(val) {
normalForm.value.zylxmc = val.text
normalForm.value.zylx = val.value
rylxPicker.value = false
}
//获取检查站数据
function _getJczList() {
return new Promise((ok) => {
let data = {
dwlx: "02",
type: isUserDept.value ? 1 : 2,
keyword: kwd.value,
};
getKfdList(data).then((res) => {
for (let i = 0; i < res.length; i++) {
res[i].value = `${res[i].ssbm}-${res[i].kfdMc}`;
res[i].key = res[i].kfdId;
}
list.jczList = res;
ok();
});
});
}
//获取快反点数据
function _getKfdList() {
return new Promise((ok) => {
let data = {
dwlx: "01",
type: isUserDept.value ? 1 : 2,
keyword: kwd.value,
};
getKfdList(data).then((res) => {
for (let i = 0; i < res.length; i++) {
res[i].value = `${res[i].ssbm}-${res[i].kfdMc}`;
res[i].key = res[i].kfdId;
}
list.kfdList = res;
ok();
});
});
}
//获取用户的报备信息
function _getMybbTodayNew() {
getMybbTodayNew().then((res) => {
if (res) {
const resData = JSON.parse(JSON.stringify(res));
obj.bbInfo = resData;
disableForm.value = true;
_setSubmitData(resData);
} else {
disableForm.value = false;
//没有报备信息 查询排版信息
_getMyXfpbToday();
}
})
.catch((err) => {
});
}
//设置需要提交的参数
function _setSubmitData(obj) {
normalForm.value = obj
normalForm.value.mjList = obj.pbmj ? JSON.parse(obj.pbmj) : [];
normalForm.value.fjList = obj.pbfj ? JSON.parse(obj.pbfj) : [];
normalForm.value.znzbList = obj.txzb ? JSON.parse(obj.txzb) : [];
normalForm.value.jyqxList = obj.jyqx ? JSON.parse(obj.jyqx) : [];
normalForm.value.clList = obj.pbcl ? JSON.parse(obj.pbcl) : [];
normalForm.value.wqzbList = obj.wqzb ? obj.wqzb.split(',') : [];
// 组员类型
let lx = D_BZ_RYLX.find(v => { return v.value = obj.zylx })
normalForm.value.zylxmc = lx.text
// 勤务类型
let arr = JSON.parse(JSON.stringify(D_BZ_QWLX))._object.D_BZ_QWLX
let textVlue = arr.find(v => { return v.value == obj.qwlx })
normalForm.value.qwlxMc = textVlue ? textVlue.text : ''
if (obj.jzId) dataList.jzList = [{ key: obj.jzId }]// 警组
}
// 处理数组
function handelArr(arr, brr, key, type) {
let obj = { str: '', crr: [] }
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < brr.length; j++) {
if (arr[i] == brr[j][key]) {
obj.crr.push(brr[j]);
}
}
}
return obj
}
//确认巡防日期选择
function onConfirmTime(val) {
calShow.value = false;
chooseTime.value = dateFormat("", val);
normalForm.value.xfrq = chooseTime.value;
}
//打开选择框
function showDialogfn(type) {
selectType.value = type; //选取的类型
showSelect.value = true; //打开弹窗
hasCheckedList.value = []
r_checked.value = ''
hasChooseData()
selectIndex.value++;
}
// 已经选取的数据回显
function hasChooseData() {
switch (selectType.value) {
case 'qwbc':
if (!dataList.bcList.length) return false
r_checked.value = dataList.bcList[0].key;
break;
case "jz":
if (!dataList.jzList.length) return false
r_checked.value = dataList.jzList[0].key;
break;
case "fzr":
if (!dataList.fzrList.length) return false
r_checked.value = dataList.fzrList[0].key;
break;
case "mj":
if (!dataList.mjList.length) return false
hasCheckedList.value = dataList.mjList.map(item => { return item.key })
break;
case "fj":
if (!dataList.fjList.length) return false
hasCheckedList.value = dataList.fjList.map(item => { return item.key })
break;
case "zn":
if (!dataList.znzbList.length) return false
hasCheckedList.value = dataList.znzbList.map(item => { return item.key })
break;
case "cl":
if (!dataList.clList.length) return false
hasCheckedList.value = dataList.clList.map(item => { return item.key })
break;
case "jy":
if (!dataList.jyqxList.length) return false
hasCheckedList.value = dataList.jyqxList.map(item => { return item.key })
break;
}
}
//获取用户排班信息
function _getMyXfpbToday() {
getMyXfpbToday().then((res) => {
if (res) {
const resData = JSON.parse(JSON.stringify(res));
if (!resData.jyqx) {
resData.jyqx = JSON.stringify([]);
}
if (!resData.pbmj) {
resData.pbmj = JSON.stringify([]);
}
if (!resData.pbfj) {
resData.pbfj = JSON.stringify([]);
}
if (!resData.txzb) {
resData.txzb = JSON.stringify([]);
}
if (!resData.pbcl) {
resData.pbcl = JSON.stringify([]);
}
obj.pbInfo = resData;
_setSubmitData(resData);
} else {
hintToast("没有排班和报备信息,请自行填写并报备");
}
});
}
// 开始时间弹窗
function ksConfirm(val) {
normalForm.value.kssj = val + ":00"
showkssjPicker.value = false;
}
// 结束时间弹窗
function jsConfirm(val) {
normalForm.value.jssj = val + ":00"
showjssjPicker.value = false;
}
//确认选择
function onComfirm(val) {
if (val.length <= 0) return false;
switch (selectType.value) {
case "qwbc":
dataList.bcList = val //选取的班次数据
onbcConfirm(val[0]);
break;
case "jz":
dataList.jzList = val //选取的警组数据
onjzConfirm(val[0]);
break;
case "fzr":
dataList.fzrList = val //选取的负责人数据
onfzrConfirm(val[0]);
break;
case "mj":
normalForm.value.mjList = []
dataList.mjList = val
val.forEach((item) => { toggle(item); });
break;
case "fj":
normalForm.value.fjList = []
dataList.fjList = val
val.forEach((item) => { toggle(item); });
break;
case "zn":
dataList.znzbList = val
normalForm.value.znzbList = []
val.forEach((item) => { toggle(item); });
break;
case "cl":
dataList.clList = val
normalForm.value.clList = []
val.forEach((item) => { toggle(item); });
break;
case "jy":
dataList.jyqxList = val;
normalForm.value.jyqxList = []
val.forEach((item) => { toggle(item); });
break;
}
}
//选中的勤务班次数据
function onbcConfirm(val) {
normalForm.value.qwbcId = val.id;
normalForm.value.zqsc = val.zqsc;
normalForm.value.kssj = val.kssj
normalForm.value.jssj = val.jssj
}
//设置选中值
const toggle = (item) => {
switch (selectType.value) {
case "mj":
normalForm.value.mjList.push({
jh: item.jh,
jllx: item.fl,
jlxm: item.xm,
sfzh: item.sfzh,
xm: item.xm,
lxdh: item.lxdh,
xfbmid: item.xbdm,
id: item.ryid,
qwjzId: "",
jlId: item.ryid,
});
break;
case "fj":
normalForm.value.fjList.push({
jh: item.jh,
jllx: item.fl,
jlxm: item.xm,
id: item.id,
sfzh: item.sfzh,
xm: item.xm,
lxdh: item.lxdh,
xfbmid: item.xbdm,
qwjzId: "",
jlId: item.id,
});
break;
case "zn":
normalForm.value.znzbList.push({
sbmc: item.sbmc,
text: item.sbmc,
txzblx: item.scode,
txzbId: item.id,
hh: item.sbbh,
sfrh: item.sfrh,
sfxt: item.sfxt,
sfzy: item.sfzy,
});
break;
case "jy":
normalForm.value.jyqxList.push({
qxid: item.id,
qxmc: item.qxMc,
text: item.qxMc,
qxsl: item.sl ? item.sl : 1,
qxlx: item.scode,
});
normalForm.value.wzlx = "0";
break;
case "cl":
normalForm.value.clList.push({
clId: item.cid,
jdchphm: item.cph,
text: item.cph,
jdchpzldm: item.cllx,
});
normalForm.value.xlfs = "0";
break;
}
};
// 警组回显
function onjzConfirm(val) {
normalForm.value.mjList = [];
normalForm.value.fjList = [];
normalForm.value.clList = [];
normalForm.value.znzbList = [];
normalForm.value.jyqxList = [];
normalForm.value.jzMc = val.jzMc;
normalForm.value.jzId = val.id;
dataList.fzrList = [] //负责人
dataList.fzrList = [{ key: val.ddMjid }]
normalForm.value.jh = val.ddMjjh;
normalForm.value.ssbm = val.ssbm;
normalForm.value.ssbmdm = val.ssbmdm;
// 民警辅警已有赋值
dataList.mjList = [] //缓存民警
dataList.fjList = [] //缓存辅警
val.jzryList.forEach((m) => {
m.key = m.ryId
if (m.jllx === "01") {
dataList.mjList.push(m);
normalForm.value.mjList.push({
jh: m.jh,
jllx: m.jllx,
jlxm: m.jlxm,
text: m.jlxm,
nl: m.nl,
qwjzId: m.qwjzId,
jlId: m.ryId,
sfzh: m.sfzh,
xfbmid: m.xbdm,
xm: m.jlxm,
jh: m.jh,
lxdh: m.lxdh,
});
}
if (m.jllx === "02") {
dataList.fjList.push(m);
normalForm.value.fjList.push({
jh: m.jh,
jllx: m.jllx,
jlxm: m.jlxm,
text: m.jlxm,
nl: m.nl,
qwjzId: m.qwjzId,
jlId: m.ryId,
sfzh: m.sfzh,
xfbmid: m.xbdm,
xm: m.jlxm,
jh: m.jh,
lxdh: m.lxdh,
});
}
});
// 车辆
dataList.clList = []
if (val.clList.length > 0) {
normalForm.value.xlfs = "0";
val.clList.forEach((c) => {
c.key = c.clId
dataList.clList.push(c);
normalForm.value.clList.push({
clId: c.clId,
jdchphm: c.jdchphm,
text: c.jdchphm,
jdchpzldm: c.jdchpzldm,
qwjzId: c.qwjzId,
});
});
}
// 警用器械
dataList.jyqxList = []
val.jyqxList.forEach((j) => {
j.key = j.qxId
dataList.jyqxList.push(j);
normalForm.value.jyqxList.push({
qxid: j.qxid,
qxmc: j.qxmc,
text: j.qxmc,
qxsl: j.sl ? j.sl : 1,
qxlx: j.qxlx,
qwjzId: j.qwjzId,
});
});
// 智能装备
dataList.znzbList = []
val.txzbList.forEach((z) => {
z.key = z.zbId
dataList.znzbList.push(z);
normalForm.value.znzbList.push({
sbmc: z.sbmc,
text: z.sbmc,
txzblx: z.txzblx,
txzbId: z.zbId,
qwjzId: z.qwjzId,
hh: z.hh,
sfrh: z.sfrh,
sfxt: z.sfxt,
sfzy: z.sfzy,
});
});
}
//选中负责人
function onfzrConfirm(val) {
normalForm.value.xfbmid = val.xbdm;
}
//删除选中数据
function deleteCheckTag(item, index, val) {
switch (val) {
case "mj":
normalForm.value.mjList.splice(index, 1);
dataList.mjList.splice(index, 1);
break;
case "fj":
normalForm.value.fjList.splice(index, 1);
dataList.fjList.splice(index, 1);
break;
case "zn":
normalForm.value.znzbList.splice(index, 1);
dataList.znzbList.splice(index, 1);
break;
case "jy":
normalForm.value.jyqxList.splice(index, 1);
dataList.jyqxList.splice(index, 1);
list.jyqxList.forEach((el) => { if (el.id === item.qxid) el.qxsl = 1; });
if (!normalForm.value.jyqxList.map((j) => j.scode).includes("01")) {
normalForm.value.wzlx = "2";
}
break;
case "cl":
normalForm.value.clList.splice(index, 1);
dataList.clList.splice(index, 1);
if (normalForm.value.clList.length == 0) normalForm.value.xlfs = "1";
break;
}
}
function getUUid() {
var list = [];
var hexDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
for (var i = 0; i < 32; i++) {
list[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
list[14] = "4";
list[19] = hexDigits.substr((list[19] & 0x3) | 0x8, 1);
list[8] = list[13] = list[18] = list[23];
let uuid = list.join("");
return uuid;
}
// 新增报备接口
function onSubmit() {
normalForm.value.jlList = [...normalForm.value.mjList, ...normalForm.value.fjList];
normalForm.value.xfbmid = normalForm.value.ssbmid ? normalForm.value.ssbmid : userInfo.deptList[0].deptId;
normalForm.value.xfpbId = obj.pbInfo ? obj.pbInfo.id : "";
normalForm.value.bblx = "02";
Dialog.confirm({ title: "提示", message: "是否确认报备信息无误!", confirmButtonColor: "#3e6ee8", }).then((res) => {
loading.value = true;
if (normalForm.value.wqzbList.length > 0) {
normalForm.value.wqzb = normalForm.value.wqzbList.join(',')
}
normalForm.value.id = getUUid()
addXFBB(normalForm.value).then((res) => {
getMybbTodayNew().then((_res) => {
loading.value = false
if (!_res) return false
userInfo.bbId = _res.id;
userInfo.jzId = _res.jzId;
userInfo.jzMc = _res.jzMc;
setStorage("userInfo", JSON.stringify(userInfo));
}).catch(() => {
loading.value = false
});;
hintToast("报备成功!");
router.replace('/Home');
finishReport({ bbzt: "0", id: res, }).then((res) => { });
}).catch(() => {
loading.value = false
});
});
}
//结束报备
function editFn(e) {
Dialog.confirm({
title: "提示",
message: "是否确认结束报备!",
confirmButtonColor: "#3e6ee8",
}).then((res) => {
loading.value = true
finishReport({
bbzt: "1",
id: obj.bbInfo.id,
}).then((res) => {
loading.value = false
hintToast("报备结束成功");
userInfo.bbId = "";
userInfo.jzId = "";
userInfo.jzMc = "";
router.go(-1);
setStorage("userInfo", JSON.stringify(userInfo));
}).catch(() => {
loading.value = false
});
});
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.popupTitle {
text-align: center;
background-color: rgb(11, 137, 247);
height: 6vh;
line-height: 6vh;
}
.popbtn-box {
width: 100%;
display: flex;
justify-content: space-around;
}
.check-item-tag {
display: inline-block;
margin: 0 6px;
}
.check-data-box {
height: 25vh;
overflow: auto;
}
.time-box {
display: flex;
}
::v-deep .mulSelect .van-cell__title,
.van-cell__value {
flex: unset;
}
::v-deep .mulSelect .van-cell__value {
flex: 1;
}
.title_tab {
@include font_color($font-color-theme);
padding-left: 7vw;
position: relative;
margin: 2vw 0;
letter-spacing: 2px;
}
.title_tab::after {
content: "";
position: absolute;
top: 0;
left: 5vw;
bottom: 0;
width: 4px;
background: #3b6be7;
border-radius: 2px;
}
.van-cell:after {
display: none;
}
.van-cell {
@include table_item_color($table-item-theme);
box-sizing: border-box;
border-radius: 4px;
padding: 6px;
margin: 8px 5%;
width: 90%;
overflow: hidden;
color: var(--van-cell-text-color);
font-size: var(--van-cell-font-size);
line-height: var(--van-cell-line-height);
}
.popupTitle {
color: #fff;
}
::v-deep .van-field__label {
margin-right: 0px;
}
::v-deep .van-radio-group--horizontal,
.van-checkbox-group--horizontal {
flex-wrap: nowrap;
@include font_size($font_medium_s);
}
::v-deep .van-field__control--custom {
justify-content: flex-end;
}
::v-deep .van-checkbox-group {
display: flex;
}
::v-deep .van-checkbox {
margin-left: 10px;
}
</style>

View File

@ -0,0 +1,262 @@
<template>
<div class="container" style="padding-top: 13vw">
<TopNav navTitle="临时勤务列表" />
<!-- <van-search
v-model="xfqList.xfqMc"
placeholder="请输入巡防区名称"
@update:model-value="getList(1)"
/> -->
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="没有更多了"
@load="onLoad"
>
<div
class="item-box item_box"
v-for="(item, index) in xfqList.list"
:key="index"
>
<div class="titleSJY">勤务说明: {{ item.bz }}</div>
<div>
勤务时间: {{ item.xfrq }}&nbsp; {{ item.kssj }}&nbsp;&nbsp;{{
item.jssj
}}
</div>
<div><van-icon name="user-o" /> 负责人: {{ item.fzrXm }}</div>
<div @click="getPop(item.mjsl, item.pbmj, '民警')">
民警数量{{ item.mjsl }}
</div>
<div @click="getPop(item.mjsl, item.pbfj, '辅警')">
辅警数量{{ item.fjsl }}
</div>
<div @click="getPop(item.mjsl, item.pbcl, '车辆')">
车辆数量{{ item.jcsl }}
</div>
<div>
智能装备
<template v-if="item.znzbList.length > 0">
<span v-for="(el, index) in item.znzbList" :key="index"
>{{ el.sbmc }}&nbsp;</span
>
</template>
<template v-else></template>
</div>
<div>
警用器械
<template v-if="item.jyqxList.length > 0">
<span v-for="(el2, index2) in item.jyqxList" :key="index2"
>{{ el2.sbmc }}&nbsp;</span
>
</template>
<template v-else></template>
</div>
</div>
</van-list>
</div>
<van-popup
v-model:show="showList"
round
:style="{ height: '60%', width: '90%' }"
>
<div class="jllbsty">{{ popTitle }}</div>
<div class="police-list">
<van-list
v-model:loading="loading4"
:finished="finished4"
finished-text="没有数据了"
offset="100"
@load="onLoad(4)"
:immediate-check="false"
>
<div
class="list-item item_box detail_box"
v-for="(ele, index5) in popList"
:key="index5"
>
<div class="detail_item" v-if="popTitle == '车辆'">
<div class="user_info">
<div>
<span>{{ ele.jdchphm }}</span>
</div>
</div>
<div>车辆号牌类型: {{ setDict(ele.jdchpzldm, D_BZ_CLLX) }}</div>
</div>
<div class="detail_item" v-else>
<div class="user_info">
<div>
<span>{{ ele.jlxm }}</span>
<!-- <span> ({{ ele.sfzh }}) </span> -->
</div>
<van-tag type="primary">{{
setDict(ele.jllx, D_BZ_JLLX)
}}</van-tag>
</div>
<div>身份证号: {{ ele.sfzh }}</div>
</div>
</div>
</van-list>
</div>
</van-popup>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import { getXfbb } from "../../../api/qwzx.js";
import { getPbbbByMonth } from "../../../api/calender";
import { ref, reactive, onMounted } from "vue";
import { getDictList, setDict } from "../../../utils/dict";
import { useRouter } from "vue-router";
const router = useRouter();
const { D_BZ_CLLX, D_BZ_XQLX, D_BZ_JLLX } = getDictList(
"D_BZ_CLLX",
"D_BZ_XQLX",
"D_BZ_JLLX"
);
const xfqList = reactive({
list: [],
xfqMc: "",
});
onMounted(() => {
getList();
});
const loading = ref(false);
const finished = ref(false);
const page = ref(1);
const total = ref(0);
function getList(val) {
loading.value = false;
getXfbb({
pageCurrent: page.value,
pageSize: 10,
bblx: "02",
})
.then((res) => {
if (val === 1) {
xfqList.list = res.records;
} else {
res.records.forEach((ele) => {
xfqList.list.push(ele);
});
}
total.value = res.total;
onLoad();
finished.value = true;
})
.catch((err) => {
finished.value = true;
});
}
function onLoad() {
if (page.value * 10 < total.value) {
page.value++;
getXfqList();
}
}
const showList = ref(false);
const popTitle = ref("");
const popList = ref([]);
function getPop(sl, item, title) {
if (sl > 0) {
popTitle.value = title;
showList.value = true;
popList.value = JSON.parse(item);
}
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.item-box {
padding: 2vw;
line-height: 1.8em;
margin: 3vw 3vw 0 3vw;
border-bottom: 1px solid #f3f3f3;
@include font_color($font-color-theme);
@include font_size($font_medium_s);
}
.titleSJY {
color: #1f6cec;
font-weight: bold;
@include font_size($font_medium);
}
.detail_box {
margin-top: 1vw;
display: flex;
position: relative;
@include font_size($font_medium_s);
.detail_item {
flex: 3.5;
margin-left: 2vw;
.user_info {
@include font_size($font_medium);
display: flex;
justify-content: space-between;
font-weight: 600;
color: #507ce9;
& > div > span {
display: inline-block;
margin-right: 2vw;
}
}
.item {
line-height: 6vw;
}
}
}
.jllbsty {
text-align: center;
@include font_size($font_medium);
color: #507ce9;
margin-top: 2vh;
}
.police-list {
@include font_color($font-color-theme);
padding: 3vw;
.list-item {
padding: 3vw;
margin: 2vh 0;
// box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
border-radius: 2vw;
.phone-icon {
position: absolute;
right: 5vw;
}
.address-box {
display: flex;
justify-content: space-between;
.adress-left {
color: #3e6ee8;
}
}
.name-text {
@include font_size($font_medium);
color: #3e6ee8;
margin-bottom: 1vh;
font-weight: bold;
display: flex;
justify-content: flex-start;
align-items: center;
}
.title {
@include font_size($font_medium);
font-weight: 550;
}
.num-text1 {
@include font_size($font_large_s);
color: #3e6ee8;
}
.num-text2 {
@include font_size($font_large_s);
color: #eea82f;
}
.num-text3 {
@include font_size($font_large_s);
color: #25b882;
}
}
}
</style>

View File

@ -0,0 +1,233 @@
<!--
* @Author: 孙总
* @Date: 2022-11-03 10:33:34
* @LastEditTime: 2022-11-03 10:36:50
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \gx-app\src\pages\yyzx\yjtjInfo\gzyInfo.vue
-->
<template>
<div>
<TopNav navTitle="感知源预警清单" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Tabs :list="tabs" @onYjjb="onSelect" :type="'car'"></Tabs>
<!-- <Search
placeholder="请输入预警人员姓名"
v-model="kwd"
:isSx="true"
@update:sx="showPopup = !showPopup "
@update:modelValue="onSearch"
></Search> -->
</div>
</van-sticky>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text=""
@load="onLoad"
offset="1"
:immediate-check="false"
>
<List
v-for="(item, index) in yjxx.list"
:key="index"
:item="item"
:path="`/yyzx/yjxx/yjDetail?id=${item.id}`"
:dict="{ D_BZ_YJLX, D_BZ_TYJB }"
/>
<van-empty
description="暂无预警信息"
image="default"
v-if="yjxx.list.length <= 0 && !loading"
/>
</van-list>
</van-pull-refresh>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import Tabs from "../../../components/tabs.vue";
import { getYjxxTj, getPageList } from "../../../api/yjxx.js";
import { useRoute } from "vue-router"
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/YjList.vue";
import Search from "../../../components/search.vue";
import { setTimeQuantum } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, watch, reactive, onMounted } from "vue";
const { D_BZ_YJLX, D_BZ_TYJB } = getDictList("D_BZ_YJLX", "D_BZ_TYJB"); //字典信息
watch(D_BZ_YJLX, (newValue) => {
for (let i = 0; i < newValue.length; i++) {
newValue[i].name = newValue[i].text;
newValue[i].key = newValue[i].dm;
newValue[i].isCheck = false;
}
yjxx.sxList = [
{
title: "预警类型",
isCheckBox: true,
array: newValue,
},
];
//时间段选项
yjxx.sxList[1] = setTimeQuantum();
});
const tabs = ref([
{
name: "全部",
count: 0,
yjjb: "",
},
{
name: "红色预警",
count: 0,
yjjb: "10",
},
{
name: "橙色预警",
count: 0,
yjjb: "20",
},
{
name: "黄色预警",
count: 0,
yjjb: "30",
},
{
name: "蓝色预警",
count: 0,
yjjb: "40",
},
]);
const yjxx = reactive({
pageNum: 1,
pageSize: 10,
yjJb: "",
yjLx: "",
startTime: "",
endTime: "",
yjLx: "",
sxList: [], //筛选条件数据
list: [], //预警列表数据
});
const { yj_gzyid } = useRoute().query
const kwd = ref("");
const finished = ref(false);
const loading = ref(false);
const showPopup = ref(false); //筛选弹窗
const loadingPull = ref(false);
const total = ref(0);
onMounted(() => {
getList();
getTabs();
});
//下拉刷新
function onRefresh() {
yjxx.pageNum = 1;
yjxx.yjJb = "";
kwd.value = "";
yjxx.startTime = "";
yjxx.endTime = "";
yjxx.yjLx = "";
yjxx.list = [];
getList();
getTabs();
}
// 预警信息统计
function getTabs() {
getYjxxTj({
yjGzyid: yj_gzyid
}).then((res) => {
res.forEach((element) => {
tabs.value[0].count += element.count;
if (element.yj_jb == "40") {
tabs.value[4].count = element.count;
}
if (element.yj_jb == "30") {
tabs.value[3].count = element.count;
}
if (element.yj_jb == "20") {
tabs.value[2].count = element.count;
}
if (element.yj_jb == "10") {
tabs.value[1].count = element.count;
}
});
});
}
// 获取预警信息
function getList() {
loading.value = true;
getPageList({
pageNum: yjxx.pageNum,
pageSize: yjxx.pageSize,
yjJb: yjxx.yjJb,
yjRyxm: kwd.value,
startTime: yjxx.startTime,
endTime: yjxx.endTime,
yjLx: yjxx.yjLx,
yjGzyid: yj_gzyid
})
.then((res) => {
loading.value = false;
loadingPull.value = false;
if (yjxx.pageNum == 1) {
yjxx.list = res.records;
} else {
res.records.forEach((item) => {
yjxx.list.push(item);
});
}
total.value = res.pages;
})
.catch((err) => {
loading.value = false;
});
}
/**
* tab选择
* @param {Object} val
*/
function onSelect(val) {
yjxx.pageNum = 1;
yjxx.yjJb = tabs.value[val].yjjb;
getList();
}
/**
* 关键字搜索
* @param {Object} val
*/
function onSearch(val) {
yjxx.pageNum = 1;
getList();
}
// 弹框盒子
function onConfirm(val) {
yjxx.startTime = val.startTime;
yjxx.endTime = val.endTime;
let arr = [];
val.list[0].array.forEach((item) => {
if (item.isCheck) {
arr.push(item.value);
}
});
yjxx.yjLx = arr.join(",");
yjxx.pageNum = 1;
getList();
showPopup.value = false;
}
function onLoad() {
if (yjxx.pageNum >= total.value) {
finished.value = true;
return;
}
yjxx.pageNum += 1;
getList();
}
</script>
<style>
</style>

View File

@ -0,0 +1,232 @@
<template>
<div>
<TopNav navTitle="派出所预警分析" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Tabs :list="tabs" @onYjjb="onSelect" :type="'car'"></Tabs>
<Search
placeholder="请输入预警人员姓名"
v-model="kwd"
:isSx="true"
@update:sx="showPopup = !showPopup "
@update:modelValue="onSearch"
></Search>
</div>
</van-sticky>
<SxPopup
:showPopup="showPopup"
:list="yjxx.sxList"
:p_top="145"
@update:close="showPopup = false"
@update:onConfirm="onConfirm"
/>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text=""
@load="onLoad"
offset="1"
:immediate-check="false"
>
<List
v-for="(item, index) in yjxx.list"
:key="index"
:item="item"
:path="`/yyzx/yjxx/yjDetail?id=${item.id}`"
:dict="{ D_BZ_YJLX, D_BZ_TYJB }"
/>
<van-empty
description="暂无预警信息"
image="default"
v-if="yjxx.list.length <= 0 && !loading"
/>
</van-list>
</van-pull-refresh>
</div>
</template>
<script setup>
import { getYjxxTj, getPageList } from "../../../api/yjxx.js";
import TopNav from "../../../components/topNav.vue";
import Search from "../../../components/search.vue";
import Tabs from "../../../components/tabs.vue";
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/YjList.vue";
import { setTimeQuantum } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, reactive, onMounted, watch } from "vue";
import { useRoute } from 'vue-router';
const { D_BZ_YJLX, D_BZ_TYJB } = getDictList("D_BZ_YJLX", "D_BZ_TYJB"); //字典信息
watch(D_BZ_YJLX, (newValue) => {
for (let i = 0; i < newValue.length; i++) {
newValue[i].name = newValue[i].text;
newValue[i].key = newValue[i].dm;
newValue[i].isCheck = false;
}
yjxx.sxList = [
{
title: "预警类型",
isCheckBox: true,
array: newValue,
},
];
//时间段选项
yjxx.sxList[1] = setTimeQuantum();
});
const tabs = ref([
{
name: "全部",
count: 0,
yjjb: "",
},
{
name: "红色预警",
count: 0,
yjjb: "10",
},
{
name: "橙色预警",
count: 0,
yjjb: "20",
},
{
name: "黄色预警",
count: 0,
yjjb: "30",
},
{
name: "蓝色预警",
count: 0,
yjjb: "40",
},
]);
const yjxx = reactive({
pageNum: 1,
pageSize: 10,
yjJb: "",
yjLx: "",
startTime: "",
endTime: "",
yjLx: "",
sxList: [], //筛选条件数据
list: [], //预警列表数据
});
const { yj_ssbm, yj_ssbmdm } = useRoute().query
const kwd = ref("");
const finished = ref(false);
const loading = ref(false);
const showPopup = ref(false); //筛选弹窗
const loadingPull = ref(false);
const total = ref(0);
onMounted(() => {
getList();
getTabs();
});
//下拉刷新
function onRefresh() {
yjxx.pageNum = 1;
yjxx.yjJb = "";
kwd.value = "";
yjxx.startTime = "";
yjxx.endTime = "";
yjxx.yjLx = "";
yjxx.list = [];
getList();
getTabs();
}
// 预警信息统计
function getTabs() {
getYjxxTj({
ssbmdm: yj_ssbmdm
}).then((res) => {
res.forEach((element) => {
tabs.value[0].count += element.count;
if (element.yj_jb == "40") {
tabs.value[4].count = element.count;
}
if (element.yj_jb == "30") {
tabs.value[3].count = element.count;
}
if (element.yj_jb == "20") {
tabs.value[2].count = element.count;
}
if (element.yj_jb == "10") {
tabs.value[1].count = element.count;
}
});
});
}
// 获取预警信息
function getList() {
loading.value = true;
getPageList({
pageNum: yjxx.pageNum,
pageSize: yjxx.pageSize,
yjJb: yjxx.yjJb,
yjRyxm: kwd.value,
startTime: yjxx.startTime,
endTime: yjxx.endTime,
yjLx: yjxx.yjLx,
ssbmdm: yj_ssbmdm
})
.then((res) => {
loading.value = false;
loadingPull.value = false;
if (yjxx.pageNum == 1) {
yjxx.list = res.records;
} else {
res.records.forEach((item) => {
yjxx.list.push(item);
});
}
total.value = res.total;
})
.catch((err) => {
loading.value = false;
});
}
/**
* tab选择
* @param {Object} val
*/
function onSelect(val) {
yjxx.pageNum = 1;
yjxx.yjJb = tabs.value[val].yjjb;
getList();
}
/**
* 关键字搜索
* @param {Object} val
*/
function onSearch(val) {
yjxx.pageNum = 1;
getList();
}
// 弹框盒子
function onConfirm(val) {
yjxx.startTime = val.startTime;
yjxx.endTime = val.endTime;
let arr = [];
val.list[0].array.forEach((item) => {
if (item.isCheck) {
arr.push(item.value);
}
});
yjxx.yjLx = arr.join(",");
yjxx.pageNum = 1;
getList();
showPopup.value = false;
}
function onLoad() {
if (yjxx.list.length >= total.value) {
finished.value = true;
return;
}
yjxx.pageNum += 1;
getList();
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,222 @@
<!--
* @Author: 孙总
* @Date: 2022-11-03 10:33:34
* @LastEditTime: 2022-11-03 10:36:50
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \gx-app\src\pages\yyzx\yjtjInfo\gzyInfo.vue
-->
<template>
<div>
<TopNav navTitle="人员预警清单" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Tabs :list="tabs" @onYjjb="onSelect" :type="'car'"></Tabs>
<!-- <Search
placeholder="请输入预警人员姓名"
v-model="kwd"
:isSx="true"
@update:sx="showPopup = !showPopup "
@update:modelValue="onSearch"
></Search> -->
</div>
</van-sticky>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list
v-model:loading="loading"
:finished="finished"
finished-text=""
@load="onLoad"
offset="1"
:immediate-check="false"
>
<List
v-for="(item, index) in yjxx.list"
:key="index"
:item="item"
:path="`/yyzx/yjxx/yjDetail?id=${item.id}`"
:dict="{ D_BZ_YJLX, D_BZ_TYJB }"
/>
<van-empty
description="暂无预警信息"
image="default"
v-if="yjxx.list.length <= 0 && !loading"
/>
</van-list>
</van-pull-refresh>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import Tabs from "../../../components/tabs.vue";
import { getYjxxTj, getPageList } from "../../../api/yjxx.js";
import { useRoute } from "vue-router"
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/YjList.vue";
import Search from "../../../components/search.vue";
import { setTimeQuantum } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, watch, reactive, onMounted } from "vue";
const { D_BZ_YJLX, D_BZ_TYJB } = getDictList("D_BZ_YJLX", "D_BZ_TYJB"); //字典信息
const tabs = ref([
{
name: "全部",
count: 0,
yjjb: "",
},
{
name: "红色预警",
count: 0,
yjjb: "10",
},
{
name: "橙色预警",
count: 0,
yjjb: "20",
},
{
name: "黄色预警",
count: 0,
yjjb: "30",
},
{
name: "蓝色预警",
count: 0,
yjjb: "40",
},
]);
const yjxx = reactive({
pageNum: 1,
pageSize: 10,
yjJb: "",
yjLx: "",
startTime: "",
endTime: "",
yjLx: "",
sxList: [], //筛选条件数据
list: [], //预警列表数据
});
//时间段选项
yjxx.sxList[1] = setTimeQuantum();
const kwd = ref("");
const finished = ref(false);
const loading = ref(false);
const showPopup = ref(false); //筛选弹窗
const loadingPull = ref(false);
const total = ref(0);
const { yj_rysfzh, yj_ryxm } = useRoute().query
onMounted(() => {
// getList();
getTabs();
});
//下拉刷新
function onRefresh() {
yjxx.pageNum = 1;
yjxx.yjJb = "";
kwd.value = "";
yjxx.startTime = "";
yjxx.endTime = "";
yjxx.yjLx = "";
yjxx.list = [];
getList();
getTabs();
}
// 预警信息统计
function getTabs() {
getYjxxTj({
yjRysfzh: yj_rysfzh,
yjRyxm: yj_ryxm
}).then((res) => {
res.forEach((element) => {
tabs.value[0].count += element.count;
if (element.yj_jb == "40") {
tabs.value[4].count = element.count;
}
if (element.yj_jb == "30") {
tabs.value[3].count = element.count;
}
if (element.yj_jb == "20") {
tabs.value[2].count = element.count;
}
if (element.yj_jb == "10") {
tabs.value[1].count = element.count;
}
});
});
}
// 获取预警信息
function getList() {
loading.value = true;
getPageList({
pageNum: yjxx.pageNum,
pageSize: yjxx.pageSize,
yjJb: yjxx.yjJb,
yjRyxm: yj_ryxm,
// startTime: yjxx.startTime,
// endTime: yjxx.endTime,
// yjLx: 1,
yjRysfzh: yj_rysfzh
})
.then((res) => {
loading.value = false;
loadingPull.value = false;
if (yjxx.pageNum == 1) {
yjxx.list = res.records;
} else {
res.records.forEach((item) => {
yjxx.list.push(item);
});
}
total.value = res.pages;
})
.catch((err) => {
loading.value = false;
});
}
getList();
/**
* tab选择
* @param {Object} val
*/
function onSelect(val) {
yjxx.pageNum = 1;
yjxx.yjJb = tabs.value[val].yjjb;
getList();
}
/**
* 关键字搜索
* @param {Object} val
*/
function onSearch(val) {
yjxx.pageNum = 1;
getList();
}
// 弹框盒子
function onConfirm(val) {
yjxx.startTime = val.startTime;
yjxx.endTime = val.endTime;
let arr = [];
val.list[0].array.forEach((item) => {
if (item.isCheck) {
arr.push(item.value);
}
});
yjxx.yjLx = arr.join(",");
yjxx.pageNum = 1;
getList();
showPopup.value = false;
}
function onLoad() {
if (yjxx.pageNum >= total.value) {
finished.value = true;
return;
}
finished.value = false;
yjxx.pageNum += 1;
getList();
}
</script>
<style>
</style>

View File

@ -0,0 +1,155 @@
<template>
<div id="lineCharts" class="chartsBox"></div>
</template>
<script setup>
import { dateFormat } from "../../../../utils/tools.js";
import { getGsdYj } from "../../../../api/yjxx.js";
import * as echarts from "echarts";
import { ref, onMounted, defineProps, watch } from "vue";
import { getListHotMap } from "../../../../api/yjxx.js";
const props = defineProps({
type: {
type: Number,
default: 0,
}
});
watch(()=> props.type, (val)=>{
getList()
})
function lineChartFn() {
var chartDom = document.getElementById("lineCharts");
var myChart = echarts.init(chartDom, "");
var option;
option = {
tooltip: {
trigger: "axis",
},
legend: {
data: ["人员预警", "车辆预警", "事件预警"],
},
grid: {
left: "3%",
right: "5%",
bottom: "3%",
top: "18%",
containLabel: true,
},
xAxis: {
type: "category",
boundaryGap: false,
data: ["0", "2", "4", "6", "8", "10", "12", "14", "16", "18", "20", "22"],
},
yAxis: {
type: "value",
},
series: [
{
name: "人员预警",
type: "line",
data: manList.value,
smooth: true,
itemStyle: {
normal: {
color: "#177FFF",
},
},
},
{
name: "车辆预警",
type: "line",
data: carList.value,
smooth: true,
itemStyle: {
normal: {
color: "#ffcc40",
},
},
},
{
name: "事件预警",
type: "line",
data: evtList.value,
smooth: true,
itemStyle: {
normal: {
color: "#F6426C",
},
},
},
],
};
option && myChart.setOption(option);
document.getElementById("lineCharts").setAttribute("_echarts_instance_", "");
}
const timeList = [
"0",
"2",
"4",
"6",
"8",
"10",
"12",
"14",
"16",
"18",
"20",
"22",
];
const manList = ref([]);
const carList = ref([]);
const evtList = ref([]);
function getList() {
let tempList = ref([]);
let m = [];
let c = [];
let e = [];
getGsdYj({
// kssj: dateFormat() + " " + "00:00:00",
// jssj: dateFormat() + " " + "23:59:59",
type: props.type + 1,
}).then((res) => {
tempList.value = res;
if (tempList.value && tempList.value.length > 0) {
tempList.value.forEach((el) => (el.sj = el.h));
tempList.value.forEach((item) => {
if (item.type === "1") {
m.push(item);
}
if (item.type === "2") {
c.push(item);
}
if (item.type === "3") {
e.push(item);
}
});
manList.value = compareArray(timeList, m);
carList.value = compareArray(timeList, c);
evtList.value = compareArray(timeList, e);
lineChartFn();
}
});
}
function compareArray(timeList, targetList) {
let list = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
for (let item of targetList) {
let _index = timeList.findIndex((c) => c == item.sj);
if (_index > -1) {
list[_index] = item.total;
}
}
return list;
}
onMounted(() => {
getList();
lineChartFn();
});
</script>
<style lang="scss" scoped>
.chartsBox {
height: 55vw;
padding: 10px 0 0 0;
box-sizing: border-box;
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<div id="lineChartsPcs" class="chartsBox"></div>
</template>
<script setup>
import { dateFormat } from "../../../../utils/tools.js";
import * as echarts from "echarts";
import { ref, onMounted, defineProps, watch } from "vue";
import { pcsyjpm } from "../../../../api/yjxx.js";
import { getRecentDay } from "../../../../utils/tools";
import router from "../../../../router/index.js";
const props = defineProps({
type: {
type: Number,
default: 0,
},
});
watch(
() => props.type,
(val) => {
getList();
}
);
function lineChartFn() {
var chartDom = document.getElementById("lineChartsPcs");
var myChart = echarts.init(chartDom, "");
var option;
option = {
tooltip: {
trigger: "axis",
},
legend: {
data: ["派出所预警总数"],
},
grid: {
left: "3%",
right: "5%",
bottom: "3%",
top: "18%",
containLabel: true,
},
xAxis: {
type: "category",
boundaryGap: false,
data: xdata.value,
},
yAxis: {
type: "value",
},
series: [
{
name: "派出所预警总数",
type: "line",
data: datas.value,
smooth: true,
itemStyle: {
normal: {
color: "#177FFF",
},
},
},
],
};
myChart.on("click", "series.line", function (params) {
let row = {};
tempList.value.forEach((item) => {
if (item.ssbm === params.name) {
row.yj_ssbmdm = item.ssbmdm;
row.yj_ssbm = item.ssbm;
}
});
router.push({
path: "/yyzx/yjtjInfo/pcsyjinfo",
query: row,
});
});
option && myChart.setOption(option);
document
.getElementById("lineChartsPcs")
.setAttribute("_echarts_instance_", "");
}
const tempList = ref([]);
const xdata = ref([]);
const datas = ref([]);
function getList() {
pcsyjpm({
kssj: getRecentDay(props.type, "ymd"),
jssj: getRecentDay(0, "ymd"),
}).then((res) => {
tempList.value = res;
if (tempList.value && tempList.value.length > 0) {
tempList.value.forEach((item) => {
xdata.value.push(item.ssbm);
datas.value.push(item.total);
});
lineChartFn();
}
});
}
onMounted(() => {
getList();
lineChartFn();
});
</script>
<style lang="scss" scoped>
.chartsBox {
height: 55vw;
padding: 10px 0 0 0;
box-sizing: border-box;
}
</style>

View File

@ -0,0 +1,124 @@
<template>
<!-- <div v-if="dataLoad" class="empty-box">数据加载中...</div> -->
<div class="cccc">
<ul class="rankingBox" v-if="list.length > 0">
<li v-for="item in list" :key="item.yj_rysfzh">
<div class="leftBox">
<div class="top">
<span class="dian blue"></span
><span @click="routerPush(item)" class="name text_title"
>{{ item.yj_ryxm }}{{ item.yj_rysfzh }}</span>
</div>
<div class="jdtBox">
<div
class="jdt"
:style="{
width: (parseInt(item.total) / totalWidth) * 100 + '%',
}"
></div>
</div>
</div>
<div class="rightBox">
<span class="numb">{{ item.total }}</span>
</div>
</li>
</ul>
<van-empty description="暂无数据" v-if="list.length === 0" />
</div>
</template>
<script setup>
import { dateFormat } from "../../../../utils/tools.js";
import { getManRankYj } from "../../../../api/yjxx.js";
import { ref, reactive, watch, onMounted, defineProps } from "vue";
import router from "../../../../router/index.js";
import { getRecentDay } from "../../../../utils/tools";
const props = defineProps({
type: {
type: Number,
default: 0,
}
});
watch(()=> props.type, (val)=>{
getList()
})
const list = ref([]);
const totalWidth = ref(0);
const dataLoad = ref(true);
function getList() {
getManRankYj({
kssj: getRecentDay(props.type, 'ymd'),
jssj: dateFormat(),
})
.then((res) => {
list.value = res;
if (list.value && list.value.length > 0) {
dataLoad.value = false;
totalWidth.value = Math.max(...list.value.map((item) => item.total));
}
})
.catch((err) => {
dataLoad.value = false;
});
}
function routerPush(row){
router.push({
path:'/yyzx/yjtjInfo/ryyjinfo',
query:row
})
}
onMounted(() => {
getList();
});
</script>
<style lang="scss" scoped>
.cccc {
height: 55vw;
overflow: auto;
margin-top: 1.5vw;
}
ul.rankingBox {
height: 100%;
overflow: auto;
li {
display: flex;
justify-content: space-between;
padding-top: 8px;
.leftBox {
flex: 1;
.top {
height: 28px;
.name {
font-size: 14px;
vertical-align: middle;
}
}
.jdtBox {
height: 7px;
background: #dbdbdb;
border-radius: 4px;
overflow: hidden;
.jdt {
background: #00c0fa;
height: 100%;
border-radius: 4px;
}
}
}
.rightBox {
width: 68px;
text-align: right;
color: #4896ff;
font-size: 14px;
line-height: 50px;
height: 34px;
.numb {
font-size: 14px;
color: #333;
}
}
}
}
</style>

View File

@ -0,0 +1,145 @@
<!--
* @Author: your name
* @Date: 2022-10-07 14:10:51
* @LastEditTime: 2022-10-14 15:49:47
* @LastEditors: Please set LastEditors
* @Description: In User Settings Edit
* @FilePath: \rsga\src\views\moduleHome\warningCenter\components\ranking.vue
-->
<template>
<!-- <div v-if="dataLoad" class="empty-box">数据加载中...</div> -->
<ul class="rankingBox" v-if="list.length > 0">
<li v-for="item in list" :key="item.yj_gzyid">
<template v-if="item.yj_gzymc">
<div class="leftBox">
<div class="top">
<span class="dian blue"></span>
<span @click="routerPush(item)" class="name text_title">{{
item.yj_gzymc
}}</span>
</div>
<div class="jdtBox">
<div
class="jdt"
:style="{
width: (parseInt(item.total) / totalWidth) * 100 + '%',
}"
></div>
</div>
</div>
<div class="rightBox">
<span class="numb">{{ item.total }}</span>
</div>
</template>
</li>
</ul>
<van-empty description="暂无数据" v-if="list.length === 0" />
</template>
<script setup>
import { dateFormat } from "../../../../utils/tools.js";
import { getGzyYj } from "../../../../api/yjxx.js";
import { ref, reactive, watch, onMounted } from "vue";
import { getRecentDay } from "../../../../utils/tools";
import router from "../../../../router/index.js";
const props = defineProps({
type: {
type: Number,
default: 0,
}
});
watch(()=> props.type, (val)=>{
getList()
})
const list = ref([]);
const totalWidth = ref(0);
const dataLoad = ref(true);
function getList() {
getGzyYj({
kssj: getRecentDay(props.type, 'ymd'),
jssj: dateFormat(),
})
.then((res) => {
list.value = res;
if (list.value && list.value.length > 0) {
dataLoad.value = false;
totalWidth.value = Math.max(
...list.value
.filter((item) => !item.yj_gzymc === false)
.map((item) => item.total)
);
}
})
.catch((err) => {
dataLoad.value = false;
});
}
function routerPush(row) {
router.push({
path: "/yyzx/yjtjInfo/gzyInfo",
query: row,
});
}
onMounted(() => {
getList();
});
</script>
<style lang="scss" scoped>
ul.rankingBox {
height: 55vw;
overflow: auto;
margin-top: 1.5vw;
li {
display: flex;
justify-content: space-between;
padding-top: 8px;
.leftBox {
flex: 1;
.top {
height: 28px;
display: flex;
align-items: center;
.name {
font-size: 14px;
vertical-align: middle;
flex: 50;
}
.dian {
flex: 1.455;
display: inline-block;
width: 2vw !important;
height: 2vw !important;
border-radius: 50%;
background: #4896ff;
margin-right: 0.5vw;
}
}
.jdtBox {
height: 7px;
background: #dbdbdb;
border-radius: 4px;
overflow: hidden;
.jdt {
background: #00c0fa;
height: 100%;
border-radius: 4px;
}
}
}
.rightBox {
width: 68px;
text-align: right;
color: #4896ff;
font-size: 14px;
line-height: 50px;
height: 34px;
.numb {
font-size: 14px;
color: #333;
}
}
}
}
</style>

View File

@ -0,0 +1,261 @@
<template>
<div>
<TopNav navTitle="预警信息" :showRight="false" :showLeft="true" />
<van-sticky>
<div class="sticky_box">
<Tabs
:list="tabs"
@onYjjb="onSelect"
:type="'car'"
:key="tabsIndex"
></Tabs>
<Search
placeholder="请输入预警人员姓名"
v-model="kwd"
:isSx="true"
@update:sx="showPopup = !showPopup"
@update:modelValue="onSearch"
></Search>
</div>
</van-sticky>
<SxPopup
:showPopup="showPopup"
:list="yjxx.sxList"
:p_top="145"
@update:close="showPopup = false"
@update:onConfirm="onConfirm"
:kssj="dateFormat()"
:jssj="dateFormat()"
/>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list
:finished="finished"
finished-text=""
@load="onLoad"
offset="1"
:immediate-check="false"
>
<List
v-for="(item, index) in yjxx.list"
:key="index"
:item="item"
:path="`/yyzx/yjxx/yjDetail?id=${item.id}`"
:dict="{ D_BZ_YJLX, D_BZ_TYJB }"
/>
</van-list>
</van-pull-refresh>
<van-loading style="text-align: center" v-if="loading"
>加载中...</van-loading
>
<van-empty description="暂无预警信息" image="default" v-if="showEmpty" />
</div>
</template>
<script>
export default {
name: "yyzx/yjxx/index",
};
</script>
<script setup>
import { getYjxxTj, getPageList } from "../../../api/yjxx.js";
import TopNav from "../../../components/topNav.vue";
import Search from "../../../components/search.vue";
import Tabs from "../../../components/tabs.vue";
import SxPopup from "../../../components/SxPopup.vue";
import List from "../../../components/YjList.vue";
import { setTimeQuantum, dateFormat } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, reactive, onMounted, watch, onActivated } from "vue";
import { useRoute,onBeforeRouteLeave } from "vue-router";
import { Toast } from "vant";
const { D_BZ_YJLX, D_BZ_TYJB } = getDictList("D_BZ_YJLX", "D_BZ_TYJB"); //字典信息
watch(D_BZ_YJLX, (newValue) => {
for (let i = 0; i < newValue.length; i++) {
newValue[i].name = newValue[i].text;
newValue[i].key = newValue[i].dm;
newValue[i].isCheck = false;
}
yjxx.sxList = [
{
title: "预警类型",
isCheckBox: true,
array: newValue,
},
];
//时间段选项
yjxx.sxList[1] = setTimeQuantum();
yjxx.sxList[1].array[0].isCheck = true;
});
const tabs = ref([
{
name: "全部",
count: 0,
yjjb: "",
},
{
name: "红色预警",
count: 0,
yjjb: "10",
},
{
name: "橙色预警",
count: 0,
yjjb: "20",
},
{
name: "黄色预警",
count: 0,
yjjb: "30",
},
{
name: "蓝色预警",
count: 0,
yjjb: "40",
},
]);
const yjxx = reactive({
pageNum: 1,
pageSize: 10,
yjJb: "",
yjLx: "",
startTime: "",
endTime: "",
yjLx: "",
sxList: [], //筛选条件数据
list: [], //预警列表数据
});
const kwd = ref("");
const finished = ref(false);
const loading = ref(false);
const showPopup = ref(false); //筛选弹窗
const loadingPull = ref(false);
const showEmpty = ref(false);
const total = ref(0);
const tabsIndex = ref(1);
onMounted(() => {
let yjlx = useRoute().query.yjLx;
if (yjlx != yjxx.yjLx) {
yjxx.yjLx = useRoute().query.yjLx;
yjxx.pageNum = 1;
yjxx.yjJb = "";
kwd.value = "";
yjxx.startTime = dateFormat();
yjxx.endTime = dateFormat();
yjxx.list = [];
getList();
getTabs();
}
});
//下拉刷新
function onRefresh() {
yjxx.pageNum = 1;
yjxx.yjJb = "";
kwd.value = "";
yjxx.startTime = dateFormat();
yjxx.endTime = dateFormat();
yjxx.yjLx = "";
yjxx.list = [];
finished.value = false;
loading.value = false;
loadingPull.value = false;
tabsIndex.value++;
getList();
getTabs();
}
// 预警信息统计
function getTabs() {
getYjxxTj({ kssj: yjxx.startTime, jssj: yjxx.endTime }).then((res) => {
tabs.value[0].count = 0;
res.forEach((element) => {
tabs.value[0].count += element.count;
if (element.yj_jb == "40") {
tabs.value[4].count = element.count;
}
if (element.yj_jb == "30") {
tabs.value[3].count = element.count;
}
if (element.yj_jb == "20") {
tabs.value[2].count = element.count;
}
if (element.yj_jb == "10") {
tabs.value[1].count = element.count;
}
});
});
}
// 获取预警信息
function getList() {
loading.value = true;
showEmpty.value = false;
getPageList({
pageNum: yjxx.pageNum,
pageSize: yjxx.pageSize,
yjJb: yjxx.yjJb,
yjRyxm: kwd.value,
startTime: yjxx.startTime,
endTime: yjxx.endTime,
yjLx: yjxx.yjLx,
})
.then((res) => {
loading.value = false;
loadingPull.value = false;
if (res.records.length === 0) {
showEmpty.value = true;
} else {
showEmpty.value = false;
}
if (yjxx.pageNum == 1) {
yjxx.list = res.records;
} else {
res.records.forEach((item) => {
yjxx.list.push(item);
});
}
total.value = res.total;
})
.catch((err) => {
loading.value = false;
showEmpty.value = true;
loadingPull.value = false;
});
}
/**
* tab选择
* @param {Object} val
*/
function onSelect(val) {
yjxx.list = [];
loading.value = true;
showEmpty.value = false;
yjxx.pageNum = 1;
yjxx.yjJb = tabs.value[val].yjjb;
getList();
}
/**
* 关键字搜索
* @param {Object} val
*/
function onSearch(val) {
yjxx.pageNum = 1;
getList();
}
// 弹框盒子
function onConfirm(val) {
yjxx.startTime = val.startTime;
yjxx.endTime = val.endTime;
yjxx.pageNum = 1;
getList();
showPopup.value = false;
}
function onLoad() {
if (yjxx.list.length >= total.value) {
finished.value = true;
return;
}
yjxx.pageNum += 1;
getList();
}
</script>
<style scoped>
</style>

View File

@ -0,0 +1,620 @@
<template>
<div class="">
<TopNav navTitle="预警轨迹详情" :showRight="false" :showLeft="true" />
<div v-if="!!Object.keys(yjRyDetail).length">
<van-sticky>
<div class="sticky_box">
<Tabs :list="tabs" @onYjjb="onSelect" :type="'car'"></Tabs>
<div class="ry_info">
<List
:item="yjRyDetail"
style="border: none"
:dict="{ D_BZ_YJLX, D_BZ_TYJB }"
/>
<div class="but_box">
<van-button
round
type="primary"
style="margin: 0 2vw; padding: 0 5vw"
@click="onClickPr"
size="mini"
>
人员档案
</van-button>
<van-button
round
type="warning"
style="margin: 0 2vw; padding: 0 5vw"
@click="onClickPc"
size="mini"
>
{{ zlCount > 0 ? "指令详情" : "转为指令" }}
</van-button>
<van-button
round
style="margin: 0 2vw; padding: 0 5vw"
type="success"
size="mini"
:to="`/yyzx/yjxx/yjMapPoint?id=${yjRyDetail.id}`"
@click="onClickZf"
>
地图模式
</van-button>
</div>
</div>
</div>
</van-sticky>
<van-list
v-model:loading="loading"
:finished="finished"
finished-text="没有轨迹数据了"
@load="onLoad"
offset="1"
:immediate-check="false"
>
<Steps :data="stepsData" time="yjFssj">
<template v-slot:default="{ scope }">
<div class="content">
<div class="cont_l">
<div v-if="scope.yjjb === '10'" class="red bg_red">红色</div>
<div v-else-if="scope.yjjb === '40'" class="blue bg_bule">
蓝色
</div>
<div v-else-if="scope.yjjb === '20'" class="orange bg_orange">
橙色
</div>
<div v-else class="yellow bg_yellow">黄色</div>
<div class="text">
来源:{{ setDict(scope.yjSjly, D_BZ_SJLYUAN) }}
</div>
<div class="text">
相似度:{{ scope.xsd ? scope.xsd * 100 + "%" : "" }}
</div>
<div class="text">管辖派出所{{ scope.ssbm }}</div>
<div class="text">地址{{ scope.yjDz }}</div>
</div>
</div>
</template>
</Steps>
</van-list>
</div>
<!-- <van-loading style="marginTop: 10vh;textAlign:center;" v-else-if="!Object.keys(yjRyDetail).length" vertial type="spinner" size="24px">加载中</van-loading> -->
<van-popup
v-model:show="turnZl"
:style="{ height: '75%', width: '90%' }"
round
placement="top"
>
<van-field name="radio" label="类型">
<template #input>
<van-radio-group
v-model="checked"
direction="horizontal"
@change="checkedChange"
>
<van-radio name="01">人员</van-radio>
<van-radio name="02">部门</van-radio>
<van-radio name="03">巡组</van-radio>
</van-radio-group>
</template>
</van-field>
<div class="nr_box">
<template v-if="switchFlag == '01'">
<van-cell class="ry_cell" title="人员">
<template #value>
<span v-if="array.length == 0">请选择人员</span>
<span v-else v-for="(item, index) in array" :key="index">
<van-tag plain type="primary">{{ item.xm }}</van-tag
>&nbsp;
</span>
</template>
</van-cell>
<van-cell>
<template #title>
<van-radio-group
v-model="checkedry"
direction="horizontal"
@change="checkedChangery"
>
<van-radio name="1">本部门</van-radio>
<van-radio name="2">全部</van-radio>
</van-radio-group>
</template>
</van-cell>
<van-search
v-model="form.pname"
placeholder="请输入人员姓名"
@update:model-value="getUserOrDeptList"
@search="getUserOrDeptList"
@cancel="getUserOrDeptList"
></van-search>
<div style="height: 36vh; overflow: auto">
<SelectCell
v-my-load="onPload"
:list="pList"
title="xm"
showSfzh="sfzh"
@update:choose="onSelectList"
/>
</div>
</template>
<template v-if="switchFlag == '02'">
<van-field
v-model="form.fielddept"
readonly
is-link
label="部门"
placeholder="请选择部门"
>
</van-field>
<div class="deptBox">
<van-cascader
v-model="form.deptName"
:closeable="false"
@change="onChange"
:show-header="false"
title="请选择部门"
:options="options"
:field-names="customFieldName"
>
</van-cascader>
</div>
</template>
<template v-if="switchFlag == '03'">
<van-cell title="巡组">
<template #value>
<span v-if="xzArray.length == 0">请选择巡组</span>
<span v-else v-for="(item, index) in xzArray" :key="index">
<van-tag plain type="primary">{{
item.jzMc ? item.jzMc : item.fzrXm + "巡组"
}}</van-tag
>&nbsp;
</span>
</template>
</van-cell>
<div style="textalign: center" v-if="xzList.length <= 0">无巡组</div>
<SelectCell
:list="xzList"
title="jzMc"
showSfzh=""
@update:choose="onSelectXzList"
/>
</template>
</div>
<div class="yp_btn">
<van-button
size="small"
icon="edit"
type="warning"
block
@click="onSubmit"
>
转为指令
</van-button>
</div>
</van-popup>
</div>
</template>
<script setup>
//局部懒加载指令
const vMyLoad = {
mounted: (el, binding) => {
el.addEventListener("scroll", function () {
const condition =
this.scrollHeight - this.scrollTop === this.clientHeight;
if (condition) {
binding.value();
}
});
},
};
import {
getSyrkYjxx,
getInfo,
getStatistics,
selectPage,
selectNextPage,
yjConvertZl,
} from "../../../api/yjxx.js";
import { getJmxz } from "../../../api/qwzx";
import { getXfllList } from "../../../api/common.js";
import SelectCell from "../../../components/SelectCell.vue";
import { getRecentDay, timeValidate } from "../../../utils/tools";
import TopNav from "../../../components/topNav.vue";
import Steps from "../../../components/Steps.vue";
import Tabs from "../../../components/tabs.vue";
import List from "../../../components/YjList.vue";
import { getBase64 } from "../../../utils/tools.js";
import { Toast } from "vant";
import router from "../../../router";
import {
ref,
onMounted,
reactive,
watch,
defineComponent,
onActivated,
} from "vue";
import { useRouter, useRoute } from "vue-router";
import { getDictList, setDict } from "../../../utils/dict";
const route = useRoute();
var queryId = route.query.id;
onActivated(() => {
if (queryId !== route.query.id) {
getYjDetail();
getUserOrDeptList();
queryId = route.query.id;
}
});
const { D_BZ_SJLYUAN, D_BZ_YJLX, D_BZ_TYJB } = getDictList(
"D_BZ_SJLYUAN",
"D_BZ_YJLX",
"D_BZ_TYJB"
); //字典信息
//预警人员详情
const yjRyDetail = ref({});
const stepsData = ref([]);
const tabs = ref([
{
name: "今日预警",
count: 0,
},
{
name: "近7天",
count: 0,
},
{
name: "近30天",
count: 0,
},
{
name: "累计预警",
count: 0,
},
]);
const zlCount = ref();
const turnZl = ref(false); // 转为指令
const checked = ref("01");
const options = ref([]);
const pList = ref([]);
const loading = ref(false);
const form = reactive({
fielddept: "",
fieldname: "",
pname: "",
casValue: "",
deptName: "",
});
const kssj = ref(getRecentDay(0, "ymd"));
const jssj = ref(getRecentDay(0, "ymd"));
onMounted(() => {
getYjDetail();
});
const customFieldName = {
text: "orgName",
value: "orgName",
children: "childDeptList",
};
const customFieldFzrName = {
text: "userName",
};
//人员懒加载
const pLoading = ref(false);
const pFinished = ref(false);
const queryPlist = reactive({
page: 1,
size: 10,
total: 0,
});
function onPload() {
if (pList.value.length >= queryPlist.total) {
return;
}
queryPlist.page++;
getPlist();
}
const { id } = useRoute().query;
// 获取预警信息详情
function getYjDetail() {
getInfo(route.query.id).then((res) => {
yjRyDetail.value = res;
zlCount.value = yjRyDetail.value.sfFszl;
getListBySfz();
getTjList();
});
}
// 通过身份证或车牌号查询
const size = ref(10);
const current = ref(1);
const total = ref(0);
const finished = ref(false);
function getListBySfz() {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
loading.value = true;
getSyrkYjxx({
zjhm: yjRyDetail.value.yjRysfzh,
cph: yjRyDetail.value.yjClcph,
pageCurrent: current.value,
pageSize: size.value,
kssj: kssj.value,
jssj: jssj.value,
})
.then((res) => {
loading.value = false;
Toast.clear();
res.records.forEach((item) => {
stepsData.value.push(item);
});
total.value = res.pages;
})
.catch((err) => {
loading.value = false;
Toast.clear();
});
}
// 统计查询
function getTjList() {
getStatistics({
yjRysfzh: yjRyDetail.value.yjRysfzh,
yjClcph: yjRyDetail.value.yjClcph,
}).then((res) => {
tabs.value[3].count = res.all;
tabs.value[2].count = res.data30;
tabs.value[1].count = res.data7;
tabs.value[0].count = res.today;
});
}
function onSelect(val) {
stepsData.value = [];
finished.value = false;
current.value = 1;
switch (val) {
case 0:
kssj.value = getRecentDay(0, "ymd");
jssj.value = getRecentDay(0, "ymd");
break;
case 1:
kssj.value = getRecentDay(-7, "ymd");
jssj.value = getRecentDay(0, "ymd");
break;
case 2:
kssj.value = getRecentDay(-30, "ymd");
jssj.value = getRecentDay(0, "ymd");
break;
default:
kssj.value = "";
jssj.value = "";
break;
}
getListBySfz();
}
// 指令详情或者转为指令
function onClickPc() {
if (zlCount.value > 0) {
}
if (zlCount.value == 0) {
turnZl.value = true;
form.pname = "";
form.fieldname = "";
form.fielddept = "";
array.value = [];
xzArray.value = [];
checkedry.value = "1";
getUserOrDeptList();
}
}
//获取base64地址
function _getBase64(item) {
getBase64((res) => {
item.baseUrl = res;
}, item.yjTp);
}
// 切换
const switchFlag = ref("01");
function checkedChange(val) {
switchFlag.value = val;
}
// 人员本部门和全部切换
const checkedry = ref("1");
function checkedChangery(val) {
xzArray.value = [];
checkedry.value = val;
getUserOrDeptList();
}
function getPlist() {
pLoading.value = true;
getXfllList({
jllx: "01",
type: checkedry.value,
keyword: form.pname,
pageCurrent: queryPlist.page,
pageSize: queryPlist.size,
}).then((res) => {
pLoading.value = false;
queryPlist.total = res.total;
if (queryPlist.page === 1) {
pList.value = res.records;
} else {
pList.value.push(...res.records);
}
});
}
// 查询用户和部门信息和巡组
const xzList = ref([]);
function getUserOrDeptList() {
getPlist();
selectNextPage({
size: 100,
current: 1,
}).then((res) => {
options.value = [res.records[0]];
});
// 巡组
getJmxz({
bbrq: timeValidate(new Date(), "ymd"),
xfzt: "0,1,2",
bblx: "02",
pageSize: 100,
pageCurrent: 1,
}).then((res) => {
xzList.value = res.records;
});
}
const bmArray = ref([]);
function onChange(value, selectedOptions) {
bmArray.value = [];
form.fielddept = value.value;
bmArray.value.push(value.selectedOptions[value.selectedOptions.length - 1]);
}
// 人员选择
function onChangeName(val) {
form.fieldname = val.userName;
}
// 转指令确认按钮
function onSubmit() {
turnZl.value = false;
let temp = [];
switch (switchFlag.value) {
case "01": // 人员
if (array.value.length > 0) {
array.value.forEach((item) => {
temp.push({
zxrLx: "01",
zxrId: item.id,
zxrJllx: item.fl,
zxrXm: item.xm,
zxrSfz: item.sfzh,
zxrDh: item.lxdh,
bz: "",
});
});
}
break;
case "02": // 部门
if (bmArray.value.length > 0) {
bmArray.value.forEach((item) => {
temp.push({
zxrLx: "02",
ssbmid: item.id,
ssbmmc: item.orgName,
bz: "",
});
});
}
break;
case "03": // 巡组
if (xzArray.value.length > 0) {
xzArray.value.forEach((item) => {
temp.push({
zxrLx: "03",
zxrXzid: item.id,
zxrXzmc: item.jzMc,
});
});
}
break;
}
yjConvertZl({
yjid: route.query.id,
zxrList: temp,
}).then((res) => {
});
}
function onLoad() {
if (current.value >= total.value) {
finished.value = true;
return;
}
current.value += 1;
getListBySfz();
}
// 选中的文件
const array = ref([]);
function onSelectList(val) {
array.value = val.list;
}
// 选中的巡组
const xzArray = ref([]);
function onSelectXzList(val) {
xzArray.value = val.list;
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.ry_info {
margin: 2vw 3vw;
border-radius: 2vw;
@include jrtz_fill_color($jrtz-fill-color-theme);
padding-bottom: 2vw;
}
.but_box {
display: flex;
margin-top: 1vw;
}
.text {
@include font_size($font_medium_s);
@include font_color($font-color-theme);
line-height: 3.5vw;
margin-top: 2vw;
}
.content {
display: flex;
padding-bottom: 20px;
.cont_l {
margin-right: 16px;
.red,
.yellow,
.blue,
.orange {
display: inline-block;
padding: 2px 16px;
border-radius: 10px;
@include font_size($font_medium_s);
color: #fff;
}
}
}
.yp_btn {
margin: 10px 10vw;
display: flex;
justify-content: center;
}
.nr_box {
height: 57vh;
}
.deptBox {
height: 57vh;
// overflow-y: auto;
}
::v-deep .van-tabs__track {
height: 44vh;
overflow-y: auto;
}
::v-deep .ry_cell .van-cell__value {
flex: 3;
max-height: 8vh;
overflow: hidden;
overflow-y: auto;
}
::v-deep .ry_cell .van-cell__title {
flex: 1;
}
::v-deep .ry .van-cell__value {
flex: 8;
}
::v-deep .ry .van-cell__title {
flex: 1;
}
</style>

View File

@ -0,0 +1,190 @@
<template>
<div>
<TopNav navTitle="地图模式" :showRight="false" :showLeft="true" />
<GdMap />
<div class="top_btn">
<span @click="checkActive(!isRlt)">{{
isRlt ? "点位图" : "热力图"
}}</span>
</div>
<div class="map_but_box">
<van-button round block type="primary" :to="`/yyzx/yjxx/yjDetail?id=${useRoute().query.id}`">
列表模式
</van-button>
</div>
</div>
</template>
<script setup>
import { getSyrkYjxx, getInfo } from "../../../api/yjxx.js";
import { ref, onMounted } from "vue";
import { useRoute } from "vue-router";
import TopNav from "../../../components/topNav.vue";
import GdMap from "../../../components/GdMap/index.vue";
import YjItem from "../../../components/yjItem.vue";
import emitter from "../../../utils/eventBus.js";
import { hintToast } from "../../../utils/tools.js";
const item = ref(null); // 警情数据
const isRlt = ref(false);
onMounted(() => {
window.closeMapTitle = closeMapTitle;
getYjDetail();
});
const yjRyDetail = ref({});
const stepsData = ref([]);
// 获取预警信息详情
function getYjDetail() {
getInfo(useRoute().query.id).then((res) => {
yjRyDetail.value = res;
getListBySfz(1);
});
}
//关闭弹窗dom
function closeMapTitle(val) {
let doms = document.getElementById(val);
doms.remove();
}
// 通过身份证查人
function getListBySfz(val) {
getSyrkYjxx({
zjhm: yjRyDetail.value.yjRysfzh,
cph: yjRyDetail.value.yjClcph,
pageCurrent: 1,
pageSize: 100,
}).then((res) => {
stepsData.value = res.records;
let coords = [];
let arr = [];
let array = [];
for (let index = 0; index < stepsData.value.length; index++) {
if (
stepsData.value[index].jd != null &&
stepsData.value[index].wd != null
) {
coords.push({
jd: stepsData.value[index].jd,
wd: stepsData.value[index].wd,
yjDz: stepsData.value[index].yjGzymc,
yjFssj: stepsData.value[index].yjFssj,
});
arr.push(stepsData.value[index].jd);
arr.push(stepsData.value[index].wd);
let obj = {
lng: stepsData.value[index].jd,
lat: stepsData.value[index].wd,
count: 1,
};
array.push(obj);
}
}
let coordsStr = arr.join(",");
// 点位图
if (val == 1) {
if (coords.length > 0) {
emitter.emit("bd_closeOverlay");
emitter.emit("addPointArea", {
coords: coords,
icon: require("../../../assets/pointIcon/icon-gzy.png"),
flag: "yj",
});
} else {
hintToast("点位没有坐标信息!");
}
} else {
if (array.length > 0) {
emitter.emit("bd_closeOverlay");
emitter.emit("thermodynamicChart", {
flag: "rlt",
arr: array,
});
} else {
hintToast("热力图没有坐标信息!");
}
}
});
}
//切看地图查看方式
function checkActive(flag) {
isRlt.value = flag;
if (flag) {
getListBySfz(2);
} else {
getListBySfz(1);
}
}
//设置点位图
// function setPoint() {
// emitter.emit("bd_closeOverlay");
// let coords = [
// { jd: "104.046207", wd: "30.62707" },
// { jd: "104.064353", wd: "30.617933" },
// { jd: "104.063922", wd: "30.641426" },
// ];
// emitter.emit("addPointArea", {
// coords: coords,
// icon: require("../../../assets/pointIcon/icon-gzy.png"),
// flag: "yj",
// });
// emitter.emit(
// "drawLine",
// "104.046207,30.62707,104.064353,30.617933,104.063922,30.641426"
// );
// }
// //随机生成坐标
// function setPint() {
// let array = [];
// for (let i = 0; i < 2000; i++) {
// let obj = {
// lng: 104.019822 + Math.random() / 5,
// lat: 30.450369 + Math.random() / 5,
// count: 1,
// };
// array.push(obj);
// }
// return array;
// }
// //设置热力图
// function setRlt() {
// emitter.emit("bd_closeOverlay");
// emitter.emit("deletePointArea", "drawLine");
// emitter.emit("thermodynamicChart", {
// flag: "rlt",
// arr: setPint(),
// });
// }
</script>
<style lang="scss" scoped>
.map_but_box {
position: absolute;
bottom: 10vw;
width: 50%;
left: 50%;
z-index: 99;
margin-left: -25%;
}
.top_btn {
position: fixed;
top: 16vw;
left: 0;
right: 12px;
height: 24px;
color: #fff;
z-index: 9;
text-align: right;
span {
display: inline-block;
border: 1px solid #fff;
line-height: 22px;
padding: 0 12px;
border-radius: 12px;
font-size: 14px;
}
span.active {
background: #517cea;
border-color: #517cea;
}
}
</style>

View File

@ -0,0 +1,119 @@
<template>
<div style="padding-top: 15vw">
<TopNav navTitle="预警统计" :showRight="false" :showLeft="true" />
<TopSelectTime @chenge:time="onSelectTime" />
<TopTotal :list="yjTotal.list" />
<!-- 任务完成情况 -->
<div class="item_box gsdyj_box">
<div class="other_type_title">各时段预警</div>
<LineChart :type="timeType" />
</div>
<div class="item_box gsdyj_box">
<div class="other_type_title">感知源预警排名</div>
<Ranking :type="timeNum" />
</div>
<div class="item_box gsdyj_box">
<div class="other_type_title">人员预警排名</div>
<PeopleRanking :type="timeNum" />
</div>
<div class="item_box gsdyj_box">
<div class="other_type_title">派出所预警分析</div>
<LineChartPcs :type="timeNum"/>
</div>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from "vue";
import TopNav from "../../../components/topNav.vue";
import TopSelectTime from "../../../components/topSelectTime.vue";
import TopTotal from "../../../components/topTotal";
import LineChart from "./components/lineChart.vue";
import LineChartPcs from "./components/lineChartPcs.vue";
import PeopleRanking from "./components/peopleRanking.vue";
import Ranking from "./components/ranking.vue";
import { getYjxxTjYjlx } from "../../../api/yjxx.js";
import { getRecentDay } from "../../../utils/tools";
const timeActive = ref(0);
const yjTotal = reactive({
list: [
{
title: "预警总数",
count: 0,
},
{
title: "人员预警",
count: 0,
},
{
title: "车辆预警",
count: 0,
},
{
title: "事件预警",
count: 0,
},
{
title: "重点人员管控预警",
count: 0,
},
],
});
onMounted(() => {
_getYjxxTjYjlx(0);
});
//时间查询
const timeType = ref(0);
const timeNum = ref(0);
function onSelectTime(val) {
timeType.value = val;
timeNum.value = val == 3 ? -90 : val == 1 ? -7 : val == 2 ? -30 : 0;
_getYjxxTjYjlx(timeNum.value);
}
//获取预警类型统计
function _getYjxxTjYjlx(val) {
yjTotal.list.forEach((el) => {
el.count = 0;
});
getYjxxTjYjlx({
kssj: getRecentDay(val, "ymd"),
jssj: getRecentDay(0, "ymd"),
}).then((res) => {
res.forEach((item) => {
yjTotal.list[0].count += item.count;
switch (item.yj_lx) {
case "1":
yjTotal.list[1].count = item.count;
break;
case "2":
yjTotal.list[2].count += item.count;
break;
case "3":
yjTotal.list[2].count += item.count;
break;
case "4":
yjTotal.list[2].count += item.count;
break;
case "5":
yjTotal.list[3].count = item.count;
break;
case "6":
yjTotal.list[4].count = item.count;
break;
}
});
});
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.gsdyj_box {
margin: 2vw 3vw 5vw 3vw;
padding: 2vw;
}
.other_type_title {
margin-left: 2vw;
}
::v-deep .van-tabs__nav--card {
margin: 0 3vw;
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<div class="container" style="padding-top: 13vw">
<TopNav :navTitle="title" />
<normalReport @setTitle="onSetTitle" />
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import normalReport from "../components/normalReport.vue";
import { computed, ref, reactive, watch, onMounted } from "vue";
import { useRouter, useRoute } from "vue-router";
import { Toast } from "vant";
const router = useRouter();
const route = useRoute();
const title = ref("值班排班信息");
const active = ref("a");
//设置标题信息
function onSetTitle(e) {
title.value = e;
}
</script>
<style lang="scss" scoped>
.container {
margin-top: 2vw;
}
.nav_tab {
padding: 2vw;
display: flex;
justify-content: space-around;
.tab {
background: #a4aec8;
color: #fff;
height: 32px;
line-height: 32px;
width: 40vw;
text-align: center;
border-radius: 16px 16px 16px 0;
}
.tab.active {
background: #517cea;
}
}
</style>

View File

@ -0,0 +1,455 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="我的值班清单" :showLeft="true" />
<div class="calenderBox">
<div class="calender-head">
<div class="btn" @click="last">
<van-icon name="arrow-left" color="#fff" />
</div>
<div class="text">{{ Year }}{{ month }}</div>
<div class="btn" @click="next">
<van-icon name="arrow" color="#fff" />
</div>
<div class="change" @click="isChange = !isChange">
<van-icon name="exchange" size="16" color="#3e6ee8" />
{{ isChange ? "切换表格" : "切换列表" }}
</div>
</div>
<!-- 日历列表 -->
<div v-if="!isChange" class="list">
<ul class="week">
<li class="days" v-for="(item, index) in week" :key="index">
{{ item }}
</li>
</ul>
<div class="wrap">
<div class="item" v-for="(item, index) in calendarList" :key="index">
<div class="num">
{{ item.day }}<span v-show="item.list"></span>
</div>
<div class="status" v-show="item.status">
<span
@click="routePush(evn, item)"
v-for="(evn, index) in item.status"
:key="index + 'evn'"
v-show="evn.text"
:style="{ background: evn.color }"
>{{ evn.text }}</span
>
</div>
</div>
</div>
</div>
<!-- 日历列表 -->
<div v-else class="list">
<CalendarList :listData="listData"></CalendarList>
</div>
</div>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import CalendarList from "../components/calendarListZb.vue";
import router from "../../../router/index.js";
import { getZbbbByMonth } from "@/api/calender";
import { onMounted, reactive, ref } from "vue";
import { Toast } from "vant";
const isChange = ref(false);
const week = ref(["周日", "周一", "周二", "周三", "周四", "周五", "周六"]);
const Year = ref(new Date().getFullYear()); //日历上的年份
const month = ref(new Date().getMonth() + 1); //日历上的月份
const Day = ref(new Date().getDate()); //日历上的天份
const nowYear = ref(new Date().getFullYear());
const nowmonth = ref(new Date().getMonth() + 1);
const nowDay = ref(new Date().getDate());
const starttime = ref("");
const endtime = ref("");
const nowtime = ref("");
const loading = ref(false);
const listData = ref([]);
//状态字典
const ztDict = [
{
label: "待值班",
value: "01",
color: "#7b7b7b",
},
{
label: "值班中",
value: "02",
color: "",
},
{
label: "已值班",
value: "03",
color: "#0084ff",
},
{
label: "",
value: "04",
color: "",
},
];
const calendarList = ref([]);
//状态数据处理
function checkZt(list = []) {
var zt = [];
if (list.length > 0) {
zt = list.map((item) => {
return {
text: ztDict.filter((item2) => item2.value === item.zt)[0].label,
color: ztDict.filter((item2) => item2.value === item.zt)[0].color,
id: item.id,
zt: item.zt,
time: item.time,
};
});
}
return zt;
}
onMounted(() => {
Toast.loading({
message: "加载...",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
Promise.all([
getzbCalendar(Year.value, month.value),
Draw(nowYear.value, nowmonth.value),
])
.then((res) => {
Toast.clear();
})
.catch((err) => {
Toast.clear();
});
let time_month = nowmonth.value; //现在的月份
let time_day = nowDay.value; //现在的天数
if (nowmonth.value < 10) {
time_month = 0 + "" + nowmonth.value;
}
if (nowDay.value < 10) {
time_day = 0 + "" + nowDay.value;
}
nowtime.value = nowYear.value + "" + time_month + "" + time_day;
starttime.value = nowtime.value;
endtime.value = nowtime.value;
});
//跳转报备
function routePush(evn, item) {
// router.push("/yyzx/views/addZbbb");
let flag = 0;
let currentTi = "";
let y = Year.value; //现在的月份
let m = month.value; //现在的天数
if (y < 10) {
y = 0 + "" + y;
}
if (m < 10) {
m = 0 + "" + m;
}
currentTi = y + "" + m + "" + item.day;
if (nowtime.value === currentTi) {
flag = 1;
}
if (evn.zt !== "04") {
router.push({
path: "/yyzx/views/addZbbbInfo",
query: {
zt: evn.zt,
id: evn.id,
text: evn.text,
color: evn.color,
flag: flag,
},
});
}
}
//初始化日历数据
function Draw(Year, Month) {
var calendar = [];
//用当月第一天在一周中的日期值作为当月离第一天的天数(获取当月第一天是周几)
for (
var i = 1, firstDay = new Date(Year, Month - 1, 1).getDay();
i <= firstDay;
i++
) {
calendar.push("");
}
//用当月最后一天在一个月中的日期值作为当月的天数
for (
var i = 1, monthDay = new Date(Year, Month, 0).getDate();
i <= monthDay;
i++
) {
let time_month = Month;
let time_day = i;
if (Month < 10) {
time_month = 0 + "" + Month;
}
if (i < 10) {
time_day = 0 + "" + i;
}
calendar.push({
value: i,
kssj: "20:00", //假数据
jssj: "23:59",
status: "值班", //假的状态
count: Year + "" + time_month + "" + time_day,
});
}
calendar[10].status = "未报备";
calendar[15].status = "未报备";
calendar[20].status = "请假";
calendar[21].status = "请假";
calendar[20].time = "";
calendar[21].time = "";
calendarList.value = calendar;
}
// 上个月
function last() {
month.value--;
if (month.value == 0) {
month.value = 12;
Year.value--;
}
Draw(Year.value, month.value);
getzbCalendar(Year.value, month.value);
}
// 下个月
function next() {
month.value++;
if (month.value == 13) {
month.value = 1;
Year.value++;
}
Draw(Year.value, month.value);
getzbCalendar(Year.value, month.value);
}
// 获取日历数据
const getzbCalendar = (Year, Month) => {
getZbbbByMonth({
time: Year + "-" + Month,
}).then((res) => {
if (res && res.length > 0) {
listData.value = [];
res.map((item) => {
if (item.list.length === 0) {
listData.value.push({
time: Year + "-" + Month + "-" + item.day,
zqsj: "--",
zqzt: "--",
zt: "04",
});
} else {
item.list.map((env) => {
listData.value.push({
time: Year + "-" + Month + "-" + item.day,
zqsj: env.time,
zqzt: ztDict.filter((item2) => item2.value === env.zt)[0].label,
zt: env.zt,
id: env.id,
});
});
}
});
res.forEach((element) => {
if (element.list.length > 0) {
element.status = checkZt(element.list);
}
});
}
calendarList.value = res;
for (
var i = 1, firstDay = new Date(Year, Month - 1, 1).getDay();
i <= firstDay;
i++
) {
calendarList.value.unshift("");
}
});
};
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.calenderBox {
width: 100%;
padding: 1vw;
box-sizing: border-box;
.calender-head {
width: 100%;
height: 15vw;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
font-weight: bold;
line-height: 40px;
position: relative;
.change {
position: absolute;
right: 1vw;
bottom: 2vw;
cursor: pointer;
color: #3e6ee8;
@include font_size($font_medium_s);
}
.btn {
width: 7vw;
height: 7vw;
line-height: 7vw;
text-align: center;
border-radius: 1vw;
background: #3e6ee8;
color: #fff;
}
.text {
margin: 0 4vw;
@include font_color($font-color-theme);
}
}
.week {
width: 100%;
display: flex;
flex-wrap: nowrap;
text-align: center;
height: 10vw;
line-height: 10vw;
@include font_size($font_medium_s);
background: #164acc;
color: #fff;
.days {
flex: 1;
}
}
.wrap {
width: 100%;
// height: auto;
// overflow: hidden;
display: flex;
flex-wrap: wrap;
.item {
width: calc((100% / 7) - 1.3px);
border: 1px solid #3e6ee8;
border-top: none;
font-size: 10px;
min-height: 17vw;
.num {
@include font_color($font-color-theme);
text-align: right;
height: 5vw;
line-height: 5vw;
padding-right: 1vw;
box-sizing: border-box;
}
.status {
text-align: center;
// height: 5vw;
line-height: 5vw;
margin: 1vw 0;
span {
background: #3e6ee8;
display: inline-block;
padding: 1px 1vw;
margin: 4px 0;
color: #fff;
border-radius: 1vw;
}
.green {
background: #1adb10;
}
.gray {
background: #83868f;
}
}
.time {
font-size: 10px;
height: 5vw;
// line-height: 7vw;
color: #3e6ee8;
text-align: center;
}
.greenColor {
color: #1adb10;
}
.grayColr {
color: #83868f;
}
.BlueColor {
color: #3e6ee8;
}
}
.item:nth-child(7n + 2) {
border-left: none;
}
.item:nth-child(7n + 3) {
border-left: none;
}
.item:nth-child(7n + 4) {
border-left: none;
}
.item:nth-child(7n + 5) {
border-left: none;
}
.item:nth-child(7n + 6) {
border-left: none;
}
.item:nth-child(7n + 7) {
border-left: none;
}
}
}
.list {
max-height: calc(100vh - 35vw);
// overflow: hidden;
// overflow-y: auto;
}
@import "../../../assets/styles/mixin.scss";
.box-rank {
width: 100%;
height: 100%;
.item {
display: flex;
align-items: center;
justify-content: center;
height: 8vw;
@include font_size($font_medium_s);
@include font_color($font-color-theme);
.text {
flex: 1;
text-align: center;
}
.mc {
color: #3e6ee8;
}
}
.item:nth-child(2n + 1) {
@include table_item_color($table-item-theme);
}
.item:nth-child(1) {
background: #3e6ee8 !important;
color: #fff;
}
.red {
color: red !important;
}
.green {
color: #88e9af;
}
.blue {
color: #3e6ee8;
}
}
</style>

View File

@ -0,0 +1,129 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="指令" :showRight="false" :showLeft="true" />
<div class="main_box">
<van-form @submit="onSubmit" class="form" :disabled="isSeeInfo ? false : true">
<van-field v-model="params.zlbt" name="zlbt" label="指令标题" placeholder="请输入指令标题"
:rules="[{ required: true, message: '请输入指令标题' }]" />
<van-field v-model="params.zlnr" name="zlnr" type="textarea" label="指令内容" placeholder="请输入指令内容"
:rules="[{ required: true, message: '请输入指令内容' }]" />
<van-field name="uploader" label="图片">
<template #input>
<van-uploader :max-count="1" :disabled="isSeeInfo ? false : true" v-model="wpTpIdList" multiple
:after-read="upLoadImg" />
</template>
</van-field>
<div style="margin: 16px" v-show="isSeeInfo">
<van-button round block type="primary" native-type="submit" :loading="isLoading" loading-type="spinner"
loading-text="提交中...">提交</van-button>
</div>
</van-form>
</div>
</div>
</template>
<script setup>
import TopNav from "../../../components/topNav.vue";
import { qcckGet, qcckPost } from "../../../api/qcckApi.js";
import ImageCompressor from "image-compressor.js";
import {
timeValidate
} from "../../../utils/tools.js";
import { ImagePreview } from "vant";
import { getMybbTodayNew } from "../../../api/common";
import { useRoute } from "vue-router";
import { onMounted, ref } from 'vue';
import { upImage } from "@/api/common";
import { hintToast } from "@/utils/tools";
import router from "@/router";
import { getDictList, setDict } from "../../../utils/dict";
const { D_QW_CJSBLX } = getDictList(
"D_QW_CJSBLX"
);
const route = useRoute();
const wpTpIdList = ref([]);
const isSeeInfo = ref(true);
const fileList = ref([])
const params = ref({
cjsbTpid: '',//图片
zllx: '10',
zlbt:'请求协助'
})
const baseUrl = ref("");
const workTips = ref();
// 上传图片
async function upLoadImg(file) {
file.message = "上传中...";
let fileBlob = await _compressImage(file.file);
let fileData = new File([fileBlob], fileBlob.name, { type: fileBlob.type });
const data = new FormData();
data.append("file", fileData);
upImage(data).then((res) => {
console.log(res, 'res');
file.status = "done";
file.message = "上传成功";
if (!fileList.value.includes(res)) fileList.value.push(res);
});
}
//压缩图片
const _compressImage = (file) => {
return new Promise((resolve, reject) => {
new ImageCompressor(file, {
quality: 0.6, //压缩质量
success(res) {
resolve(res);
},
error(e) {
reject(e);
},
});
});
};
const onSubmit = () => {
let { lng, lat, zbly } = getLocation();
params.value.jd = lng;
params.value.wd = lat;
if (fileList.value.length > 0) params.value.fjId = fileList.value.join(',');
qcckPost(params.value, "/mosty-yjzl/tbZl/addZl").then(res => {
hintToast('添加成功')
router.back()
})
}
const getImageUrl = (item) => {
return new Promise((ok) => {
qcckGet({}, `/mosty-base/minio/file/download/${item}`).then(res => {
ok(res.url);
})
});
}
onMounted(async () => {
if (route.query.item) {
isSeeInfo.value = false;
params.value = JSON.parse(route.query.item);
let imgId = params.value.cjsbTpid.split(',');
for (let i = 0; i < imgId.length; i++) {
const el = imgId[i];
fileList.value.push({ url: await getImageUrl(el) });
}
}
})
</script>
<style lang="scss" scoped>
.main_box {
padding: 10px;
box-sizing: border-box;
}
::v-deep .van-radio {
margin-bottom: 4px;
}
::v-deep .van-radio__label--disabled {
color: #000 !important;
}
::v-deep .van-field__label {
color: #000 !important;
}
</style>

View File

@ -0,0 +1,560 @@
<template>
<div id="scrollDIV" class="message_list_box" style="height: 100%">
<div v-for="(item, index) in list" :key="index" id="message_item_box" class="message_item">
<!-- 对方的消息 -->
<div class="item_left" v-if="item.type == 1">
<div class="df_avator">{{ item.name.substring(0, 1) }}</div>
&nbsp;
<div>
<div style="margin-bottom: 2vw">
<span>{{ item.time }}</span>&emsp;<span>{{ item.name }}</span>
</div>
<!-- 图片文件 -->
<van-image width="100px" height="100px" fit="cover" :src="baseUrl + item.fjid"
v-if="item.fjid && item.fileFormat == 'png'" @click="onClickImg(item.fjid)">
<template v-slot:loading>
<van-loading type="spinner" size="20" />
</template>
</van-image>
<!-- 文档文件 -->
<div class="left_message" v-if="item.fileFormat == 'file'">
<a style="text-decoration: underline" :href="baseUrl + item.fjid">{{
item.text
}}</a>
</div>
<!-- 消息 -->
<div class="left_message" v-if="item.text && !item.fjid">
{{ item.text }}
</div>
<!-- 语音消息 -->
<div class="audio-detail-msg" v-if="item.fileFormat == 'mp3'">
<div class="audio-style" style="margin-right: 8px"
:class="{ 'add-animation': isPlay && audioId == item.fjid }" :style="{
width: handleAudioStyleWidth(item.yysc ? item.yysc : 1),
}" @click="playAudio(item.fjid, item.yysc ? item.yysc : 1)">
<div class="small"></div>
<div class="middle"></div>
<div class="large"></div>
</div>
<div class="duration-seconds">{{ item.yysc ? item.yysc : 1 }}s</div>
<audio :id="item.fjid" style="display: none"></audio>
</div>
<!-- 视频 -->
<div class="videos_box" v-if="item.fileFormat == 'mp4'">
<video :src="item.videoUrl" class="video_image"></video>
<!-- <img :src="`${baseUrl}${item.sptpid}`" alt="" class="video_image" /> -->
<!-- <div class="yysc left_video_time">{{ item.yysc }}s</div> -->
<img class="play_box left_video_play" src="../../../../assets/images/play.png" alt=""
@click="onClickVideo(item.videoUrl)" />
</div>
</div>
</div>
<!-- 自己的消息 -->
<div class="item_right" v-if="item.type == 2">
<!-- 图片文件 -->
<div>
<div style="margin-bottom: 2vw">{{ item.time }}</div>
<van-image width="100px" height="100px" fit="cover" :src="baseUrl + item.fjid"
v-if="item.fjid && item.fileFormat == 'png'" @click="onClickImg(item.fjid)">
<template v-slot:loading>
<van-loading type="spinner" size="20" />
</template>
</van-image>
<!-- 文档文件 -->
<div class="right_message" v-if="item.fileFormat == 'file'">
<a style="text-decoration: underline" @click="getPreviewText(item)">{{ item.text }}</a>
</div>
<!-- 消息 -->
<div class="right_message" v-if="item.text && !item.fjid">
{{ item.text }}
</div>
<!-- 语音消息 -->
<div class="audio-detail-msg msgRight_box" v-if="item.fileFormat == 'mp3'">
<div class="duration-seconds">{{ item.yysc ? item.yysc : 1 }}s</div>
<div style="margin-left: 8px" class="audio-style msgRight"
:class="{ 'add-animation': isPlay && audioId == item.fjid }" :style="{
width: handleAudioStyleWidth(item.yysc ? item.yysc : 1),
}" @click="playAudio(item.fjid, item.yysc ? item.yysc : 1)">
<div class="small"></div>
<div class="middle"></div>
<div class="large"></div>
</div>
<audio :id="item.fjid" style="display: none"></audio>
</div>
<!-- 视频 -->
<div class="videos_box" v-if="item.fileFormat == 'mp4'">
<video :src="item.videoUrl" class="video_image"></video>
<!-- <img :src="`${baseUrl}${item.sptpid}`" alt="" class="video_image" /> -->
<!-- <div class="yysc right_video_time">{{ item.yysc }}s</div> -->
<img class="play_box right_video_play" src="../../../../assets/images/play.png" alt=""
@click="onClickVideo(item.videoUrl)" />
</div>
</div>
&nbsp;
<div class="df_avator">{{ item.name.substring(0, 1) }}</div>
</div>
</div>
<Iframe :url="fillFrams" :isPreviw="isPreviw" @closePre="isPreviw = false"></Iframe>
</div>
</template>
<script setup>
import emitter from "@/utils/eventBus";
import {
ref,
onMounted,
defineProps,
defineEmits,
watch,
onBeforeUnmount,
} from "vue";
import { baseUrl2 } from "../../../../utils/request.js";
import { ImagePreview } from "vant";
import { dataQc } from "../../../../utils/tools.js";
import { getFjInfo } from "../../../../api/rwzx.js";
import Iframe from "../../../../assets/html/filePreview.vue";
import axios from "axios";
const props = defineProps({
list: {
type: Boolean,
default: [],
}, //消息数据
mesHeight: Number, //盒子高度
});
const baseUrl = `${baseUrl2}/mosty-api/mosty-base/minio/image/download/`;
const emits = defineEmits(["update:scroll", "click:video"]);
const isPlay = ref(false); //开始语音播放动画
const playAudioTimer = ref(null); //语音播放定时器
const audioId = ref(""); //被选中播放的音频ID
const divHeight = ref(0);
const timeValue = ref(null);
const fillFrams = ref(null);
const isPreviw = ref(false);
watch(
() => props.list,
(newVal) => {
newVal.forEach((item) => {
if (item.fileFormat == "mp3" || item.fileFormat == "mp4") {
axios
.get(
`${baseUrl2}/mosty-api/mosty-base/minio/file/download/${item.fjid}`,
{
params: {},
}
)
.then((res) => {
if (res) {
let url = res.data.data.url.replace(
"http://80.93.7.13:9009",
"/zyminio"
);
// let url = res.data.data.url;
if (item.fileFormat == "mp3") {
let au = document.getElementById(item.fjid);
au.src = `${baseUrl2 + url}`;
} else {
item.videoUrl = `${baseUrl2 + url}`;
}
}
});
}
});
},
{ immediate: true, deep: true }
);
onMounted(() => {
dataQc(props.list, "id");
scrollDIV();
timeValue.value = setInterval(() => {
if (divHeight.value <= 50) scrollDIV();
}, 1.5e3);
scrollBotton();
});
onBeforeUnmount(() => {
clearTimeout(playAudioTimer.value);
playAudioTimer.value = null;
clearTimeout(timeValue.value);
timeValue.value = null;
});
// 获取预览文件
function getPreviewText(item) {
getFjInfo(item.fjid).then((res) => {
let url = res.url; //要预览文件的访问地址
let Base64Url = Base64.encode(url);
fillFrams.value =
"http://10.64.201.126:8012/onlinePreview?url=" +
encodeURIComponent(Base64Url);
isPreviw.value = true;
});
}
//点击视频
function onClickVideo(url) {
emits("click:video", url);
}
//播放语音
function playAudio(id, yysc) {
let au = document.getElementById(id);
audioId.value = id;
if (isPlay.value) {
isPlay.value = false;
au.pause();
return;
}
isPlay.value = true;
playAudioTimer.value = setTimeout(() => {
isPlay.value = false;
}, parseInt(yysc * 1000));
au.play();
}
// 设置语音条宽度样式
function handleAudioStyleWidth(yycs) {
if (yycs === 1) {
return "38px";
} else if (yycs > 1 && yycs < 20) {
return `${38 + (yycs / 10) * 36}px`;
} else if (yycs >= 20) {
return `${106.39 + (yycs / 10) * 18.935}px`;
}
}
//预览图片
function onClickImg(fjid) {
let url = baseUrl + fjid;
ImagePreview([url]);
}
//滚动到元素底部
function scrollDIV() {
try {
const div = document.getElementById("scrollDIV");
div.scrollTop = div.scrollHeight;
} catch (error) {}
}
//监听是否到达底部
function scrollBotton() {
const div = document.getElementById("scrollDIV");
div.addEventListener("scroll", () => {
const clientHeight = div.clientHeight;
const scrollTop = div.scrollTop;
const scrollHeight = div.scrollHeight;
const dist = scrollHeight - scrollTop - clientHeight;
divHeight.value = dist;
// emits("update:scroll", dist);
});
}
</script>
<style lang="scss" scoped>
@import "../../../../assets/styles/mixin.scss";
.message_list_box {
// padding: 2.5vw;
@include font_color($font-color-theme);
@include font_size($font_medium_s);
overflow: auto;
.message_item {
.item_left,
.item_right {
display: flex;
margin-bottom: 4vw;
.left_message {
background: #fff;
box-shadow: -1px 1px 1px 1px rgba(0, 0, 0, 0.1);
}
}
.item_left {
justify-content: flex-start;
text-align: left;
}
.item_right {
text-align: right;
justify-content: flex-end;
.right_message {
background: rgba(149, 236, 105, 0.5);
box-shadow: 1px 1px 1px 1px rgba(0, 0, 0, 0.1);
text-align: left;
}
}
}
}
.left_message,
.right_message {
padding: 1.5vw;
display: inline-block;
border-radius: 3px;
color: #333;
word-break: break-all;
}
img {
width: 25vw;
height: 25vw;
}
.df_avator {
@include font_size($font_medium_s);
display: inline-block;
height: 35px;
min-width: 35px;
border-radius: 50%;
background-color: #0078e0;
text-align: center;
line-height: 35px;
color: #fff;
overflow: hidden;
overflow-x: auto;
}
// 语音条
.audio-detail-msg {
display: flex;
align-items: center;
.msgRight {
transform: rotate(180deg);
}
.audio-style {
display: flex;
align-items: center;
height: 32px;
padding: 0 10px;
border-radius: 4px;
background: rgba(149, 236, 105, 0.5);
.small {
border: 4px solid #4c4c4c;
border-top-color: transparent;
border-left-color: transparent;
border-bottom-color: transparent;
}
.middle {
width: 16px;
height: 16px;
margin-left: -11px;
opacity: 1;
}
.large {
width: 24px;
height: 24px;
margin-left: -19px;
opacity: 1;
}
&>div {
border: 2px solid #4c4c4c;
border-top-color: transparent;
border-left-color: transparent;
border-bottom-color: transparent;
border-radius: 50%;
box-sizing: border-box;
}
&.add-animation {
.middle {
animation: show2 1.2s ease-in-out infinite;
}
.large {
animation: show3 1.2s ease-in-out infinite;
}
}
}
// 语音播放动画
@keyframes show2 {
0% {
opacity: 0;
}
10% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes show3 {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
60% {
opacity: 0;
}
100% {
opacity: 0;
}
}
// 语音录制动画
@keyframes backgroundInfinite2 {
0% {
background: #666;
}
20% {
background: #f5f5f5;
}
95% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite3 {
0% {
background: #666;
}
30% {
background: #f5f5f5;
}
85% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite4 {
0% {
background: #666;
}
55% {
background: #f5f5f5;
}
75% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite5 {
0% {
background: #666;
}
45% {
background: #666;
}
60% {
background: #f5f5f5;
}
75% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite6 {
0% {
background: #666;
}
65% {
background: #666;
}
85% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite7 {
0% {
background: #666;
}
75% {
background: #666;
}
95% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
}
.msgRight_box {
justify-content: flex-end;
}
.videos_box {
position: relative;
.yysc {
position: absolute;
bottom: 1.5vw;
color: #fff;
}
.play_box {
position: absolute;
width: 10vw;
height: 10vw;
top: 50%;
margin-top: -5vw;
}
.right_video_time {
right: 1vw;
}
.left_video_time {
left: 1vw;
}
.right_video_play {
right: 11vw;
margin-right: -5vw;
}
.left_video_play {
left: 11vw;
margin-left: -5vw;
}
}
.video_image {
height: 40vw;
}
</style>

View File

@ -0,0 +1,123 @@
<template>
<div class="zl">
<div class="zl_title">
<span v-for="(item, index) in list" :key="index">{{ item.label }}</span>
</div>
<div class="zl_table">
<div
class="zl_table_item"
v-for="(item, index) in tableList"
:key="index"
>
<div class="tab_item">
<img
v-if="index === 0"
:src="require('../../../../assets/gxapp/j.png')"
alt=""
width="18"
height="22"
/>
<img
v-else-if="index === 1"
:src="require('../../../../assets/gxapp/y.png')"
alt=""
width="18"
height="22"
/>
<img
v-else-if="index === 2"
:src="require('../../../../assets/gxapp/t.png')"
alt=""
width="18"
height="22"
/>
<span v-else>{{ index + 1 }}</span>
</div>
<div class="tab_item">{{ item.name }}</div>
<div class="tab_item">
{{ Number(item.ytotal) + Number(item.ntotal) }}
</div>
<div class="tab_item">{{ item.ytotal }}</div>
<div class="tab_item">{{ item.ntotal }}</div>
<div class="tab_item">
{{ item.wcl ? (item.wcl * 100).toFixed(2) + "%" : "--" }}
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, defineProps, watch } from "vue";
import { zlPhTjxx } from "../../../..//api/zlzx.js";
const props = defineProps({
timeType: {
type: String,
default: "1",
},
});
watch(
() => props.timeType,
() => {
getList();
},{deep:true}
);
const list = ref([
{ label: "排名" },
{ label: "部门名称" },
{ label: "总数" },
{ label: "已完成" },
{ label: "未完成" },
{ label: "完成率" },
]);
const tableList = ref([]);
function getList() {
tableList.value = []
zlPhTjxx({ type: props.timeType }).then((res) => {
for (let i = 0; i < res.length; i++) {
if (res[i].name == "高新区分局") {
res[i].name = "高新分局";
} else {
res[i].name = res[i].name
.replace(/高新区分局/g, "")
.replace(/派出所/g, "");
}
}
tableList.value = res;
const total = res.length;
});
}
onMounted(() => {
getList();
});
</script>
<style lang="scss" scoped>
@import "../../../../assets/styles/mixin.scss";
.zl {
margin: 5px 0;
@include font_color($font-color-theme);
@include font_size($font_medium_s);
.zl_title {
margin: 0 5px;
padding: 0 7px;
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
}
.zl_table {
margin-top: 5px;
.zl_table_item {
min-height: 26px;
display: flex;
justify-content: space-between;
align-items: center;
.tab_item {
flex: 1;
text-align: center;
}
}
}
}
</style>

View File

@ -0,0 +1,558 @@
<template>
<div>
<!-- 音频录制 -->
<div class="audio-record">
<p class="duration-seconds-style">
<span v-show="countDownRecord"
>{{ countDownSecond }}&nbsp;后停止录制</span
>
</p>
<div class="icon">
<img src="../../../../assets/images/audio.png" width="45" />
<div class="voice-animation" ref="voiceAnimation">
<p v-for="item in 7" :key="item"></p>
</div>
</div>
</div>
<div class="btn_crossAndbtn_succes">
<div class="cross_box" :class="{ voiceCanael: isCancel }">
<van-icon name="cross" />
</div>
<!-- <div><van-icon name="success" /></div> -->
</div>
</div>
</template>
<script setup>
// import TitleTab from "../components/TitleTab.vue";
import {
reactive,
onMounted,
ref,
watch,
defineExpose,
defineProps,
} from "vue";
import { uploadImg } from "../../../../api/yyzxApi.js";
import emitter from "../../../../utils/eventBus.js";
import { Toast } from "vant";
const recordStatus = ref(false); //是否显示录音
const showDurationSeconds = ref(0); // 语音时长
const durationSeconds = ref(0); // 语音时长
const isDurationSeconds = ref(false); // 开始录制时间状态
const playAudioTimer = ref(null); // 语音播放定时器
const confTime = ref(null); //录音动画 定时函数
const startRecord = ref(false); // 开始录制按钮状态
const isShowAudio = ref(true); //是否显示语音条
const countDownRecord = ref(false); // 倒计时录制状态
const countDownSecond = ref(60); // 倒计时录制时间
const isPlay = ref(false); //是否可以播放
const voiceAnimation = ref(); //录音动画demo
//webkitURL is deprecated but nevertheless
const URL = window.URL || window.webkitURL;
const fileName = ref(""); //文件名
var gumStream; //语音
var rec; //Recorder.js 对象
var input; //MediaStreamAudioSourceNode we'll be recording //文件
// shim for AudioContext when it's not avb.
var AudioContext = window.AudioContext || window.webkitAudioContext;
var audioContext; //audio context to help us record
const props = defineProps({
isCancel: Boolean, //是否取消
});
onMounted(() => {});
// 完成录制并发送
function sendRecord() {
stopRecording();
// isShowAudio.value = true;
}
// 取消语音录制
function cancelRecord() {
showDurationSeconds.value = durationSeconds.value;
recordStatus.value = false;
startRecord.value = false;
isDurationSeconds.value = false;
countDownRecord.value = false;
voiceAnimation.value.classList.add("start");
clearInterval(confTime.value);
confTime.value = null;
durationSeconds.value = 0;
rec.stop();
countDownSecond.value = 60;
}
// 开始录制语音消息开始动画效果
function startAudioRecord() {
startRecord.value = true;
isDurationSeconds.value = true;
voiceAnimation.value.classList.add("start");
confTime.value = setInterval(() => {
durationSeconds.value++;
countDownSecond.value--;
//开启录音倒计时
if (durationSeconds.value === 10) {
countDownRecord.value = true;
}
//自动结束录音并发送
if (countDownSecond.value === 0) {
clearInterval(confTime.value);
confTime.value = null;
stopRecording();
emitter.emit("hideAudio", {});
}
}, 1000);
startRecording();
}
//开始录音
function startRecording() {
var constraints = {
audio: true,
video: false,
};
//调用录音
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
audioContext = new AudioContext();
gumStream = stream;
/* use the stream */
input = audioContext.createMediaStreamSource(stream);
rec = new Recorder(input, {
numChannels: 1,
});
rec.record();
});
}
//点击暂停 | 恢复录音
function pauseRecording() {
if (rec.recording) {
//pause
rec.stop();
} else {
//resume
rec.record();
}
}
//停止录音
function stopRecording() {
//停止录音
rec.stop();
gumStream.getAudioTracks()[0].stop();
rec.exportWAV(createDownloadLink);
clearInterval(confTime.value);
confTime.value = null;
}
//添加语音内容
function createDownloadLink(blob) {
uploadMav(blob);
// var url = URL.createObjectURL(blob);
// var au = document.getElementById("audio");
// //添加语音标签
// au.controls = true;
// au.src = url;
// //文件名称
// var filename = new Date().toISOString();
// fileName.value = filename + ".wav"
}
//上传语音文件
function uploadMav(blob) {
Toast({
message: "图片发送中。。。",
forbidClick: true,
duration: 0,
});
const data = new FormData();
const filename = new Date().toISOString();
const files = new File([blob], filename + ".wav");
data.append("file", files);
uploadImg(data)
.then((res) => {
if (res) {
emitter.emit("getAudio", {
durationSeconds: durationSeconds.value,
fjid: res,
});
Toast.clear();
}
})
.catch((err) => {
Toast.clear();
});
}
defineExpose({
cancelRecord,
stopRecording,
startAudioRecord,
});
</script>
<style lang="scss" scoped>
p {
margin: 0;
}
// 音频录制
.audio-record {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 150px;
// height: 160px;
background: rgba(0, 0, 0, 0.8);
padding: 15px;
border-radius: 15px;
color: #ccc;
font-size: 15px;
text-align: center;
.cancel-img {
position: absolute;
top: 10px;
right: 10px;
cursor: pointer;
}
.duration-seconds-style {
height: 20px;
}
.icon {
display: flex;
justify-content: center;
align-items: flex-end;
margin: 18px 0 30px;
}
.voice-animation {
margin-left: 15px;
p {
height: 3px;
margin-top: 4px;
background: #666;
}
p:nth-of-type(1) {
width: 28px;
}
p:nth-of-type(2) {
width: 24px;
}
p:nth-of-type(3) {
width: 20px;
}
p:nth-of-type(4) {
width: 16px;
}
p:nth-of-type(5) {
width: 12px;
}
p:nth-of-type(6) {
width: 8px;
}
p:nth-of-type(7) {
width: 5px;
}
&.start {
p:nth-of-type(1) {
animation: backgroundInfinite7 1.5s ease-in-out infinite;
}
p:nth-of-type(2) {
animation: backgroundInfinite6 1.5s ease-in-out infinite;
}
p:nth-of-type(3) {
animation: backgroundInfinite5 1.5s ease-in-out infinite;
}
p:nth-of-type(4) {
animation: backgroundInfinite4 1.5s ease-in-out infinite;
}
p:nth-of-type(5) {
animation: backgroundInfinite3 1.5s ease-in-out infinite;
}
p:nth-of-type(6) {
animation: backgroundInfinite2 1.5s ease-in-out infinite;
}
p:nth-of-type(7) {
background: #f5f5f5;
}
}
}
.record-status {
width: 100px;
height: 28px;
margin: 0 auto;
line-height: 28px;
color: #888;
border-radius: 2px;
&:hover {
color: #04113d;
background: #e1e1e1;
}
p {
cursor: pointer;
}
}
.ly_btn {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 4vw;
div {
width: 60px;
height: 30px;
color: #888;
cursor: pointer;
line-height: 30px;
border-radius: 4px;
}
.cancel {
color: #cbcbcb;
background: #830808;
}
.send {
color: #cbcbcb;
background: #4a8b2a;
}
}
}
// 语音条
.audio-detail-msg {
display: flex;
align-items: center;
justify-content: flex-end;
.audio-style {
display: flex;
align-items: center;
height: 32px;
margin-left: 8px;
padding: 0 10px;
border-radius: 4px;
background: #fff;
transform: rotate(180deg);
.small {
border: 4px solid #4c4c4c;
border-top-color: transparent;
border-left-color: transparent;
border-bottom-color: transparent;
}
.middle {
width: 16px;
height: 16px;
margin-left: -11px;
opacity: 1;
}
.large {
width: 24px;
height: 24px;
margin-left: -19px;
opacity: 1;
}
& > div {
border: 2px solid #4c4c4c;
border-top-color: transparent;
border-left-color: transparent;
border-bottom-color: transparent;
border-radius: 50%;
box-sizing: border-box;
}
&.add-animation {
.middle {
animation: show2 1.2s ease-in-out infinite;
}
.large {
animation: show3 1.2s ease-in-out infinite;
}
}
}
// 语音播放动画
@keyframes show2 {
0% {
opacity: 0;
}
10% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes show3 {
0% {
opacity: 0;
}
50% {
opacity: 1;
}
60% {
opacity: 0;
}
100% {
opacity: 0;
}
}
// 语音录制动画
@keyframes backgroundInfinite2 {
0% {
background: #666;
}
20% {
background: #f5f5f5;
}
95% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite3 {
0% {
background: #666;
}
30% {
background: #f5f5f5;
}
85% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite4 {
0% {
background: #666;
}
55% {
background: #f5f5f5;
}
75% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite5 {
0% {
background: #666;
}
45% {
background: #666;
}
60% {
background: #f5f5f5;
}
75% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite6 {
0% {
background: #666;
}
65% {
background: #666;
}
85% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
@keyframes backgroundInfinite7 {
0% {
background: #666;
}
75% {
background: #666;
}
95% {
background: #f5f5f5;
}
100% {
background: #666;
}
}
}
.btn_crossAndbtn_succes {
display: flex;
justify-content: space-between;
position: absolute;
bottom: 20vw;
width: 100%;
padding: 13vw;
.cross_box {
width: 15vw;
height: 15vw;
border-radius: 50%;
text-align: center;
line-height: 15vw;
}
.voiceCanael {
color: #fff;
background: rgba(230, 23, 24, 0.6);
}
}
</style>

View File

@ -0,0 +1,234 @@
<template>
<div class="zl">
<div id="pie" style="width: 100%; height: 55vw"></div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted, watch,defineProps } from "vue";
import * as echarts from "echarts";
import { zlZqtjxx } from "../../../../api/zlzx.js";
const props = defineProps({
timeType: {
type: String,
default: "1",
},
})
watch(
() => props.timeType,
() => {
getData();
},{deep:true}
);
const D_BZ_ZLLY = [
{ label: "巡逻方案", value: "01" },
{ label: "人员预警", value: "02" },
{ label: "车辆预警", value: "03" },
{ label: "事件预警", value: "04" },
{ label: "警情", value: "05" },
{ label: "人员", value: "06" },
{ label: "事务", value: "08" },
];
const data = reactive({
data1: [0, 0, 0, 0, 0, 0, 0],
data2: [0, 0, 0, 0, 0, 0, 0],
data3: [0, 0, 0, 0, 0, 0, 0],
data4: [0, 0, 0, 0, 0, 0, 0],
data5: [0, 0, 0, 0, 0, 0, 0],
data6: [0, 0, 0, 0, 0, 0, 0],
data7: [0, 0, 0, 0, 0, 0, 0],
data8: [0, 0, 0, 0, 0, 0, 0],
time:[1,2,3,4,5,6,7]
});
function lineChartFn() {
var chartDom = document.getElementById("pie");
var myChart = echarts.init(chartDom);
var option;
option = {
grid: {
left: "3%",
right: "5%",
bottom: "3%",
top: "40%",
containLabel: true,
},
legend: {
show: true,
textStyle: {
color: "#333",
},
},
tooltip: {},
xAxis: {
type: "category",
data: data.time,
axisLine: {
show: true,
axisTick: {
show: false,
},
},
axisLabel: {
color: "#333",
},
axisLabel: {
interval: 0,
rotate: 30, // 主要是这个 设置角度即可 - 90 ~ 90 旋转方向也不同
},
},
yAxis: {
show: true,
minInterval: 1,
axisLine: {
show: true,
},
splitLine: {
show: false,
},
axisLabel: {
color: "#333",
},
},
series: [
{
name: "巡逻方案",
type: "bar",
barWidth: 4,
itemStyle: {
normal: {
color: "#ffcc40",
barBorderRadius: [15, 15, 15, 15],
},
},
data: data.data1,
},
{
name: "人员预警",
type: "bar",
barWidth: 4,
itemStyle: {
normal: {
color: "#F6426C",
barBorderRadius: [15, 15, 15, 15],
},
},
data: data.data2,
},
{
name: "车辆预警",
type: "bar",
barWidth: 4,
itemStyle: {
normal: {
color: "#177FFF",
barBorderRadius: [15, 15, 15, 15],
},
},
data: data.data3,
},
{
name: "事件预警",
type: "bar",
barWidth: 4,
itemStyle: {
normal: {
color: "#FF18F1",
barBorderRadius: [15, 15, 15, 15],
},
},
data: data.data4,
},
{
name: "警情",
type: "bar",
barWidth: 4,
itemStyle: {
normal: {
color: "#45E3FF",
barBorderRadius: [15, 15, 15, 15],
},
},
data: data.data5,
},
{
name: "人工",
type: "bar",
barWidth: 4,
itemStyle: {
normal: {
color: "#45E30F",
barBorderRadius: [15, 15, 15, 15],
},
},
data: data.data6,
},
{
name: "人员管控",
type: "bar",
barWidth: 4,
itemStyle: {
normal: {
color: "#fff981",
barBorderRadius: [15, 15, 15, 15],
},
},
data: data.data7,
},
{
name: "事务",
type: "bar",
barWidth: 4,
itemStyle: {
normal: {
color: "#f56925",
barBorderRadius: [15, 15, 15, 15],
},
},
data: data.data8,
},
],
};
option && myChart.setOption(option);
document.getElementById("pie").setAttribute("_echarts_instance_", "");
}
//获取近一周日期集合
function getWeek() {
const time = new Date().getTime();
var timeArr = [];
for (let i = 0; i < 7; i++) {
const timen = new Date(time - i * 60 * 60 * 24 * 1000);
var y = timen.getFullYear();
var m =
timen.getMonth() < 9 ? "0" + timen.getMonth() + 1 : timen.getMonth() + 1;
var d = timen.getDate() < 10 ? "0" + timen.getDate() : timen.getDate();
timeArr.unshift(y + "-" + m + "-" + d);
}
return timeArr;
}
function getData() {
zlZqtjxx({ type: props.timeType }).then((res) => {
({
data1: data.data1,
data2: data.data2,
data3: data.data3,
data4: data.data4,
data5: data.data5,
data6: data.data6,
data7: data.data7,
data8: data.data8,
} = res);
data.time = res.time
lineChartFn();
});
}
onMounted(() => {
getData();
});
</script>
<style lang="scss" scoped>
.zl {
margin: 5px 0;
padding-top: 8px;
}
</style>

View File

@ -0,0 +1,126 @@
<template>
<div class="zl">
<div id="bar" style="width: 100%; height: 55vw"></div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted,defineProps,watch } from "vue";
import * as echarts from "echarts";
import { zlDjtjxx } from "../../../../api/zlzx.js";
const props = defineProps({
timeType: {
type: String,
default: "1",
},
})
watch(
() => props.timeType,
() => {
getData();
},{deep:true}
);
const data = ref([
{
name: "蓝色",
value: 0,
dict: "40",
},
{
name: "橙色",
value: 0,
dict: "20",
},
{
name: "黄色",
value: 0,
dict: "30",
},
{
name: "红色",
value: 0,
dict: "10",
},
]);
function lineChartFn() {
var chartDom = document.getElementById("bar");
var myChart = echarts.init(chartDom);
let bgColor = "#fff";
let title = "总量";
let formatNumber = function (num) {
let reg = /(?=(\B)(\d{3})+$)/g;
return num.toString().replace(reg, ",");
};
let total = data.value.reduce((a, b) => {
return a + b.value * 1;
}, 0);
var option;
const color = ["#177FFF", "orange", "#ffcc40", "#F6426C"];
option = {
color,
tooltip: {
trigger: "item",
},
legend: {
bottom: "0",
left: "center",
textStyle: {
color: "#333",
},
},
// legend: {},
series: [
{
type: "pie",
radius: ["45%", "70%"],
center: ["50%", "50%"],
data: data.value,
hoverAnimation: false,
labelLine: {
normal: {
length: 20,
length2: 30,
},
},
label: {
normal: {
formatter: function(val){
if(val.percent === undefined){
return val.name +'('+ val.value +')'+ '\n' + 0 +'%'
}else{
return val.name +'('+ val.value +')'+'\n' + val.percent +'%'
}
}
},
},
},
],
};
option && myChart.setOption(option);
document.getElementById("bar").setAttribute("_echarts_instance_", "");
}
function getData() {
zlDjtjxx({type:props.timeType}).then((res) => {
res.forEach((v) => {
data.value.filter((item) => item.dict === v.zldj).map((item) => {
item.value = v.total;
});
});
lineChartFn();
});
}
onMounted(() => {
getData();
});
</script>
<style lang="scss" scoped>
.zl {
margin: 5px 0;
padding-top: 8px;
background-size: 100% 100%;
}
</style>

View File

@ -0,0 +1,970 @@
<template>
<div style="padding-top: 13vw">
<TopNav navTitle="指令详情" :showRight="false" :showLeft="true" />
<div class="people_detail" ref="zlxq">
<div class="p_qb_info" v-if="zlDetail">
<div class="p_title">{{ zlDetail.zlbt }}</div>
<div class="p_info">
<div class="p_img_box" v-if="zlDetail.zltp">
<van-image width="75px" height="82px" fit="fill" :class="_getBase64(zlDetail)" :src="zlDetail.baseUrl"
@click="onClickImg(zlDetail.baseUrl)">
<template v-slot:loading>
<van-loading type="spinner" size="20" />
</template>
</van-image>
</div>
<div class="p_text_info">
<div class="first_line">
<div class="first_line_text">
<span>指令等级</span> &emsp;
<span :class="{
text_red: zlDetail.zldj == '10',
text_orange: zlDetail.zldj == '20',
text_yellow: zlDetail.zldj == '30',
text_bule: zlDetail.zldj == '40',
}">{{
zlDetail.zldj == "10"
? "红"
: zlDetail.zldj == "20"
? "橙"
: zlDetail.zldj == "30"
? "黄"
: "蓝"
}}</span>
</div>
<template style="display: flex" v-if="!['92', '93', '94'].includes(dqzt)">
<van-button round type="primary" style="padding: 0 5vw" size="mini" color="#009944" v-if="dqzt == '01'"
@click="onClickQs('签收')">
签收
</van-button>
<van-button round type="primary" style="padding: 0 5vw" size="mini" color="#009944"
v-if="(dqzt == '02' || dqzt == '03') && zlDetail.zllx != '07'" @click="onClickQs('到达现场')">
到达现场
</van-button>
<!-- trs研判 -->
<van-button round type="primary" color="#009944" style="padding: 0 5vw" size="mini" v-if="
dqzt == '11' ||
dqzt == '21' ||
dqzt == '22' ||
dqzt == '23' ||
dqzt == '24' ||
dqzt == '25' ||
(dqzt == '31' && zlDetail.zllx != '07')
" @click="onClickQs('处置完成')">
处置完成
</van-button>
<van-button round type="primary" color="#009944" style="padding: 0 5vw" size="mini" v-if="dqzt == '32'"
@click="onClickQs('完结')">
完结
</van-button>
</template>
</div>
<div class="other_line">
来源: {{ setDict(zlDetail.zlly, D_BZ_ZLLY) }} &emsp; &emsp; 类型:
{{ setDict(zlDetail.zllx, D_BZ_ZLLX) }}
</div>
<div class="other_line">时间: {{ zlDetail.zlfqsj }}</div>
<div class="other_line" v-if="fjList.length > 0">
附件:
<span style="color:blue;margin-right2px;" v-for="(item, index) in fjList" :key="index + 'file'">
<a @click="getPreviewText(item)" style="text-decoration: underline;margin-right2px;">附件{{ index +
1}}</a>
</span>
</div>
<div class="video_line"></div>
</div>
</div>
<div class="nr_text">内容: {{ zlDetail.zlnr }}</div>
<div class="check_box">
<div class="check_btn" @click="onClickPr">盘查人员</div>
<div class="check_btn" @click="onClickPc">盘查车辆</div>
</div>
</div>
<div class="chat_box">
<MesssageList :list="zlMessage.messageList" :mesHeight="mesHeight" :audioSc="audioSc"
@click:video="onClickVideoUrl" />
</div>
</div>
<div class="bottom_box" :style="{ background: themeType == 'light' ? '' : '#092556' }"
v-if="dqzt != '92' && dqzt != '93' && dqzt != '94'">
&nbsp;<van-icon :name="require('../../../assets/images/audio_h.png')" size="35"
@click="(showAudio = !showAudio), (voiceCanael = false)"></van-icon>
<div class="message_box">
<van-config-provider :theme-vars="themeVars" v-if="!showAudio">
<van-field v-model="message" label-width="60px" placeholder="请输入你描述的内容..." type="textarea" autosize>
<template #button>
<van-button size="small" type="primary" @click="onClickSend">发送</van-button>
</template>
</van-field>
</van-config-provider>
<div class="azsh_btn" @touchstart="onTouchstart" @touchmove="onTouchmove" @touchend="onTouchchend" v-else>
<van-button type="default" block>按住说话</van-button>
</div>
</div>
&nbsp;<van-icon name="add-o" size="35" @click="showShare = true"></van-icon>
&nbsp;
</div>
<!-- 附件弹窗 -->
<van-popup v-model:show="showShare" position="bottom" round>
<div class="addfj_box">
<van-uploader :after-read="afterRead">
<div class="fj_item">
<img src="../../../assets/images/images.png" alt="" />
<div>图片</div>
</div>
</van-uploader>
<div class="fj_item" @click="onSelectShare">
<img src="../../../assets/images/videos.png" alt="" />
<div>视频</div>
</div>
</div>
<div class="fj_cancel" @click="(showShare = false), Toast.clear()">
取消
</div>
</van-popup>
<!-- 盘人 -->
<checkedPeople ref="peo" :zlId="zlDetail.id" />
<!-- 盘车 -->
<checkedCar ref="car" :zlId="zlDetail.id" />
<van-dialog v-model:show="isWjShow" title="完结说明" show-cancel-button confirm-button-color="#3e6ee8"
@cancel="isWjShow = false" @confirm="onConfirmWjsm">
<van-field v-model="wjsmVal" type="textarea" placeholder="请输入完结说明"></van-field>
</van-dialog>
<van-overlay :show="showAudio">
<Voice ref="voices" :key="voiceIndex" :isCancel="voiceCanael" />
</van-overlay>
<input type="file" accept="video/*" capture="camcorder" style="display: none" id="getVideo" @change="changeVideo" />
<div class="video_play_box" v-show="showLangVideoUrl">
<video style="width: 100%; height: 100vh" controls id="langVideo"></video>
<div class="cross_box" @click="onCloseVideo">
<van-icon name="cross" size="15" color="#fff"></van-icon>
</div>
</div>
<Iframe :url="fillFrams" :isPreviw="isPreviw" @closePre="isPreviw = false"></Iframe>
</div>
</template>
<script setup>
import axios from "axios";
import Base64 from "base-64";
import { getMyTaskDetail, getFjInfo } from "../../../api/rwzx.js";
import {
trsGetRequest,
trsPostRequest,
trs2PostRequest,
timeValidate,
} from "../../../utils/tools";
import Voice from "./components/voice.vue";
import { ImagePreview } from "vant";
import { baseUrl2 } from "../../../utils/request.js";
import TopNav from "../../../components/topNav.vue";
import checkedCar from "../../spsHome/components/checkCar.vue";
import checkedPeople from "../../spsHome/components/checkPeople.vue";
import { ref, reactive, onMounted, onUnmounted, onBeforeUnmount } from "vue";
import MesssageList from "./components/messsageList.vue";
import upVideo from "../../../utils/fpsc.js";
import Iframe from "../../../assets/html/filePreview.vue";
import {
dateFormat,
getDistance,
IS_PNG,
IS_MP3,
IS_MP4,
getBase64,
hintToast,
dataQc,
} from "../../../utils/tools.js";
import emitter from "../../../utils/eventBus.js";
import { Dialog, Toast } from "vant";
import { useRoute } from "vue-router";
import {
getZlczData,
getZlDetail,
addZxjl,
updateZlStatus,
zlHandleRygk,
getToken,
} from "../../../api/zlzx.js";
import { endTaskStatus } from "../../../api/yyzxApi.js";
import { upImage, bigDataUpload } from "../../../api/common.js";
import { getDictList, setDict } from "../../../utils/dict";
const { D_BZ_ZLLY, D_BZ_ZLLX, D_BZ_ZXZTAI } = getDictList(
"D_BZ_ZLLY",
"D_BZ_ZLLX",
"D_BZ_ZXZTAI"
); //字典信息
const baseUrl = `${baseUrl2}/mosty-api/mosty-base/minio/image/download/`;
const themeType = ref(getStorage("themeSetting"));
const themeVars = {
cellBackgroundColor: themeType.value == "light" ? "#ffffff" : "#092556",
cellHorizontalPadding: "8px",
cellVerticalPadding: "8px",
fieldRightIconColor: themeType.value == "light" ? "#333" : "#fff",
FieldIconSize: "28px",
};
const URL = window.URL || window.webkitURL;
const audioSc = ref("");
const voiceIndex = ref(1);
const caEnevt = ref(null); //按住说话事件
const showAudio = ref(false); //是否显示录音弹窗
const peo = ref(); //盘查人员组件对象
const car = ref(); //盘查车辆组件对象
const zlxq = ref(""); //指令详情dom
const message = ref(""); //消息类容
const mesHeight = ref(47); //聊天盒子高度
const mesIndex = ref(1); //消息盒子组件KEY
const id = ref(""); //指令ID
const lastTime = ref(""); //最后一条流程时间
const zlDetail = ref({}); //指令详情
const userInfo = JSON.parse(getStorage("userInfo"));
// const token = getStorage("TRS") && JSON.parse(getStorage("TRS"));
const mesTime = ref(null); // 消息记录轮询时间函数
const isArriveTime = ref(null); //是否到达时间函数
const isWjShow = ref(false); //是否显示完结说明弹窗
const wjsmVal = ref(""); //完结说明内容
const fjid = ref(""); //上传成功的附件ID
const yp = ref(false); // 研判弹框
const ypText = ref("");
const voices = ref(); //语音组件
const showShare = ref(false); //显示附件弹窗
const showLangVideoUrl = ref(false); //是否显示大视频
const isPreviw = ref(false);
const fillFrams = ref(null);
//手指触摸开始位置
const startBtn = ref({
s_x: 0,
s_y: 0,
});
//手指触摸结束位置
const endBtn = ref({
e_x: 0,
e_y: 0,
});
const voiceCanael = ref(false); //是否取消发送语音
const zlMessage = reactive({
//消息数据
messageList: [], //消息记录
});
const sptpid = ref(""); //视频第一帧图片ID
const toast3 = ref(""); //视频上传时间提示
const toast4 = ref(""); //消息发送提示
Toast.allowMultiple();
onMounted(() => {
id.value = useRoute().query.id;
//点击盘查功能
emitter.on("onClickPc", (res) => {
if (res == "pr") {
checkPeople();
} else {
checkCar();
}
});
Promise.all([_getZlczData(true), _getZlDetail(id.value)]).then((res) => {
mesTime.value = setInterval(() => {
//获取做最后一条数据的时间
if (zlMessage.messageList.length > 0) {
lastTime.value =
zlMessage.messageList[zlMessage.messageList.length - 1].time;
_getZlczData();
}
}, 1500);
//获取语音时长
emitter.on("getAudio", (res) => {
audioSc.value = res.durationSeconds;
message.value = `${res.fjid}.wav`;
fjid.value = res.fjid;
submitMessage("audio");
});
//自动结束关闭语音窗口
emitter.on("hideAudio", (res) => {
showAudio.value = false;
voiceIndex.value++;
message.value = "";
});
});
scrollToBottom();
});
onBeforeUnmount(() => {
clearInterval(mesTime.value);
mesTime.value = null;
clearInterval(isArriveTime.value);
isArriveTime.value = null;
});
onUnmounted(() => {
emitter.off("onClickPc");
emitter.off("getAudio");
});
// 获取预览文件
function getPreviewText(item) {
let url = item.url; //要预览文件的访问地址
let Base64Url = Base64.encode(url);
fillFrams.value =
"http://10.64.201.126:8012/onlinePreview?url=" +
encodeURIComponent(Base64Url);
isPreviw.value = true;
}
//关闭大视频
function onCloseVideo() {
let videos = document.getElementById("langVideo");
videos.pause();
showLangVideoUrl.value = false;
}
//获取放大视频地址
function onClickVideoUrl(url) {
if (url) {
let videos = document.getElementById("langVideo");
videos.src = url;
videos.play();
showLangVideoUrl.value = true;
}
}
//调用
function onSelectShare() {
window.addEventListener("message", receivePost);
// let videos = document.getElementById("getVideo");
// videos.click();
// toast3.value = Toast({
// message: "拍摄视频请不要超过20s",
// position: "bottom",
// duration: 6000,
// });
try {
bridge.recordVideo(
`${baseUrl2}/mosty-api/mosty-base/minio/image/upload/id`,
30
);
} catch (error) { }
}
//接收postMessage消息由安卓上传的视频 返回ID
function receivePost(mes) {
try {
let str = mes.data.type;
switch (str) {
case "videoId":
fjid.value = mes.data.data;
message.value = `${new Date().getTime()}_video.mp4`;
showShare.value = false;
submitMessage("video");
window.removeEventListener("message", receivePost);
break;
}
} catch (error) { }
}
//长按事件
function onTouchstart(item) {
//获取起点位置
startBtn.value.s_x = item.touches[0].pageX;
startBtn.value.s_y = item.touches[0].pageY;
item.stopPropagation();
//长按事件后执行录音
caEnevt.value = setTimeout(() => {
caEnevt.value = 0;
voices.value.startAudioRecord();
}, 800);
return false;
}
//手指移动
function onTouchmove(item) {
//手指离开的位置
let e_x = item.changedTouches[0].pageX;
let e_y = item.changedTouches[0].pageY;
//计算出偏移度
let direction = getDirection(
startBtn.value.s_x,
startBtn.value.s_y,
e_x,
e_y
).toFixed(0);
//手指滑动到取消范围内 取消高亮
if (direction < -110 && direction > -150) {
voiceCanael.value = true;
}
}
//释放事件
function onTouchchend(item) {
//手指离开的位置
endBtn.value.e_x = item.changedTouches[0].pageX;
endBtn.value.e_y = item.changedTouches[0].pageY;
//计算出偏移度
let direction = getDirection(
startBtn.value.s_x,
startBtn.value.s_y,
endBtn.value.e_x,
endBtn.value.e_y
).toFixed(0);
item.stopPropagation();
showAudio.value = false;
voiceIndex.value++;
//在取消范围取消语音发送
if (direction < -110 && direction > -150) {
clearTimeout(caEnevt.value);
voices.value.cancelRecord();
} else {
//松开手指或者不在取消范围 就发送语音
if (caEnevt.value != 0) {
hintToast("说话时间太短!!");
clearTimeout(caEnevt.value);
} else {
voices.value.stopRecording();
}
}
clearTimeout(caEnevt.value);
return false;
}
//获得角度
function getAngle(angx, angy) {
return (Math.atan2(angx, angy) * 180) / Math.PI;
}
//计算偏移量
function getDirection(startX, startY, endX, endY) {
let angx = endX - startX;
let angy = endY - startY;
let result = 0;
if (Math.abs(angx) < 2 && Math.abs(angy) < 2) {
return result;
}
let angle = getAngle(angx, angy);
result = angle;
return result;
}
//预览图片
function onClickImg(fjid) {
ImagePreview([fjid]);
}
//结束任务
function _endTaskStatus(rwxl, ywid, rwzt, rwxxlx) {
let data = { rwxl, ywid, rwzt, rwxxlx };
try {
let location = JSON.parse(bridge.getLocation());
data.jd = location.app_x;
data.wd = location.app_y;
} catch (error) { }
endTaskStatus(data).then((res) => { });
}
//获取base64地址
function _getBase64(item) {
getBase64((res) => {
item.baseUrl = res;
}, item.zltp);
}
// 滚动条始终在最底部
function scrollToBottom() {
var container = document.getElementsByClassName("check_box")[0];
container.scrollTop = container.scrollHeight;
}
//获取指令详情
const dqzt = ref();
function _getZlDetail(id) {
getZlDetail(id).then((res) => {
zlDetail.value = res;
dqzt.value = res.zxrVo.dqzt;
_getFile(res.fjId);
if (res.zlzxzt == "02" || res.zlzxzt == "03") {
countJl();
isArriveTime.value = setInterval(() => {
countJl();
}, 30e3);
} else {
clearInterval(isArriveTime.value);
isArriveTime.value = null;
}
});
}
const fjList = ref([]);
function _getFile(fjid) {
try {
const requestArr = fjid.split(",").map((item) => {
return getFjInfo(item);
});
Promise.all(requestArr).then((resArr) => {
resArr.forEach((res) => {
if (IS_PNG(res.suffix.substring(1, res.suffix.length))) {
res.fileFormat = "png";
} else {
res.fileFormat = "file";
}
fjList.value.push(res);
});
});
} catch (error) { }
}
//获取指令处置流程
function _getZlczData(flag) {
let data = {
zlid: id.value,
time: lastTime.value,
};
getZlczData(data).then((res) => {
if (res && res.length > 0) {
res.forEach((item) => {
let fileFormat = "";
if (item.zxnr && item.fjid) {
//判断是那种文件类型.
let fjIndex = item.zxnr.lastIndexOf(".");
if (fjIndex != -1) {
let file_Format = item.zxnr.substring(
fjIndex + 1,
item.zxnr.length
);
if (IS_PNG(file_Format)) {
fileFormat = "png";
} else if (IS_MP3(file_Format)) {
fileFormat = "mp3";
} else if (IS_MP4(file_Format)) {
fileFormat = "mp4";
} else {
fileFormat = "file";
}
}
}
zlMessage.messageList.push({
time: item.zxsj,
type: userInfo.id == item.xtCjrId ? 2 : 1, //1为 对方的数据 2为自己的数据
text: item.zxnr,
yysc: item.yysc,
name: item.xtCjr || "系统",
fjid: item.fjid,
sptpid: item.sptpid,
fileFormat,
});
dataQc(zlMessage.messageList, "id");
});
}
});
}
//点击盘人
function onClickPr() {
peo.value.handleOpen();
}
//点击盘车
function onClickPc() {
car.value.handleOpen();
}
//确认完结说明
function onConfirmWjsm() {
isWjShow.value = false;
_updateZlStatus("04");
}
//签收
const ypflag = ref(true);
const fkFlag = ref(true);
// 处理状态
function onClickQs(text) {
if (text == "完结") return isWjShow.value = true;
Dialog.confirm({ title: "提示", message: `是否${text}!`, }).then((res) => {
switch (text) {
case "签收":
_updateZlStatus("01");
break;
case "到达现场":
_updateZlStatus("02", 1);
break;
case "处置完成":
_updateZlStatus("03");
break;
}
}).catch((err) => { });
}
//计算用户与指令地址距离
function countJl() {
try {
let location = JSON.parse(bridge.getLocation());
let jl = getDistance(
zlDetail.value.jd,
zlDetail.value.wd,
location.app_x,
location.app_y
);
//小于100米 自动到达现场
if (jl < 100) {
_updateZlStatus("02", 0);
}
} catch (error) { }
}
//修改指令状态
function _updateZlStatus(type, sfsddd) {
let { zxrVo, ssbmid, zlfsdd, zljsdx } = zlDetail.value;
let data = {
ssbmid: ssbmid,
zlzxdd: zlfsdd,
zljsdx: zljsdx,
zlzxrDh: zxrVo.zxrDh,
zlzxrId: zxrVo.zxrId,
zlzxrSfz: zxrVo.zxrSfz,
zlzxrXm: zxrVo.zxrXm,
zlzxrXzid: zxrVo.zxrXzid,
zlzxzt: type,
zlId: zxrVo.zlId,
zlwjsm: wjsmVal.value,
sfsddd,
};
try {
let location = JSON.parse(bridge.getLocation());
data.jd = location.app_x;
data.wd = location.app_y;
} catch (error) {
data.jd = 104.065637;
data.wd = 30.592008;
}
updateZlStatus(data).then((res) => {
hintToast("成功");
_getZlDetail(id.value);
_getZlczData();
_endTaskStatus("05", zlDetail.value.id, "2", type);
});
}
//获取文件
function afterRead(file) {
toast4.value = Toast({
message: "图片发送中。。。",
forbidClick: true,
});
showShare.value = false;
const data = new FormData();
data.append("file", file.file);
upImage(data).then((res) => {
if (res) {
fjid.value = res;
message.value = file.file.name;
submitMessage("img");
}
});
}
//发送消息
function onClickSend() {
if (!message.value) return;
lastTime.value = zlMessage.messageList[zlMessage.messageList.length - 1].time;
submitMessage();
}
//提交聊天数据到后台
function submitMessage(type) {
if (type == "audio") {
toast4.value = Toast({
message: "语音发送中。。。",
forbidClick: true,
});
}
let data = {
zlId: id.value,
zlzxdd: zlDetail.value.zlfsdd,
zxnr: message.value,
fjid: fjid.value,
yysc: audioSc.value,
sptpid: sptpid.value,
};
message.value = "";
try {
let location = JSON.parse(bridge.getLocation());
data.jd = location.app_x;
data.wd = location.app_y;
} catch (error) { }
addZxjl(data).then((res) => {
fjid.value = "";
message.value = "";
_getZlczData();
})
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
::v-deep .van-field__control {
@include border_color($border-color-theme);
@include user_function_item_color($user-function-item-theme);
@include font_size($font_medium_s);
padding: 1vw;
height: 35px !important;
border-radius: 5px;
}
.top {
padding: 3vw;
margin: 2vw;
}
.basic-info {
color: #4d4d4d;
display: flex;
flex-direction: row;
.img-box {
flex: 1;
}
.IDcard-info {
flex: 3;
@include font_size($font_medium_s);
.text {
@include font_size($font_medium);
font-weight: bold;
color: #1f6cec;
}
}
}
.but_box {
display: flex;
justify-content: space-between;
margin-top: 1vw;
}
.bottom_box {
position: fixed;
width: 100vw;
bottom: 0;
max-height: 21vw;
background-color: #eff0f2;
display: flex;
justify-content: space-between;
align-items: center;
border-top: 1px solid #cac9c9;
z-index: 1001;
.message_box {
flex: 1;
}
}
.zldj_item {
display: inline-block;
width: 3.5vw;
height: 3.5vw;
border-radius: 50%;
}
.contact-way {
margin-top: 3.5vw;
@include font_size($font_medium_s);
.zl_detail {
height: 14vw;
overflow: auto;
margin-bottom: 1vw;
}
.fjsp {
display: flex;
justify-content: space-between;
.fjsp_item {
display: flex;
align-items: center;
}
}
}
.preview-cover {
position: absolute;
bottom: 0;
box-sizing: border-box;
width: 100%;
padding: 4px;
color: #fff;
font-size: 12px;
text-align: center;
background: rgba(0, 0, 0, 0.3);
}
.fj_box {
padding: 20px;
font-size: 12px;
}
.yp_btn {
margin: 40px 10px 10px 10px;
display: flex;
justify-content: center;
}
.people_detail {
@include font_size($font_medium_s);
display: flex;
flex-direction: column;
.p_qb_info {
background-image: linear-gradient(to bottom,
#b7dafc 0%,
#ffffff 35%,
#ffffff 100%);
padding: 12px 17px 17px 17px;
}
.p_title {
@include font_size($font_medium);
font-weight: bold;
color: #004cab;
word-wrap: break-all;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.p_info {
display: flex;
margin-top: 1vh;
.p_text_info {
position: relative;
flex: 1;
.first_line {
display: flex;
justify-content: space-between;
.first_line_text {
@include font_size($font_medium);
font-weight: bold;
.text_red {
color: #e20000;
}
.text_orange {
color: #fa5200;
}
.text_yellow {
color: #f18608;
}
.text_bule {
color: #013791;
}
}
}
.other_line {
line-height: 3vh;
}
.video_line {
position: absolute;
right: 0;
bottom: 0.5vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.video_text {
color: #0289fe;
@include font_size($font_medium_s);
}
}
}
}
.nr_text {
color: #555;
}
.check_box {
display: flex;
justify-content: space-between;
overflow-anchor: none;
.check_btn {
width: 44vw;
height: 6vh;
text-align: center;
line-height: 6vh;
background-color: #f7e4e0;
@include font_size($font_medium);
font-weight: bold;
border-radius: 3px;
margin-top: 2vh;
}
}
.chat_box {
padding: 17px;
box-sizing: border-box;
height: 61vh;
overflow: hidden;
overflow-y: auto;
background-color: #eff0f2;
}
}
::v-deep .van-divider {
border-color: #cac9c9;
}
::v-deep .van-cell {
background-color: #eff0f2;
}
::v-deep .trs.van-button--block {
width: unset;
}
::v-deep .van-field__right-icon {
padding-top: 2vw;
}
::v-deep .van-overlay {
z-index: 1000;
}
.azsh_btn {
background: #e1e1e1;
text-align: center;
-webkit-touch-callout: none !important;
-webkit-user-select: none;
}
.addfj_box {
display: flex;
@include font_size($font_medium);
.fj_item {
text-align: center;
padding: 7vw;
&>img {
width: 12vw;
height: 11.8vw;
}
}
}
.fj_cancel {
border-top: 3vw solid #eff0f2;
text-align: center;
padding: 4vw;
}
.video_play_box {
position: fixed;
z-index: 9999999999;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 1);
.cross_box {
position: fixed;
z-index: 999999999912;
top: 5vw;
right: 5vw;
width: 7vw;
height: 7vw;
background: gray;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
}
</style>

View File

@ -0,0 +1,148 @@
<template>
<div style="padding-top: 15vw">
<TopNav navTitle="指令统计" :showRight="false" :showLeft="true" />
<TopSelectTime @chenge:time="onSelectTime" />
<TopTotal :list="zlTotal.list" />
<!-- 任务完成情况 -->
<div class="item_box gsdyj_box">
<div class="other_type_title">完成率排名</div>
<TaskRank :timeType="timeType" />
</div>
<div class="item_box gsdyj_box">
<div class="other_type_title">指令趋势</div>
<WeekTrendBar :timeType="timeType" />
</div>
<div class="item_box gsdyj_box">
<div class="other_type_title">指令等级统计</div>
<WeekTrendPie :timeType="timeType" />
</div>
</div>
</template>
<script setup>
import { ref, onMounted, reactive } from "vue";
import TopSelectTime from "../../../components/topSelectTime.vue";
import TopNav from "../../../components/topNav.vue";
import TopTotal from "../../../components/topTotal";
import TaskRank from "./components/taskRank";
import WeekTrendBar from "./components/weekTrendBar";
import WeekTrendPie from "./components/weekTrendPie";
import { getTjOfZllx } from "../../../api/zlzx.js";
import { Toast } from "vant";
const timeType = ref("1"); // 统计条件
const zlTotal = reactive({
list: [
{
title: "全部",
count: 0,
zllx: "",
},
{
title: "巡逻指令",
count: 0,
zllx: "01",
},
{
title: "感知预警指令",
count: 0,
zllx: "02",
},
{
title: "警情处置指令",
count: 0,
zllx: "05",
},
{
title: "人工指令",
count: 0,
zllx: "06",
},
{
title: "人员管控指令",
count: 0,
zllx: "07",
},
],
});
function onSelectTime(val) {
const copyTime = timeType.value;
timeType.value = val + 1 + "";
if (timeType.value !== copyTime) {
_getZlTotal();
}
}
onMounted(() => {
_getZlTotal();
});
//获取指令统计
function _getZlTotal() {
Toast.loading({
message: "加载中",
forbidClick: true,
loadingType: "spinner",
duration: 0,
});
zlTotal.list = [
{
title: "全部",
count: 0,
zllx: "",
},
{
title: "巡逻指令",
count: 0,
zllx: "01",
},
{
title: "感知预警指令",
count: 0,
zllx: "02",
},
{
title: "警情处置指令",
count: 0,
zllx: "05",
},
{
title: "人工指令",
count: 0,
zllx: "06",
},
{
title: "人员管控指令",
count: 0,
zllx: "07",
},
];
getTjOfZllx({ type: timeType.value }).then((res) => {
res.forEach((item) => {
zlTotal.list[0].count += item.count;
if (["02", "03", "04"].includes(item.zllx)) {
zlTotal.list[2].count += item.count;
} else {
zlTotal.list.forEach((el) => {
if (item.zllx == el.zllx) {
el.count = item.count;
}
});
}
});
Toast.clear();
});
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.gsdyj_box {
margin: 2vw 3vw 5vw 3vw;
padding: 2vw;
}
.other_type_title {
margin-left: 2vw;
}
::v-deep .van-tabs__nav--card {
margin: 0 3vw;
}
</style>

View File

@ -0,0 +1,417 @@
<template>
<div>
<TopNav navTitle="信息交互" :showRight="true" :showLeft="true" rightIcon="add-o" @clickRight="onClickRight" />
<van-sticky>
<div class="sticky_box">
<van-tabs v-model:active="activeTabName" class="top_tabs" :class="activeTabName == '01' ? 'left_top_tabs' : ''"
@change="changeTab">
<van-tab :title="item.name" :name="item.type" v-for="item in toptabs" :key="item"></van-tab>
</van-tabs>
<Tabs v-if="activeTabName == '01'" :list="tabs" @onYjjb="onSelect" :key="tabsIndex"></Tabs>
<Search placeholder="请输入关键字" v-model="kwd" :isSx="true" @update:sx="showPopup = !showPopup"
@update:modelValue="onSearch"></Search>
</div>
</van-sticky>
<van-pull-refresh v-model="loadingPull" @refresh="onRefresh">
<van-list v-model:loading="loading" :finished="finished" finished-text=" " @load="onLoad" offset="1"
:immediate-check="false">
<ZlList v-for="(item, index) in zlList.list" :key="index" :item="item" :dict="{ D_BZ_ZXZTAI }"
:path="`/yyzx/zlzx/zlDetail?id=${item.zlId}`"></ZlList>
<van-empty description="暂无指令信息" image="default" v-if="zlList.list.length <= 0 && loadingPull == false" />
</van-list>
</van-pull-refresh>
<SxPopup :showPopup="showPopup" :list="zlList.sxTypeList" :p_top="145" @update:close="showPopup = false"
@update:onConfirm="onConfirm" />
</div>
</template>
<script setup>
import { getTrsToken } from "@/api/common";
import Tabs from "../../../components/tabs.vue";
import TopNav from "../../../components/topNav.vue";
import Search from "../../../components/search.vue";
import ZlList from "../../../components/zlList.vue";
import SxPopup from "../../../components/SxPopup.vue";
import { dateFormat, setTimeQuantum } from "../../../utils/tools.js";
import { getDictList, setDict } from "../../../utils/dict";
import { ref, onMounted, reactive, watch } from "vue";
import router from "@/router";
import { Toast } from "vant";
import { getZlList, getZlTotal } from "../../../api/zlzx.js";
import store from "../../../store";
const { D_BZ_ZXZTAI } = getDictList("D_BZ_ZXZTAI"); //字典信息
const userInfo = JSON.parse(window.localStorage.getItem("userInfo"));
const kwd = ref(""); //搜索关键字
const showPopup = ref(false); //赛选条件窗口
const zlztIndex = ref(-1); //选中的指令状态下标
const timeShow = ref(false); //时间选择器
const presentTime = ref(new Date()); //当前时间
const timeType = ref(""); //选择的时间类型
const startTime = ref(""); //开始时间
const endTime = ref(""); //结束时间
const loading = ref(false);
const loadingPull = ref(false);
const finished = ref(false);
const pageSize = ref(10);
const pageCurrent = ref(1);
const zllx = ref(""); // 指令类型
const zlTypeIndex = ref(""); //选中的查询类型下标
const total = ref(0); //
const tabsIndex = ref(1);
const activeTabName = ref('01');
const listQuery = ref({
zlly: '01,02,03,04,05,06,07,08,09'
})
const zlList = reactive({
list: [], //指令列表数据
sxTypeList: [], //筛选项数据
});
const toptabs = ref([
{
name: "任务下达",
type: "01",
},
{
name: "任务需求",
type: "02",
},
])
const tabs = ref([
{
name: "全部",
count: 0,
zllx: "",
},
{
name: "巡逻",
count: 0,
zllx: "01",
},
{
name: "人员",
count: 0,
zllx: "02",
},
{
name: "车辆",
count: 0,
zllx: "03",
},
{
name: "事件",
count: 0,
zllx: "04",
},
{
name: "警情",
count: 0,
zllx: "05",
},
{
name: "人工指令",
count: 0,
zllx: "06",
},
{
name: "人员管控",
count: 0,
zllx: "07",
},
{
name: "事务",
count: 0,
zllx: "08",
},
]);
watch(D_BZ_ZXZTAI, (newValue) => {
//设置筛选值
let array = [];
for (let i = 0; i < newValue.length; i++) {
array.push({
name: newValue[i].text,
key: newValue[i].dm,
isCheck: false,
});
}
zlList.sxTypeList = [
{
title: "指令进行状态",
isCheckBox: false,
array: array,
},
];
zlList.sxTypeList[1] = setTimeQuantum();
});
onMounted(() => {
_getZlTotal();
_getZlList();
});
//下拉刷新
function onRefresh() {
reset()
_getZlTotal();
_getZlList();
}
const reset = () => {
zlList.list = [];
pageCurrent.value = 1;
zlTypeIndex.value = "";
kwd.value = "";
startTime.value = "";
endTime.value = "";
loading.value = false;
loadingPull.value = false;
finished.value = false;
tabsIndex.value++;
}
// 切换tab
const changeTab = (val) => {
console.log(val, 'val');
reset()
if (val == '01') {
listQuery.value.zlly = '01,02,03,04,05,06,07,08,09';
} else if (val == '02') {
listQuery.value.zlly = '10';
}
_getZlList();
}
//关键字查询
function onSearch(e) {
kwd.value = e;
zlList.list = [];
pageCurrent.value = 1;
_getZlTotal();
_getZlList();
}
// //类型查询
function onSelect(val) {
zlList.list = [];
pageCurrent.value = 1;
zllx.value = tabs.value[val].zllx;
loading.value = false;
loadingPull.value = false;
finished.value = false;
_getZlList();
}
//获取指令数据列表
function _getZlList() {
loading.value = true;
let data = {
pageSize: pageSize.value,
pageCurrent: pageCurrent.value,
zlzxzt: zlTypeIndex.value,
zlnr: kwd.value,
kssj: startTime.value,
jssj: endTime.value,
zllx: zllx.value,
zlly: listQuery.value.zlly
};
getZlList(data)
.then((res) => {
loading.value = false;
loadingPull.value = false;
total.value = res.pages;
let arr = res.records ? res.records : [];
arr.forEach((item) => {
zlList.list.push(item);
});
})
.catch((err) => {
loading.value = false;
});
}
//获取指令统计数据
function _getZlTotal() {
getZlTotal()
.then((res) => {
tabs.value[0].count = 0;
if (res.length > 0) {
res.forEach((item) => {
tabs.value[0].count += item.count;
switch (item.zllx) {
case "01":
tabs.value[1].count = item.count;
break;
case "02":
tabs.value[2].count = item.count;
break;
case "03":
tabs.value[3].count = item.count;
break;
case "04":
tabs.value[4].count = item.count;
break;
case "05":
tabs.value[5].count = item.count;
break;
case "06":
tabs.value[6].count = item.count;
break;
case "07":
tabs.value[7].count = item.count;
break;
case "08":
tabs.value[8].count = item.count;
break;
}
});
}
})
.catch((err) => { });
}
const onClickRight = () => {
router.push('/addZlInfo')
}
//选中时间
function onTimeConfirm(val) {
if (timeType.value == "start") {
startTime.value = dateFormat("", val);
} else {
endTime.value = dateFormat("", val);
}
timeShow.value = false;
}
//选中指令状态
function onClickZlzt(index, dm) {
zlTypeIndex.value = dm;
zlztIndex.value = index;
}
//确认筛选条件
function onConfirm(val) {
zlList.list = [];
pageCurrent.value = 1;
startTime.value = val.startTime;
endTime.value = val.endTime;
zlTypeIndex.value = "";
for (let i = 0; i < val.list.length; i++) {
for (let j = 0; j < val.list[i].array.length; j++) {
if (val.list[i].array[j].isCheck) {
zlTypeIndex.value = val.list[i].array[j].key;
break;
}
}
}
_getZlList();
showPopup.value = false;
}
//重置筛选条件
function onReset() {
startTime.value = "";
endTime.value = "";
zlztIndex.value = -1;
}
//触底加载
function onLoad() {
if (pageCurrent.value >= total.value) {
finished.value = true;
return;
}
pageCurrent.value += 1;
_getZlList();
}
</script>
<style lang="scss" scoped>
@import "../../../assets/styles/mixin.scss";
.sticky_box {
@include bg_color($background-color-theme);
.tabs_box {
@include font_size($font_medium_s);
@include font_color($font-color-theme);
display: flex;
.tabs_item {
width: 25%;
text-align: center;
.tabs_count {
margin-top: 2vw;
}
}
}
}
.zl_sx_box {
@include font_size($font_medium_s);
padding: 4vw 0;
.item_title {
padding: 0 3.5vw;
font-weight: 600;
}
.zlzt_box {
padding: 4vw;
.tag_item {
margin: 0 3vw 3vw 0;
padding: 1vw 3vw;
}
}
}
.but_box {
display: flex;
justify-content: space-between;
margin-top: 5vw;
}
.item_box {
@include font_size($font_medium_s);
@include font_color($font-color-theme);
margin: 0 3.5vw 4vw 3.5vw;
padding: 2vw;
.time_box {
display: flex;
justify-content: space-between;
align-items: center;
.ststus {
font-size: 10px;
padding: 0 10px;
color: #fff;
border-radius: 10px;
}
.dfk {
background-color: rgb(242, 199, 6);
}
.yfk {
background-color: #3e6ee8;
}
.ywj {
background-color: #4fbe0d;
}
.ddc {
background-color: orangered;
}
.djc {
background-color: orange;
}
}
>div {
line-height: 20px;
}
.title {
@include font_size($font_medium);
font-weight: bold;
}
}
.top_tabs {
margin-top: 13vw;
}
.left_top_tabs {
margin-bottom: -10.5vw;
}
</style>