Browse Source

fit: 问题赋分机制列表。fit: 单位问题库

main
wxc 1 year ago
parent
commit
17971c8b25
  1. 6
      src/api/sensitivePerception/modelClueTask.ts
  2. 57
      src/components/description-pair.vue
  3. 2
      src/enums/appEnums.ts
  4. 2
      src/utils/util.ts
  5. 203
      src/views/sensitivePerception/DepartNegative.vue
  6. 299
      src/views/sensitivePerception/DictContent.vue
  7. 26
      src/views/sensitivePerception/ModelClueTask.vue
  8. 179
      src/views/system/DictContent.vue

6
src/api/sensitivePerception/modelClueTask.ts

@ -5,4 +5,10 @@ export function listModelClueTask(query) {
url: `/model/clue/tasks`,
query
});
}
export function listModelClueByDepart(taskId) {
return request.get({
url: `/model/clue/tasks/${taskId}/byDepart`
});
}

57
src/components/description-pair.vue

@ -0,0 +1,57 @@
<template>
<div class="text-center description-value" :size="size">
<span>{{ value1 }}</span>
<span class="separator">/</span>
<span class="value2">{{ value2 }}</span>
</div>
<div class="text-center description-label" :size="size">
<span>{{ label1 }}</span>
<span>/</span>
<span>{{ label2 }}</span>
</div>
</template>
<script setup>
defineProps({
label1: {
type: String,
default: "",
},
value1: {
type: String,
default: "",
},
label2: {
type: String,
default: "",
},
value2: {
type: String,
default: "",
},
size: {
type: String,
default: "",
}
});
</script>
<style lang="scss" scoped>
.description-value {
margin-bottom: 16px;
font-size: 18px;
color: var(--primary-color);
&[size=large] {
font-size: 28px;
}
.separator {
margin: 0 10px;
color: #666666;
}
.value2 {
color: #FF2B2B;
}
}
.description-label {
font-size: 16px;
color: #666666;
}
</style>

2
src/enums/appEnums.ts

@ -7,7 +7,7 @@ export enum MenuEnum {
export const MENU_ROOT_ID = 0;
export const DICT_CONTENT_ROOT_ID = -1;
export const DICT_CONTENT_ROOT_ID = '-1';
// 部门跟节点
export const ROOT_DEPART_ID = '12630';

2
src/utils/util.ts

@ -330,7 +330,7 @@ export function getFileType(fileName) {
if (fileName.endsWith('.xls') || fileName.endsWith('.xlsx')) {
return FileType.EXCEL;
}
if (fileName.endsWith('.mp3') || fileName.endsWith('.m4a')) {
if (fileName.endsWith('.mp3') || fileName.endsWith('.m4a') || fileName.endsWith('.wav')) {
return FileType.MP3;
}
if (fileName.endsWith('.mp4')) {

203
src/views/sensitivePerception/DepartNegative.vue

@ -0,0 +1,203 @@
<template>
<div class="container">
<header>
<el-form :label-width="114">
<el-row>
<el-col :span="6">
<el-form-item label="单位名称">
<el-input
placeholder="请输入"
v-model="query.name"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="单位类型">
<el-input
placeholder="请输入"
v-model="query.six"
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="统计时间"> </el-form-item>
</el-col>
</el-row>
</el-form>
<div class="mb-25 flex end">
<div>
<el-button type="primary" @click="getList">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</div>
</header>
<div class="table-container">
<el-table :data="list">
<el-table-column label="单位名称" prop="" />
<el-table-column label="主要责任人" prop="" />
<el-table-column label="民警人数" prop="" />
<el-table-column label="协辅警人数" prop="" />
<el-table-column label="查实问题涉及人数" prop="" width="180" />
<el-table-column
label="查实问题数"
prop="departName"
width="120"
/>
<el-table-column
label="风险指数"
prop="fxzs"
width="120"
align="center"
/>
<el-table-column label="操作" width="160">
<template #default="{ row }">
<el-button type="primary" link @click="show = true"
>查看详情</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog title="单位问题画像" v-model="show" width="85vw" top="2vh">
<header class="flex center v-center gap">
<label for="">统计范围</label>
<el-button type="primary">查询</el-button>
</header>
<main>
<el-row>
<el-col :span="8">
<h5>单位情况</h5>
<div class="row">
<div class="col col-24">
<label>单位名称</label>
<span>{{}}</span>
</div>
<div class="col col-24">
<label>所长</label>
<span>{{}}</span>
</div>
<div class="col col-24">
<label>副所长</label>
<span>{{}}</span>
</div>
</div>
<el-row>
<el-col :span="12">
<description-pair
label1="民警总人数"
label2="问题涉及民警数"
value1="132"
value2="21"
size="large"
/>
</el-col>
<el-col :span="12">
<description-pair
label1="协辅警人数"
label2="问题涉及协辅警数"
value1="132"
value2="21"
size="large"
/>
</el-col>
</el-row>
</el-col>
<el-col :span="8">
<h5>问题情况</h5>
<el-row>
<el-col :span="6" class="text-center">
<div class="text-primary" style="font-size: 34px">
51
</div>
<div>问题总数</div>
</el-col>
<el-col :span="18">
<el-row>
<el-col :span="12">
<description-pair
label1="110接处警量"
label2="问题数"
value1="132"
value2="21"
/>
</el-col>
<el-col :span="12">
<description-pair
label1="执法办案"
label2="问题数"
value1="132"
value2="21"
/>
</el-col>
</el-row>
</el-col>
</el-row>
</el-col>
<el-col :span="8">
<h5>风险指数</h5>
<div class="flex center">
<el-progress
type="dashboard"
:percentage="78"
:stroke-width="16"
:width="250"
color="#DC6231"
>
<div>
<span style="">78</span>
</div>
<div>分险指标值</div>
<div>中风险</div>
</el-progress>
</div>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<h5>问题来源占比</h5>
</el-col>
<el-col :span="8">
<h5>业务类型占比</h5>
</el-col>
<el-col :span="8">
<h5>风险问题构成</h5>
</el-col>
</el-row>
<el-row>
<el-col :span="8">
<h5>个人问题排名</h5>
</el-col>
<el-col :span="8">
<h5>突出问题排名</h5>
</el-col>
<el-col :span="8">
<h5>单位问题标签</h5>
</el-col>
</el-row>
<h5>问题变化趋势</h5>
<div></div>
<h5>问题清单</h5>
<div></div>
</main>
</el-dialog>
</template>
<script lang="ts" setup>
const query = ref({
current: 1,
size: 10,
});
const list = ref<any[]>([]);
const show = ref(true);
</script>
<style lang="scss" scoped>
</style>

299
src/views/sensitivePerception/DictContent.vue

@ -0,0 +1,299 @@
<template>
<div class="container">
<header class="mb-20">
<div class="flex between">
<div>
<el-button type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增</el-button
>
</div>
<div style="width: 50%">
<el-row>
<el-col :span="12"> </el-col>
<el-col :span="12">
<div class="flex end">
<el-button type="primary" @click="getList">
<template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
>
<el-button @click="reset">重置</el-button>
</div>
</el-col>
</el-row>
</div>
</div>
<div class="flex between mt-10">
<div>
<div class="text-primary mt-10 mb-10">赋分分公式如下</div>
<div>
问题综合得分 =
基础分值x(1+问题严重等级系数)x(1+问题发生频次系数)x(1+问题发生率系数)
</div>
</div>
<a
class="flex v-center gap file-link"
:href="`${BASE_PATH}/templates/长沙公安数字督察灵敏感知体系问题赋分及风险预警机制.pdf`"
target="__blank"
>
<icon name="local-icon-pdf" :size="48" />
<span>问题赋分机制.pdf</span>
</a>
</div>
</header>
<div class="table-container">
<el-table :data="dictContents" row-key="id">
<el-table-column
label="问题条目"
prop="name"
show-overflow-tooltip=""
/>
<el-table-column label="基础分值" prop="score" width="200" align="center">
<template #default="{ row }">
<span v-if="row.level === 1">{{
getScoreRange(row)
}}</span>
<span v-else>{{ row.score }}</span>
</template>
</el-table-column>
<el-table-column
label="问题严重等级"
prop="isActiveLevel"
align="center"
>
<template #default="{ row }">
<el-tag type="success" v-if="row.isActiveLevel === true"
>开启</el-tag
>
<el-tag type="danger" v-if="row.isActiveLevel === false"
>关闭</el-tag
>
</template>
</el-table-column>
<el-table-column
label="序号"
prop="sort"
width="100"
align="center"
/>
<el-table-column label="最后更新时间" prop="updTime" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)"
>编辑</el-button
>
<el-button type="danger" link @click="handleDelete(row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<div class="mt-40">
<div>基础分值设定规则</div>
<p>
1二级问题条目设定的基础分值作为其下属三级问题条目的默认基础分值
</p>
<p>
2若三级问题条目已单独设置基础分值则赋分时以该三级条目的基础分值为准
</p>
<p>
3如三级问题条目未设置基础分值则采用其所属二级问题条目的基础分值进行赋分
</p>
</div>
</div>
<el-dialog
v-model="show"
:title="mode === 'add' ? '新增问题类型' : '编辑问题类型'"
width="600"
>
<el-form label-width="120" ref="formRef" :model="formData">
<el-form-item
label="父级节点"
:rules="{
required: true,
message: '请选择父级节点',
}"
prop="parentCode"
>
<el-tree-select
class="flex-1"
v-model="formData.parentCode"
:data="dictContentOptions"
clearable
node-key="id"
:props="{
label: 'name',
}"
:default-expanded-keys="[DICT_CONTENT_ROOT_ID]"
placeholder="请选择父级节点"
check-strictly
filterable
/>
</el-form-item>
<el-form-item
label="问题条目"
prop="name"
:rules="{
required: true,
message: '请输入问题条目',
}"
>
<el-input
v-model="formData.name"
placeholder="请输入问题条目"
clearable
/>
</el-form-item>
<el-form-item label="基础分值" prop="score" v-if="formData.parentCode != DICT_CONTENT_ROOT_ID">
<el-input
v-model="formData.score"
placeholder="请输入序号"
type="number"
clearable
/>
</el-form-item>
<el-form-item label="序号" prop="sort">
<el-input
v-model="formData.sort"
placeholder="请输入序号"
type="number"
clearable
/>
</el-form-item>
<el-form-item
label="问题严重等级"
prop="isActiveLevel"
:rules="{
required: true,
message: '请选择问题严重等级',
trigger: ['blur'],
}"
>
<el-switch
v-model="formData.isActiveLevel"
inline-prompt
active-text="开启"
inactive-text="关闭"
:active-value="true"
:inactive-value="false"
/>
</el-form-item>
</el-form>
<footer class="flex end">
<el-button @click="show = false">取消</el-button>
<el-button type="primary" @click="submit">确定</el-button>
</footer>
</el-dialog>
</template>
<script lang="ts" setup>
import { BASE_PATH } from "@/api/request";
import { DICT_CONTENT_ROOT_ID } from "@/enums/appEnums";
import {
listDictContentTree,
addDictContent,
updateDictContent,
delDictContent,
} from "@/api/system/dictContent";
import feedback from "@/utils/feedback";
const dictContents = ref([]);
const dictContentOptions = ref([
{
id: DICT_CONTENT_ROOT_ID,
name: "顶级",
children: [],
},
]);
function getList() {
listDictContentTree().then((data) => {
dictContents.value = data;
dictContentOptions.value[0].children = data;
});
}
getList();
const show = ref(false);
const formData = ref({});
const formRef = ref();
const mode = ref<string>("add");
watch(mode, (val) => {
if (val === "add") {
formData.value = {};
formRef.value.resetFields();
}
});
async function submit() {
await formRef.value.validate();
if (mode.value === "add") {
await addDictContent(formData.value);
const parentCode = formData.value.parentCode;
formData.value = {};
formRef.value.resetFields();
formData.value.parentCode = parentCode;
} else {
await updateDictContent(formData.value);
}
show.value = false;
getList();
}
function handleAdd() {
show.value = true;
mode.value = "add";
}
function handleEdit(row) {
show.value = true;
mode.value = "edit";
formData.value = {...row};
}
const handleDelete = async (row) => {
await feedback.confirm(`确定要删除 "${row.name}"?`);
await delDictContent(row.id);
getList();
feedback.msgSuccess("删除成功");
};
function getScoreRange(row) {
const sorceSet = new Set();
row.children.forEach((item) => {
if (item.score) {
sorceSet.add(item.score);
}
item.children.forEach((j) => {
if (j.score) {
sorceSet.add(j.score);
}
});
});
if (sorceSet.size === 0) {
return ''
}
if (sorceSet.size === 1) {
return sorceSet.values().next().value
}
const min = Math.min(...sorceSet);
const max = Math.max(...sorceSet);
return `${min}-${max}`
}
</script>
<style lang="scss" scoped>
.file-link {
font-size: 18px;
text-decoration: none;
color: #19257d;
padding: 0 8px;
&:hover {
background-color: #eee;
}
}
</style>

26
src/views/sensitivePerception/ModelClueTask.vue

@ -2,7 +2,7 @@
<div class="container">
<el-row :gutter="20">
<el-col :span="4">
<model-tree />
<model-tree v-model="query.modelIds" />
</el-col>
<el-col :span="20">
<header>
@ -115,29 +115,24 @@
<el-dialog title="任务统计" v-model="statisticsShow" width="80vw">
<div style="min-height: 500px">
<div class="table-container">
<el-table :data="list">
<el-table :data="departList">
<el-table-column
label="单位名称"
prop="taskName"
prop="departName"
width="200"
show-overflow-tooltip
/>
<el-table-column
label="问题数量"
prop="modelName"
prop="size"
width="200"
show-overflow-tooltip
/>
<el-table-column
label="办结数量"
prop="distributionTime"
prop="completedSize"
width="200"
/>
<el-table-column
label="问题条数"
prop="size"
align="center"
/>
<el-table-column
label="办结率"
align="center"
@ -159,7 +154,7 @@
</el-dialog>
</template>
<script lang="ts" setup>
import { listModelClueTask } from "@/api/sensitivePerception/modelClueTask";
import { listModelClueTask, listModelClueByDepart } from "@/api/sensitivePerception/modelClueTask";
import useCatchStore from "@/stores/modules/catch";
import { getDictLable } from "@/utils/util";
@ -171,6 +166,12 @@ const query = ref({});
const list = ref([]);
const total = ref(0);
watch(
() => query.value.modelIds,
() => {
getList();
}
);
onMounted(() => {
getList();
});
@ -188,7 +189,10 @@ function reset() {
}
const statisticsShow = ref(false);
const departList = ref([])
async function handleStatisticsShow(id) {
const data = await listModelClueByDepart(id)
departList.value = data;
statisticsShow.value = true;
}
</script>

179
src/views/system/DictContent.vue

@ -1,179 +0,0 @@
<template>
<div class="container">
<header class="flex between mb-20">
<div>
<el-button type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
新增</el-button
>
</div>
<div></div>
</header>
<div class="table-container">
<el-table :data="dictContents" row-key="id">
<el-table-column label="类型名称" prop="name" show-overflow-tooltip="" />
<el-table-column label="序号" prop="sort" width="200" />
<el-table-column label="最后更新时间" prop="updTime" />
<el-table-column label="操作">
<template #default="{ row }">
<el-button type="primary" link @click="handleEdit(row)"
>编辑</el-button
>
<el-button
type="danger"
link
@click="handleDelete(row)"
>删除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</div>
<el-dialog
v-model="show"
:title="mode === 'add' ? '新增问题类型' : '编辑问题类型'"
width="600"
>
<el-form label-width="120" ref="formRef" :model="formData">
<el-form-item
label="父级节点"
:rules="{
required: true,
message: '请选择父级节点',
}"
prop="parentCode"
>
<el-tree-select
class="flex-1"
v-model="formData.parentCode"
:data="dictContentOptions"
clearable
node-key="id"
:props="{
label: 'name',
}"
:default-expanded-keys="[DICT_CONTENT_ROOT_ID]"
placeholder="请选择父级节点"
check-strictly
filterable
/>
</el-form-item>
<el-form-item
label="类型名称"
prop="name"
:rules="{
required: true,
message: '请输入类型名称',
}"
>
<el-input
v-model="formData.name"
placeholder="请输入类型名称"
clearable
/>
</el-form-item>
<el-form-item label="序号" prop="sort" >
<el-input
v-model="formData.sort"
placeholder="请输入序号"
type="number"
clearable
/>
</el-form-item>
<el-form-item label="备注">
<el-input
v-model="formData.remark"
placeholder="请输入备注"
type="textarea"
clearable
/>
</el-form-item>
</el-form>
<footer class="flex end">
<el-button @click="show = false">取消</el-button>
<el-button type="primary" @click="submit">确定</el-button>
</footer>
</el-dialog>
</template>
<script lang="ts" setup>
import { DICT_CONTENT_ROOT_ID } from "@/enums/appEnums";
import {
listDictContentTree,
addDictContent,
updateDictContent,
delDictContent
} from "@/api/system/dictContent";
import feedback from "@/utils/feedback";
const dictContents = ref([]);
const dictContentOptions = ref([
{
id: DICT_CONTENT_ROOT_ID,
name: "顶级",
children: [],
},
]);
function getList() {
listDictContentTree().then((data) => {
dictContents.value = data;
dictContentOptions.value[0].children = data;
});
}
getList();
const show = ref(false);
const formData = ref({});
const formRef = ref();
const mode = ref<string>("add");
watch(mode, (val) => {
if (val === 'add') {
formData.value = {}
formRef.value.resetFields()
}
})
async function submit() {
await formRef.value.validate();
if (mode.value === "add") {
await addDictContent(formData.value);
const parentCode = formData.value.parentCode
formData.value = {}
formRef.value.resetFields()
formData.value.parentCode = parentCode
} else {
await updateDictContent(formData.value);
}
show.value = false
getList()
}
function handleAdd() {
show.value = true;
mode.value = "add";
}
function handleEdit(row) {
show.value = true;
mode.value = "edit";
formData.value = row;
}
const handleDelete = async (row) => {
await feedback.confirm(`确定要删除 "${row.name}"?`);
await delDictContent(row.id)
getList()
feedback.msgSuccess('删除成功')
};
</script>
<style lang="scss" scoped>
.form-tips {
font-size: 12px;
line-height: 1.2;
color: #666;
}
</style>
Loading…
Cancel
Save