This commit is contained in:
lcw
2025-09-16 15:50:24 +08:00
parent fa45f28c0b
commit a8834e6c73
491 changed files with 181974 additions and 364 deletions

View File

@ -1,124 +1,96 @@
<template>
<!-- 研判类型 -->
<div class="content">
<div class="btnsBox" ref="refBtn">
<CheckBox :data="checkData.yplxBtn" @changeData="changeData_yplx"></CheckBox>
</div>
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch"> </Search>
</div>
<ul class="cntlsit mb10" v-if="show" v-infinite-scroll="load" :style="{ height: listHeight + 'px' }"
v-loading="loading">
<li class="cntItem" @click.stop="lookDeatl(it)" v-for="(it, idx) in list" :key="idx">
<div class="ww100"><img class="ww100" style="height: 168px;" src="@/assets/images/mxbg.jpg" alt=""></div>
<div class="f14 lh24 pl4 pr4 one_text_detail">名称{{ it.ypMc }}</div>
<div class="flex ww100 f14 lh24 pl4 pr4 one_text_detail">类型
<DictTag :value="it.ypLx" :tag="false" :options="D_SG_TSYPGZ" />
</div>
<div class="f14 lh24 pl4 pr4 one_text_detail">数量{{ it.num }}</div>
<div class="foot">
<span class="ml10 pointer" @click.stop="openHistoricalReport(it.id)" style="color:#027ff0 ;"><el-icon style="top: 2px;"><Document /></el-icon>历史报告</span>
<span class="ml10 pointer" @click.stop="funAll(it.id)" style="color:#027ff0 ;"><el-icon style="top: 2px;"><Document /></el-icon>报告</span>
<span class="ml10 pointer" @click="handleHs(it)" style="color:#f4ac47 ;"><el-icon style="top: 2px;"><Files /></el-icon>会商</span>
</div>
</li>
<div class="ww100 flex just-center">
<MOSTY.Empty :show="!loading && list.length <= 0"></MOSTY.Empty>
</div>
<div class="tc ww100 mb4" style="color: #a29f9f;" v-if="total == list.length && total > 0">暂时没有数据了</div>
</ul>
<!-- 研判类型 -->
<div class="content">
<div class="titleBox">
<PageTitle title="模型平台">
<el-button type="primary" @click="openAddModel('add')" :icon="CirclePlus">
新增模型
</el-button>
</PageTitle>
</div>
<YpModel v-model="showModel" @SaveReport="SaveReport" :heightNumber="436" v-model:textContent="textContent"></YpModel>
<HistoricalReport v-model="showHistoricalReport" @choosed="getHistory" :chageData="chageData"/>
<div ref="searchBox">
<Search :searchArr="searchConfiger" @submit="onSearch"> </Search>
</div>
<ul class="cntlsit mb10" v-if="show" v-infinite-scroll="load" :style="{ height: listHeight + 'px' }"
v-loading="loading">
<li class="cntItem" v-for="(it, idx) in list" :key="idx">
<div class="ww100" @click.stop="openAddModel('detail', it)"><img class="ww100" style="height: 168px;"
src="@/assets/images/mxbg.jpg" alt=""></div>
<div class="foot">
<span class="ml10 pointer" style="color:#027ff0 ;" @click="openAddRule"><el-icon style="top: 2px;">
<Document />
</el-icon>查看规则</span>
<span class="ml10 pointer" style="color:#027ff0 ;" @click="openAddModel('edit', it)"><el-icon
style="top: 2px;">
<Edit />
</el-icon>编辑</span>
<span class="ml10 pointer" style="color:#f4ac47 ;"><el-icon style="top: 2px;">
<Files />
</el-icon>删除</span>
</div>
</li>
<div class="ww100 flex just-center">
<MOSTY.Empty :show="!loading && list.length <= 0"></MOSTY.Empty>
</div>
<div class="tc ww100 mb4" style="color: #a29f9f;" v-if="total == list.length && total > 0">暂时没有数据了</div>
</ul>
</div>
<AddModel ref="addModel" />
<Regulation ref="regulation" />
</template>
<script setup>
import CheckBox from '@/components/checkBox/index.vue'
import YpModel from '@/components/ypModel/index.vue'
import HistoricalReport from './historicalReport.vue'
import PageTitle from "@/components/aboutTable/PageTitle.vue";
import { CirclePlus } from '@element-plus/icons-vue'
import * as MOSTY from "@/components/MyComponents/index";
import Search from "@/components/aboutTable/Search.vue";
import { qcckPost } from "@/api/qcckApi.js";
import { timeValidate } from '@/utils/tools.js'
import { getItem } from '@/utils/storage.js'
import { useRoute, useRouter } from 'vue-router';
import { reactive, ref, onMounted, getCurrentInstance, watch, defineEmits } from "vue";
import { jqypDywdtj, jqypfxbgJqlxtj, jqypfxbgYdfx, jqypfxbgJqlytj, jqypfxbgTj, jqypfxbgCljgf, jqypfxbgCzlfx, getDictItem } from '@/api/semanticAnalysis'
import { textStyle, Firstlevelheading, Subheading, BiheadlinegTitle, BigTitle, headTitle, report, signature } from './content.js'
import { ElMessage, ElMessageBox } from 'element-plus'
const router = useRouter();
const { proxy } = getCurrentInstance();
import AddModel from "./addModel.vue";
import Regulation from "./regulation.vue";
const emit = defineEmits(['change'])
const { D_SG_SJLY, D_SG_TSYPGZ, JQLB, JQLX, JQXL, JQZL, D_BZ_JQLY, D_BZ_JQFL, JQCLJG } = proxy.$dict("D_SG_SJLY", "D_SG_TSYPGZ", "JQLB", "JQLX", "JQXL", "JQZL", "D_BZ_JQLY", "D_BZ_JQFL", "JQCLJG"); //获取字典数据
const searchBox = ref(); //搜索框
const showModel = ref(false);
const textContent = ref('');
const refBtn = ref();
const show = ref(false)
const listHeight = ref()
const searchConfiger = ref([
{ label: "研判名称", prop: "ypMc", placeholder: "请输入研判名称", showType: "input" },
{ label: "模型名称", prop: "ypMc", placeholder: "请输入模型名称", showType: "input" },
{ label: "模型类型", prop: "ypLx", placeholder: "请输入模型类型", showType: "input" },
]);
const checkData = reactive({
yplxBtn: {
hasChoose: [],
list: []
},
const PaginationConfig = reactive({
pageCurrent: 1,
pageSize: 8,
});
const page = ref(1);
const total = ref(0)
const list = ref([])
const loading = ref(false);
const formData = ref({})
const chageData=ref()
watch(() => D_SG_TSYPGZ.value, val => {
checkData.yplxBtn.list = val.map(v => v.zdmc);
checkData.yplxBtn.hasChoose = val.map(v => v.zdmc);
}, { immediate: true, deep: true });
onMounted(() => {
show.value = true;
Time()
tabHeightFn();
getLits()
})
// 研判类型
const changeData_yplx = (val) => {
checkData.yplxBtn.hasChoose = val;
let dms = [];
D_SG_TSYPGZ.value.forEach(item => {
if (val.includes(item.zdmc)) dms.push(item.dm);
});
formData.value.ypLx = dms;
page.value = 1;
getLits();
}
const onSearch = (val) => {
formData.value = { ...formData.value, ...val, };
page.value = 1;
PaginationConfig.pageCurrent = 1;
getLits();
}
const load = () => {
if (total.value == list.value.length) return;
page.value++;
PaginationConfig.pageCurrent++;
getLits();
}
const getLits = () => {
let params = {
pageCurrent: page.value,
pageSize: 8,
...PaginationConfig,
...formData.value
}
loading.value = true;
qcckPost(params, '/mosty-gsxt/tsyp/selectPage').then(res => {
let arr = res.records || [];
list.value = page.value == 1 ? arr : list.value.concat(arr);
list.value = PaginationConfig.pageCurrent == 1 ? arr : list.value.concat(arr);
total.value = res.total;
loading.value = false;
}).catch(() => {
@ -126,292 +98,71 @@ const getLits = () => {
})
}
const handleHs = (val) => {
router.push({ path: '/MeetingRoom', query: { tsypid: val.id } })
}
// 查看详情
const lookDeatl = (val) => {
emit('change', { data:val, type:'态势预警列表' })
}
// 表格高度计算
const tabHeightFn = () => {
listHeight.value = window.innerHeight - searchBox.value.offsetHeight - refBtn.value.offsetHeight - 182;
listHeight.value = window.innerHeight - searchBox.value.offsetHeight - 230;
window.onresize = function () {
tabHeightFn();
};
};
const dataList = reactive({
dyTj: {
xAxisData: [],
seriesData: [],
},
jqlxTj: [],
jqlyTj: [],
CljgfTj: [],
XsfxTj: [],
})
const sortingRatioValue = ref({
jqlx: "",
jqly: "",
dywd: "",
ydfx: "",
xlwdfx: "",
czjgfx: "",
})
const sortingRatio = (data) => {
// 提取所有number值
// 计算总数
const total = data.reduce((sum, item) => sum + item.number, 0);
// 找出第一大和第二大的值及其对应的name
const sortedData = [...data].sort((a, b) => b.number - a.number);
const dataValue = sortedData.map(item => {
return {
...item,
ratio: total > 0 ? (item.number / total * 100).toFixed(2) + '%' : '0%',
}
})
return dataValue
// 打开弹窗
const addModel = ref(null)
const openAddModel = (type, row) => {
addModel.value.init(type, row)
}
const pageData = reactive({
parameter: { bjlbList: '' }
})
const getDictItemList = () => {
const promes = {
dictCode: "00000000"
}
getDictItem(promes).then(res => {
pageData.parameter.bjlbList = res.map(item => item.dm).join(',')
console.log(pageData.parameter.bjlbList);
})
}
getDictItemList()
const funAll = (val) => {
const dev = getItem('deptId')[0]
sortingRatioValue.value = {}
textContent.value = BigTitle(`${endYears.value}年度西藏公安执法数据分析`) + headTitle({
orgName: dev.deptName,
serialNumber: timeValidate("", "mm"),
time: timeValidate(),
})
const data = `为全面、客观、准确掌握全区公安机关的执法状况,自治区公安厅基于数据统计,对全区公安机关${endYears.value}年度的执法状况作了客观分析。`
textContent.value += BiheadlinegTitle('1.接处警情况') + textStyle(data) + Firstlevelheading('一、执法状况总体分析')
getfxbgYdfx(val)
getfxbgTj(val)
getfxbgJqlxtj(val)
getfxbgJqlytj(val)
getfxbgDywdtj(val)
getfxgbCljgf(val)
getfxgbCzlfx(val)
showModel.value = true;
}
watch(() => sortingRatioValue.value, (val) => {
if (val.jqlx && val.jqly && val.dywd && val.ydfx && val.xlwdfx && val.czjgfx) {
textContent.value += val.jqlx + val.jqly + val.dywd + val.ydfx + val.xlwdfx + val.czjgfx + report() + signature()
}
}, { deep: true })
const getfxbgTj = (val) => {
jqypfxbgTj({ ypid: val }).then(res => {
const data = `${Time()} ,全区公安机关共接报各类警情${res.total}起,同比上升 ${res.tbbsb}%,同比上升${res.hbbsb}%`
textContent.value += BiheadlinegTitle('1.1接报警情') + textStyle(data)
dataList.XsfxTj = res
})
}
// 警情类型统计
const getfxbgJqlxtj = (val) => {
let params = {
...pageData.parameter,
ypid: val
}
jqypfxbgJqlxtj(params).then(res => {
const model = sortingRatio(res)
const data = `按警情类型来看,${model[0].name}最多,占到${model[0].ratio};其次为${model[1].name}最多,占到${model[1].ratio}`
sortingRatioValue.value.jqlx = Subheading('1.1.1类型维度') + textStyle(data)
})
}
// 警情来源统计
const getfxbgJqlytj = (val) => {
jqypfxbgJqlytj({ ypid: val }).then(res => {
const model = sortingRatio(res)
const data = `按警情来源来看,${model[0].name}最多,占到${model[0].ratio};其次为${model[1].name}最多,占到${model[1].ratio}`
sortingRatioValue.value.jqly = Subheading('1.1.2来源维度') + textStyle(data)
})
}
// 地域统计
const getfxbgDywdtj = (val) => {
jqypDywdtj({ ypid: val }).then(res => {
dataList.dyTj.xAxisData = res.map(it => it.ssbm)
dataList.dyTj.seriesData = [];
for (let i = 0; i < res.length; i++) {
dataList.dyTj.seriesData[i] = [];
for (let j = 0; j < res.length; j++) {
dataList.dyTj.seriesData[i][j] = 0;
}
}
for (let i = 0; i < dataList.dyTj.seriesData.length; i++) {
dataList.dyTj.seriesData[i][i] = res[i].number
}
const model = sortingRatio(res)
let data
if (model.length > 1) {
data = `从地市分布地市来看,${model[0].ssbm}警情量最大,占到全区警情总量的${model[0].number}。其次为${model[1].ssbm}${model[2].ssbm},两市警情量较为接近。警情量最少的为${model[model.length - 1].ssbm}`
} else {
data = `从地市分布地市来看,${model[0].ssbm}警情量最大,占到全区警情总量的${model[0].number}`
}
sortingRatioValue.value.dywd = Subheading('1.1.3地域维度') + textStyle(data)
})
}
//分析报告-时间维度-月分析
const getfxbgYdfx = (val) => {
jqypfxbgYdfx({ ypid: val }).then(res => {
const model = sortingRatio(res)
const data = `我们将所有警情按照月份划分进行统计发现,每月警情分布较为平均。最高月份为${model[0].month}月,占到${model[0].number};最低月份为${model[res.length - 1].month}月,占到${model[res.length - 1].number}。考虑是因为${model[0].month}月为我区传统旅游旺季,进藏人员较多。 ${model[res.length - 1].month}月一般春节及藏历新年期间,在藏人员较少。`
sortingRatioValue.value.ydfx = Subheading('1.1.4时间维度') + textStyle(data)
})
}
// 分析报告-处理结果分析
const getfxgbCljgf = (val) => {
jqypfxbgCljgf({ ypid: val }).then(res => {
// sortingRatioValue.Cljgf =
const model = sortingRatio(res)
let czjgfx = `从警情处置结果来看,`
model.forEach(item => {
czjgfx += `${item.name},占到${item.ratio};`
})
sortingRatioValue.value.xlwdfx = BiheadlinegTitle('1.2警情处置') + Firstlevelheading('1.2.1结果维度') + textStyle(czjgfx)
})
}
// 分析报告-处置率分析
const getfxgbCzlfx = (val) => {
jqypfxbgCzlfx({ ypid: val }).then(res => {
dataList.withinTj = [{
name: "超时分流(超过24小时)",
value: res.within24h ? res.within24h : 0
}, {
name: "按时分流(24小时内)",
value: res.over24h ? res.over24h : 0
}]
const data = `从处警效率来看24小时以内处警的占到${res.over24h}%。表明我区公安机关在接警之后能够在第一时间处警。`
sortingRatioValue.value.czjgfx = Subheading('1.2.2效率维度') + textStyle(data)
})
}
const timeDate = ref()
const endYears = ref()
const Time = () => {
const currentYear = new Date().getFullYear();
const startOfYear = new Date(currentYear, 0, 1); // 今年1月1日
const endOfYear = new Date(currentYear, 11, 31, 23); // 今年12月31日23:59:59.999
const year = startOfYear.getFullYear();
const month = String(startOfYear.getMonth() + 1).padStart(2, '0');
const day = String(startOfYear.getDate()).padStart(2, '0');
const endYear = endOfYear.getFullYear();
const endMonth = String(endOfYear.getMonth() + 1).padStart(2, '0');
const endDay = String(endOfYear.getDate()).padStart(2, '0');
timeDate.value = `${endYear}${endMonth}${endDay}`
endYears.value = year
return `${year}${month}${day}日 至${endYear}${endMonth}${endDay}`
}
const showHistoricalReport = ref(false)
const openHistoricalReport = (val) => {
chageData.value = val
showHistoricalReport.value = true
}
// const
const getHistory = (val) => {
textContent.value = val
showHistoricalReport.value = false
showModel.value = true
}
const SaveReport = (val) => {
ElMessageBox.prompt('请输入名称', '提示', {
confirmButtonText: '确认',
cancelButtonText: '取消',
// inputPattern:/[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/,
// inputErrorMessage: 'Invalid Email',
})
.then(({ value }) => {
const promes = {
bgmc:value,
bgnr: val,
ypid:chageData.value
}
qcckPost( promes , "/mosty-gsxt/gsxtYpbg/addEntity")
.then(() => {
ElMessage.success("保存成功");
})
})
.catch(() => {
ElMessage({
type: 'info',
message: '取消保存',
})
})
.catch(() => { });
// 打开规则弹窗
const regulation = ref(null)
const openAddRule = (type, row) => {
regulation.value.init(type, row)
}
</script>
<style lang="scss" scoped>
.content {
width: 100%;
height: 100%;
margin-top: 20px;
margin-left: 10px;
width: 100%;
height: 100%;
margin-top: 20px;
margin-left: 10px;
border-radius: 4px;
box-sizing: border-box;
.btnsBox {
background: #fff;
padding: 10px 5px;
border-radius: 4px;
margin-bottom: 10px;
}
.cntlsit {
display: flex;
flex-wrap: wrap;
align-content: start;
gap: 18px;
overflow: hidden;
overflow-y: auto;
background: #fff;
padding: 4px;
box-sizing: border-box;
.btnsBox {
background: #fff;
padding: 10px 5px;
.cntItem {
width: 300px;
border: 1px solid #ccc;
color: #787878;
border-radius: 4px;
margin-bottom: 10px;
}
.cntlsit {
display: flex;
flex-wrap: wrap;
align-content: start;
gap: 18px;
overflow: hidden;
overflow-y: auto;
background: #fff;
padding: 4px;
box-sizing: border-box;
.cntItem {
width: 300px;
border: 1px solid #ccc;
color: #787878;
border-radius: 4px;
overflow: hidden;
.foot {
text-align: right;
margin-top: 4px;
border-top: 1px solid #ccc;
padding: 4px;
box-sizing: border-box;
}
.foot {
text-align: right;
margin-top: 4px;
border-top: 1px solid #ccc;
padding: 4px;
box-sizing: border-box;
}
}
}
}
</style>