Files
sgxt_web/src/views/home/model/mapNavigation.vue
2026-03-18 11:07:40 +08:00

739 lines
20 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="homeBox">
<!-- <div class="header">
<div class="title">
<el-icon><Map /></el-icon>
地图导航
</div>
<div class="close-button" @click="close">
<el-icon>
<Close />
</el-icon>
</div>
</div> -->
<Head :defDay="false"></Head>
<div class="map-container">
<GdMap :mapid="'map-99'"></GdMap>
<div class="button-container">
<template v-for="(value, index) in butList" :key="index">
<el-popover v-if="value.label === '警情' && value.onChage" placement="top" :width="480" trigger="click"
@show="changeBut(value)">
<template #reference>
<!-- -->
<div class="but" :class="{ 'butOk': value.onChage }">
{{ value.label }}
</div>
</template>
<div class="jqdj-popover">
<div class="filter-item">
<span class="filter-label">等级</span>
<el-checkbox-group v-model="jqdjdmFilter" @change="handleJqdjFilterChange" class="checkbox-group">
<el-checkbox v-for="item in D_BZ_JQDJ" :key="item.dm" :label="item.dm" class="checkbox-item">
{{ item.zdmc }}
</el-checkbox>
</el-checkbox-group>
</div>
<div class="filter-item">
<span class="filter-label">时间</span>
<el-date-picker style="width: 100%;" v-model="timeRange" type="datetimerange" start-placeholder="开始时间" end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm:ss" @change="handleTimeRangeChange" />
</div>
</div>
</el-popover>
<el-popover v-else-if="value.label === '事件' && value.onChage" placement="top" :width="480" trigger="click"
@show="changeBut(value)">
<template #reference>
<div class="but" :class="{ 'butOk': value.onChage }">
{{ value.label }}
</div>
</template>
<div class="jqdj-popover">
<div class="filter-item">
<span class="filter-label">时间</span>
<el-date-picker v-model="sjTimeRange" type="datetimerange" style="width: 100%;" start-placeholder="开始时间" end-placeholder="结束时间"
format="YYYY-MM-DD HH:mm:ss" @change="getTimeRange" />
</div>
</div>
</el-popover>
<div v-else class="but" :class="{ 'butOk': value.onChage }" @click="changeBut(value)">
{{ value.label }}
</div>
</template>
</div>
</div>
<div class="list">
<div class="titel">
<div class="levelOneAlert">{{ listTitle }}</div>
<div class="switchover" @click="change">切换</div>
</div>
<div class="search">
<div class="jqdj-filter" v-if="changeState">
<el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">
全选
</el-checkbox>
<el-checkbox-group v-model="selectedJqdj" @change="handleCheckedChange">
<el-checkbox v-for="item in D_BZ_JQDJ" :key="item.dm" :label="item.dm">
{{ item.zdmc }}
</el-checkbox>
</el-checkbox-group>
</div>
<div>
<el-input v-model="promes.jjdbh" :placeholder="changeState ? '输入接警单编号' : '输入事件标题'" class="input-with-select"
clearable />
<el-button class="button-model" type="primary" @click="search">搜索</el-button>
<el-button type="success" :icon="Plus" @click="changeChooseShow" v-if="!changeState" />
</div>
</div>
<div class="dataList" v-infinite-scroll="loadMore" infinite-scroll-disabled="loading"
infinite-scroll-distance="10">
<template v-if="changeState">
<div class="item" v-for="(item, index) in jqList" :key="index" @click="clickJq(item)">
<div class="data-title">接警单{{ item.jjdbh }}</div>
<div class="data-row">
<div class="data-title">报警人{{ item.bjrmc }}</div>
<div class="data-title">报警电话{{ item.bjdh }}</div>
</div>
<div class="data-row">
<div class="data-title data-row">
警情等级
<DictTag :tag="false" color="red" :value="item.jqdjdm" :options="D_GS_BQ_DJ" />
</div>
<div class="data-title data-row">警情类别
<DictTag :tag="false" :value="item.jqlbdm" :options="JQLB" color="#fff" />
</div>
</div>
<div class="data-title content">报警内容{{ item.bjnr }}</div>
<div class="data-title">报警时间{{ item.bjsj }}</div>
<div class="data-title imTyle" @click.stop="updetDz(item)">报警地址<img src="@/assets/point/dingwei.png"
alt="" />{{ item.bjdz }}</div>
</div>
</template>
<template v-else>
<div class="item" v-for="(item, index) in zdsjList" :key="index" @click="clickJq(item)">
<div class="data-title">事件标题:{{ item.sjbt }}</div>
<div class="data-title display-flex">事件状态
<DictTag :tag="false" color="#fff" :value="item.sjzt" :options="D_BZ_ZDSJCZJG" />
</div>
<div class="data-title">处置结果{{ item.czjg }}</div>
<div class="data-title">发生时间{{ item.fssj }}</div>
<div class="data-title">事件性质{{ item.sjxz }}</div>
<div class="data-title">事件描述{{ item.shms }}</div>
<div class="data-title imTyle" @click.stop="updetDz(item)">事件地址<img src="@/assets/point/dingwei.png"
alt="" />{{ item.sjdz }}</div>
<div class="data-title">所属部门{{ item.ssbm }}</div>
</div>
</template>
</div>
</div>
</div>
<ZdsjLod v-model="chooseShow" :dict="{ D_BZ_ZDSJCZJG }" :zbData="zbData" />
<!-- 左边弹窗 -->
<LeftDialog></LeftDialog>
</template>
<script setup>
import LeftDialog from '../dialog/leftDialog.vue'
import GdMap from "@/components/GdMap/index.vue";
import { ref, onMounted, getCurrentInstance, onUnmounted } from 'vue'
import { Close, Map, Plus } from '@element-plus/icons-vue';
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
import emitter from "@/utils/eventBus.js";
import ZdsjLod from "@/views/home/dialog/zdsjLod.vue";
import Head from '../layout/head.vue'
const { proxy } = getCurrentInstance();
const { D_GS_BQ_DJ, JQLB, D_BZ_ZDSJCZJG, D_BZ_JQDJ } = proxy.$dict('D_GS_BQ_DJ', "JQLB", "D_BZ_ZDSJCZJG", "D_BZ_JQDJ"); //获取字典数据
const butList = ref([
{
label: '警情',
onChage: true
},
{
label: '事件',
onChage: true
},
{
label: '清除',
onChage: false
}
])
const rowData = ref()
// 警情等级筛选底部按钮的popover
const jqdjdmFilter = ref([])
// 处理警情等级筛选变化
const handleJqdjFilterChange = () => {
getLzJcjPjdb()
}
// 获取当天的开始和结束时间
const getCurrentMonthRange = () => {
const now = new Date();
const year = now.getFullYear();
const month = now.getMonth();
const day = now.getDate();
// 当天零点
const start = new Date(year, month, day, 0, 0, 0);
// 当天23:59:59
const end = new Date(year, month, day, 23, 59, 59);
return [start, end];
};
const timeRange = ref(getCurrentMonthRange())
const sjTimeRange = ref()
const handleTimeRangeChange = () => {
getLzJcjPjdb()
}
const getTimeRange = () => {
getZdsj()
};
// 底部按钮
const changeBut = (row) => {
if (row.label == '清除') {
emitter.emit('deletePointArea', 'sj_flash')
emitter.emit('deletePointArea', 'jq_flash')
emitter.emit('deletePointArea', 'jq')
emitter.emit('deletePointArea', 'sj')
return
}
// 警情按钮点击时不改变onChage状态因为它需要显示popover
if (row.label == '警情') {
// 只执行获取警情数据的操作,不改变状态
getLzJcjPjdb()
return
}
if (row.label == '事件') {
getZdsj()
return
}
let index = butList.value.findIndex(item => item.label == row.label)
butList.value[index].onChage = !butList.value[index].onChage
if (index == 0) {
if (butList.value[index].onChage) {
getLzJcjPjdb()
} else {
jqdjdmFilter.value = [] // 清空选中的警情等级
emitter.emit("deletePointArea", "jq")
}
} else {
if (butList.value[index].onChage) {
getZdsj()
} else {
emitter.emit("deletePointArea", "sj")
}
}
}
// 格式化日期为YYYY-MM-DD HH:mm:ss格式
const formatDate = (date) => {
if (!date) return '';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
const seconds = String(date.getSeconds()).padStart(2, '0');
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
};
// 获取所有的一级警情
const getLzJcjPjdb = () => {
const jqdjdmStr = jqdjdmFilter.value.length > 0 ? jqdjdmFilter.value.join(',') : ''
emitter.emit("deletePointArea", "jq")
qcckGet({
jqdjdm: jqdjdmStr,
startTime: timeRange.value ? formatDate(timeRange.value[0]) : '',
endTime: timeRange.value ? formatDate(timeRange.value[1]) : '',
}, "/mosty-gsxt/lzJcjPjdb/selectList").then(res => {
let list = res.filter(item => item.fxdwjd && item.fxdwjd).map(item => {
return {
...item,
jd: item.fxdwjd,
wd: item.fxdwwd
}
}) || [];
const dw = require("@/assets/point/jq.png")
emitter.emit("addPoint", { coords: list, icon: dw, flag: "jq" });
})
}
const loading = ref(false)
const changeState = ref(true)// 点击切换
// 获取所有的重点事件
const getZdsj = () => {
qcckGet({
startTime: sjTimeRange.value ? sjTimeRange.value[0] : '',
endTime: sjTimeRange.value ? sjTimeRange.value[1] : '',
}, "/mosty-gsxt/zdsj/selectList").then(res => {
let list = res.filter(item => item.jd && item.wd).map(item => {
return {
...item,
}
}) || [];
const dw = require("@/assets/point/zl.png")
emitter.emit("addPoint", { coords: list, icon: dw, flag: "sj" });
})
}
// 分页查询一级警情
const jqList = ref([])
// 分页查询重点事件
const zdsjList = ref([])
// 警情等级多选
const checkAll = ref(false)
const isIndeterminate = ref(false)
const selectedJqdj = ref([])
// 全选/取消全选 - 点击全选按钮时触发
const handleCheckAllChange = (val) => {
if (val) {
// 全选:选中所有选项
selectedJqdj.value = D_BZ_JQDJ.value.map(item => item.dm)
} else {
// 取消全选:清空所有选项
selectedJqdj.value = []
}
isIndeterminate.value = false
promes.value.currentPage = 1
getList()
}
// 多选框变化 - 点击具体选项时触发
const handleCheckedChange = (value) => {
const checkedCount = value.length
const totalCount = D_BZ_JQDJ.value.length
// 只有当所有选项都选中时,全选按钮才为勾选状态
checkAll.value = checkedCount === totalCount
// 部分选中时显示半选状态
isIndeterminate.value = checkedCount > 0 && checkedCount < totalCount
promes.value.currentPage = 1
getList()
}
// 分页查询
const promes = ref({
currentPage: 1,
pageSize: 10,
jjdbh: ''
})
const getList = () => {
loading.value = true
if (changeState.value) {
// 将选中的警情等级转为字符串
const jqdjdmStr = selectedJqdj.value.length > 0 ? selectedJqdj.value.join(',') : ''
qcckGet({ ...promes.value, jqdjdm: jqdjdmStr }, "/mosty-gsxt/lzJcjPjdb/selectPage").then(res => {
jqList.value = promes.value.currentPage == 1 ? res.records : jqList.value.concat(res.records)
}).finally(() => {
loading.value = false
})
} else {
qcckGet({ ...promes.value, sjbt: promes.value.jjdbh }, "/mosty-gsxt/zdsj/selectPage").then(res => {
zdsjList.value = promes.value.currentPage == 1 ? res.records : zdsjList.value.concat(res.records)
}).finally(() => {
loading.value = false
})
}
}
// chooseShow 弹窗
const chooseShow = ref(false)
const changeChooseShow = (val) => {
chooseShow.value = true
}
// 滚动加载
const loadMore = () => {
if (loading.value) return
promes.value.currentPage++
getList()
}
// 搜索一级警情
const search = () => {
promes.value.currentPage = 1;
getList()
}
onMounted(() => {
emitter.on("coordString", coordStringHandler);
// 初始化选中所有警情等级
selectedJqdj.value = D_BZ_JQDJ.value.map(item => item.dm)
checkAll.value = false
getLzJcjPjdb()
getZdsj()
getList()
})
// 组件卸载时移除事件监听器
onUnmounted(() => {
emitter.off("coordString", coordStringHandler);
});
//点击
const updetDz = (row) => {
if (changeState.value) {
proxy.$confirm('是否进行定位?', "警告", { type: "warning" }
).then(() => {
rowData.value = row
emitter.emit("drawShape", {
flag: "jq",
type: "point",
isclear: true
});
})
} else {
proxy.$confirm('是否进行定位?', "警告", { type: "warning" }
).then(() => {
rowData.value = row
emitter.emit("drawShape", {
flag: "sj",
type: "point",
isclear: true
});
})
}
}
const clickJq = (row) => {
emitter.emit('deletePointArea', 'sj_flash')
emitter.emit('deletePointArea', 'jq_flash')
if (changeState.value) {
// 添加新的闪烁点位
emitter.emit('addPointArea', { flag: 'jq_flash', coords: [{ jd: row.fxdwjd, wd: row.fxdwwd }], flash: true, offset: [-1, 28] })
// 定位到该点
emitter.emit('setMapCenter', { location: [row.fxdwjd, row.fxdwwd], zoomLevel: 15 })
} else {
// 添加新的闪烁点位
emitter.emit('addPointArea', { flag: 'sj_flash', coords: [{ jd: row.jd, wd: row.wd }], flash: true, offset: [-1, 28] })
// 定位到该点
emitter.emit('setMapCenter', { location: [row.jd, row.wd], zoomLevel: 15 })
}
}
const listTitle = ref('一级警情')
const change = (row) => {
changeState.value = !changeState.value
listTitle.value = changeState.value ? '一级警情' : '重大事件'
getList()
}
const zbData = ref()
// 事件处理函数
const coordStringHandler = (res) => {
if (res.type === "point") {
if (chooseShow.value) {
zbData.value = res.coord
} else {
proxy.$confirm('确定定位吗?', "警告", { type: "warning" }
).then(() => {
if (changeState.value) {
qcckPost({
jjdbh: rowData.value.jjdbh,
fxdwjd: res.coord[0],
fxdwwd: res.coord[1],
}, "/mosty-gsxt/lzJcjPjdb/updateJqJwd").then(resData => {
// emitter.emit("addPoint", { coords: [{jd:res.coord[0],wd:res.coord[1]}], icon: require("@/assets/point/jq.png"), flag: "jq" });
proxy.$message({ type: "success", message: "定位成功" });
emitter.emit('deletePointArea', 'jq');
getLzJcjPjdb()
})
} else {
qcckPost({
id: rowData.value.id,
jd: res.coord[0],
wd: res.coord[1],
}, "/mosty-gsxt/zdsj/updateEntity").then(resData => {
proxy.$message({ type: "success", message: "定位成功" });
emitter.emit('deletePointArea', 'sj');
getZdsj()
})
}
})
}
}
};
</script>
<style lang="scss" scoped>
@import "@/assets/css/homeScreen.scss";
.qbfkBox {
width: 100%;
height: 100%;
background-color: #07274d;
}
.title {
font-size: 18px;
font-weight: bold;
color: #008efc;
display: flex;
align-items: center;
gap: 10px;
}
.close-button {
width: 40px;
height: 40px;
background-color: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
color: white;
font-size: 20px;
transition: all 0.3s ease;
&:hover {
background-color: rgba(255, 255, 255, 0.2);
border-color: rgba(255, 255, 255, 0.3);
transform: scale(1.1);
}
&:active {
transform: scale(0.95);
}
}
.map-container {
flex: 1;
width: 100%;
height: 100%;
position: relative;
animation: fadeIn 0.5s ease-out 0.2s both;
}
.list {
position: absolute;
top: 70px;
right: 20px;
width: 350px;
height: 600px;
background-color: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 5px;
// padding: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
background: #052249;
overflow: auto;
z-index: 3;
.titel {
background: url('~@/assets/images/bg17.png') no-repeat center center;
background-size: 100% 100%;
width: 100%;
height: 40px;
line-height: 40px;
font-size: 16px;
font-weight: bold;
color: white;
display: flex;
justify-content: space-between;
padding: 0 20px;
align-items: center;
.levelOneAlert {
margin-left: 20px;
}
.switchover {
font-size: 14px;
color: #ff6702;
font-weight: bold;
cursor: pointer;
}
}
.search {
padding: 10px;
display: flex;
flex-direction: column;
gap: 10px;
.jqdj-filter {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
color: white;
:deep(.el-checkbox) {
color: white;
margin-right: 10px;
}
:deep(.el-checkbox__label) {
color: white;
}
}
>div:last-child {
display: flex;
justify-content: space-between;
flex-wrap: nowrap;
}
.button-model {
margin-left: 10px;
}
}
.dataList {
height: calc(100% - 135px);
background-color: #052249;
overflow: auto;
padding: 5px 0;
.item {
background-color: #0a3a6e;
border-radius: 5px;
padding: 5px;
margin: 0 10px 5px;
}
.data-title {
color: white;
font-size: 14px;
line-height: 1.5;
padding: 2px 0;
}
.content {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
overflow: hidden;
text-overflow: ellipsis;
}
.data-row {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
.data-title {
// flex: 1;
}
}
}
}
.button-container {
// background-color: rgb(0, 0, 0);
position: absolute;
bottom: 20px;
width: 50%;
left: 50%;
transform: translateX(-50%);
z-index: 1;
display: flex;
justify-content: center;
.but {
width: 155px;
height: 33px;
background-image: url('~@/assets/images/home_btns_right.png');
background-size: cover;
background-repeat: no-repeat;
background-position: center;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 16px;
font-weight: bold;
}
.butOk {
width: 155px;
height: 33px;
background-image: url('~@/assets/images/home_btns_right_active.png');
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
}
.jqdj-popover {
padding: 10px;
.filter-item {
margin-bottom: 10px;
display: flex;
align-items: center;
flex-wrap: nowrap;
gap: 10px;
}
.filter-label {
white-space: nowrap;
color: #333;
font-size: 14px;
}
.checkbox-group {
display: flex;
flex-wrap: nowrap;
gap: 15px;
align-items: center;
}
:deep(.el-checkbox) {
margin-right: 0;
}
:deep(.el-checkbox__label) {
white-space: nowrap;
}
:deep(.el-date-editor) {
width: 200px;
}
}
.display-flex {
display: flex;
}
.imTyle {
display: flex;
align-items: center;
img {
margin-right: 4px;
}
}
// 动画效果
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>