|
|
|
|
@ -114,281 +114,33 @@
|
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<el-dialog |
|
|
|
|
title="个人问题详情" |
|
|
|
|
v-model="show" |
|
|
|
|
width="85vw" |
|
|
|
|
top="1vh" |
|
|
|
|
style="margin: 1vh auto" |
|
|
|
|
> |
|
|
|
|
<header class="flex center v-center gap"> |
|
|
|
|
<label>统计范围</label> |
|
|
|
|
<div style="width: 320px"> |
|
|
|
|
<date-time-range-picker-ext |
|
|
|
|
v-model="time" |
|
|
|
|
style="width: 300px" |
|
|
|
|
@change="getProfileData" |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
<el-button type="primary" @click="getProfileData">查询</el-button> |
|
|
|
|
</header> |
|
|
|
|
<el-scrollbar |
|
|
|
|
max-height="calc(98vh - 120px)" |
|
|
|
|
v-loading="loading" |
|
|
|
|
element-loading-text="个人问题详情加载中..." |
|
|
|
|
> |
|
|
|
|
<main> |
|
|
|
|
<el-row class="mb-20" :gutter="20"> |
|
|
|
|
<el-col :span="8"> |
|
|
|
|
<h5>民警基本情况</h5> |
|
|
|
|
<div class="card-item h-220"> |
|
|
|
|
<el-row> |
|
|
|
|
<el-col :span="6"> |
|
|
|
|
<div class="flex v-center" style="height: 100%"> |
|
|
|
|
<img |
|
|
|
|
v-if="policeInfo.avatarUrl" |
|
|
|
|
:src="`${BASE_PATH}/file/stream/${policeInfo.avatarUrl}`" |
|
|
|
|
class="police-avatar" |
|
|
|
|
style="width: 94px" |
|
|
|
|
/> |
|
|
|
|
<icon name="local-icon-police" :size="120" v-else /> |
|
|
|
|
</div> |
|
|
|
|
</el-col> |
|
|
|
|
<el-col :span="18"> |
|
|
|
|
<div class="row"> |
|
|
|
|
<div class="col col-12"> |
|
|
|
|
<label>姓名</label> |
|
|
|
|
<span>{{ policeInfo.name }}</span> |
|
|
|
|
</div> |
|
|
|
|
<div class="col col-12"> |
|
|
|
|
<label>性别</label> |
|
|
|
|
<span>{{ getGenderFromIdCode(policeInfo.idCode) }}</span> |
|
|
|
|
</div> |
|
|
|
|
<div class="col col-24"> |
|
|
|
|
<label>所属单位</label> |
|
|
|
|
<span> |
|
|
|
|
<span |
|
|
|
|
>{{ |
|
|
|
|
activeRow.parentDepartName |
|
|
|
|
? activeRow.parentDepartName + "/" |
|
|
|
|
: activeRow.parentDepartName |
|
|
|
|
}}{{ activeRow.departName }}</span |
|
|
|
|
> |
|
|
|
|
</span> |
|
|
|
|
</div> |
|
|
|
|
<div class="col col-24"> |
|
|
|
|
<label>警号</label> |
|
|
|
|
<span>{{ policeInfo.empNo }}</span> |
|
|
|
|
</div> |
|
|
|
|
<div class="col col-24"> |
|
|
|
|
<label>身份证号</label> |
|
|
|
|
<span>{{ policeInfo.idCode }}</span> |
|
|
|
|
</div> |
|
|
|
|
<div class="col col-24"> |
|
|
|
|
<label>入职时间</label> |
|
|
|
|
<span>{{ policeInfo.employmentDate || "/" }}</span> |
|
|
|
|
</div> |
|
|
|
|
<div class="col col-24"> |
|
|
|
|
<label>手机号</label> |
|
|
|
|
<span>{{ policeInfo.mobile || "/" }}</span> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</el-col> |
|
|
|
|
</el-row> |
|
|
|
|
</div> |
|
|
|
|
</el-col> |
|
|
|
|
<el-col :span="8"> |
|
|
|
|
<h5>问题情况</h5> |
|
|
|
|
<div class="card-item h-220"> |
|
|
|
|
<div class="flex v-center h100"> |
|
|
|
|
<div style="width: 25%" class="text-center"> |
|
|
|
|
<div class="text-primary" style="font-size: 34px"> |
|
|
|
|
{{ negativeInfo.size }} |
|
|
|
|
</div> |
|
|
|
|
<div class="mb-10">问题总数</div> |
|
|
|
|
</div> |
|
|
|
|
<div style="width: 75%" class="text-center"> |
|
|
|
|
<div |
|
|
|
|
v-if="negativeInfo.jcj110BusinessSize || negativeInfo.jcj110Size" |
|
|
|
|
class="mb-20" |
|
|
|
|
> |
|
|
|
|
<description-pair |
|
|
|
|
label="110接处警" |
|
|
|
|
label1="量" |
|
|
|
|
label2="问题数" |
|
|
|
|
:value1="negativeInfo.jcj110BusinessSize" |
|
|
|
|
:value2="negativeInfo.jcj110Size" |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
<div |
|
|
|
|
v-if="negativeInfo.jcj122BusinessSize || negativeInfo.jcj122Size" |
|
|
|
|
class="mb-20" |
|
|
|
|
> |
|
|
|
|
<description-pair |
|
|
|
|
label="122接处警" |
|
|
|
|
label1="量" |
|
|
|
|
label2="问题数" |
|
|
|
|
:value1="negativeInfo.jcj122BusinessSize" |
|
|
|
|
:value2="negativeInfo.jcj122Size" |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
<div> |
|
|
|
|
<description-pair |
|
|
|
|
label="执法办案" |
|
|
|
|
label2="问题数" |
|
|
|
|
:value1="negativeInfo.zfbaBusinessSize" |
|
|
|
|
:value2="negativeInfo.zfbaSize" |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</el-col> |
|
|
|
|
<el-col :span="8"> |
|
|
|
|
<h5>问题累计分值</h5> |
|
|
|
|
<div class="flex center card-item wrap h-220"> |
|
|
|
|
<el-progress |
|
|
|
|
type="dashboard" |
|
|
|
|
:percentage="100" |
|
|
|
|
:stroke-width="16" |
|
|
|
|
:width="200" |
|
|
|
|
color="#5B8FF9" |
|
|
|
|
> |
|
|
|
|
<div class="score-progress-body"> |
|
|
|
|
<div> |
|
|
|
|
<div style="font-size: 16px">分数</div> |
|
|
|
|
<div> |
|
|
|
|
<span |
|
|
|
|
class="score-progress_score score-theme text-bold" |
|
|
|
|
style="color: #19257d" |
|
|
|
|
>{{ score }}</span |
|
|
|
|
> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
|
</el-progress> |
|
|
|
|
<div style="width: 100%" class="text-center">累计{{ days }}天分值</div> |
|
|
|
|
</div> |
|
|
|
|
</el-col> |
|
|
|
|
</el-row> |
|
|
|
|
<el-row class="mb-20" :gutter="20"> |
|
|
|
|
<el-col :span="8"> |
|
|
|
|
<h5>问题来源占比</h5> |
|
|
|
|
<div class="card-item"> |
|
|
|
|
<v-charts |
|
|
|
|
style="height: 320px" |
|
|
|
|
:option="problemSourcesPieOptions" |
|
|
|
|
autoresize |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
</el-col> |
|
|
|
|
<el-col :span="8"> |
|
|
|
|
<h5>问题涉及方面</h5> |
|
|
|
|
<div class="card-item"> |
|
|
|
|
<v-charts |
|
|
|
|
style="height: 320px" |
|
|
|
|
:option="problemTypePieOptions" |
|
|
|
|
autoresize |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
</el-col> |
|
|
|
|
<el-col :span="8"> |
|
|
|
|
<h5>突出问题排名</h5> |
|
|
|
|
<div class="flex center card-item h-320"> |
|
|
|
|
<datav-chart-bar1 |
|
|
|
|
size="small" |
|
|
|
|
:data="problemTypeBarList" |
|
|
|
|
:color="colors" |
|
|
|
|
labelPosition="top" |
|
|
|
|
/> |
|
|
|
|
<el-empty v-if="problemTypeBarList.length === 0" /> |
|
|
|
|
</div> |
|
|
|
|
</el-col> |
|
|
|
|
</el-row> |
|
|
|
|
|
|
|
|
|
<h5>问题变化趋势</h5> |
|
|
|
|
|
|
|
|
|
<div class="card-item"> |
|
|
|
|
<v-charts style="height: 320px" :option="barOption" autoresize /> |
|
|
|
|
</div> |
|
|
|
|
<h5>问题清单 {{ negativeList.length }}</h5> |
|
|
|
|
<el-table :data="negativeList" height="500"> |
|
|
|
|
<el-table-column label="发现时间" prop="discoveryTime" width="160" /> |
|
|
|
|
<el-table-column label="问题来源" prop="problemSources" width="150" /> |
|
|
|
|
<el-table-column label="业务类别" prop="businessTypeName" width="150" /> |
|
|
|
|
<el-table-column label="问题详情" prop="thingDesc" show-overflow-tooltip /> |
|
|
|
|
<el-table-column |
|
|
|
|
label="核查情况" |
|
|
|
|
prop="checkStatusDesc" |
|
|
|
|
show-overflow-tooltip |
|
|
|
|
/> |
|
|
|
|
<el-table-column label="问题类型" prop="problemType" show-overflow-tooltip /> |
|
|
|
|
<el-table-column label="分值" width="100" align="center"> |
|
|
|
|
<template #default="{ row }"> |
|
|
|
|
<span class="text-danger">{{ row.score }}</span> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
<el-table-column label="操作" width="160"> |
|
|
|
|
<template #default="{ row }"> |
|
|
|
|
<el-button type="primary" link @click="handleAction(row)" |
|
|
|
|
>查看详情 |
|
|
|
|
</el-button> |
|
|
|
|
</template> |
|
|
|
|
</el-table-column> |
|
|
|
|
</el-table> |
|
|
|
|
</main> |
|
|
|
|
</el-scrollbar> |
|
|
|
|
</el-dialog> |
|
|
|
|
<negativeInfo-police-dialog v-model="show" :id-code="activeRow.idCode" :active-row="activeRow" /> |
|
|
|
|
|
|
|
|
|
<alarm-dialog |
|
|
|
|
v-model="showNotification" |
|
|
|
|
:departId="activeDepartId" |
|
|
|
|
@close="showNotification = false" |
|
|
|
|
/> |
|
|
|
|
|
|
|
|
|
<negative-dialog |
|
|
|
|
v-model="negativeShow" |
|
|
|
|
:id="activeNegativeId" |
|
|
|
|
@close="negativeShow = false" |
|
|
|
|
/> |
|
|
|
|
</template> |
|
|
|
|
<script lang="ts" setup> |
|
|
|
|
import { BASE_PATH } from "@/api/request"; |
|
|
|
|
import vCharts from "vue-echarts"; |
|
|
|
|
import { |
|
|
|
|
listPoliceNegative, |
|
|
|
|
getPoliceProfile, |
|
|
|
|
listNegativeByPoliceIdCode, |
|
|
|
|
listNegativeMonthly, |
|
|
|
|
} from "@/api/sensitivePerception/profilePolice"; |
|
|
|
|
import { HostLevel, InspectCase } from "@/enums/dictEnums"; |
|
|
|
|
import { listPoliceNegative } from "@/api/sensitivePerception/profilePolice"; |
|
|
|
|
import { getDictLable, getGenderFromIdCode } from "@/utils/util"; |
|
|
|
|
import moment from "moment"; |
|
|
|
|
|
|
|
|
|
import useCatchStore from "@/stores/modules/catch"; |
|
|
|
|
|
|
|
|
|
import feedback from "~/utils/feedback"; |
|
|
|
|
|
|
|
|
|
const catchStore = useCatchStore(); |
|
|
|
|
const dict = catchStore.getDicts(["personType"]); |
|
|
|
|
let showNotification = ref(false); |
|
|
|
|
const showNotification = ref(false); |
|
|
|
|
const activeDepartId = ref(""); |
|
|
|
|
const handleShowNotification = (row) => { |
|
|
|
|
showNotification.value = true; |
|
|
|
|
activeDepartId.value = row.departId; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
const activeRow = ref<any>({}); |
|
|
|
|
const show = ref(false); |
|
|
|
|
const query = ref({ |
|
|
|
|
current: 1, |
|
|
|
|
size: 10, |
|
|
|
|
crtTime: [ |
|
|
|
|
// moment().startOf("year").format("YYYY-MM-DD HH:mm:ss"), |
|
|
|
|
// moment().format("YYYY-MM-DD HH:mm:ss"), |
|
|
|
|
], |
|
|
|
|
crtTime: [] as string[], |
|
|
|
|
}); |
|
|
|
|
const list = ref<any[]>([]); |
|
|
|
|
const total = ref(0); |
|
|
|
|
|
|
|
|
|
const mainLoading = ref(false); |
|
|
|
|
|
|
|
|
|
function getList() { |
|
|
|
|
@ -412,195 +164,15 @@ function reset() {
|
|
|
|
|
getList(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
onMounted(() => { |
|
|
|
|
getList(); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const activeRow = ref({}); |
|
|
|
|
const show = ref(false); |
|
|
|
|
const policeInfo = ref({}); |
|
|
|
|
const negativeInfo = ref({}); |
|
|
|
|
const loading = ref(false); |
|
|
|
|
|
|
|
|
|
const negativeList = ref([]); |
|
|
|
|
const negativeTotal = ref(0); |
|
|
|
|
|
|
|
|
|
const problemSourcesPieOptions = ref({ |
|
|
|
|
tooltip: { |
|
|
|
|
trigger: "item", |
|
|
|
|
}, |
|
|
|
|
series: [ |
|
|
|
|
{ |
|
|
|
|
type: "pie", |
|
|
|
|
radius: ["40%", "70%"], |
|
|
|
|
data: [], |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
}); |
|
|
|
|
const problemTypePieOptions = ref({ |
|
|
|
|
tooltip: { |
|
|
|
|
trigger: "item", |
|
|
|
|
}, |
|
|
|
|
series: [ |
|
|
|
|
{ |
|
|
|
|
type: "pie", |
|
|
|
|
radius: ["40%", "70%"], |
|
|
|
|
data: [], |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const barOption = ref({ |
|
|
|
|
xAxis: { |
|
|
|
|
type: "category", |
|
|
|
|
data: [], |
|
|
|
|
}, |
|
|
|
|
yAxis: { |
|
|
|
|
type: "value", |
|
|
|
|
}, |
|
|
|
|
series: [ |
|
|
|
|
{ |
|
|
|
|
data: [], |
|
|
|
|
type: "bar", |
|
|
|
|
color: "#5B8FF9 ", |
|
|
|
|
}, |
|
|
|
|
], |
|
|
|
|
}); |
|
|
|
|
function handleShowNotification(row: any) { |
|
|
|
|
showNotification.value = true; |
|
|
|
|
activeDepartId.value = row.departId; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async function handleShowProfile(row) { |
|
|
|
|
function handleShowProfile(row: any) { |
|
|
|
|
activeRow.value = row; |
|
|
|
|
show.value = true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
watch(activeRow, async () => { |
|
|
|
|
time.value = [ |
|
|
|
|
moment().startOf("year").format("YYYY-MM-DD HH:mm:ss"), |
|
|
|
|
moment().format("YYYY-MM-DD HH:mm:ss"), |
|
|
|
|
]; |
|
|
|
|
await getProfileData(); |
|
|
|
|
listNegativeMonthly(activeRow.value.idCode).then((data) => { |
|
|
|
|
barOption.value.xAxis.data = data.months; |
|
|
|
|
barOption.value.series[0].data = data.values; |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
const time = ref([]); |
|
|
|
|
|
|
|
|
|
const problemTypeBarList = ref([]); |
|
|
|
|
|
|
|
|
|
const score = ref(0); |
|
|
|
|
const days = ref(0); |
|
|
|
|
|
|
|
|
|
async function getProfileData() { |
|
|
|
|
loading.value = true; |
|
|
|
|
|
|
|
|
|
const data = await getPoliceProfile(activeRow.value.idCode, { |
|
|
|
|
beginTime: time.value.length ? time.value[0] : "", |
|
|
|
|
endTime: time.value.length ? time.value[1] : "", |
|
|
|
|
}); |
|
|
|
|
score.value = Math.round(data.score); |
|
|
|
|
days.value = data.days; |
|
|
|
|
negativeList.value = data.negatives; |
|
|
|
|
policeInfo.value = data.policeInfo; |
|
|
|
|
negativeInfo.value = data.negativeInfo; |
|
|
|
|
problemSourcesPieOptions.value.series[0].data = data.problemSourcesList; |
|
|
|
|
problemTypePieOptions.value.series[0].data = data.problemTypeList; |
|
|
|
|
problemTypeBarList.value = data.problemTypeBarList; |
|
|
|
|
loading.value = false; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const negativeShow = ref(false); |
|
|
|
|
const activeNegativeId = ref(""); |
|
|
|
|
|
|
|
|
|
function handleAction(row) { |
|
|
|
|
negativeShow.value = true; |
|
|
|
|
activeNegativeId.value = row.id; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const colors = [ |
|
|
|
|
{ color: "var(--success-color)", percentage: 60 }, |
|
|
|
|
{ color: "#DC6231", percentage: 80 }, |
|
|
|
|
{ color: "var(--danger-color)", percentage: 100 }, |
|
|
|
|
]; |
|
|
|
|
|
|
|
|
|
function getType(val) { |
|
|
|
|
if (val < 60) { |
|
|
|
|
return "success"; |
|
|
|
|
} |
|
|
|
|
if (val < 80) { |
|
|
|
|
return "warning"; |
|
|
|
|
} |
|
|
|
|
return "danger"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getColor(val) { |
|
|
|
|
if (val < 60) { |
|
|
|
|
return "var(--success-color)"; |
|
|
|
|
} |
|
|
|
|
if (val < 80) { |
|
|
|
|
return "#e87749"; |
|
|
|
|
} |
|
|
|
|
return "var(--danger-color)"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function getScoreLabel() { |
|
|
|
|
if (score.value === 0) { |
|
|
|
|
return "无法预测"; |
|
|
|
|
} |
|
|
|
|
if (score.value < 60) { |
|
|
|
|
return "低风险"; |
|
|
|
|
} |
|
|
|
|
if (score.value < 80) { |
|
|
|
|
return "中风险"; |
|
|
|
|
} |
|
|
|
|
return "高风险"; |
|
|
|
|
} |
|
|
|
|
onMounted(getList); |
|
|
|
|
</script> |
|
|
|
|
<style lang="scss" scoped> |
|
|
|
|
.col { |
|
|
|
|
--label-width: 60px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.score-progress-body { |
|
|
|
|
text-align: center; |
|
|
|
|
font-size: 18px; |
|
|
|
|
|
|
|
|
|
.score-progress_score { |
|
|
|
|
font-size: 50px; |
|
|
|
|
line-height: 70px; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.score-progress_title { |
|
|
|
|
font-size: 26px; |
|
|
|
|
line-height: 22px; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
.score-theme { |
|
|
|
|
&[type="success"] { |
|
|
|
|
color: var(--success-color); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&[type="warning"] { |
|
|
|
|
color: #e87749; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
&[type="danger"] { |
|
|
|
|
color: var(--danger-color); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
h5 { |
|
|
|
|
margin-bottom: 12px; |
|
|
|
|
} |
|
|
|
|
.card-item { |
|
|
|
|
background: #f9faff; |
|
|
|
|
padding: 16px; |
|
|
|
|
min-height: 200px; |
|
|
|
|
} |
|
|
|
|
.h-220 { |
|
|
|
|
height: 220px; |
|
|
|
|
} |
|
|
|
|
.h-320 { |
|
|
|
|
height: 320px; |
|
|
|
|
} |
|
|
|
|
</style> |
|
|
|
|
|