预警分析
This commit is contained in:
@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div style="height: 100%; width: 100%" :id="echartsId"></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import {
|
||||
onMounted,
|
||||
ref,
|
||||
reactive,
|
||||
defineProps,
|
||||
onUnmounted,
|
||||
watch,
|
||||
nextTick
|
||||
} from "vue";
|
||||
const props = defineProps({
|
||||
echartsId: {
|
||||
type: String,
|
||||
default: "lineId"
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "#fff"
|
||||
},
|
||||
data: {
|
||||
type: Object,
|
||||
default: {}
|
||||
}
|
||||
});
|
||||
|
||||
function chartFn() {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
var option = {
|
||||
legend: {
|
||||
data: ['出城车辆', '入城车辆'],
|
||||
textStyle: { color: "#fff" },
|
||||
},
|
||||
grid: {
|
||||
top: "10%",
|
||||
right: "0",
|
||||
left: "0",
|
||||
bottom: "10%",
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "axis",
|
||||
axisPointer: {
|
||||
lineStyle: {
|
||||
color: "#ddd"
|
||||
}
|
||||
},
|
||||
backgroundColor: "rgba(255,255,255,1)",
|
||||
padding: [5, 10],
|
||||
textStyle: {
|
||||
color: "#7588E4"
|
||||
},
|
||||
extraCssText: "box-shadow: 0 0 5px rgba(0,0,0,0.3)"
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
boundaryGap: false,
|
||||
data: props.data.rzcl.map((el) => el.time)
|
||||
},
|
||||
yAxis: {
|
||||
type: "value"
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: "出城车辆",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
smooth: true,
|
||||
data: props.data.rzcl.map((el) => el.num)
|
||||
},
|
||||
{
|
||||
name: "入城车辆",
|
||||
type: "line",
|
||||
stack: "Total",
|
||||
smooth: true,
|
||||
data: props.data.czcl.map((el) => el.num)
|
||||
},
|
||||
]
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.addEventListener("resize", function () {
|
||||
myChart.resize();
|
||||
});
|
||||
}
|
||||
onMounted(() => {
|
||||
// chartFn();
|
||||
});
|
||||
watch(() => props.data, (val) => {
|
||||
if (val) {
|
||||
chartFn();
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div style="height: 100%; width: 100%" :id="echartsId"></div>
|
||||
</template>
|
||||
<script setup>
|
||||
import * as echarts from "echarts";
|
||||
import {
|
||||
onMounted,
|
||||
ref,
|
||||
reactive,
|
||||
defineProps,
|
||||
onUnmounted,
|
||||
watch,
|
||||
nextTick
|
||||
} from "vue";
|
||||
const props = defineProps({
|
||||
echartsId: {
|
||||
type: String,
|
||||
default: "pieId"
|
||||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "#fff"
|
||||
},
|
||||
data: {
|
||||
type: Array,
|
||||
default: []
|
||||
}
|
||||
});
|
||||
|
||||
function chartFn() {
|
||||
var myChart = echarts.init(document.getElementById(props.echartsId));
|
||||
var option = {
|
||||
legend: {
|
||||
bottom: '5%',
|
||||
left: 'center',
|
||||
textStyle: { color: "#fff" },
|
||||
},
|
||||
grid: {
|
||||
top: "0",
|
||||
right: "0",
|
||||
left: "0",
|
||||
bottom: "12%",
|
||||
containLabel: true
|
||||
},
|
||||
tooltip: {
|
||||
trigger: "item",
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '',
|
||||
type: 'pie',
|
||||
radius: ['40%', '70%'],
|
||||
avoidLabelOverlap: false,
|
||||
label: {
|
||||
show: false,
|
||||
position: 'center'
|
||||
},
|
||||
labelLine: {
|
||||
show: false
|
||||
},
|
||||
data: props.data
|
||||
}
|
||||
]
|
||||
};
|
||||
option && myChart.setOption(option);
|
||||
window.addEventListener("resize", function () {
|
||||
myChart.resize();
|
||||
});
|
||||
}
|
||||
onMounted(() => {
|
||||
// chartFn();
|
||||
});
|
||||
watch(() => props.data, (val) => {
|
||||
if (val) {
|
||||
chartFn();
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped></style>
|
||||
@ -0,0 +1,359 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="dashboard-container">
|
||||
<!-- 顶部数据卡片区域 -->
|
||||
<div class="top-cards">
|
||||
<el-card class="card-item" v-for="item in topData" :key="item">
|
||||
<div class="card-title">{{ item.bt }}</div>
|
||||
<div class="card-value">{{ item.num }}</div>
|
||||
<div class="card-desc">{{ item.nr }}</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 中间图表+数据区域 -->
|
||||
<div class="middle-section">
|
||||
<!-- 左侧:车流量折线图 -->
|
||||
<el-card class="section-item">
|
||||
<div class="section-title flex just-between align-center">
|
||||
<div>进出镇区主干道卡口数据监测</div>
|
||||
<!-- <el-select v-model="value" placeholder="请选择" style="width: 240px">
|
||||
<el-option label="今日数量" value="0" />
|
||||
</el-select> -->
|
||||
</div>
|
||||
<LineEchart :data="clData" style="height: 200px" />
|
||||
<div class="traffic-footer">
|
||||
<div>入镇口:{{ clData.rck }}</div>
|
||||
<div>出镇口:{{ clData.cck }}</div>
|
||||
<div>重点卡口:{{ clData.zdkk }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
|
||||
<!-- 右侧:人口结构环形图 -->
|
||||
<el-card class="section-item">
|
||||
<div class="section-title">入镇人员分析模型-人口数据统计</div>
|
||||
<PieEcharts style="height: 210px" :data="yjfxData" />
|
||||
<div class="population-footer">
|
||||
<div v-for="item in yjfxData" :key="item">{{ item.bt }}:{{ item.num }} ({{ item.bfb }}%)</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
|
||||
<!-- 底部数据+地图区域 -->
|
||||
<div class="bottom-section">
|
||||
<!-- 左侧:预警人员表格 -->
|
||||
<el-card class="section-item_small">
|
||||
<div class="section-title">人员数据比对分析-预警人员信息</div>
|
||||
<el-row>
|
||||
<el-col :span="2">
|
||||
<div>#</div>
|
||||
</el-col>
|
||||
<el-col :span="10">人员信息</el-col>
|
||||
<el-col :span="8">预警类型</el-col>
|
||||
<el-col :span="4">风险等级</el-col>
|
||||
</el-row>
|
||||
<el-row v-for="(el, index) in tableData" :key="el.id">
|
||||
<el-col :span="2">
|
||||
<div>{{ index + 1 }}</div>
|
||||
</el-col>
|
||||
<el-col :span="10"> {{ el.yjRyxm }} </el-col>
|
||||
<el-col :span="8"> <dict-tag :options="D_BZ_YJLX" :value="el.yjLx" :tag="false" /> </el-col>
|
||||
<el-col :span="4" style="text-align: center;"> <dict-tag :options="D_BZ_YJJB" :value="el.yjJb"
|
||||
:tag="false" /> </el-col>
|
||||
</el-row>
|
||||
<el-button type="primary" style="width: 100%; margin-top: 10px">查看全部预警人员(63人)</el-button>
|
||||
</el-card>
|
||||
|
||||
<!-- 右侧:地图+监控说明 -->
|
||||
<el-card class="section-item map-card">
|
||||
<div class="section-title flex just-between align-center">
|
||||
<div>预警人员轨迹追踪系统-多源数据联动</div>
|
||||
<div class="flex">
|
||||
<el-input readonly @click="chooseUserVisible = true" v-model="listQuery.yjRyxm" placeholder="请选择预警人员"
|
||||
clearable />
|
||||
<!-- <el-button type="primary">轨迹跟踪</el-button> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="map-container">
|
||||
<div class="mapbox">
|
||||
<GdMap />
|
||||
</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ChooseYjUser v-model="chooseUserVisible" @choosedUsers="saveUsers" :Single="true"></ChooseYjUser>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import GdMap from "@/components/GdMap/index.vue";
|
||||
import { qcckGet, qcckPost } from "@/api/qcckApi.js";
|
||||
import ChooseYjUser from "@/components/MyComponents/ChooseYjUser";
|
||||
import LineEchart from "./components/lineEcharts.vue";
|
||||
import PieEcharts from "./components/pieEcharts.vue";
|
||||
import { reactive, ref, onMounted, getCurrentInstance } from "vue";
|
||||
const { proxy } = getCurrentInstance();
|
||||
const { D_BZ_YJLX, D_BZ_YJJB } = proxy.$dict("D_BZ_YJLX", "D_BZ_YJJB");
|
||||
// 预警人员列表数据
|
||||
const listQuery = ref({
|
||||
pageCurrent: 1,
|
||||
pageSize: 10
|
||||
});
|
||||
const topData = ref([]);
|
||||
const clData = ref({});
|
||||
const yjfxData = ref(null);
|
||||
const value = ref();
|
||||
const chooseUserVisible = ref(false);
|
||||
const tableData = ref([]);
|
||||
onMounted(() => {
|
||||
Promise.all([getTopTj(), getclTj(), getYjfxTj(), getListData()]);
|
||||
});
|
||||
//查询条件
|
||||
const queryCondition = ref({});
|
||||
// 统计
|
||||
const getTopTj = () => {
|
||||
qcckGet({}, "/mosty-jcz/kktj/getKkgkfx").then((res) => {
|
||||
topData.value = res;
|
||||
});
|
||||
};
|
||||
|
||||
const getclTj = () => {
|
||||
qcckGet({}, "/mosty-jcz/kktj/getClkksjtj")
|
||||
.then((res) => {
|
||||
clData.value = res;
|
||||
})
|
||||
};
|
||||
const getYjfxTj = () => {
|
||||
qcckGet({}, "/mosty-jcz/kktj/getRjryfxmx")
|
||||
.then((res) => {
|
||||
yjfxData.value = res.map((el) => {
|
||||
return { value: el.num, name: el.bt, ...el }
|
||||
});
|
||||
})
|
||||
};
|
||||
const getListData = () => {
|
||||
qcckPost(listQuery.value, '/mosty-jcz/tbJczYjxx/getPageList').then((res) => {
|
||||
tableData.value =
|
||||
listQuery.value.pageCurrent == 1
|
||||
? res.records
|
||||
: tableData.value.concat(res.records);
|
||||
});
|
||||
};
|
||||
const columnInfo = (val) => {
|
||||
// 过站类型(01 入林 02 出林) 01 入林 02 出林
|
||||
dialogSearch.value.kkId = val.row.kkId;
|
||||
switch (val.column.property) {
|
||||
case "gzryNum":
|
||||
dialogSearch.value.gzlx = "";
|
||||
showGjry.value = true;
|
||||
break;
|
||||
case "rlclNum":
|
||||
dialogSearch.value.gzlx = "01";
|
||||
showGjry.value = true;
|
||||
break;
|
||||
case "clryNum":
|
||||
dialogSearch.value.gzlx = "02";
|
||||
showGjry.value = true;
|
||||
break;
|
||||
case "gzclNum":
|
||||
dialogSearch.value.gzlx = "";
|
||||
showGjcl.value = true;
|
||||
break;
|
||||
case "rlclNum":
|
||||
dialogSearch.value.gzlx = "01";
|
||||
showGjcl.value = true;
|
||||
break;
|
||||
case "clclNum":
|
||||
dialogSearch.value.gzlx = "02";
|
||||
showGjcl.value = true;
|
||||
break;
|
||||
case "gzwpNum":
|
||||
dialogSearch.value.gzlx = "";
|
||||
showGjwp.value = true;
|
||||
break;
|
||||
case "rlwpNum":
|
||||
dialogSearch.value.gzlx = "01";
|
||||
showGjwp.value = true;
|
||||
break;
|
||||
case "clwpNum":
|
||||
dialogSearch.value.gzlx = "02";
|
||||
showGjwp.value = true;
|
||||
break;
|
||||
}
|
||||
};
|
||||
//选择预警人员
|
||||
const saveUsers = (users) => {
|
||||
listQuery.value.yjRyxm = users[0].yjRyxm;
|
||||
listQuery.value.yjRysfzh = users[0].yjRysfzh;
|
||||
qcckPost({ yjRysfzh: listQuery.value.yjRysfzh }, '/mosty-jcz/tbJczYjxx/getPageList').then((res) => {
|
||||
let list = res.records.filter((item) => {
|
||||
return item.jd && item.wd
|
||||
})
|
||||
emitter.emit("echoPlane", {
|
||||
fontColor: "#12fdb8",
|
||||
coords: list,
|
||||
type: "line",
|
||||
flag: "yjry_gj",
|
||||
color: "rgba(2,20,51,0.5)",
|
||||
linecolor: "#1C97FF"
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dashboard-container {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 顶部卡片 */
|
||||
.top-cards {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.card-item {
|
||||
flex: 1;
|
||||
background-color: #1e1e30;
|
||||
border: none;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.card-item.warning {
|
||||
border: 1px solid #f56c6c;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 14px;
|
||||
color: #ccc;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card-desc {
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
/* 中间区域 */
|
||||
.middle-section {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
margin-bottom: 10px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.section-item {
|
||||
flex: 1;
|
||||
background-color: #1e1e30;
|
||||
border: none;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.section-item_small {
|
||||
width: 33%;
|
||||
background-color: #1e1e30;
|
||||
border: none;
|
||||
color: #fff;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
margin-bottom: 10px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.traffic-footer,
|
||||
.population-footer {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 10px 0;
|
||||
font-size: 14px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* 底部区域 */
|
||||
.bottom-section {
|
||||
display: flex;
|
||||
gap: 20px;
|
||||
height: 340px;
|
||||
/* 适配剩余高度 */
|
||||
}
|
||||
|
||||
.map-card {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.map-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
|
||||
.mapbox {
|
||||
width: 100%;
|
||||
padding: 0 10px;
|
||||
height: 250px;
|
||||
box-sizing: border-box;
|
||||
background: #000;
|
||||
}
|
||||
}
|
||||
|
||||
.map-bg {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url("https://picsum.photos/800/400") center/cover;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.monitor-tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background-color: rgba(20, 20, 30, 0.8);
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
.tip-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tip-desc {
|
||||
font-size: 14px;
|
||||
color: #ccc;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tip-features {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 5px;
|
||||
font-size: 12px;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
::v-deep .el-col {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
@ -27,10 +27,8 @@ const open = async (row) => {
|
||||
visible.value = true
|
||||
await nextTick()
|
||||
emitter.emit('map-resize')
|
||||
|
||||
const res = await RyGjTrajectory({ sfzh: sfzh.value, days: 30 })
|
||||
const list = Array.isArray(res) ? res : (res?.data?.data || [])
|
||||
|
||||
if (!list || list.length === 0) {
|
||||
ElMessage({ message: '近30天无轨迹数据', type: 'info' })
|
||||
emitter.emit('removeElement', 'rygj')
|
||||
@ -46,7 +44,7 @@ const open = async (row) => {
|
||||
// 撒点显示历史轨迹
|
||||
const pointObjs = list.map(it => ({ jd: Number(it.jd), wd: Number(it.wd) }))
|
||||
emitter.emit('addPointArea', { coords: pointObjs, icon: require('@/assets/images/bi/gzy.png'), flag: 'rygj_points' })
|
||||
|
||||
|
||||
}
|
||||
|
||||
defineExpose({ open })
|
||||
|
||||
Reference in New Issue
Block a user