初始提交
This commit is contained in:
129
src/pages/yyzx/zlzx/addzl.vue
Normal file
129
src/pages/yyzx/zlzx/addzl.vue
Normal 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>
|
||||
560
src/pages/yyzx/zlzx/components/messsageList.vue
Normal file
560
src/pages/yyzx/zlzx/components/messsageList.vue
Normal 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>
|
||||
|
||||
<div>
|
||||
<div style="margin-bottom: 2vw">
|
||||
<span>{{ item.time }}</span> <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>
|
||||
|
||||
<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>
|
||||
123
src/pages/yyzx/zlzx/components/taskRank.vue
Normal file
123
src/pages/yyzx/zlzx/components/taskRank.vue
Normal 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>
|
||||
558
src/pages/yyzx/zlzx/components/voice.vue
Normal file
558
src/pages/yyzx/zlzx/components/voice.vue
Normal file
@ -0,0 +1,558 @@
|
||||
<template>
|
||||
<div>
|
||||
<!-- 音频录制 -->
|
||||
<div class="audio-record">
|
||||
<p class="duration-seconds-style">
|
||||
<span v-show="countDownRecord"
|
||||
>{{ countDownSecond }}″ 后停止录制</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>
|
||||
234
src/pages/yyzx/zlzx/components/weekTrendBar.vue
Normal file
234
src/pages/yyzx/zlzx/components/weekTrendBar.vue
Normal 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>
|
||||
126
src/pages/yyzx/zlzx/components/weekTrendPie.vue
Normal file
126
src/pages/yyzx/zlzx/components/weekTrendPie.vue
Normal 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>
|
||||
970
src/pages/yyzx/zlzx/zlDetail.vue
Normal file
970
src/pages/yyzx/zlzx/zlDetail.vue
Normal 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>  
|
||||
<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) }}     类型:
|
||||
{{ 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-right:2px;" v-for="(item, index) in fjList" :key="index + 'file'">
|
||||
<a @click="getPreviewText(item)" style="text-decoration: underline;margin-right:2px;">附件{{ 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'">
|
||||
<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>
|
||||
<van-icon name="add-o" size="35" @click="showShare = true"></van-icon>
|
||||
|
||||
</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>
|
||||
148
src/pages/yyzx/zlzx/zlTotal.vue
Normal file
148
src/pages/yyzx/zlzx/zlTotal.vue
Normal 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>
|
||||
417
src/pages/yyzx/zlzx/zlzxIndex.vue
Normal file
417
src/pages/yyzx/zlzx/zlzxIndex.vue
Normal 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>
|
||||
Reference in New Issue
Block a user