This commit is contained in:
lcw
2026-01-28 11:18:47 +08:00
parent 57f1e2a1e5
commit c724ff9e12
78 changed files with 1001 additions and 745 deletions

View File

@ -219,6 +219,7 @@
import { ref, reactive, watch } from "vue";
import * as MOSTY from "@/components/MyComponents/index";
import { jczsavel, Xfbbupdate } from "@/api/mosty-jcz.js";
import { qcckGet } from "@/api/qcckApi";
import { ElMessage } from "element-plus";
import ChooseTable from "@/components/chooseList/chooseTable.vue";
import { timeValidate } from "@/utils/tools.js";
@ -253,8 +254,18 @@ let pageType = ref("add");
const mjData = ref([]);
const fjData = ref([]);
const isDetail=ref(false)
//
const getjyqx = () => {
qcckGet({}, "/mosty-jcz/tpJczJyqx/getJyqxList").then((res) => {
console.log(res);
listQuery.value.qxList = res;
});
}
// 初始化数据
const init = (type, row) => {
getjyqx()
pageType.value = type;
dialogForm.value = true;
// 根据type和row初始化表单数据

View File

@ -3,116 +3,30 @@
<div class="head_box">
<span class="title">{{ pageInfo[pageType].title }}</span>
<div>
<el-button
size="small"
type="primary"
v-if="['add', 'edit'].includes(pageType)"
@click="_onSave"
>保存</el-button
>
<el-button size="small" type="primary" v-if="['add', 'edit'].includes(pageType)" @click="_onSave">保存</el-button>
<el-button size="small" @click="close">关闭</el-button>
</div>
</div>
<div class="cntinfo">
<el-form ref="elform" :model="form" :inline="true" label-position="top">
<el-form-item prop="ssbmdm" label="预警类型" style="width: 40%">
<el-select
clearable
disabled
v-model="listQuery.yjLx"
placeholder="请选择"
style="width: 100%"
>
<el-option
v-for="(item, index) in dict.D_BZ_YJLX"
:key="index"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="感知源名称" style="width: 40%">
<el-input
v-model="listQuery.yjGzymc"
placeholder="感知源名称"
clearable
disabled
style="width: 100%"
/>
</el-form-item>
<el-form-item prop="scode" label="预警发生时间" style="width: 40%">
<el-date-picker
v-model="listQuery.yjSj"
type="datetime"
placeholder="请选中开始时间"
format="YYYY-MM-DD hh:mm:ss"
disabled
value-format="YYYY-MM-DD hh:mm:ss"
/>
</el-form-item>
<el-form-item prop="sbmc" label="预警对象" style="width: 40%">
<el-input
v-model="DX"
placeholder="请输入装备名称"
clearable
disabled
style="width: 100%"
/>
</el-form-item>
<el-form-item label="预警地址" style="width: 40%">
<el-input
v-model="listQuery.yjDz"
placeholder="请输入预警地址"
disabled
clearable
style="width: 100%"
/>
</el-form-item>
<el-form-item label="预警级别" style="width: 40%">
<el-select
clearable
disabled
v-model="listQuery.yjJb"
placeholder="请选择"
style="width: 100%"
>
<el-option
v-for="(item, index) in dict.D_BZ_YJJB"
:key="index"
:label="item.label"
:value="item.value"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="预警内容" style="width: 100%">
<el-input
v-model="listQuery.yjNr"
disabled
placeholder="请输入关键字"
show-word-limit
type="textarea"
/>
</el-form-item>
<el-form-item label="预警图片">
<el-image
:preview-src-list="[listQuery.yjTp]"
fit="cover"
style="width: 100px; height: 100px"
:src="listQuery.yjTp"
></el-image>
</el-form-item>
</el-form>
<FormMessage :disabled="true" v-model="listQuery" :formList="formData" ref="elform" :rules="rules" position="top">
<template #yjRyxm="{ row }">
<el-input v-if="listQuery.yjLx == '1'" v-model="listQuery.yjRyxm" placeholder="请输入预警接收人姓名" clearable
style="width: 100%" />
<el-input v-else v-model="listQuery.yjClcph" placeholder="请输入预警接收人手机号" clearable style="width: 100%" />
</template>
<template #yjTp="{ row }">
<el-image :preview-src-list="[listQuery.yjTp]" fit="cover" style="width: 100px; height: 100px"
:src="listQuery.yjTp"></el-image>
</template>
</FormMessage>
</div>
</div>
</template>
<script setup>
import { ref, reactive, onMounted } from "vue";
import { ref, reactive, onMounted, watch } from "vue";
import * as MOSTY from "@/components/MyComponents/index";
import FormMessage from "@/components/aboutTable/FormMessage.vue";
import { TcsbsaveTcsbsave, Tcsbupdate } from "@/api/mosty-jcz.js";
import { Right, Back } from "@element-plus/icons-vue";
import { baseselectPage } from "@/api/mosty-base";
@ -120,7 +34,7 @@ import { ElMessage } from "element-plus";
const props = defineProps({
dict: {
type: Object,
default: () => {}
default: () => { }
}
});
@ -147,14 +61,12 @@ const propsTree = ref({
multiple: false
});
// 初始化数据
const DX = ref();
const init = (type, row) => {
pageType.value = type;
dialogForm.value = true;
// 根据type和row初始化表单数据
tabHeightFn();
if (type == "edit" || type == "detail") {
DX.value = row.yjRyxm ? row.yjRyxm : row.yjClcph;
listQuery.value = { ...row };
} else {
listQuery.value = {};
@ -165,8 +77,26 @@ const init = (type, row) => {
const close = () => {
dialogForm.value = false;
listQuery.value = {};
DX.value = "";
};
const formData = ref()
watch(() => props.dict, (newVal, oldVal) => {
if (newVal) {
formData.value = [
{ label: "预警类型", prop: "yjLx", type: "select", options: props.dict.D_BZ_YJLX, width: '45%' },
{ label: "感知源名称", prop: "yjGzymc", type: "input", width: '45%' },
{ label: "请选中开始时间", prop: "yjSj", type: "datetime", width: '45%' },
{ label: "预警对象", prop: "yjRyxm", type: "slot", width: '45%' },
{ label: "预警标签", prop: "yjbqmc", type: "input", width: '45%' },
{ label: "所属部门", prop: "ssbm", type: "input", width: '45%' },
{ label: "预警地址", prop: "yjDz", type: "input", width: '45%' },
{ label: "预警级别", prop: "yjJb", type: "select", options: props.dict.D_BZ_YJJB, width: '45%' },
{ label: "预警内容", prop: "yjNr", type: "textarea", width: '100%' },
{ label: "预警图片", prop: "yjTp", type: "slot", width: '100%' }
]
}
});
// 表格高度计算
const tableHeight1 = ref();
const tabHeightFn = () => {
@ -179,21 +109,25 @@ defineExpose({ init });
<style lang="scss" scoped>
.dialog {
padding: 20px;
.head_box {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.cntinfo {
height: calc(100% - 70px);
overflow: hidden;
overflow-y: auto;
}
}
.my_transfer {
height: calc(100% - 50px);
display: flex;
.btn {
width: 50px;
display: flex;
@ -201,53 +135,65 @@ defineExpose({ init });
justify-content: center;
margin: 0 10px;
}
.left {
margin: 12px;
flex: 1;
position: relative;
.tableBox {
position: absolute;
width: 100%;
}
.serch {
position: relative;
width: 100%;
// height: 96px;
> .el-form--inline {
>.el-form--inline {
display: block;
width: 100%;
padding: 0;
> .el-form-item--default {
>.el-form-item--default {
width: 31%;
}
}
}
.tableBox {
width: 100%;
}
}
.right {
width: 380px;
margin: 12px;
}
}
.phone {
width: 95px;
height: 120px;
.el-image {
width: 95px;
max-height: 120px;
}
}
::v-deep .el-upload {
width: 90px;
height: 100px;
border: 1px dashed #e0e0e0;
margin-bottom: 14px;
.el-icon {
margin-top: 34px;
font-size: 26px;
}
.el-image {
width: 100%;
height: 100%;

View File

@ -8,15 +8,9 @@
<Search :searchArr="searchConfiger" @submit="onSearch" />
</div>
<div class="tabBox">
<MyTable
:tableData="pageData.tableData"
:tableColumn="pageData.tableColumn"
:tableHeight="pageData.tableHeight"
:key="pageData.keyCount"
:tableConfiger="pageData.tableConfiger"
:controlsWidth="pageData.controlsWidth"
@chooseData="chooseData"
>
<MyTable :tableData="pageData.tableData" :tableColumn="pageData.tableColumn" :tableHeight="pageData.tableHeight"
:key="pageData.keyCount" :tableConfiger="pageData.tableConfiger" :controlsWidth="pageData.controlsWidth"
@chooseData="chooseData">
<template #yjTp="{ row }">
<div class="phone">
<el-image v-if="row.tp" :src="urlImg + row.yjTp" fit="cover" lazy />
@ -32,15 +26,10 @@
<el-link type="primary" @click="addEdit('detail', row)">详情</el-link>
</template>
</MyTable>
<Pages
@changeNo="changeNo"
@changeSize="changeSize"
:tableHeight="pageData.tableHeight"
:pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"
></Pages>
<Pages @changeNo="changeNo" @changeSize="changeSize" :tableHeight="pageData.tableHeight" :pageConfiger="{
...pageData.pageConfiger,
total: pageData.total
}"></Pages>
</div>
<!-- 编辑详情 -->
<!-- 编辑详情 -->
@ -54,11 +43,12 @@ import MyTable from "@/components/aboutTable/MyTable.vue";
import Pages from "@/components/aboutTable/Pages.vue";
import EditAddForm from "./components/editAddForm.vue";
import Search from "@/components/aboutTable/Search.vue";
import { jczgetPageList } from "@/api/mosty-jcz.js";
import { jczgetPageList, selectJczFullList } from "@/api/mosty-jcz.js";
import { reactive, ref, onMounted, getCurrentInstance, watch } from "vue";
const { proxy } = getCurrentInstance();
const urlImg = "/mosty-api/mosty-base/minio/image/download/";
const { D_BZ_YJLX, D_BZ_YJJB } = proxy.$dict("D_BZ_YJLX", "D_BZ_YJJB");
const jczList = ref()
const searchConfiger = ref([
{
label: "预警类型",
@ -66,6 +56,12 @@ const searchConfiger = ref([
placeholder: "预警类型",
showType: "select",
options: D_BZ_YJLX
}, {
label: "所属检查站",
prop: "jczid",
placeholder: "所属检查站",
showType: "select",
options: {}
},
{
label: "发生时间",
@ -73,12 +69,6 @@ const searchConfiger = ref([
placeholder: "发生时间",
showType: "datetimerange"
}
// {
// label: "预警对象",
// prop: "yjLx",
// placeholder: "请输入预警对象",
// showType: "input"
// }
]);
const detailDiloag = ref();
@ -107,6 +97,8 @@ const pageData = reactive({
});
onMounted(() => {
tabHeightFn();
getselectJczFullList()
});
//查询条件
@ -124,17 +116,34 @@ const getjczgetXfllList = () => {
pageData.tableConfiger.loading = false;
});
};
// 获取检查站数据
const getselectJczFullList = () => {
selectJczFullList().then((res) => {
console.log(res);
jczList.value = res.map(item => ({
label: item.jczmc,
value: item.id
}))
searchConfiger.value[1].options = jczList.value
})
}
getjczgetXfllList();
// 搜索
const onSearch = (val) => {
console.log(val);
const startTime = {
startTime : val.startTime[0],
endTime : val.startTime[1]
...val,
startTime: val.startTime ? val.startTime[0] : "",
endTime: val.startTime ? val.startTime[1] : ""
}
queryCondition.value = { ...queryCondition.value,...startTime};
queryCondition.value = { ...queryCondition.value, ...startTime };
getjczgetXfllList();
};

View File

@ -1,13 +1,19 @@
<template>
<div class="mian_box">
<div class="item" v-for="item in dataList" :key="item">{{ item.zdmc }}:<span
@click="openDialog(item.dm)">{{ item.num }}</span></div>
<div class="item" v-for="item in dataList" :key="item">
<img :src="item.img" alt="" class="item-img" />
<div class="item-content">
<div class="item-title">{{ item.zdmc }}</div>
<div @click="openDialog(item.dm)" class="item-num">{{ item.num }}</div>
</div>
</div>
</div>
<pointList v-model="pointListShow" :lxType="lxType" />
</template>
<script setup>
import pointList from "./pointList.vue";
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
import { divide } from "lodash";
import { ref, onMounted, reactive } from "vue";
const lxType = ref();
const pointListShow = ref(false);
@ -23,9 +29,37 @@ const openDialog = (val) => {
onMounted(() => {
getTotal()
})
const dataContent = [
{
key: '临时交通卡点',
img: require('@/assets/images/lsjt.png'),
},
{
key: '智能抓拍',
img: require('@/assets/images/znzp.png'),
},
{
key: '公安检查站',
img: require('@/assets/images/jc.png'),
}, {
key: '临时治安卡点',
img: require('@/assets/images/lsza.png'),
},
]
const getTotal = () => {
qcckGet({}, "/mosty-jcz/jcztj/jczZqlxtj").then(res => {
dataList.value = res;
dataList.value = res.map(item => {
const content = dataContent.findIndex(items => items.key == item.zdmc)
return {
...item,
img: dataContent[content].img
}
});
console.log(dataList.value);
})
}
</script>
@ -37,5 +71,35 @@ const getTotal = () => {
color: #fff;
align-items: center;
height: 100%;
flex-wrap: wrap;
width: 90%;
margin: auto;
.item {
cursor: pointer;
display: flex;
align-items: center;
width: 50%;
}
.item-img {
width: 50px;
height: 50px;
margin-right: 10px;
}
.item-content {
flex: 1;
}
.item-title {
text-align: center;
font-size: 14px;
}
.item-num {
text-align: center;
color: #00f0ff;
cursor: pointer;
}
}
</style>

View File

@ -2,234 +2,56 @@
<div class="warning-analysis">
<div class="chart-section">
<h2 class="section-title">人员预警分析</h2>
<div ref="vehicleChartRef" class="chart-container"></div>
<BaseChart :data="vehicleData" :total="vehicleTotal" />
</div>
<div class="chart-section">
<h2 class="section-title">车辆预警分析</h2>
<div ref="personChartRef" class="chart-container"></div>
<BaseChart :data="personData" :total="personTotal" />
</div>
</div>
</template>
<script setup>
import { choseRbgb } from "@/utils/tools";
import { ref, onMounted, onUnmounted } from "vue";
import { jczgetYjbqtj } from "@/api/mosty-jcz";
import * as echarts from "echarts";
import { ref, onMounted } from "vue";
import BaseChart from "@/components/BaseChart.vue";
import { useWarningData } from "@/composables/useWarningData";
const vehicleChartRef = ref(null);
const personChartRef = ref(null);
let vehicleChart = null;
let personChart = null;
const createChartOption = (data, colors, total) => {
return {
title: {
text: `${total}`,
subtext: "总数",
left: "center",
top: "center", //top待调整
textStyle: {
color: "#fff",
fontSize: 24,
fontWeight: "normal"
},
subtextStyle: {
color: "#fff",
fontSize: 14
}
},
tooltip: {
trigger: "item"
},
legend: {
orient: "horizontal",
top: 0,
bottom: "50px",
textStyle: {
color: "#fff",
rich: {
value: {
color: "#fff"
},
percentage: {
padding: [0, 0, 0, 10]
},
blue: {
color: colors[0]
},
lightBlue: {
color: colors[1]
},
orange: {
color: colors[2]
},
green: {
color: colors[3]
}
}
},
formatter: (name) => {
const item = data.find((d) => d.name === name);
return `${name} ${item.value}`;
}
},
series: [
{
type: "pie",
radius: ["55%", "70%"],
center: ["50%", "55%"],
data: data.map((item) => ({
...item,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: item.color[0] },
{ offset: 1, color: item.color[1] }
])
}
})),
label: {
show: false
},
emphasis: {
scale: false,
focus: "none"
},
z: 2
},
{
type: "pie",
radius: ["65%", "85%"],
center: ["50%", "55%"],
data: data.map((item) => ({
...item,
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{ offset: 0, color: item.color1[0] },
{ offset: 1, color: item.color1[1] }
])
}
})),
label: {
show: false
},
emphasis: {
scale: false,
focus: "none"
},
z: 1,
silent: true
}
]
};
};
const randomHexColor = () => {
return "#" + Math.floor(Math.random() * 16777215).toString(16);
};
const { getVehicleWarningData, getPersonWarningData } = useWarningData();
const initCharts = async () => {
let clTotal = 0;
let ryTotal = 0;
vehicleChart = echarts.init(vehicleChartRef.value);
personChart = echarts.init(personChartRef.value);
const colors = ["#00f0ff", "#0066ff", "#ff9900", "#00cc66"];
// 车辆预警数据
const res = await jczgetYjbqtj({ yjLx: 1 });
const res2 = await jczgetYjbqtj({ yjLx: 2 });
clTotal = res2
.map((el) => el.sl)
.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
ryTotal = res
.map((el) => el.sl)
.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
const vehicleData = ref([]);
const vehicleTotal = ref(0);
const personData = ref([]);
const personTotal = ref(0);
const vehicleData = res.map((item) => {
const color = randomHexColor();
const color2 = randomHexColor();
return {
value: item.sl,
name: item.yjbq,
// colorType: color,
color: [color, color2],
color1: [choseRbgb(color, 0.3), choseRbgb(color2, 0.3)]
};
});
const initData = async () => {
const vehicleResult = await getVehicleWarningData();
vehicleData.value = vehicleResult.processedData;
vehicleTotal.value = vehicleResult.total;
// 人员预警数据
const personData = res2.map((item) => {
const color = randomHexColor();
const color2 = randomHexColor();
return {
value: item.sl,
name: item.yjbq,
// colorType: color,
color: [color, color2],
color1: [choseRbgb(color, 0.3), choseRbgb(color2, 0.3)]
};
});
// [
// {
// value: 25,
// name: "涉稳人员",
// colorType: "blue",
// color: ["#00f0ff", "#00a0cc"],
// color1: [choseRbgb("#00f0ff", 0.3), choseRbgb("#00a0cc", 0.3)]
// },
// {
// value: 30,
// name: "涉毒人员",
// colorType: "lightBlue",
// color: ["#0066ff", "#0044cc"],
// color1: [choseRbgb("#0066ff", 0.3), choseRbgb("#0044cc", 0.3)]
// },
// {
// value: 17,
// name: "涉黄人员",
// colorType: "orange",
// color: ["#ff9900", "#cc7a00"],
// color1: [choseRbgb("#ff9900", 0.3), choseRbgb("#cc7a00", 0.3)]
// },
// {
// value: 28,
// name: "前科人员",
// colorType: "green",
// color: ["#00cc66", "#009944"],
// color1: [choseRbgb("#00cc66", 0.3), choseRbgb("#009944", 0.3)]
// }
// ];
vehicleChart.setOption(createChartOption(vehicleData, colors, ryTotal));
personChart.setOption(createChartOption(personData, colors, clTotal));
};
const handleResize = () => {
vehicleChart?.resize();
personChart?.resize();
const personResult = await getPersonWarningData();
personData.value = personResult.processedData;
personTotal.value = personResult.total;
};
onMounted(() => {
initCharts();
window.addEventListener("resize", handleResize);
});
onUnmounted(() => {
window.removeEventListener("resize", handleResize);
vehicleChart?.dispose();
personChart?.dispose();
initData();
});
</script>
<style scoped lang="scss">
.warning-analysis {
padding: 20px;
// padding: 20px;
height: 100%;
}
.chart-section {
height: 50%;
height: 40%;
margin-bottom: 20px;
}
.section-title {
font-size: 18px;
// margin-bottom: 20px;
margin-bottom: 10px;
position: relative;
padding-left: 12px;
background: linear-gradient(0deg, #59a6f4 0%, #ffffff 90%);
@ -248,9 +70,4 @@ onUnmounted(() => {
background: url("~@/assets/images/bg_02.png");
background-size: 100% 100%;
}
.chart-container {
height: calc(100% - 40px);
width: 100%;
}
</style>

View File

@ -266,6 +266,7 @@ const getMapData = () => {
// background: url("~@/assets/images/border_L_T.png") no-repeat center center;
background-size: 100% 100%;
}
}
// 右边
@ -275,13 +276,13 @@ const getMapData = () => {
box-sizing: border-box;
.asideL-top {
height: 20%;
height: 25%;
background: url("~@/assets/images/border_R_T.png") no-repeat center center;
background-size: 100% 100%;
}
.asideL-bottom {
height: 60%;
height: 50%;
background: url("~@/assets/images/border_R_B.png") no-repeat center center;
background-size: 100% 100%;
}

View File

@ -203,10 +203,10 @@
<div class="btItem">警用器械</div>
<div class="info">
<el-form-item>
<div v-for="(item, index) in listQuery.qxList" :key="index" style="width: 50%; margin-bottom: 10px">
<div class="flex">
<div style="width: 30%">{{ item.qxmc }}</div>
<el-input-number v-model="item.qxsl" :step="1" />
<div v-for="(item, index) in listQuery.qxList" :key="index" class="qx-item">
<div class="flex align-center qx-item-inner">
<div class="qx-name">{{ item.qxmc }}</div>
<el-input-number v-model="item.qxsl" :step="1" class="qx-input" />
</div>
</div>
</el-form-item>
@ -222,6 +222,7 @@ import { ref, reactive, getCurrentInstance, onMounted, watch } from "vue";
import * as MOSTY from "@/components/MyComponents/index";
import { jczqueryById } from "@/api/mosty-jcz";
import { jczsavel, Xfbbupdate } from "@/api/mosty-jcz.js";
import { qcckGet } from "@/api/qcckApi";
import { ElMessage } from "element-plus";
import ChooseTable from "@/components/chooseList/chooseTable.vue";
import ChoosePersonnel from "@/components/chooseList/choosePersonnel.vue";
@ -288,32 +289,39 @@ const fz = (val) => {
});
return data;
};
const getjyqx = () => {
qcckGet({
pageSize: 1000,
pageCurrent: 1
}, "/mosty-jcz/tpJczJyqx/getJyqxList").then((res) => {
listQuery.value.qxList = res.records.map((item) => {
return {
qxmc: item.qxMc,
qxsl: 0
}
}) || []
init();
});
}
// 初始化数据
const init = (type) => {
pageType.value = type == undefined || type == 'add' ? "add" : "detail";
console.log(type);
dialogForm.value = true;
// 根据type和row初始化表单数据
if (props.row) {
if (props.row.data) {
pageType.value = "detail"
listQuery.value = { ...props.row };
if (props.row.ryList && props.row.ryList.length > 0) {
const data = fz(props.row.ryList);
mjData.value = data.filter((item) => item.fl == "01");
fjData.value = data.filter((item) => item.fl == "02");
}
if (listQuery.value.qxList && listQuery.value.qxList.length == 0) {
listQuery.value.qxList = props.dic.D_BZ_JYQXFL.map((item) => {
return { qxmc: item.label, qxsl: 0 };
});
}
} else {
pageType.value = "add";
listQuery.value.qxList = props.dic.D_BZ_JYQXFL.map((item) => {
return { qxmc: item.label, qxsl: 0 };
});
}
};
watch(
() => props.row,
@ -324,7 +332,7 @@ watch(
);
const routerList = ref({})
onMounted(() => {
init();
getjyqx()
routerList.value = route.query
});
// 验证规则
@ -521,6 +529,7 @@ const chooseDataGzy = (val) => {
margin-top: 1px;
padding: 10px;
box-sizing: border-box;
width: 100%;
.gapline {
height: 1px;
@ -585,6 +594,27 @@ const chooseDataGzy = (val) => {
padding-left: 100px;
box-sizing: border-box;
}
.qx-item {
width: 50%;
margin-bottom: 10px;
}
.qx-item-inner {
justify-content: space-between;
}
.qx-name {
min-width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.qx-input {
flex: 1;
min-width: 100px;
}
}
::v-deep .el-form-item--default {