数字督察一体化平台-前端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

756 lines
28 KiB

<template>
<div class="container">
<el-row :gutter="20">
<el-col :span="4">
<div class="menu">
<div @click="handleChangeClass()" :active="!query.classId">
全部
</div>
<div
v-for="(item, index) in classes"
:key="index"
@click="handleChangeClass(item.id)"
:active="query.classId === item.id"
>
{{ item.name }}
</div>
</div>
</el-col>
<el-col :span="20">
<el-form :label-width="140">
<el-row>
<el-col :span="8">
<el-form-item label="模型名称">
<el-input
placeholder="请输入"
v-model="query.modelName"
clearable
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="分发方式">
<el-select
v-model="query.distributionMethod"
clearable
>
<el-option
v-for="item in dict.distributionMethod"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex between mb-20">
<el-button type="primary" @click="handleAdd">
<template #icon>
<icon name="el-icon-Plus" />
</template>
添加模型</el-button
>
<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>
<div>
<el-row :gutter="18">
<el-col :span="8" v-for="item in list" class="mb-18">
<div class="model-card" @click="openDetail(item)">
<div class="flex v-center">
<div class="model-card-icon">
<icon
:name="item.icon"
:size="76"
v-if="item.icon"
/>
</div>
<div
class="model-card-content"
style="width: calc(100% - 76px)"
>
<el-tooltip :content="item.remarks">
<div>
<div class="row">
<div class="col">
<label>模型名称</label>
<span>{{
item.modelName
}}</span>
</div>
</div>
<div class="row">
<div class="col">
<label>创建单位</label>
<span>{{
item.createDepartName
}}</span>
</div>
</div>
<div class="row">
<div class="col col-12">
<label>分发方式</label>
<span>{{
getDictLable(
dict.distributionMethod,
item.distributionMethod
)
}}</span>
</div>
</div>
<div class="col">
<label>最近活跃时间</label>
<span>{{
item.updateTime
}}</span>
</div>
</div>
</el-tooltip>
</div>
</div>
</div>
</el-col>
</el-row>
<el-empty description="无数据" v-if="list.length === 0" />
<div class="flex end mt-8">
<el-pagination
@size-change="getList"
@current-change="getList"
:current-page="query.current"
:page-sizes="[9, 18, 36]"
v-model:page-size="query.size"
v-model:current-page="query.current"
layout="total, sizes, prev, pager, next"
:total="total"
v-if="list.length"
>
</el-pagination>
</div>
</div>
</el-col>
</el-row>
</div>
<el-dialog
:title="mode === 'add' ? '添加模型' : '编辑模型'"
v-model="show"
top="4vh"
>
<el-form label-width="120" ref="formRef" :model="form">
<el-form-item
label="模型类型"
prop="classId"
:rules="{
required: true,
message: '请选择模型类型',
}"
>
<el-select v-model="form.classId" style="width: 340px">
<el-option
v-for="item in classes"
:key="item.id"
:label="item.name"
:value="item.id"
/>
</el-select>
</el-form-item>
<el-form-item
label="模型名称"
prop="modelName"
:rules="{
required: true,
message: '请输入模型名称',
trigger: ['blur'],
}"
>
<el-input
placeholder="请输入模型名称"
style="width: 340px"
v-model="form.modelName"
/>
</el-form-item>
<el-form-item
label="建模方式"
prop="modelingMethod"
:rules="{
required: true,
message: '请选择建模方式',
}"
>
<el-select v-model="form.modelingMethod" style="width: 340px">
<el-option
v-for="item in dict.modelingMethod"
:key="item.dictValue"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item
label="模型图标"
prop="icon"
:rules="{
required: true,
message: '请选择模型图标',
}"
>
<model-icon-picker v-model="form.icon" />
</el-form-item>
<el-form-item
label="数据类型"
prop="modelDataType"
:rules="{
required: true,
message: '请选择数据类型',
}"
>
<el-radio-group v-model="form.modelDataType" class="block">
<el-radio
v-for="item in dict.modelDataType"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{ item.remark ? `(${item.remark})` : "" }}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item
label="分发方式"
prop="distributionMethod"
:rules="{
required: true,
message: '请选择分发方式',
}"
v-if="form.modelDataType === ModelDataType.NEGATIVE"
>
<el-radio-group v-model="form.distributionMethod" class="block">
<el-radio
v-for="item in dict.distributionMethod"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{ item.remark ? `(${item.remark})` : "" }}</el-radio
>
</el-radio-group>
</el-form-item>
<template
v-if="
form.modelDataType === ModelDataType.NEGATIVE &&
form.distributionMethod ===
DistributionMethod.DIRECTLY_DISTRIBUTE
"
>
<el-form-item
label="分发周期"
prop="distributionCycle"
:rules="{
required: true,
message: '请选择分发周期',
}"
>
<el-radio-group
v-model="form.distributionCycle"
class="block"
>
<el-radio
v-for="item in dict.distributionCycle"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{
item.remark ? `(${item.remark})` : ""
}}</el-radio
>
</el-radio-group>
<div class="flex ml-20" v-if="form.distributionCycle">
<el-form-item
label="周"
prop=""
label-width="80"
:rules="{
required: true,
message: '请选择',
}"
v-if="
form.distributionCycle ===
DistributionCycle.WEEKLY
"
>
<el-select style="width: 120px" clearable>
<el-option
v-for="(item, index) in WEEKS"
:key="index"
:label="`周${item}`"
:value="index"
/>
</el-select>
</el-form-item>
<el-form-item
label="时间"
prop="distributionCycleTime"
label-width="80"
:rules="{
required: true,
message: '请选择',
}"
>
<el-time-picker
v-model="form.distributionCycleTime"
placeholder="请选择"
style="width: 120px"
value-format="HH:mm:ss"
clearable
/>
</el-form-item>
</div>
</el-form-item>
<el-form-item
label="办理时限"
prop="timeLimit"
:rules="{
required: true,
message: '请选择办理时限',
}"
>
<time-limit-select
v-model="form.timeLimit"
v-model:maxSignDuration="form.maxSignDuration"
v-model:maxHandleDuration="form.maxHandleDuration"
v-model:maxExtensionDuration="form.maxExtensionDuration"
/>
</el-form-item>
<el-form-item
label="下发流程"
prop="distributionFlow"
:rules="{
required: true,
message: '请选择下发流程',
}"
>
<el-radio-group
v-model="form.distributionFlow"
class="block"
>
<el-radio
v-for="item in dict.distributionFlow"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{
item.remark ? `(${item.remark})` : ""
}}</el-radio
>
</el-radio-group>
</el-form-item>
<el-form-item
label="审核流程"
prop="approvalFlow"
:rules="{
required: true,
message: '请选择审核流程',
}"
>
<el-radio-group v-model="form.approvalFlow">
<el-radio
v-for="item in dict.approvalFlow"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{
item.remark ? `(${item.remark})` : ""
}}</el-radio
>
</el-radio-group>
</el-form-item>
</template>
<el-form-item
label="模型描述"
prop="remarks"
:rules="{
required: true,
message: '请输入模型描述',
}"
>
<el-input
type="textarea"
:autosize="{ minRows: 4 }"
v-model="form.remarks"
placeholder="请输入"
/>
</el-form-item>
<el-form-item label="提示">
<div style="line-height: 1.4">
预警数据将以任务形式分批下发至相关单位处理。每次下发的预警数据都会在“任务分发”模块中生成一条记录。任务名称将按照“模型名称_下发时间”的格式命名,例如:“取保候审期间未按要求传讯犯罪嫌疑人_20240919”
</div>
</el-form-item>
</el-form>
<footer class="flex end">
<el-button @click="show = false" size="large">取消</el-button>
<el-button type="primary" size="large" @click="handleSubmit">{{
mode === "add" ? "添加模型" : "确认"
}}</el-button>
</footer>
</el-dialog>
<el-dialog title="模型详情" v-model="detailShow" top="5vh" width="70vw">
<h4 style="margin: 10px 0" class="text-primary">模型信息</h4>
<el-row>
<el-col :span="4">
<div class="mb-10">模型图标</div>
<div>
<icon :name="activeModel.icon" :size="80" />
</div>
</el-col>
<el-col :span="20">
<div class="row">
<div class="col col-24">
<label>模型名称</label>
<span>{{ activeModel.modelName }}</span>
</div>
</div>
<div class="row">
<div class="col col-8">
<label>建模方式</label>
<span>{{
getDictLable(
dict.modelingMethod,
activeModel.modelingMethod
)
}}</span>
</div>
<div class="col col-8">
<label>数据类型</label>
<span>{{
getDictLable(
dict.modelDataType,
activeModel.modelDataType
)
}}</span>
</div>
</div>
<div class="row">
<div class="col col-8">
<label>分发方式</label>
<span>{{
getDictLable(
dict.distributionMethod,
activeModel.distributionMethod
)
}}</span>
</div>
<div class="col col-8">
<label>分发周期</label>
<span>
<span>{{
getDictLable(
dict.distributionCycle,
activeModel.distributionCycle
)
}}</span>
<span class="ml-20">{{
activeModel.distributionCycleTime
}}</span>
</span>
</div>
</div>
<div class="row">
<div class="col col-8">
<label>办理时限</label>
<span>{{
getDictLable(dict.timeLimit, activeModel.timeLimit)
}}</span>
</div>
<div class="col col-8">
<label>下发流程</label>
<span>{{
getDictLable(
dict.distributionFlow,
activeModel.distributionFlow
)
}}</span>
</div>
<div class="col col-8">
<label>审核流程</label>
<span>{{
getDictLable(
dict.approvalFlow,
activeModel.approvalFlow
)
}}</span>
</div>
</div>
<div class="row">
<div class="col col-8">
<label>最近活跃时间</label>
<span>{{ activeModel.updateTime }}</span>
</div>
<div class="col col-8">
<label>创建单位</label>
<span>{{ activeModel.createDepartName }}</span>
</div>
</div>
<div class="row mb-20">
<div class="col col-24">
<label>模型描述</label>
<span>{{ activeModel.remarks }}</span>
</div>
</div>
<div class="flex end mb-20">
<el-button
type="primary"
plain
@click="
router.push({
path: `/sensitivePerception/modelClue`,
query: {
modelId: activeModel.id,
},
})
"
>查看线索数据</el-button
>
<el-button type="primary" plain @click="handleDetailConfigShow">
<template #icon>
<icon name="el-icon-Edit" />
</template>
线索详细信息配置</el-button
>
</div>
</el-col>
</el-row>
<div class="mb-10">
<h4 style="margin: 10px 0" class="text-primary">预警记录</h4>
<div style="min-height: 300px">
<div class="table-container">
<el-table :data="tableData" size="small">
<el-table-column
label="同步时间"
prop="createTime"
/>
<el-table-column
label="预警条数"
prop="size"
align="center"
/>
<el-table-column
label="分发状态"
align="center"
>
<template #default="{ row }">
<el-tag
type="success"
v-if="row.state === 'success'"
>成功</el-tag
>
<el-tooltip
effect="dark"
:content="row.errMsg"
placement="top-start"
v-else
>
<el-tag type="danger">失败</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table>
</div>
</div>
</div>
<footer class="flex end">
<el-button @click="handleEdit" type="primary" plain size="large"
>编辑模型</el-button
>
<el-button type="danger" plain @click="handleDel" size="large"
>删除模型</el-button
>
</footer>
</el-dialog>
<el-dialog title="线索详细信息配置" v-model="detailConfigShow" width="800px">
</el-dialog>
</template>
<script setup>
import {
DistributionMethod,
DistributionCycle,
ModelDataType,
} from "@/enums/dictEnums";
import { WEEKS } from "@/enums/appEnums";
import { listModelClass } from "@/api/sensitivePerception/modelClass";
import {
addModel,
updateModel,
delModel,
listModel,
} from "@/api/sensitivePerception/model";
import { listModelClue } from "@/api/sensitivePerception/modelClue";
import { listTopModelClueRecords } from "@/api/sensitivePerception/modelClue";
import useCatchStore from "@/stores/modules/catch";
import { getDictLable } from "@/utils/util";
import feedback from "@/utils/feedback";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"distributionMethod",
"distributionCycle",
"distributionFlow",
"timeLimit",
"approvalFlow",
"modelingMethod",
"modelDataType",
]);
const router = useRouter();
const query = ref({
size: 9,
current: 1,
});
const total = ref(0);
const list = ref([]);
const classes = ref([]);
function getList() {
listModel(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {
size: 9,
current: 1,
};
getList();
}
onMounted(() => {
getList();
listModelClass().then((data) => {
classes.value = data;
});
});
function handleChangeClass(id) {
query.value.classId = id;
getList();
}
const show = ref(false);
const mode = ref("add");
const form = ref({
distributionMethod: "1",
});
watch(mode, (val) => {
if (val === "add") {
initForm();
}
});
function initForm() {
form.value = { distributionMethod: "1" };
}
const formRef = ref(null);
function handleAdd() {
show.value = true;
mode.value = "add";
}
function handleEdit() {
show.value = true;
mode.value = "edit";
form.value = { ...activeModel.value };
}
async function handleSubmit() {
await formRef.value.validate();
if (mode.value === "add") {
await addModel(form.value);
} else {
activeModel.value = await updateModel(form.value);
}
getList();
initForm();
show.value = false;
feedback.msgSuccess("操作成功");
}
async function handleDel() {
await feedback.confirm("确定删除该模型?");
await delModel(activeModel.value.id);
feedback.msgSuccess("操作成功");
getList();
detailShow.value = false;
}
const detailShow = ref(false);
const activeModel = ref({});
const tableData = ref([]);
async function openDetail(item) {
activeModel.value = item;
tableData.value = await listTopModelClueRecords(item.id);
detailShow.value = true;
}
const detailConfigShow = ref(false)
const modelClueData = ref({})
async function handleDetailConfigShow() {
const data = await listModelClue({
modelIds: [activeModel.value.id],
current: 1,
size: 1
})
if (data.records.length && data.records[0].data) {
console.log(data.records)
} else {
modelClueData.value = JSON.parse(data.records[0].data)
}
detailConfigShow.value = true
}
</script>
<style lang="scss" scoped>
.menu {
> div {
height: 47px;
line-height: 47px;
padding: 0 36px;
&:hover,
&[active="true"] {
background: #e1e5ff;
cursor: pointer;
}
}
}
.model-card {
background: #f6f7ff;
border: 1px solid #e1e5ff;
border-radius: 4px;
padding: 18px;
&:hover {
border-color: var(--primary-color);
cursor: pointer;
}
.model-card-icon {
width: 76px;
}
.col {
--label-width: 78px;
}
}
</style>