Browse Source

fit: 信访投诉、案件核查下发

fit: 灵敏感知任务分发
fix: 大屏优化
main
wxc 1 year ago
parent
commit
f276a68430
  1. 7
      src/api/data/caseVerif.ts
  2. 7
      src/api/data/petitionComplaint.ts
  3. 2
      src/api/request.ts
  4. 14
      src/api/sensitivePerception/modelClue.ts
  5. 8
      src/api/sensitivePerception/modelClueTask.ts
  6. 5
      src/api/work/negative.ts
  7. 188
      src/components/data/distrbute.vue
  8. 441
      src/components/data/import-case.vue
  9. 585
      src/components/data/import.vue
  10. 14
      src/components/datav/card.vue
  11. 27
      src/components/datav/date-picker.vue
  12. 19
      src/components/datav/tab-item.vue
  13. 91
      src/components/datav/tabs.vue
  14. 2
      src/components/dict-select.vue
  15. 2
      src/components/file/list.vue
  16. 39
      src/components/file/upload-group.vue
  17. 54
      src/components/model-tree.vue
  18. 154
      src/components/negative/add.vue
  19. 4
      src/components/negative/description.vue
  20. 12
      src/components/negative/distribute.vue
  21. 1
      src/components/negative/verify-description.vue
  22. 2
      src/components/negative/verify.vue
  23. 125
      src/components/time-limit-select.vue
  24. 16
      src/enums/dictEnums.ts
  25. 8
      src/layout/Index.vue
  26. 5
      src/layout/components/MultipleTabs.vue
  27. 7
      src/stores/modules/multipleTabs.ts
  28. 23
      src/style/datav.scss
  29. 7
      src/style/public.scss
  30. 4
      src/utils/feedback.ts
  31. 340
      src/views/data/Ajhc.vue
  32. 272
      src/views/data/Gabxf.vue
  33. 270
      src/views/data/Gjxf.vue
  34. 121
      src/views/datav/CaseVerif.vue
  35. 171
      src/views/sensitivePerception/Model.vue
  36. 172
      src/views/sensitivePerception/ModelClue.vue
  37. 528
      src/views/sensitivePerception/ModelClueManual.vue
  38. 100
      src/views/sensitivePerception/ModelClueTask.vue
  39. 9
      src/views/sensitivePerception/Rwff.vue
  40. 9
      src/views/sensitivePerception/Sgff.vue
  41. 9
      src/views/sensitivePerception/Yjxs.vue
  42. 8
      src/views/system/Menu.vue
  43. 20
      src/views/system/Police.vue
  44. 16
      src/views/work/Query.vue

7
src/api/data/caseVerif.ts

@ -26,3 +26,10 @@ export function delCaseVerif(id) {
url: `/data/caseVerif/${id}` url: `/data/caseVerif/${id}`
}); });
} }
export function distributeCaseVerif(body) {
return request.post({
url: `/data/caseVerif/distribute`,
body
});
}

7
src/api/data/petitionComplaint.ts

@ -26,3 +26,10 @@ export function delPetitionComplaint(id) {
url: `/data/petitionComplaint/${id}` url: `/data/petitionComplaint/${id}`
}); });
} }
export function distributePetitionComplaint(body) {
return request.post({
url: `/data/petitionComplaint/distribute`,
body
});
}

2
src/api/request.ts

@ -93,7 +93,7 @@ function ajax(url: string, options: Options) {
} else { } else {
let message = res.message; let message = res.message;
if (res.code === 401) { if (res.code === 401) {
// deleteToken() deleteToken()
location.href = '/' location.href = '/'
} }
feedback.msgError(message) feedback.msgError(message)

14
src/api/sensitivePerception/modelClue.ts

@ -12,3 +12,17 @@ export function listTopModelClueRecords(modelId) {
url: `/model/clue/records/${modelId}/top` url: `/model/clue/records/${modelId}/top`
}); });
} }
export function manuelModelClueTask(body) {
return request.post({
url: `/model/clues/task/distribute/manuel`,
body
});
}
export function updateDepartModelClue(id, body) {
return request.post({
url: `/model/clues/${id}/updateDepart`,
body
});
}

8
src/api/sensitivePerception/modelClueTask.ts

@ -0,0 +1,8 @@
import request from "@/api/request";
export function listModelClueTask(query) {
return request.get({
url: `/model/clue/tasks`,
query
});
}

5
src/api/work/negative.ts

@ -43,3 +43,8 @@ export function negativeExport(query) {
}); });
} }
export function delNegative(id) {
return request.del({
url: `/negative/${id}`
});
}

188
src/components/data/distrbute.vue

@ -0,0 +1,188 @@
<template>
<el-dialog title="问题分发" v-model="show" width="80vw" top="5vh">
<header>
<div class="flex v-center end mb-20">
<span class="mr-20"
>
<span class="text-primary">{{ data.length }}</span>
条数据</span
>
</div>
</header>
<div style="min-height: 500px">
<div class="table-container">
<el-table :data="data">
<el-table-column
label="案件编号"
prop="originId"
show-overflow-tooltip
/>
<el-table-column
label="受理时间"
prop="discoveryTime"
show-overflow-tooltip
/>
<el-table-column
label="问题发生时间"
prop="happenTime"
show-overflow-tooltip
/>
<el-table-column
label="问题来源"
prop="problemSources"
show-overflow-tooltip
/>
<el-table-column
label="投诉人"
prop="responderName"
width="90"
/>
<el-table-column
label="投诉人电话"
prop="contactPhone"
width="120"
/>
<el-table-column label="业务类别" prop="businessTypeName" />
<el-table-column label="涉嫌问题" prop="involveProblem" />
<el-table-column label="涉及警种" prop="policeTypeName" />
<el-table-column
label="涉及单位"
prop="involveDepartName"
/>
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column label="操作" width="140">
<template #default="{ row }">
<el-button
type="info"
link
@click="handleRemoveDistribute(row)"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</div>
<footer class="flex end mt-20">
<el-button
type="primary"
size="large"
@click="handleShowDistributeDialog"
:disabled="data.length === 0"
>确认数据</el-button
>
</footer>
</el-dialog>
<el-dialog title="任务分发" v-model="distributeShow" width="50vw" top="5vh">
<el-form :label-width="120" ref="formRef" :model="form">
<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="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>
<div class="tips mt-10">
<p>
三级审核 在问题提交办结时需经过所队>二级机构>市局三级审核通过后方可办结
</p>
<p>
二级审核 在问题提交办结时仅需经过所队>二级机构两级审核通过后即可办结
</p>
</div>
</el-form-item>
</el-form>
<footer class="flex end mt-20">
<el-button type="primary" size="large" @click="handleSubmit"
>确认下发</el-button
>
</footer>
</el-dialog>
</template>
<script setup>
import useCatchStore from "@/stores/modules/catch";
import { distributePetitionComplaint } from "@/api/data/petitionComplaint";
const catchStore = useCatchStore();
const dict = catchStore.getDicts(["timeLimit", "approvalFlow"]);
const props = defineProps({
show: {
type: Boolean,
default: false,
},
data: {
type: Array,
default: [],
},
});
const emit = defineEmits(["update:data", "update:show", "update"]);
const show = ref(props.show);
const distributeShow = ref(false);
watch(
() => props.show,
(val) => {
show.value = val;
}
);
watch(show, (val) => {
emit("update:show", val);
});
function handleRemoveDistribute(row) {
let data = [...props.data];
data.splice(props.data.indexOf(row), 1);
emit("update:data", data);
}
const form = ref({});
const formRef = ref();
function handleShowDistributeDialog() {
distributeShow.value = true;
}
async function handleSubmit() {
await formRef.value.validate();
form.value.data = props.data;
await distributePetitionComplaint(form.value);
form.value = {};
distributeShow.value = false;
show.value = false;
emit("update");
emit("update:data", []);
}
</script>
<style lang="scss" scoped>
</style>

441
src/components/data/import-case.vue

@ -0,0 +1,441 @@
<template>
<el-dialog width="80vw" top="5vh" v-model="show" :title="title">
<div style="height: 600px">
<template v-if="step === 1">
<div class="mt-20">
<span>案件核查问题台账模板</span>
<a
class="link"
:href="`${BASE_PATH}/templates/案件核查问题台账(模板).xlsx`"
target="__blank"
>下载</a
>
</div>
<el-upload
drag
:multiple="false"
:auto-upload="false"
:show-file-list="false"
v-model:file-list="fileList"
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
class="mt-20"
>
<template v-if="fileList.length === 0">
<el-icon class="el-icon--upload"
><upload-filled
/></el-icon>
<div class="el-upload__text">
点击或拖拽文件到此区域上传
</div>
</template>
<template v-else>
<el-icon class="el-icon--upload"><Select /></el-icon>
<div class="el-upload__text">
已选择文件{{ fileList[fileList.length - 1].name }}
</div>
</template>
</el-upload>
<el-radio-group v-model="dataUpdateMethod" class="mt-20">
<el-radio value="incremental" border>增量更新</el-radio>
<el-radio value="overwrite" border>覆盖更新</el-radio>
</el-radio-group>
</template>
<template v-else>
<el-page-header @back="step = 1" class="mb-20"></el-page-header>
<div style="height: 556px; overflow: hidden">
<el-scrollbar height="556px">
<el-tabs v-model="activeTab">
<el-tab-pane label="全部" name="all">
<div class="table-container">
<el-table
:data="importTableData"
ref="tableRef"
>
<el-table-column
type="selection"
:selectable="
(row) => row.state === 'success'
"
/>
<el-table-column
label="案件编号"
prop="originId"
show-overflow-tooltip
/>
<el-table-column
label="受理时间"
prop="discoveryTime"
show-overflow-tooltip
/>
<el-table-column
label="问题发生时间"
prop="happenTime"
width="160"
show-overflow-tooltip
/>
<el-table-column
label="问题来源"
prop="problemSources"
show-overflow-tooltip
/>
<el-table-column
label="投诉人"
prop="responderName"
width="90"
/>
<el-table-column
label="投诉人电话"
prop="contactPhone"
width="120"
/>
<el-table-column
label="业务类别"
prop="businessTypeName"
/>
<el-table-column
label="涉嫌问题"
prop="involveProblem"
/>
<el-table-column
label="涉及警种"
prop="policeTypeName"
/>
<el-table-column
label="涉及单位"
prop="involveDepartName"
>
<template #default="{ row }">
<span>{{ involveSecondDepartName }}</span>
<span>{{ involveThirdDepartName }}</span>
</template>
</el-table-column>
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column
label="数据校验"
width="120"
>
<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-column
label="操作"
width="120"
>
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleEdit(row)"
>编辑</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane name="fail">
<template #label>
<el-badge
:value="importTableFailData.length"
>
<span>异常</span>
</el-badge>
</template>
<div class="table-container">
<el-table :data="importTableFailData">
<el-table-column
label="案件编号"
prop="originId"
show-overflow-tooltip
/>
<el-table-column
label="受理时间"
prop="discoveryTime"
show-overflow-tooltip
/>
<el-table-column
label="问题发生时间"
prop="happenTime"
/>
<el-table-column
label="问题来源"
prop="problemSources"
show-overflow-tooltip
/>
<el-table-column
label="投诉人"
prop="responderName"
width="90"
/>
<el-table-column
label="投诉人电话"
prop="contactPhone"
width="120"
/>
<el-table-column
label="业务类别"
prop="businessTypeName"
/>
<el-table-column
label="涉嫌问题"
prop="involveProblem"
/>
<el-table-column
label="涉及警种"
prop="policeTypeName"
/>
<el-table-column
label="涉及单位"
prop="complainedDepartName"
/>
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column
label="数据校验"
width="120"
>
<template #default="{ row }">
<el-tooltip
effect="dark"
:content="row.errMsg"
placement="top-start"
>
<el-tag type="danger"
>异常</el-tag
>
</el-tooltip>
</template>
</el-table-column>
<el-table-column
label="操作"
width="120"
>
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleEdit(row)"
>编辑</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</el-scrollbar>
</div>
</template>
</div>
<footer class="flex end mt-20 v-center">
<span class="mr-20" v-if="step === 2"
>选中<b>{{ checkRowSize }}</b
>条数据</span
>
<el-button size="large" @click="show = false">取消</el-button>
<el-button
type="primary"
size="large"
@click="handleImport"
:disabled="fileList.length === 0"
v-if="step === 1"
v-loading="loading"
>下一步</el-button
>
<el-button
type="primary"
size="large"
@click="handleSaveImport"
:disabled="checkRowSize === 0"
v-else
>确认导入</el-button
>
</footer>
</el-dialog>
<el-dialog width="660px" top="5vh" v-model="editShow" title="编辑数据">
<el-form :label-width="120" :model="form" ref="formRef">
<el-form-item
label="案件编号"
prop="originId"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<el-input placeholder="请输入" v-model="form.originId" />
</el-form-item>
<el-form-item label="受理时间">
<el-date-picker type="datetime" v-model="form.discoveryTime" />
</el-form-item>
<el-form-item label="问题发生时间">
<el-date-picker type="datetime" v-model="form.happenTime" />
</el-form-item>
<el-form-item label="问题来源">
<el-input placeholder="请输入" v-model="form.problemSources" />
</el-form-item>
<el-form-item label="投诉人">
<el-input placeholder="请输入" v-model="form.responderName" />
</el-form-item>
<el-form-item label="投诉人电话">
<el-input placeholder="请输入" v-model="form.contactPhone" />
</el-form-item>
<el-form-item label="业务类别">
<el-input placeholder="请输入" v-model="form.businessTypeName" />
</el-form-item>
<el-form-item label="涉嫌问题">
<el-input placeholder="请输入" v-model="form.involveProblem" />
</el-form-item>
<el-form-item label="涉及警种">
<el-input placeholder="请输入" v-model="form.policeTypeName" />
</el-form-item>
<el-form-item
label="涉及单位"
prop="involveThirdDepartId"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<depart-tree-select
v-model="form.involveThirdDepartId"
:check-strictly="false"
@node-click="(node) => form.involveThirdDepartName = node.shortName"
/>
</el-form-item>
<el-form-item
label="具体内容"
prop="thingDesc"
:rules="{
required: true,
message: '请输入',
trigger: ['blur'],
}"
>
<el-input type="textarea" v-model="form.thingDesc" />
</el-form-item>
</el-form>
<footer class="flex end mt-20">
<el-button @click="editShow = false">取消</el-button>
<el-button type="primary" @click="handleEditSumbit"
>确认修改</el-button
>
</footer>
</el-dialog>
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
import { getDictLable } from "@/utils/util";
import { importCaseVerif, addCaseVerif } from "@/api/data/caseVerif";
import feedback from "@/utils/feedback";
const props = defineProps({
modelValue: {
type: Boolean,
default: false,
},
title: {
type: String,
}
});
const emit = defineEmits(["update:modelValue", "close", "update"]);
const show = ref(false);
watch(
() => props.modelValue,
(val) => {
show.value = val;
}
);
watch(show, (val) => {
emit("update:modelValue", val);
});
const dataUpdateMethod = ref("incremental");
const fileList = ref([]);
const importTableData = ref([]);
const importTableFailData = computed(() => {
return importTableData.value.filter((item) => item.state === "fail");
});
const step = ref(1);
const loading = ref(false);
async function handleImport() {
const formData = new FormData();
formData.append("file", fileList.value[fileList.value.length - 1].raw);
loading.value = true;
try {
importTableData.value = await importCaseVerif(formData);
} catch(e) {
loading.value = false;
return
}
loading.value = false;
step.value = 2;
nextTick(() => {});
}
const checkRowSize = computed(
() => tableRef.value?.getSelectionRows().length || 0
);
const tableRef = ref(null);
async function handleSaveImport() {
const rows = tableRef.value.getSelectionRows();
await addCaseVerif(dataUpdateMethod.value, [...rows]);
feedback.msgSuccess(`成功导入${rows.length}条数据`);
step.value = 1;
importTableData.value = [];
fileList.value = [];
emit("close");
emit("update");
}
let activeIndex = -1;
function handleEdit(row) {
form.value = { ...row };
activeIndex = importTableData.value.indexOf(row);
editShow.value = true;
}
const editShow = ref(false);
const form = ref({});
const formRef = ref();
const activeTab = ref("all");
async function handleEditSumbit() {
await formRef.value.validate();
form.value.state = "success";
importTableData.value[activeIndex] = form.value;
editShow.value = false;
}
</script>
<style lang="scss" scoped>
</style>

585
src/components/data/import.vue

@ -0,0 +1,585 @@
<template>
<el-dialog width="80vw" top="5vh" v-model="show" :title="title">
<div style="height: 600px">
<template v-if="step === 1">
<div class="mt-20">
<span>信访投诉数据台账模板</span>
<a
class="link"
:href="`${BASE_PATH}/templates/信访投诉数据台账(模板).xlsx`"
target="__blank"
>下载</a
>
</div>
<el-upload
drag
:multiple="false"
:auto-upload="false"
:show-file-list="false"
v-model:file-list="fileList"
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
class="mt-20"
>
<template v-if="fileList.length === 0">
<el-icon class="el-icon--upload"
><upload-filled
/></el-icon>
<div class="el-upload__text">
点击或拖拽文件到此区域上传
</div>
</template>
<template v-else>
<el-icon class="el-icon--upload"><Select /></el-icon>
<div class="el-upload__text">
已选择文件{{ fileList[fileList.length - 1].name }}
</div>
</template>
</el-upload>
<el-radio-group v-model="dataUpdateMethod" class="mt-20">
<el-radio value="incremental" border>增量更新</el-radio>
<el-radio value="overwrite" border>覆盖更新</el-radio>
</el-radio-group>
</template>
<template v-else>
<el-page-header @back="step = 1" class="mb-20"></el-page-header>
<div style="height: 556px; overflow: hidden">
<el-scrollbar height="556px">
<el-tabs v-model="activeTab">
<el-tab-pane label="全部" name="all">
<div class="table-container">
<el-table
:data="importTableData"
ref="tableRef"
>
<el-table-column
type="selection"
:selectable="
(row) => row.state === 'success'
"
/>
<el-table-column
label="信件编号"
prop="originId"
show-overflow-tooltip
/>
<el-table-column
label="投诉渠道"
prop="channelForFilingComplaints"
/>
<el-table-column
label="受理层级"
prop="acceptanceLevel"
/>
<el-table-column
label="登记时间"
prop="discoveryTime"
show-overflow-tooltip
/>
<el-table-column
label="投诉人"
prop="responderName"
width="90"
/>
<el-table-column
label="投诉人电话"
prop="contactPhone"
width="120"
/>
<el-table-column
label="初重信访"
align="center"
width="90"
>
<template #default="{ row }">
<span>{{
getDictLable(
dict.initialPetition,
row.initialPetition
)
}}</span>
</template>
</el-table-column>
<el-table-column
label="缠访闹访"
width="90"
align="center"
>
<template #default="{ row }">
<span
v-if="
row.entanglementVisits ===
true
"
></span
>
<span
v-if="
row.entanglementVisits ===
false
"
></span
>
</template>
</el-table-column>
<el-table-column
label="群众集访"
width="90"
align="center"
>
<template #default="{ row }">
<span
v-if="
row.massVisits === true
"
></span
>
<span
v-if="
row.massVisits === false
"
></span
>
</template>
</el-table-column>
<el-table-column label="被投诉机构" show-overflow-tooltip>
<template #default="{ row }">
<span>{{
row.involveSecondDepartName
}}</span>
<span>{{
row.involveThirdDepartName
}}</span>
</template>
</el-table-column>
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column
label="数据校验"
width="120"
>
<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-column
label="操作"
width="120"
>
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleEdit(row)"
>编辑</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
<el-tab-pane name="fail">
<template #label>
<el-badge
:value="importTableFailData.length"
class="item"
>
<span>异常</span>
</el-badge>
</template>
<div class="table-container">
<el-table :data="importTableFailData">
<el-table-column
label="信件编号"
prop="originId"
show-overflow-tooltip
/>
<el-table-column
label="投诉渠道"
prop="channelForFilingComplaints"
/>
<el-table-column
label="受理层级"
prop="acceptanceLevel"
/>
<el-table-column
label="登记时间"
prop="discoveryTime"
show-overflow-tooltip
/>
<el-table-column
label="投诉人"
prop="responderName"
width="90"
/>
<el-table-column
label="投诉人电话"
prop="contactPhone"
width="120"
/>
<el-table-column
label="初重信访"
align="center"
width="90"
>
<template #default="{ row }">
<span>{{
getDictLable(
dict.initialPetition,
row.initialPetition
)
}}</span>
</template>
</el-table-column>
<el-table-column
label="缠访闹访"
width="90"
align="center"
>
<template #default="{ row }">
<span
v-if="
row.entanglementVisits ===
true
"
></span
>
<span
v-if="
row.entanglementVisits ===
false
"
></span
>
</template>
</el-table-column>
<el-table-column
label="群众集访"
width="90"
align="center"
>
<template #default="{ row }">
<span
v-if="
row.massVisits === true
"
></span
>
<span
v-if="
row.massVisits === false
"
></span
>
</template>
</el-table-column>
<el-table-column label="被投诉机构" show-overflow-tooltip>
<template #default="{ row }">
<span>{{
row.involveSecondDepartName
}}</span>
<span>{{
row.involveThirdDepartName
}}</span>
</template>
</el-table-column>
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column
label="数据校验"
width="120"
>
<template #default="{ row }">
<el-tooltip
effect="dark"
:content="row.errMsg"
placement="top-start"
>
<el-tag type="danger"
>异常</el-tag
>
</el-tooltip>
</template>
</el-table-column>
<el-table-column
label="操作"
width="120"
>
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleEdit(row)"
>编辑</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</el-tab-pane>
</el-tabs>
</el-scrollbar>
</div>
</template>
</div>
<footer class="flex end mt-20 v-center">
<span class="mr-20" v-if="step === 2"
>选中<b>{{ checkRowSize }}</b
>条数据</span
>
<el-button size="large" @click="show = false">取消</el-button>
<el-button
type="primary"
size="large"
@click="handleImport"
:disabled="fileList.length === 0"
v-if="step === 1"
v-loading="loading"
>下一步</el-button
>
<el-button
type="primary"
size="large"
@click="handleSaveImport"
:disabled="checkRowSize === 0"
v-else
>确认导入</el-button
>
</footer>
</el-dialog>
<el-dialog width="660px" top="5vh" v-model="editShow" title="编辑数据">
<el-form :label-width="120" :model="form" ref="formRef">
<el-form-item
label="信件编号"
prop="originId"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<el-input placeholder="请输入" v-model="form.originId" />
</el-form-item>
<el-form-item label="投诉渠道">
<el-input
placeholder="请输入"
v-model="form.channelForFilingComplaints"
/>
</el-form-item>
<el-form-item label="受理层级">
<el-input placeholder="请输入" v-model="form.acceptanceLevel" />
</el-form-item>
<el-form-item label="登记时间">
<el-date-picker type="datetime" v-model="form.discoveryTime" />
</el-form-item>
<el-form-item label="投诉人">
<el-input placeholder="请输入" v-model="form.responderName" />
</el-form-item>
<el-form-item label="投诉人电话">
<el-input placeholder="请输入" v-model="form.contactPhone" />
</el-form-item>
<el-form-item
label="初重信访"
prop="initialPetition"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<el-select clearable v-model="form.initialPetition">
<el-option
v-for="item in dict.initialPetition"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
<el-form-item
label="缠访闹访"
prop="entanglementVisits"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<el-select v-model="form.entanglementVisits">
<el-option :value="true" label="是" />
<el-option :value="false" label="否" />
</el-select>
</el-form-item>
<el-form-item
label="群众集访"
prop="massVisits"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<el-select v-model="form.massVisits">
<el-option :value="true" label="是" />
<el-option :value="false" label="否" />
</el-select>
</el-form-item>
<el-form-item
label="被投诉机构"
prop="involveThirdDepartId"
:rules="{
required: true,
message: '请选择',
trigger: ['blur'],
}"
>
<depart-tree-select
v-model="form.involveThirdDepartId"
:check-strictly="false"
@node-click="
(node) =>
(form.involveThirdDepartName = node.shortName)
"
/>
</el-form-item>
<el-form-item
label="具体内容"
prop="thingDesc"
:rules="{
required: true,
message: '请输入',
trigger: ['blur'],
}"
>
<el-input type="textarea" v-model="form.thingDesc" />
</el-form-item>
</el-form>
<footer class="flex end mt-20">
<el-button @click="editShow = false">取消</el-button>
<el-button type="primary" @click="handleEditSumbit"
>确认修改</el-button
>
</footer>
</el-dialog>
</template>
<script setup>
import { BASE_PATH } from "@/api/request";
import { getDictLable } from "@/utils/util";
import {
importPetitionComplaint,
addPetitionComplaint,
} from "@/api/data/petitionComplaint";
import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
import { computed } from "vue";
const catchStore = useCatchStore();
const dict = catchStore.getDicts(["initialPetition"]);
const props = defineProps({
modelValue: {
type: Boolean,
default: false,
},
title: {
type: String,
},
problemSourcesCode: {
type: String,
},
});
const emit = defineEmits(["update:modelValue", "close", "update"]);
const show = ref(false);
watch(
() => props.modelValue,
(val) => {
show.value = val;
}
);
watch(show, (val) => {
emit("update:modelValue", val);
});
const dataUpdateMethod = ref("incremental");
const fileList = ref([]);
const importTableData = ref([]);
const importTableFailData = computed(() => {
return importTableData.value.filter((item) => item.state === "fail");
});
const step = ref(1);
const loading = ref(false);
async function handleImport() {
const formData = new FormData();
formData.append("file", fileList.value[fileList.value.length - 1].raw);
loading.value = true;
importTableData.value = await importPetitionComplaint(formData);
loading.value = false;
step.value = 2;
nextTick(() => {});
}
const checkRowSize = computed(
() => tableRef.value?.getSelectionRows().length || 0
);
const tableRef = ref(null);
async function handleSaveImport() {
const rows = tableRef.value.getSelectionRows();
await addPetitionComplaint({
dataUpdateMethod: dataUpdateMethod.value,
problemSourcesCode: props.problemSourcesCode,
data: [...rows],
});
feedback.msgSuccess(`成功导入${rows.length}条数据`);
step.value = 1;
importTableData.value = [];
fileList.value = [];
emit("close");
emit("update");
}
let activeIndex = -1;
function handleEdit(row) {
form.value = { ...row };
activeIndex = importTableData.value.indexOf(row);
editShow.value = true;
}
const editShow = ref(false);
const form = ref({});
const formRef = ref();
const activeTab = ref("all");
async function handleEditSumbit() {
await formRef.value.validate();
form.value.state = "success";
importTableData.value[activeIndex] = form.value;
editShow.value = false;
}
</script>
<style lang="scss" scoped>
</style>

14
src/components/datav/card.vue

@ -1,11 +1,9 @@
<template> <template>
<div class="datav-card"> <div class="datav-card">
<div class="datav-card_content"> <div class="datav-card_content">
<header class="flex between"> <header class="flex between" v-if="title">
<div class="datav-card_title">{{ title }}</div> <div class="datav-card_title">{{ title }}</div>
<div> <div class="datav-card_sub-title">{{ subTitle }}</div>
<slot name="header-append"></slot>
</div>
</header> </header>
<slot></slot> <slot></slot>
</div> </div>
@ -16,6 +14,10 @@ defineProps({
title: { title: {
type: String, type: String,
}, },
subTitle: {
type: String,
default: ""
}
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -48,5 +50,9 @@ defineProps({
margin-top: 0; margin-top: 0;
margin-bottom: 8px; margin-bottom: 8px;
} }
.datav-card_sub-title {
color: #597AE9;
font-size: 14px;
}
} }
</style> </style>

27
src/components/datav/date-picker.vue

@ -0,0 +1,27 @@
<template>
<div class="datav-col">
<label for="">统计周期</label>
<el-date-picker
v-model="value"
type="daterange"
range-separator="-"
start-placeholder="开始日期"
end-placeholder="结束日期"
format="YYYY年MM月DD日"
style="--el-input-bg-color: transparent; box-shadow: none; --el-text-color-regular: #fff; --el-text-color-primary: #fff"
/>
</div>
</template>
<script setup>
const value = ref([])
</script>
<style lang="scss" scoped>
.datav-col {
font-size: 14px;
text-align: center;
margin-bottom: 16px;
label {
color: #859DEC;
}
}
</style>

19
src/components/datav/tab-item.vue

@ -0,0 +1,19 @@
<template>
<div v-if="name === activeTab">
<slot />
</div>
</template>
<script setup>
defineProps({
label: {
type: String,
},
name: {
type: String,
},
});
const activeTab = inject("activeTab");
</script>
<style lang="scss" scoped>
</style>

91
src/components/datav/tabs.vue

@ -0,0 +1,91 @@
<template>
<div class="tabs">
<div class="tab-header flex gap-20 mb-40" v-if="type === ''">
<div
class="tab-title-item"
v-for="item in slots"
:key="item.props.name"
:active="item.props.name === activeTab"
@click="handleChangeActiveTab(item.props.name)"
>
{{ item.props.label }}
</div>
</div>
<div class="tabs-content">
<slot></slot>
</div>
<div
class="flex tab-title flex center mt-20 mb-20"
v-if="type === 'bottom-button'"
>
<div
class="tab-title-item"
v-for="item in slots"
:key="item.props.name"
:active="item.props.name === activeTab"
@click="handleChangeActiveTab(item.props.name)"
>
{{ item.props.label }}
</div>
</div>
</div>
</template>
<script setup>
const props = defineProps({
modelValue: {
type: String,
},
// bottom-button
type: {
type: String,
default: "",
},
});
const emit = defineEmits(["update:modelValue"]);
const activeTab = ref(props.modelValue);
provide("activeTab", activeTab);
const slots = useSlots().default();
function handleChangeActiveTab(name) {
activeTab.value = name;
emit("update:modelValue", name);
}
</script>
<style lang="scss" scoped>
.tab-header {
.tab-title-item {
font-size: 22px;
line-height: 34px;
color: #597ae9;
border-bottom: 5px solid transparent;
cursor: pointer;
&[active="true"] {
color: #fff;
border-color: #28E6FF;
}
}
}
.tab-title {
margin-bottom: 4px;
cursor: pointer;
.tab-title-item {
width: 119px;
height: 32px;
line-height: 32px;
border: 1px solid #24d2ee;
text-align: center;
&[active="true"] {
background: #24d2ee;
color: #0724b2;
}
&:first-child {
border-radius: 103px 0px 0px 103px;
}
&:last-child {
border-radius: 0 103px 103px 0;
}
}
}
</style>

2
src/components/dict-select.vue

@ -10,7 +10,7 @@
</el-select> </el-select>
</template> </template>
<template v-else-if="selectTree.includes(name)"> <template v-else-if="selectTree.includes(name)">
<el-tree-select :data="data" :props="{value: 'id'}" node-key="id" clearable filterable @current-change="(nodeData, node) => change(nodeData)" /> <el-tree-select :data="data" :props="{value: 'id'}" node-key="id" clearable filterable @node-click="(nodeData, node) => change(nodeData)" />
</template> </template>
</template> </template>
<script setup> <script setup>

2
src/components/file/list.vue

@ -230,6 +230,7 @@ const props = defineProps({
default: false, default: false,
}, },
}); });
const emit = defineEmits(["update:files"]); const emit = defineEmits(["update:files"]);
const preview = ref(false); const preview = ref(false);
@ -281,6 +282,7 @@ function next() {
<style lang="scss" scoped> <style lang="scss" scoped>
.file-container { .file-container {
min-height: 80px; min-height: 80px;
margin: 2px;
.item { .item {
width: 80px; width: 80px;
height: 80px; height: 80px;

39
src/components/file/upload-group.vue

@ -122,8 +122,35 @@
activeFileIds.includes(item.uid) activeFileIds.includes(item.uid)
" "
> >
<template
v-if="
getFileType(item.fileName) ===
FileType.IMG
"
>
<div
class="img-box"
:style="{
backgroundImage: `url(${BASE_PATH}/file/stream/${item.filePath})`,
}"
@click="filePreview(item)"
></div>
<a
class="remove-btn"
@click="remove(index)"
v-if="removeEnable"
>
<icon
name="el-icon-CircleCloseFilled"
:size="20"
/>
</a>
</template>
<template v-else>
<icon <icon
:name="getIconName(item.fileName)" :name="
getIconName(item.fileName)
"
:size="40" :size="40"
/> />
<span class="filename">{{ <span class="filename">{{
@ -138,6 +165,7 @@
:size="16" :size="16"
/> />
</a> </a>
</template>
</div> </div>
</div> </div>
</template> </template>
@ -230,10 +258,9 @@
import { getToken } from "@/utils/token"; import { getToken } from "@/utils/token";
import { BASE_PATH } from "@/api/request"; import { BASE_PATH } from "@/api/request";
import feedback from "@/utils/feedback"; import feedback from "@/utils/feedback";
import { getIconName } from "@/utils/util"; import { getIconName, getFileType } from "@/utils/util";
import { import { ProblemSources } from "@/enums/dictEnums";
ProblemSources import { FileType } from "@/enums/fileEnums";
} from "@/enums/dictEnums";
const props = defineProps({ const props = defineProps({
files: { files: {
@ -339,7 +366,7 @@ function handleSubmit() {
} }
function remove(index) { function remove(index) {
debugger debugger;
const files = [...props.files]; const files = [...props.files];
files.splice(index, 1); files.splice(index, 1);
emit("update:files", files); emit("update:files", files);

54
src/components/model-tree.vue

@ -6,10 +6,11 @@
</el-input> </el-input>
<el-tree <el-tree
:data="treeData" :data="treeData"
node-key="id" node-key="value"
:render-content="renderContent" :render-content="renderContent"
:default-expanded-keys="[0]" :default-expanded-keys="[ROOT_ID]"
:filter-node-method="filterNode" :filter-node-method="filterNode"
@node-click="handleClick"
ref="treeRef" ref="treeRef"
/> />
</template> </template>
@ -17,22 +18,22 @@
import Icon from "@/components/icon/index.vue"; import Icon from "@/components/icon/index.vue";
import { treeModel } from "@/api/sensitivePerception/model"; import { treeModel } from "@/api/sensitivePerception/model";
const ROOT_ID = 0;
const treeData = ref([ const treeData = ref([
{ {
label: "全部", label: "全部",
id: 0, value: ROOT_ID,
type: "modelClass", type: "modelClass",
children: [], children: [],
}, },
]); ]);
const list = ref([]); const list = ref([]);
const total = ref(0) const total = ref(0);
onMounted(() => { onMounted(() => {
treeModel().then((data) => { treeModel().then((data) => {
treeData.value[0].children = data; treeData.value[0].children = data;
getList()
}); });
}); });
@ -69,17 +70,46 @@ function renderContent(
); );
} }
const filterText = ref('') const filterText = ref("");
const treeRef = ref(null) const treeRef = ref(null);
const filterNode = (value: string, data: Tree) => { const filterNode = (value: string, data: Tree) => {
if (!value) return true if (!value) return true;
return data.label.includes(value) return data.label.includes(value);
} };
watch(filterText, (val) => { watch(filterText, (val) => {
treeRef.value!.filter(val) treeRef.value!.filter(val);
}) });
const props = defineProps({
modelValue: {
type: Array,
defalut: [],
},
});
const emit = defineEmits(["update:modelValue"]);
function handleClick(node) {
if (node.value === ROOT_ID) {
emit("update:modelValue", null);
return;
}
const arr = [];
getModelId(arr, node);
emit("update:modelValue", arr);
}
function getModelId(arr, node) {
if (node.type === "model") {
arr.push(node.value);
} else if (node.children && node.children.length) {
node.children.forEach((item) => {
getModelId(arr, item);
});
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
:deep() { :deep() {

154
src/components/negative/add.vue

@ -1,6 +1,10 @@
<template> <template>
<el-dialog title="问题录入" width="54vw" :lock-scroll="false" top="5vh"> <el-dialog title="问题录入" width="54vw" :lock-scroll="false" top="5vh">
<el-scrollbar height="75vh"> <el-scrollbar
height="75vh"
v-loading="loading"
element-loading-text="问题下发中..."
>
<el-form <el-form
label-width="148" label-width="148"
:model="form" :model="form"
@ -179,13 +183,16 @@
:rules="{ :rules="{
required: true, required: true,
message: '请选择问题涉及单位', message: '请选择问题涉及单位',
trigger: ['blur'],
}" }"
> >
<depart-tree-select <depart-tree-select
v-model="form.involveDepartId" v-model="form.involveDepartId"
:check-strictly="true"
@node-click=" @node-click="
(row) => (row) =>
(form.involveDepartName = row.shortName) (form.involveDepartName =
row.shortName)
" "
/> />
</el-form-item> </el-form-item>
@ -261,6 +268,7 @@
:rules="{ :rules="{
required: true, required: true,
message: '请输入事情简要描述', message: '请输入事情简要描述',
trigger: ['blur'],
}" }"
> >
<el-input <el-input
@ -323,7 +331,17 @@
}" }"
> >
<div class="flex gap"> <div class="flex gap">
<div style="width: 280px">
<template
v-if="form.hostLevel === HostLevel.THREE"
>
<depart-tree-select
v-model="form.departId"
v-loading="departLoading"
/>
</template>
<el-tree-select <el-tree-select
v-else
:data="departs" :data="departs"
:props="{ label: 'shortName', value: 'id' }" :props="{ label: 'shortName', value: 'id' }"
node-key="id" node-key="id"
@ -333,7 +351,9 @@
@node-click="handleSelectDepart" @node-click="handleSelectDepart"
check-strictly check-strictly
style="width: 280px" style="width: 280px"
v-loading="departLoading"
/> />
</div>
<el-button <el-button
type="primary" type="primary"
@click="handleLinkDepart" @click="handleLinkDepart"
@ -354,89 +374,17 @@
trigger: ['blur'], trigger: ['blur'],
}" }"
> >
<el-radio-group v-model="form.timeLimit" class="block"> <time-limit-select
<el-radio v-model="form.timeLimit"
v-for="item in dict.timeLimit" v-model:maxSignDuration="form.maxSignDuration"
:key="item.dictCode" v-model:maxHandleDuration="form.maxHandleDuration"
:value="item.dictValue" v-model:maxExtensionDuration="
>{{ item.dictLabel form.maxExtensionDuration
}}{{ "
item.remark ? `(${item.remark})` : ""
}}</el-radio
>
</el-radio-group>
</el-form-item>
</div>
<template v-if="form.timeLimit === TimeLimit.OTHER">
<el-row>
<el-col :span="7">
<el-form-item
label="最大签收时长"
prop="maxSignDuration"
:rules="{
required: true,
message: '请输入最大签收时长',
trigger: ['blur'],
}"
>
<div class="flex gap">
<el-input
v-model="form.maxSignDuration"
type="number"
style="width: 70px"
:min="1"
:max="99"
/>
<span style="width: 60px">工作日</span>
</div>
</el-form-item>
</el-col>
<el-col :span="7">
<el-form-item
label="最大办理时长"
prop="maxHandleDuration"
:rules="{
required: true,
message: '请输入最大办理时长',
trigger: ['blur'],
}"
>
<div class="flex gap">
<el-input
v-model="form.maxHandleDuration"
type="number"
style="width: 70px"
:min="1"
:max="99"
/> />
<span style="width: 60px">工作日</span>
</div>
</el-form-item> </el-form-item>
</el-col>
<el-col :span="7">
<el-form-item
label="最大延期天数"
prop="maxExtensionDuration"
:rules="{
required: true,
message: '请输入最大延期天数',
trigger: ['blur'],
}"
>
<div class="flex gap">
<el-input
v-model="form.maxExtensionDuration"
type="number"
style="width: 70px"
:min="1"
:max="99"
/>
<span></span>
</div> </div>
</el-form-item>
</el-col>
</el-row>
</template>
<h2>审批流程</h2> <h2>审批流程</h2>
<div class="add-negation-container"> <div class="add-negation-container">
<el-form-item <el-form-item
@ -473,7 +421,11 @@
</el-scrollbar> </el-scrollbar>
<footer class="flex end"> <footer class="flex end">
<el-button @click="emit('close')" size="large">取消</el-button> <el-button @click="emit('close')" size="large">取消</el-button>
<el-button type="primary" @click="handleAddNegative" size="large" <el-button
type="primary"
@click="handleAddNegative"
size="large"
:loading="loading"
>下发问题</el-button >下发问题</el-button
> >
</footer> </footer>
@ -489,7 +441,7 @@ import {
} from "@/enums/dictEnums"; } from "@/enums/dictEnums";
import feedback from "@/utils/feedback"; import feedback from "@/utils/feedback";
import { addNegative, generateOriginId } from "@/api/work/negative"; import { addNegative, generateOriginId } from "@/api/work/negative";
import { secondList, departTree, listByFirstHost } from "@/api/system/depart"; import { secondList, listByFirstHost } from "@/api/system/depart";
import useCatchStore from "@/stores/modules/catch"; import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore(); const catchStore = useCatchStore();
@ -510,14 +462,19 @@ const form = ref({
timeLimit: TimeLimit.WORK_137, timeLimit: TimeLimit.WORK_137,
approvalFlow: ApprovalFlow.SECOND, approvalFlow: ApprovalFlow.SECOND,
}); });
getDeparts();
watch( watch(
() => form.value.hostLevel, () => form.value.hostLevel,
() => { () => {
getDeparts(); getDeparts();
} }
); );
onMounted(() => {
getDeparts();
})
const formRef = ref(null); const formRef = ref(null);
const loading = ref(false);
async function handleAddNegative() { async function handleAddNegative() {
try { try {
await formRef.value.validate(); await formRef.value.validate();
@ -528,7 +485,14 @@ async function handleAddNegative() {
form.value.thingFiles = form.value.thingFiles.filter( form.value.thingFiles = form.value.thingFiles.filter(
(item) => item.filePath (item) => item.filePath
); );
loading.value = true;
try {
await addNegative(form.value); await addNegative(form.value);
} catch (e) {
loading.value = false;
return;
}
loading.value = false;
form.value = { form.value = {
thingFiles: [], thingFiles: [],
hostLevel: HostLevel.THREE, hostLevel: HostLevel.THREE,
@ -540,23 +504,15 @@ async function handleAddNegative() {
} }
const departs = ref<any[]>([]); const departs = ref<any[]>([]);
const departLoading = ref(false)
async function getDeparts() { async function getDeparts() {
departLoading.value = true
if (form.value.hostLevel === HostLevel.FIRST) { if (form.value.hostLevel === HostLevel.FIRST) {
departs.value = await listByFirstHost() departs.value = await listByFirstHost();
} else if (form.value.hostLevel === HostLevel.SECOND) {
departs.value = await secondList();
} }
else if (form.value.hostLevel === HostLevel.SECOND) { departLoading.value = false
departs.value = await secondList()
}
else if (form.value.hostLevel === HostLevel.THREE) {
const data = await departTree()
data.forEach(item => {
if (item.level === 1) {
item.disabled = true
}
})
departs.value = data
}
} }
function handleSelectDepart(row, node) { function handleSelectDepart(row, node) {

4
src/components/negative/description.vue

@ -20,11 +20,11 @@
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div class="col col-6"> <div class="col col-6" v-if="negative.responderName">
<label>投诉反映人</label> <label>投诉反映人</label>
<span>{{ negative.responderName }}</span> <span>{{ negative.responderName }}</span>
</div> </div>
<div class="col col-6"> <div class="col col-6" v-if="negative.contactPhone">
<label>联系电话</label> <label>联系电话</label>
<span>{{ negative.contactPhone }}</span> <span>{{ negative.contactPhone }}</span>
</div> </div>

12
src/components/negative/distribute.vue

@ -32,6 +32,7 @@
filterable filterable
v-model="form.departId" v-model="form.departId"
@change="handleSelectDepart" @change="handleSelectDepart"
@node-click="(node) => form.departName = node.shortName"
/> />
<div class="tips mt-10"> <div class="tips mt-10">
<p>请根据问题信息的内容再次确认涉及单位是否正确</p> <p>请根据问题信息的内容再次确认涉及单位是否正确</p>
@ -41,15 +42,8 @@
</el-row> </el-row>
<template v-if="negative.flowKey === FlowNodeEnum.FIRST_DISTRIBUTE"> <template v-if="negative.flowKey === FlowNodeEnum.FIRST_DISTRIBUTE">
<el-form-item label="办理时限" prop="timeLimit"> <el-form-item label="办理时限" prop="timeLimit">
<el-radio-group v-model="form.timeLimit">
<el-radio <time-limit-select v-model="form.timeLimit" v-model:maxSignDuration="form.maxSignDuration" v-model:maxHandleDuration="form.maxHandleDuration" v-model:maxExtensionDuration="form.maxExtensionDuration" />
v-for="item in dict.timeLimit"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{ item.remark ? `(${item.remark})` : "" }}</el-radio
>
</el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="审批流程" prop="approvalFlow"> <el-form-item label="审批流程" prop="approvalFlow">
<el-radio-group v-model="form.approvalFlow"> <el-radio-group v-model="form.approvalFlow">

1
src/components/negative/verify-description.vue

@ -172,6 +172,7 @@ const dict = useCatchStore().getDicts(["accountabilityTarget"]);
const activeNames = ref(['verify', 'involved_department', 'completionAttachment']) const activeNames = ref(['verify', 'involved_department', 'completionAttachment'])
const negative = inject('negative'); const negative = inject('negative');
for (let i = 0; i < negative.value.blames.filter(item => item.type === BlameType.PERSONAL).length; i++) { for (let i = 0; i < negative.value.blames.filter(item => item.type === BlameType.PERSONAL).length; i++) {
activeNames.value.push('involved' + i) activeNames.value.push('involved' + i)
} }

2
src/components/negative/verify.vue

@ -1177,7 +1177,7 @@ function getFormData() {
? AccountabilityTarget.PERSONAL ? AccountabilityTarget.PERSONAL
: "", : "",
blames: negative.value.blames, blames: negative.value.blames,
files: [], files: negative.value.files || [],
}; };
} }

125
src/components/time-limit-select.vue

@ -0,0 +1,125 @@
<template>
<el-radio-group v-model="value" class="block">
<el-radio
v-for="item in dict.timeLimit"
:key="item.dictCode"
:value="item.dictValue"
>{{ item.dictLabel
}}{{ item.remark ? `(${item.remark})` : "" }}</el-radio
>
</el-radio-group>
<template v-if="value === TimeLimit.OTHER">
<el-row>
<el-col :span="8">
<el-form-item
label="签收"
prop="maxSignDuration"
label-width="80"
:rules="{
required: true,
message: '请输入最大签收时长'
}"
>
<div class="flex gap">
<el-input
v-model="maxSignDurationValue"
type="number"
style="width: 70px"
:min="1"
:max="99"
/>
<span style="width: 60px">工作日</span>
</div>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="办理"
prop="maxHandleDuration"
label-width="80"
:rules="{
required: true,
message: '请输入最大办理时长'
}"
>
<div class="flex gap">
<el-input
v-model="maxHandleDurationValue"
type="number"
style="width: 70px"
:min="1"
:max="99"
/>
<span style="width: 60px">工作日</span>
</div>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item
label="延期"
prop="maxExtensionDuration"
:rules="{
required: true,
message: '请输入最大延期天数'
}"
>
<div class="flex gap">
<el-input
v-model="maxExtensionDurationValue"
type="number"
style="width: 70px"
:min="1"
:max="99"
/>
<span></span>
</div>
</el-form-item>
</el-col>
</el-row>
</template>
</template>
<script setup>
import {
TimeLimit
} from "@/enums/dictEnums";
import useCatchStore from "@/stores/modules/catch";
import { watch } from "vue";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"timeLimit"
]);
const props = defineProps({
modelValue: {
type: String
},
maxSignDuration: {
type: String
},
maxHandleDuration: {
type: String
},
maxExtensionDuration: {
type: String
},
})
const emit = defineEmits(['update:modelValue', 'update:maxSignDuration', 'update:maxHandleDuration', 'update:maxExtensionDuration'])
const value = ref(props.modelValue)
const maxSignDurationValue = ref(props.maxSignDuration)
const maxHandleDurationValue = ref(props.maxHandleDuration)
const maxExtensionDurationValue = ref(props.maxExtensionDuration)
watch(value, () => {
emit('update:modelValue', value.value)
})
watch(maxSignDurationValue, () => {
emit('update:maxSignDuration', maxSignDurationValue.value)
})
watch(maxHandleDurationValue, () => {
emit('update:maxHandleDuration', maxHandleDurationValue.value)
})
watch(maxExtensionDurationValue, () => {
emit('update:maxExtensionDuration', maxExtensionDurationValue.value)
})
</script>
<style lang="scss" scoped>
</style>

16
src/enums/dictEnums.ts

@ -110,9 +110,8 @@ export enum SubjectiveAspect {
// 分发方式 // 分发方式
export enum DistributionMethod { export enum DistributionMethod {
NEGATIVE_DISTRIBUTE = '1', DIRECTLY_DISTRIBUTE = '1',
DATA_SAVE = '2', MANUALLY_DISTRIBUTE = '2'
WARNING_NOTIFICATION = '3'
} }
// 分发周期 // 分发周期
@ -120,3 +119,14 @@ export enum DistributionCycle {
DAY = 'day', DAY = 'day',
WEEKLY = 'weekly' WEEKLY = 'weekly'
} }
export enum ModelDataType {
NEGATIVE = '1',
NOTIFICATION = '2'
}
export enum DistributionState {
UNDISTRIBUTED = '0',
DISTRIBUTED = '1',
HANDLED = '2'
}

8
src/layout/Index.vue

@ -5,7 +5,11 @@
<div> <div>
<MultipleTabs /> <MultipleTabs />
<main> <main>
<router-view /> <router-view v-slot="{ Component, route }">
<keep-alive :include="tabsStore.getCacheTabList" :max="10">
<component :is="Component" :key="route.fullPath" />
</keep-alive>
</router-view>
</main> </main>
</div> </div>
</div> </div>
@ -14,7 +18,9 @@
import Header from "./components/Header.vue"; import Header from "./components/Header.vue";
import LayoutAside from "./components/Aside.vue"; import LayoutAside from "./components/Aside.vue";
import MultipleTabs from "./components/MultipleTabs.vue"; import MultipleTabs from "./components/MultipleTabs.vue";
import useTabsStore from "@/stores/modules/multipleTabs";
const tabsStore = useTabsStore()
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
main { main {

5
src/layout/components/MultipleTabs.vue

@ -10,7 +10,7 @@
<template v-for="item in tabList" :key="item.fullPath"> <template v-for="item in tabList" :key="item.fullPath">
<el-tab-pane <el-tab-pane
:label="item.title" :label="item.title"
:name="item.fullPath" :name="item.path"
closable closable
></el-tab-pane> ></el-tab-pane>
</template> </template>
@ -38,11 +38,10 @@ watch(
); );
const currentTab = computed(() => { const currentTab = computed(() => {
return route.fullPath; return route.path;
}); });
const handleChange = (fullPath: any) => { const handleChange = (fullPath: any) => {
console.log(fullPath);
router.push(fullPath); router.push(fullPath);
}; };

7
src/stores/modules/multipleTabs.ts

@ -23,8 +23,8 @@ interface TabsSate {
indexRouteName: RouteRecordName indexRouteName: RouteRecordName
} }
const getHasTabIndex = (fullPath: string, tabList: TabItem[]) => { const getHasTabIndex = (path: string, tabList: TabItem[]) => {
return tabList.findIndex((item) => item.fullPath == fullPath) return tabList.findIndex((item) => item.path == path)
} }
const getComponentName = (route: RouteLocationNormalized) => { const getComponentName = (route: RouteLocationNormalized) => {
@ -76,7 +76,7 @@ const useTabsStore = defineStore({
const { name, query, meta, params, fullPath, path } = route const { name, query, meta, params, fullPath, path } = route
// TODO // TODO
const hasTabIndex = getHasTabIndex(fullPath!, this.tabList) const hasTabIndex = getHasTabIndex(path!, this.tabList)
const componentName = getComponentName(route) const componentName = getComponentName(route)
const tabItem = { const tabItem = {
name: name!, name: name!,
@ -97,6 +97,7 @@ const useTabsStore = defineStore({
}, },
removeTab(fullPath: string, router: Router) { removeTab(fullPath: string, router: Router) {
const { currentRoute, push } = router const { currentRoute, push } = router
const index = getHasTabIndex(fullPath, this.tabList) const index = getHasTabIndex(fullPath, this.tabList)
// 移除tab // 移除tab
if (this.tabList.length > 1) { if (this.tabList.length > 1) {

23
src/style/datav.scss

@ -37,26 +37,3 @@
font-size: 29px; font-size: 29px;
font-weight: 700; font-weight: 700;
} }
.tab-title {
margin-bottom: 4px;
cursor: pointer;
.tab-title-item {
width: 119px;
height: 32px;
line-height: 32px;
border: 1px solid #24d2ee;
text-align: center;
&.active {
background: #24d2ee;
color: #0724b2;
}
&:first-child {
border-radius: 103px 0px 0px 103px;
}
&:last-child {
border-radius: 0 103px 103px 0;
}
}
}

7
src/style/public.scss

@ -10,6 +10,7 @@
--primary-color: #162582; --primary-color: #162582;
--success-color: #064D00; --success-color: #064D00;
--danger-color: #F60000; --danger-color: #F60000;
--warning-color: #D05200;
} }
body { body {
@ -160,6 +161,10 @@ svg+span {
color: var(--success-color); color: var(--success-color);
} }
.text-warning {
color: var(--warning-color);
}
.text-bold { .text-bold {
font-weight: 700; font-weight: 700;
} }
@ -319,7 +324,7 @@ svg+span {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
.col { .col {
margin-bottom: 10px; margin-bottom: 12px;
} }
} }
.col { .col {

4
src/utils/feedback.ts

@ -62,9 +62,9 @@ export class Feedback {
ElNotification.warning(msg) ElNotification.warning(msg)
} }
// 确认窗体 // 确认窗体
confirm(msg: string) { confirm(msg: string, confirmButtonText: '确定') {
return ElMessageBox.confirm(msg, '温馨提示', { return ElMessageBox.confirm(msg, '温馨提示', {
confirmButtonText: '确定', confirmButtonText: confirmButtonText,
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })

340
src/views/data/Ajhc.vue

@ -31,8 +31,10 @@
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="登记时间"> <el-form-item label=" 受理时间">
<date-time-range-picker-ext v-model="query.discoveryTime" /> <date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
@ -43,12 +45,37 @@
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6">
<el-form-item label="分发状态">
<el-select v-model="query.distributionState">
<el-option
v-for="item in dict.distributionState"
:key="item.id"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select>
</el-form-item>
</el-col>
</el-row> </el-row>
</el-form> </el-form>
<div class="mb-25 flex between"> <div class="mb-25 flex between">
<div>
<el-button type="primary" @click="show = true" <el-button type="primary" @click="show = true"
>数据导入</el-button >数据导入</el-button
> >
<el-badge
:value="distributeList.length"
class="ml-10"
v-if="distributeList.length"
>
<el-button
type="primary"
@click="distributeListShow = true"
>问题下发</el-button
>
</el-badge>
</div>
<div> <div>
<el-button type="primary" @click="getList"> <el-button type="primary" @click="getList">
<template #icon> <template #icon>
@ -75,6 +102,7 @@
<el-table-column <el-table-column
label="问题发生时间" label="问题发生时间"
prop="happenTime" prop="happenTime"
show-overflow-tooltip
/> />
<el-table-column <el-table-column
label="问题来源" label="问题来源"
@ -91,36 +119,57 @@
prop="contactPhone" prop="contactPhone"
width="120" width="120"
/> />
<el-table-column <el-table-column label="业务类别" prop="businessTypeName" />
label="业务类别" <el-table-column label="涉嫌问题" prop="involveProblem" />
prop="businessTypeName" <el-table-column label="涉及警种" prop="policeTypeName" />
/> <el-table-column label="涉及单位" prop="involveDepartName" />
<el-table-column
label="涉嫌问题"
prop="involveProblem"
/>
<el-table-column
label="涉及警种"
prop="policeTypeName"
/>
<el-table-column
label="涉及单位"
prop="complainedDepartName"
/>
<el-table-column <el-table-column
label="具体内容" label="具体内容"
prop="thingDesc" prop="thingDesc"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column label="状态">
<template #default="{ row }">
<el-tag>{{
getDictLable(
dict.distributionState,
row.distributionState
)
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200"> <el-table-column label="操作" width="200">
<template #default="{ row }"> <template #default="{ row }">
<!-- <el-button type="primary" link>核查情况</el-button> -->
<el-button type="danger" link @click="handleDel(row)">删除</el-button> <template
<!-- <el-button v-if="
row.distributionState ===
DistributionState.UNDISTRIBUTED
"
>
<el-button
type="primary" type="primary"
link link
>问题核查</el-button @click="handleAddDistribute(row)"
> --> v-if="
distributeList.filter(
(item) => item.originId === row.originId
).length === 0
"
>加入问题下发</el-button
>
<el-button
type="info"
link
v-else
@click="handleRemoveDistribute(row)"
>移除</el-button
>
</template>
<el-button type="danger" link @click="handleDel(row)"
>删除</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -140,52 +189,33 @@
</div> </div>
</div> </div>
<el-dialog title="案件核查 数据导入" v-model="show" width="80vw"> <data-import-case
<div style="min-height: 500px"> v-model="show"
<template v-if="step === 1"> title="案件核查 数据导入"
<div class="mt-20"> @close="show = false"
<span>案件核查问题台账模板</span> @update="getList"
<a />
class="link"
:href="`${BASE_PATH}/templates/案件核查问题台账(模板).xlsx`" <el-dialog
target="__blank" title="问题分发"
>下载</a v-model="distributeListShow"
width="80vw"
top="5vh"
> >
</div> <header>
<el-upload <div class="flex v-center end mb-20">
drag <span class="mr-20"
:multiple="false" >
:auto-upload="false" <span class="text-primary">{{
:show-file-list="false" distributeList.length
v-model:file-list="fileList" }}</span>
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" 条数据</span
class="mt-20"
> >
<template v-if="fileList.length === 0">
<el-icon class="el-icon--upload"
><upload-filled
/></el-icon>
<div class="el-upload__text">
点击或拖拽文件到此区域上传
</div> </div>
</template> </header>
<template v-else> <div style="min-height: 500px">
<el-icon class="el-icon--upload"><Select /></el-icon>
<div class="el-upload__text">
已选择文件{{ fileList[fileList.length - 1].name }}
</div>
</template>
</el-upload>
<el-radio-group v-model="dataUpdateMethod" class="mt-20">
<el-radio value="incremental" border>增量更新</el-radio>
<el-radio value="overwrite" border>覆盖更新</el-radio>
</el-radio-group>
</template>
<template v-else>
<el-page-header @back="step = 1" class="mb-20"></el-page-header>
<div class="table-container"> <div class="table-container">
<el-table :data="importTableData" ref="tableRef"> <el-table :data="distributeList">
<el-table-column type="selection" />
<el-table-column <el-table-column
label="案件编号" label="案件编号"
prop="originId" prop="originId"
@ -196,10 +226,7 @@
prop="discoveryTime" prop="discoveryTime"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column <el-table-column label="问题发生时间" prop="happenTime" show-overflow-tooltip />
label="问题发生时间"
prop="happenTime"
/>
<el-table-column <el-table-column
label="问题来源" label="问题来源"
prop="problemSources" prop="problemSources"
@ -215,56 +242,93 @@
prop="contactPhone" prop="contactPhone"
width="120" width="120"
/> />
<el-table-column <el-table-column label="业务类别" prop="businessTypeName" />
label="业务类别" <el-table-column label="涉嫌问题" prop="involveProblem" />
prop="businessTypeName" <el-table-column label="涉及警种" prop="policeTypeName" />
/>
<el-table-column
label="涉嫌问题"
prop="involveProblem"
/>
<el-table-column
label="涉及警种"
prop="policeTypeName"
/>
<el-table-column <el-table-column
label="涉及单位" label="涉及单位"
prop="complainedDepartName" prop="involveDepartName"
/> />
<el-table-column <el-table-column
label="具体内容" label="具体内容"
prop="thingDesc" prop="thingDesc"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column label="数据校验" width="120"> <el-table-column label="操作" width="140">
<template #default="{ row }"> <template #default="{ row }">
<el-tag type="success">正确</el-tag>
<el-button
type="info"
link
@click="handleRemoveDistribute(row)"
>移除</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
</template>
</div> </div>
<footer class="flex end mt-20 v-center"> <footer class="flex end mt-20">
<span class="mr-20" v-if="step === 2"
>选中<b>{{ checkRowSize }}</b>条数据</span
>
<el-button size="large" @click="show = false">取消</el-button>
<el-button <el-button
type="primary" type="primary"
size="large" size="large"
@click="handleImport" @click="handleShowDistributeDialog"
:disabled="fileList.length === 0" :disabled="distributeList.length === 0"
v-if="step === 1" >确认数据</el-button
>下一步</el-button
> >
</footer>
</el-dialog>
<el-dialog title="任务分发" v-model="distributeShow" width="50vw" top="5vh">
<el-form :label-width="120" ref="formRef" :model="form">
<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="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>
<div class="tips mt-10">
<p>
三级审核 在问题提交办结时需经过所队>二级机构>市局三级审核通过后方可办结
</p>
<p>
二级审核 在问题提交办结时仅需经过所队>二级机构两级审核通过后即可办结
</p>
</div>
</el-form-item>
</el-form>
<footer class="flex end mt-20">
<el-button <el-button
type="primary" type="primary"
size="large" size="large"
@click="handleSaveImport" @click="handleSubmit"
:disabled="checkRowSize === 0" >确认下发</el-button
v-else
>确认导入</el-button
> >
</footer> </footer>
</el-dialog> </el-dialog>
@ -272,18 +336,27 @@
<script setup> <script setup>
import { BASE_PATH } from "@/api/request"; import { BASE_PATH } from "@/api/request";
import { import {
importCaseVerif,
listCaseVerif, listCaseVerif,
addCaseVerif, delCaseVerif,
delCaseVerif distributeCaseVerif,
} from "@/api/data/caseVerif"; } from "@/api/data/caseVerif";
import { ProblemSources } from '@/enums/dictEnums' import { DistributionState } from "@/enums/dictEnums";
import { getDictLable } from "@/utils/util";
import feedback from "@/utils/feedback"; import feedback from "@/utils/feedback";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"distributionState",
"timeLimit",
"approvalFlow"
]);
const query = ref({ const query = ref({
size: 10, size: 10,
current: 1, current: 1,
responderKey: 'name' responderKey: "name",
}); });
const list = ref([]); const list = ref([]);
@ -299,7 +372,7 @@ function reset() {
query.value = { query.value = {
size: 10, size: 10,
current: 1, current: 1,
responderKey: 'name' responderKey: "name",
}; };
getList(); getList();
} }
@ -307,41 +380,44 @@ function reset() {
getList(); getList();
const show = ref(false); const show = ref(false);
const dataUpdateMethod = ref("incremental");
const fileList = ref([]); async function handleDel(row) {
await feedback.confirm("确定要删除该数据?");
await delCaseVerif(row.originId);
getList();
}
const distributeListShow = ref(false);
const distributeList = ref([]);
const distributeShow = ref(false);
const importTableData = ref([]); function handleAddDistribute(row) {
const step = ref(1); distributeList.value.push(row);
async function handleImport() {
const formData = new FormData();
formData.append("file", fileList.value[fileList.value.length - 1].raw);
importTableData.value = await importCaseVerif(formData);
step.value = 2;
nextTick(() => {
tableRef.value.toggleAllSelection();
});
} }
const checkRowSize = computed( function handleShowDistributeDialog() {
() => tableRef.value?.getSelectionRows().length || 0 distributeShow.value = true;
); }
const form = ref({});
const formRef = ref()
const tableRef = ref(null); function handleRemoveDistribute(row) {
async function handleSaveImport() { distributeList.value.splice(
const rows = tableRef.value.getSelectionRows(); distributeList.value.findIndex(
await addCaseVerif(dataUpdateMethod.value, [...rows]); (item) => item.originId === row.originId
feedback.msgSuccess(`成功导入${rows.length}条数据`); ),
show.value = false; 1
step.value = 1 );
importTableData.value = []
fileList.value = []
getList();
} }
async function handleDel(row) { async function handleSubmit() {
await feedback.confirm('确定要删除该数据?') await formRef.value.validate()
await delCaseVerif(row.originId) form.value.data = distributeList.value
await distributeCaseVerif(form.value)
form.value = {}
distributeShow.value = false
distributeListShow.value = false
feedback.msgSuccess('下发成功')
getList() getList()
} }
</script> </script>

272
src/views/data/Gabxf.vue

@ -32,7 +32,9 @@
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="登记时间"> <el-form-item label="登记时间">
<date-time-range-picker-ext v-model="query.discoveryTime" /> <date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
@ -46,9 +48,20 @@
</el-row> </el-row>
</el-form> </el-form>
<div class="mb-25 flex between"> <div class="mb-25 flex between">
<div>
<el-button type="primary" @click="show = true" <el-button type="primary" @click="show = true"
>数据导入</el-button >数据导入</el-button
> >
<el-badge
:value="distributeList.length"
class="ml-10"
v-if="distributeList.length"
>
<el-button type="primary" @click="distributeShow = true"
>问题下发</el-button
>
</el-badge>
</div>
<div> <div>
<el-button type="primary" @click="getList"> <el-button type="primary" @click="getList">
<template #icon> <template #icon>
@ -103,7 +116,7 @@
<el-table-column label="涉嫌问题" prop="involveProblem" /> <el-table-column label="涉嫌问题" prop="involveProblem" />
<el-table-column <el-table-column
label="被投诉机构" label="被投诉机构"
prop="involveProblem" prop="involveDepartName"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column <el-table-column
@ -111,15 +124,46 @@
prop="thingDesc" prop="thingDesc"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column label="状态">
<template #default="{ row }">
<el-tag>{{
getDictLable(
dict.distributionState,
row.distributionState
)
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200"> <el-table-column label="操作" width="200">
<template #default="{ row }"> <template #default="{ row }">
<!-- <el-button type="primary" link>核查情况</el-button> --> <template
<el-button type="danger" link @click="handleDel(row)">删除</el-button> v-if="
<!-- <el-button row.distributionState ===
DistributionState.UNDISTRIBUTED
"
>
<el-button
type="primary" type="primary"
link link
>问题核查</el-button @click="handleAddDistribute(row)"
> --> v-if="
distributeList.filter(
(item) => item.originId === row.originId
).length === 0
"
>加入问题下发</el-button
>
<el-button
type="info"
link
v-else
@click="handleRemoveDistribute(row)"
>移除</el-button
>
</template>
<el-button type="danger" link @click="handleDel(row)"
>删除</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -139,137 +183,19 @@
</div> </div>
</div> </div>
<el-dialog title="公安部信访投诉 数据导入" v-model="show" width="80vw"> <data-import
<div style="min-height: 500px"> v-model="show"
<template v-if="step === 1"> title="公安部信访投诉 数据导入"
<div class="mt-20"> :problemSourcesCode="ProblemSources.GABXF"
<span>信访投诉数据台账模板</span> @close="show = false"
<a @update="getList"
class="link"
:href="`${BASE_PATH}/templates/信访投诉数据台账(模板).xlsx`"
target="__blank"
>下载</a
>
</div>
<el-upload
drag
:multiple="false"
:auto-upload="false"
:show-file-list="false"
v-model:file-list="fileList"
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
class="mt-20"
>
<template v-if="fileList.length === 0">
<el-icon class="el-icon--upload"
><upload-filled
/></el-icon>
<div class="el-upload__text">
点击或拖拽文件到此区域上传
</div>
</template>
<template v-else>
<el-icon class="el-icon--upload"><Select /></el-icon>
<div class="el-upload__text">
已选择文件{{ fileList[fileList.length - 1].name }}
</div>
</template>
</el-upload>
<el-radio-group v-model="dataUpdateMethod" class="mt-20">
<el-radio value="incremental" border>增量更新</el-radio>
<el-radio value="overwrite" border>覆盖更新</el-radio>
</el-radio-group>
</template>
<template v-else>
<el-page-header @back="step = 1" class="mb-20"></el-page-header>
<div class="table-container">
<el-table :data="importTableData" ref="tableRef">
<el-table-column type="selection" />
<el-table-column
label="信件编号"
prop="originId"
show-overflow-tooltip
/>
<el-table-column
label="投诉渠道"
prop="channelForFilingComplaints"
/>
<el-table-column
label="受理层级"
prop="acceptanceLevel"
/> />
<el-table-column
label="登记时间" <data-distrbute
prop="discoveryTime" v-model:show="distributeShow"
show-overflow-tooltip v-model:data="distributeList"
/> @update="getList"
<el-table-column
label="投诉人"
prop="responderName"
width="90"
/>
<el-table-column
label="投诉人电话"
prop="contactPhone"
width="120"
/>
<el-table-column
label="初重信访"
prop="initialPetition"
align="center"
width="90"
/>
<el-table-column
label="缠访闹访"
prop="entanglementVisits"
width="90"
/>
<el-table-column
label="群众集访"
prop="massVisits"
width="90"
/>
<el-table-column
label="被投诉机构"
prop="complainedDepartName"
/>
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/> />
<el-table-column label="数据校验" width="120">
<template #default="{ row }">
<el-tag type="success">正确</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</template>
</div>
<footer class="flex end mt-20 v-center">
<span class="mr-20" v-if="step === 2"
>选中<b>{{ checkRowSize }}</b>条数据</span
>
<el-button size="large" @click="show = false">取消</el-button>
<el-button
type="primary"
size="large"
@click="handleImport"
:disabled="fileList.length === 0"
v-if="step === 1"
>下一步</el-button
>
<el-button
type="primary"
size="large"
@click="handleSaveImport"
:disabled="checkRowSize === 0"
v-else
>确认导入</el-button
>
</footer>
</el-dialog>
</template> </template>
<script setup> <script setup>
import { BASE_PATH } from "@/api/request"; import { BASE_PATH } from "@/api/request";
@ -277,16 +203,29 @@ import {
importPetitionComplaint, importPetitionComplaint,
listPetitionComplaint, listPetitionComplaint,
addPetitionComplaint, addPetitionComplaint,
delPetitionComplaint delPetitionComplaint,
} from "@/api/data/petitionComplaint"; } from "@/api/data/petitionComplaint";
import { ProblemSources } from '@/enums/dictEnums' import { ProblemSources, DistributionState } from "@/enums/dictEnums";
import feedback from "@/utils/feedback"; import feedback from "@/utils/feedback";
import { getDictLable } from "@/utils/util";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"distributionState",
"timeLimit",
"approvalFlow",
"distributionFlow",
"distributionState",
]);
const query = ref({ const query = ref({
size: 10, size: 10,
current: 1, current: 1,
responderKey: 'name', responderKey: "name",
problemSourcesCode: ProblemSources.GABXF problemSourcesCode: ProblemSources.GABXF,
}); });
const list = ref([]); const list = ref([]);
@ -302,8 +241,8 @@ function reset() {
query.value = { query.value = {
size: 10, size: 10,
current: 1, current: 1,
responderKey: 'name', responderKey: "name",
problemSourcesCode: ProblemSources.GABXF problemSourcesCode: ProblemSources.GABXF,
}; };
getList(); getList();
} }
@ -311,46 +250,27 @@ function reset() {
getList(); getList();
const show = ref(false); const show = ref(false);
const dataUpdateMethod = ref("incremental");
const fileList = ref([]);
const importTableData = ref([]); async function handleDel(row) {
const step = ref(1); await feedback.confirm("确定要删除该数据?");
async function handleImport() { await delPetitionComplaint(row.originId);
const formData = new FormData(); getList();
formData.append("file", fileList.value[fileList.value.length - 1].raw);
importTableData.value = await importPetitionComplaint(formData);
step.value = 2;
nextTick(() => {
tableRef.value.toggleAllSelection();
});
} }
const checkRowSize = computed( const distributeShow = ref(false)
() => tableRef.value?.getSelectionRows().length || 0 const distributeList = ref([])
);
const tableRef = ref(null); function handleAddDistribute(row) {
async function handleSaveImport() { distributeList.value.push(row);
const rows = tableRef.value.getSelectionRows();
await addPetitionComplaint({
dataUpdateMethod: dataUpdateMethod.value,
problemSourcesCode: ProblemSources.GABXF,
data: [...rows]
});
feedback.msgSuccess(`成功导入${rows.length}条数据`);
show.value = false;
step.value = 1
importTableData.value = []
fileList.value = []
getList();
} }
async function handleDel(row) { function handleRemoveDistribute(row) {
await feedback.confirm('确定要删除该数据?') distributeList.value.splice(
await delPetitionComplaint(row.originId) distributeList.value.findIndex(
getList() (item) => item.originId === row.originId
),
1
);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

270
src/views/data/Gjxf.vue

@ -32,7 +32,9 @@
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="登记时间"> <el-form-item label="登记时间">
<date-time-range-picker-ext v-model="query.discoveryTime" /> <date-time-range-picker-ext
v-model="query.discoveryTime"
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
@ -46,9 +48,20 @@
</el-row> </el-row>
</el-form> </el-form>
<div class="mb-25 flex between"> <div class="mb-25 flex between">
<div>
<el-button type="primary" @click="show = true" <el-button type="primary" @click="show = true"
>数据导入</el-button >数据导入</el-button
> >
<el-badge
:value="distributeList.length"
class="ml-10"
v-if="distributeList.length"
>
<el-button type="primary" @click="distributeShow = true"
>问题下发</el-button
>
</el-badge>
</div>
<div> <div>
<el-button type="primary" @click="getList"> <el-button type="primary" @click="getList">
<template #icon> <template #icon>
@ -103,7 +116,7 @@
<el-table-column label="涉嫌问题" prop="involveProblem" /> <el-table-column label="涉嫌问题" prop="involveProblem" />
<el-table-column <el-table-column
label="被投诉机构" label="被投诉机构"
prop="involveProblem" prop="involveDepartName"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column <el-table-column
@ -111,15 +124,46 @@
prop="thingDesc" prop="thingDesc"
show-overflow-tooltip show-overflow-tooltip
/> />
<el-table-column label="状态">
<template #default="{ row }">
<el-tag>{{
getDictLable(
dict.distributionState,
row.distributionState
)
}}</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200"> <el-table-column label="操作" width="200">
<template #default="{ row }"> <template #default="{ row }">
<!-- <el-button type="primary" link>核查情况</el-button> --> <template
<el-button type="danger" link @click="handleDel(row)">删除</el-button> v-if="
<!-- <el-button row.distributionState ===
DistributionState.UNDISTRIBUTED
"
>
<el-button
type="primary" type="primary"
link link
>问题核查</el-button @click="handleAddDistribute(row)"
> --> v-if="
distributeList.filter(
(item) => item.originId === row.originId
).length === 0
"
>加入问题下发</el-button
>
<el-button
type="info"
link
v-else
@click="handleRemoveDistribute(row)"
>移除</el-button
>
</template>
<el-button type="danger" link @click="handleDel(row)"
>删除</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -139,154 +183,40 @@
</div> </div>
</div> </div>
<el-dialog title="国家信访投诉 数据导入" v-model="show" width="80vw"> <data-import
<div style="min-height: 500px"> v-model="show"
<template v-if="step === 1"> title="国家信访投诉 数据导入"
<div class="mt-20"> :problemSourcesCode="ProblemSources.GJXFPT"
<span>信访投诉数据台账模板</span> @close="show = false"
<a @update="getList"
class="link"
:href="`${BASE_PATH}/templates/信访投诉数据台账(模板).xlsx`"
target="__blank"
>下载</a
>
</div>
<el-upload
drag
:multiple="false"
:auto-upload="false"
:show-file-list="false"
v-model:file-list="fileList"
accept="application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
class="mt-20"
>
<template v-if="fileList.length === 0">
<el-icon class="el-icon--upload"
><upload-filled
/></el-icon>
<div class="el-upload__text">
点击或拖拽文件到此区域上传
</div>
</template>
<template v-else>
<el-icon class="el-icon--upload"><Select /></el-icon>
<div class="el-upload__text">
已选择文件{{ fileList[fileList.length - 1].name }}
</div>
</template>
</el-upload>
<el-radio-group v-model="dataUpdateMethod" class="mt-20">
<el-radio value="incremental" border>增量更新</el-radio>
<el-radio value="overwrite" border>覆盖更新</el-radio>
</el-radio-group>
</template>
<template v-else>
<el-page-header @back="step = 1" class="mb-20"></el-page-header>
<div class="table-container">
<el-table :data="importTableData" ref="tableRef">
<el-table-column type="selection" />
<el-table-column
label="信件编号"
prop="originId"
show-overflow-tooltip
/>
<el-table-column
label="投诉渠道"
prop="channelForFilingComplaints"
/>
<el-table-column
label="受理层级"
prop="acceptanceLevel"
/>
<el-table-column
label="登记时间"
prop="discoveryTime"
show-overflow-tooltip
/>
<el-table-column
label="投诉人"
prop="responderName"
width="90"
/>
<el-table-column
label="投诉人电话"
prop="contactPhone"
width="120"
/> />
<el-table-column
label="初重信访" <data-distrbute
prop="initialPetition" v-model:show="distributeShow"
align="center" v-model:data="distributeList"
width="90" @update="getList"
/>
<el-table-column
label="缠访闹访"
prop="entanglementVisits"
width="90"
/>
<el-table-column
label="群众集访"
prop="massVisits"
width="90"
/>
<el-table-column
label="被投诉机构"
prop="complainedDepartName"
/>
<el-table-column
label="具体内容"
prop="thingDesc"
show-overflow-tooltip
/> />
<el-table-column label="数据校验" width="120">
<template #default="{ row }">
<el-tag type="success">正确</el-tag>
</template>
</el-table-column>
</el-table>
</div>
</template>
</div>
<footer class="flex end mt-20 v-center">
<span class="mr-20" v-if="step === 2"
>选中<b>{{ checkRowSize }}</b>条数据</span
>
<el-button size="large" @click="show = false">取消</el-button>
<el-button
type="primary"
size="large"
@click="handleImport"
:disabled="fileList.length === 0"
v-if="step === 1"
>下一步</el-button
>
<el-button
type="primary"
size="large"
@click="handleSaveImport"
:disabled="checkRowSize === 0"
v-else
>确认导入</el-button
>
</footer>
</el-dialog>
</template> </template>
<script setup> <script setup>
import { BASE_PATH } from "@/api/request";
import { import {
importPetitionComplaint,
listPetitionComplaint, listPetitionComplaint,
addPetitionComplaint, delPetitionComplaint,
delPetitionComplaint
} from "@/api/data/petitionComplaint"; } from "@/api/data/petitionComplaint";
import { ProblemSources } from '@/enums/dictEnums' import { ProblemSources, DistributionState } from "@/enums/dictEnums";
import feedback from "@/utils/feedback"; import feedback from "@/utils/feedback";
import { getDictLable } from "@/utils/util";
import useCatchStore from "@/stores/modules/catch";
const catchStore = useCatchStore();
const dict = catchStore.getDicts([
"distributionState"
]);
const query = ref({ const query = ref({
size: 10, size: 10,
current: 1, current: 1,
responderKey: 'name', responderKey: "name",
problemSourcesCode: ProblemSources.GJXFPT problemSourcesCode: ProblemSources.GJXFPT,
}); });
const list = ref([]); const list = ref([]);
@ -302,8 +232,8 @@ function reset() {
query.value = { query.value = {
size: 10, size: 10,
current: 1, current: 1,
responderKey: 'name', responderKey: "name",
problemSourcesCode: ProblemSources.GJXFPT problemSourcesCode: ProblemSources.GJXFPT,
}; };
getList(); getList();
} }
@ -311,46 +241,26 @@ function reset() {
getList(); getList();
const show = ref(false); const show = ref(false);
const dataUpdateMethod = ref("incremental"); async function handleDel(row) {
await feedback.confirm("确定要删除该数据?");
const fileList = ref([]); await delPetitionComplaint(row.originId);
getList();
const importTableData = ref([]);
const step = ref(1);
async function handleImport() {
const formData = new FormData();
formData.append("file", fileList.value[fileList.value.length - 1].raw);
importTableData.value = await importPetitionComplaint(formData);
step.value = 2;
nextTick(() => {
tableRef.value.toggleAllSelection();
});
} }
const checkRowSize = computed( const distributeList = ref([]);
() => tableRef.value?.getSelectionRows().length || 0 const distributeShow = ref(false);
);
const tableRef = ref(null); function handleAddDistribute(row) {
async function handleSaveImport() { distributeList.value.push(row);
const rows = tableRef.value.getSelectionRows();
await addPetitionComplaint({
dataUpdateMethod: dataUpdateMethod.value,
problemSourcesCode: ProblemSources.GJXFPT,
data: [...rows]
});
feedback.msgSuccess(`成功导入${rows.length}条数据`);
show.value = false;
step.value = 1
importTableData.value = []
fileList.value = []
getList();
} }
async function handleDel(row) { function handleRemoveDistribute(row) {
await feedback.confirm('确定要删除该数据?') distributeList.value.splice(
await delPetitionComplaint(row.originId) distributeList.value.findIndex(
getList() (item) => item.originId === row.originId
),
1
);
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

121
src/views/datav/CaseVerif.vue

@ -5,93 +5,127 @@
<main> <main>
<el-row :gutter="16"> <el-row :gutter="16">
<el-col :span="6"> <el-col :span="6">
<datav-card title="分县市局排名"> <datav-card title="分县市局排名" subTitle="案件数">
<datav-tabs
v-model="activeTab"
type="bottom-button"
>
<datav-tab-item label="分县市局" name="1">
<datav-chart-bar <datav-chart-bar
sub-title="案件数"
:data="data1" :data="data1"
:max="11" :max="11"
size="large" size="large"
/> />
<div class="flex tab-title flex center mt-20" style="margin-bottom: 20px"> </datav-tab-item>
<div class="tab-title-item active"> <datav-tab-item label="局属单位" name="2">
分县市局 <datav-chart-bar
</div> :data="data1"
<div class="tab-title-item">局属单位</div> :max="11"
</div> size="large"
/>
</datav-tab-item>
</datav-tabs>
</datav-card> </datav-card>
<datav-card title="案件问题性质"> <datav-card title="案件问题性质">
<datav-tabs v-model="activeTab">
<datav-tab-item label="执法办案" name="1">
<v-charts <v-charts
style="height: 300px" style="height: 340px"
:option="option2" :option="option2"
autoresize autoresize
/> />
</datav-tab-item>
<datav-tab-item label="服务管理" name="2">
<v-charts
style="height: 340px"
:option="option2"
autoresize
/>
</datav-tab-item>
<datav-tab-item label="警纪警规" name="3">
<v-charts
style="height: 340px"
:option="option2"
autoresize
/>
</datav-tab-item>
</datav-tabs>
</datav-card> </datav-card>
</el-col> </el-col>
<el-col :span="12"> <el-col :span="12">
<div class="datav-col"> <datav-date-picker />
<label for="">统计周期</label>
<span>2024年01月01日 - 2024年08月30日</span>
</div>
<div class="flex gap-42"> <div class="flex gap-42">
<datav-statistic <datav-statistic
:value="67" :value="67"
title="受理办理案件" title="案件总数(起)"
style="width: 16.66%" style="width: 16.66%"
/> />
<datav-statistic <datav-statistic
:value="0" :value="0"
title="办理中" title="查实案件数"
style="width: 16.66%" style="width: 16.66%"
/> />
<datav-statistic <datav-statistic
:value="67" :value="67"
title="已办结" title="查处问题(个)"
style="width: 16.66%" style="width: 16.66%"
/> />
<datav-statistic <datav-statistic
:value="65" :value="65"
title="涉及单位数" title="问责人次"
style="width: 16.66%" style="width: 16.66%"
/> />
<datav-statistic <datav-statistic
:value="89" :value="89"
title="涉及人数" title="问责单位数"
style="width: 16.66%" style="width: 16.66%"
/> />
<datav-statistic <datav-statistic
:value="100" :value="100"
value-unit="%" value-unit="%"
title="整改率" title="查实率"
style="width: 16.66%" style="width: 16.66%"
/> />
</div> </div>
<v-charts <v-charts
style="height: 450px" style="height: 400px"
:option="option" :option="option"
autoresize autoresize
/> />
<datav-card title="查处问题趋势"> <datav-card title="查处问题趋势">
<v-charts <v-charts
style="height: 300px" style="height: 280px"
:option="option1" :option="option1"
autoresize autoresize
/> />
</datav-card> </datav-card>
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<datav-card title="案件来源占比"> <datav-card>
<datav-tabs v-model="activeTab">
<datav-tab-item label="案件来源占比" name="1">
<v-charts <v-charts
style="height: 300px" style="height: 340px"
:option="option3" :option="option3"
autoresize autoresize
/> />
</datav-tab-item>
<datav-tab-item label="问责处理情况" name="2">
</datav-tab-item>
</datav-tabs>
</datav-card> </datav-card>
<datav-card title="停职处理情况"> <datav-card>
<datav-tabs v-model="activeTab">
<datav-tab-item label="停职处理情况" name="1">
<v-charts <v-charts
style="height: 300px" style="height: 340px"
:option="option4" :option="option4"
autoresize autoresize
/> />
</datav-tab-item>
<datav-tab-item label="禁闭处理情况" name="2">
</datav-tab-item>
</datav-tabs>
</datav-card> </datav-card>
</el-col> </el-col>
</el-row> </el-row>
@ -178,14 +212,14 @@ const option1 = ref({
lineStyle: { lineStyle: {
color: "#193775", color: "#193775",
}, },
} },
}, },
series: [ series: [
{ {
type: "line", type: "line",
smooth: true, smooth: true,
label: { label: {
show: false show: false,
}, },
lineStyle: { lineStyle: {
color: "#28E6FF", color: "#28E6FF",
@ -214,62 +248,62 @@ const option1 = ref({
const data1 = [ const data1 = [
{ {
name: "开福分局", name: "开福分局",
value: 11 value: 11,
}, },
{ {
name: "芙蓉分局", name: "芙蓉分局",
value: 9 value: 9,
}, },
{ {
name: "岳麓分局", name: "岳麓分局",
value: 7 value: 7,
}, },
{ {
name: "雨花分局", name: "雨花分局",
value: 4 value: 4,
}, },
{ {
name: "望城分局", name: "望城分局",
value: 3 value: 3,
}, },
{ {
name: "浏阳市局", name: "浏阳市局",
value: 3 value: 3,
}, },
{ {
name: "长沙县局", name: "长沙县局",
value: 1 value: 1,
}, },
]; ];
const data2 = [ const data2 = [
{ {
name: "开福分局", name: "开福分局",
value: 9700 value: 9700,
}, },
{ {
name: "芙蓉分局", name: "芙蓉分局",
value: 9021 value: 9021,
}, },
{ {
name: "岳麓分局", name: "岳麓分局",
value: 8512 value: 8512,
}, },
{ {
name: "雨花分局", name: "雨花分局",
value: 8021 value: 8021,
}, },
{ {
name: "望城分局", name: "望城分局",
value: 7111 value: 7111,
}, },
{ {
name: "浏阳市局", name: "浏阳市局",
value: 6622 value: 6622,
}, },
{ {
name: "长沙县局", name: "长沙县局",
value: 6221 value: 6221,
}, },
]; ];
@ -323,7 +357,7 @@ const option4 = {
}, },
data: [ data: [
{ value: 311, name: "其他" }, { value: 311, name: "其他" },
{ value: 735, name: '违反公安部“九个一律”' }, { value: 735, name: "违反公安部“九个一律”" },
{ value: 580, name: "违反保密工作纪律" }, { value: 580, name: "违反保密工作纪律" },
{ value: 484, name: "涉嫌泄露国家、警务秘密" }, { value: 484, name: "涉嫌泄露国家、警务秘密" },
{ value: 300, name: "违反“三个规定”" }, { value: 300, name: "违反“三个规定”" },
@ -333,8 +367,9 @@ const option4 = {
}, },
], ],
}; };
const activeTab = ref("1");
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@import "@/style/datav.scss"; @import "@/style/datav.scss";
</style> </style>

171
src/views/sensitivePerception/Model.vue

@ -1,5 +1,4 @@
<template> <template>
<div class="container"> <div class="container">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="4"> <el-col :span="4">
@ -8,7 +7,8 @@
全部 全部
</div> </div>
<div <div
v-for="item in classes" v-for="(item, index) in classes"
:key="index"
@click="handleChangeClass(item.id)" @click="handleChangeClass(item.id)"
:active="query.classId === item.id" :active="query.classId === item.id"
> >
@ -46,12 +46,18 @@
</el-row> </el-row>
</el-form> </el-form>
<div class="flex between mb-20"> <div class="flex between mb-20">
<el-button type="primary" @click="handleAdd" <el-button type="primary" @click="handleAdd">
>添加模型</el-button <template #icon>
<icon name="el-icon-Plus" />
</template>
添加模型</el-button
> >
<div> <div>
<el-button type="primary" @click="getList" <el-button type="primary" @click="getList">
>查询</el-button <template #icon>
<icon name="el-icon-Search" />
</template>
查询</el-button
> >
<el-button @click="reset">重置</el-button> <el-button @click="reset">重置</el-button>
</div> </div>
@ -62,7 +68,11 @@
<div class="model-card" @click="openDetail(item)"> <div class="model-card" @click="openDetail(item)">
<div class="flex v-center"> <div class="flex v-center">
<div class="model-card-icon"> <div class="model-card-icon">
<icon :name="item.icon" :size="76" /> <icon
:name="item.icon"
:size="76"
v-if="item.icon"
/>
</div> </div>
<div <div
class="model-card-content" class="model-card-content"
@ -96,7 +106,6 @@
) )
}}</span> }}</span>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<label>最近活跃时间</label> <label>最近活跃时间</label>
@ -134,7 +143,7 @@
<el-dialog <el-dialog
:title="mode === 'add' ? '添加模型' : '编辑模型'" :title="mode === 'add' ? '添加模型' : '编辑模型'"
v-model="show" v-model="show"
top="5vh" top="4vh"
> >
<el-form label-width="120" ref="formRef" :model="form"> <el-form label-width="120" ref="formRef" :model="form">
<el-form-item <el-form-item
@ -222,6 +231,7 @@
required: true, required: true,
message: '请选择分发方式', message: '请选择分发方式',
}" }"
v-if="form.modelDataType === ModelDataType.NEGATIVE"
> >
<el-radio-group v-model="form.distributionMethod" class="block"> <el-radio-group v-model="form.distributionMethod" class="block">
<el-radio <el-radio
@ -235,7 +245,11 @@
</el-form-item> </el-form-item>
<template <template
v-if="form.distributionMethod === DistributionMethod.NEGATIVE_DISTRIBUTE" v-if="
form.modelDataType === ModelDataType.NEGATIVE &&
form.distributionMethod ===
DistributionMethod.DIRECTLY_DISTRIBUTE
"
> >
<el-form-item <el-form-item
label="分发周期" label="分发周期"
@ -268,10 +282,18 @@
required: true, required: true,
message: '请选择', message: '请选择',
}" }"
v-if="form.distributionCycle === DistributionCycle.WEEKLY" v-if="
form.distributionCycle ===
DistributionCycle.WEEKLY
"
> >
<el-select style="width: 120px" clearable> <el-select style="width: 120px" clearable>
<el-option v-for="(item, index) in WEEKS" :key="index" :label="`周${item}`" :value="index" /> <el-option
v-for="(item, index) in WEEKS"
:key="index"
:label="`周${item}`"
:value="index"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
@ -283,7 +305,13 @@
message: '请选择', message: '请选择',
}" }"
> >
<el-time-picker v-model="form.distributionCycleTime" placeholder="请选择" style="width: 120px" value-format="HH:mm:ss" clearable /> <el-time-picker
v-model="form.distributionCycleTime"
placeholder="请选择"
style="width: 120px"
value-format="HH:mm:ss"
clearable
/>
</el-form-item> </el-form-item>
</div> </div>
</el-form-item> </el-form-item>
@ -295,17 +323,12 @@
message: '请选择办理时限', message: '请选择办理时限',
}" }"
> >
<el-radio-group v-model="form.timeLimit" class="block"> <time-limit-select
<el-radio v-model="form.timeLimit"
v-for="item in dict.timeLimit" v-model:maxSignDuration="form.maxSignDuration"
:key="item.dictCode" v-model:maxHandleDuration="form.maxHandleDuration"
:value="item.dictValue" v-model:maxExtensionDuration="form.maxExtensionDuration"
>{{ item.dictLabel />
}}{{
item.remark ? `(${item.remark})` : ""
}}</el-radio
>
</el-radio-group>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
label="下发流程" label="下发流程"
@ -380,7 +403,7 @@
</footer> </footer>
</el-dialog> </el-dialog>
<el-dialog title="模型详情" v-model="detailShow" top="5vh" width="80vw"> <el-dialog title="模型详情" v-model="detailShow" top="5vh" width="70vw">
<h4 style="margin: 10px 0" class="text-primary">模型信息</h4> <h4 style="margin: 10px 0" class="text-primary">模型信息</h4>
<el-row> <el-row>
<el-col :span="4"> <el-col :span="4">
@ -407,40 +430,47 @@
}}</span> }}</span>
</div> </div>
<div class="col col-8"> <div class="col col-8">
<label>分发方式</label> <label>数据类型</label>
<span>{{ <span>{{
getDictLable( getDictLable(
dict.distributionMethod, dict.modelDataType,
activeModel.distributionMethod activeModel.modelDataType
) )
}}</span> }}</span>
</div> </div>
</div>
<div class="row">
<div class="col col-8"> <div class="col col-8">
<label>数据类型</label> <label>分发方式</label>
<span>{{ <span>{{
getDictLable( getDictLable(
dict.modelDataType, dict.distributionMethod,
activeModel.modelDataType activeModel.distributionMethod
) )
}}</span> }}</span>
</div> </div>
<div class="col col-8"> <div class="col col-8">
<label>分发周期</label> <label>分发周期</label>
<span>
<span>{{ <span>{{
getDictLable( getDictLable(
dict.distributionCycle, dict.distributionCycle,
activeModel.distributionCycle activeModel.distributionCycle
) )
}}</span> }}</span>
<span class="ml-20">{{
activeModel.distributionCycleTime
}}</span>
</span>
</div> </div>
</div>
<div class="row">
<div class="col col-8"> <div class="col col-8">
<label>办理时限</label> <label>办理时限</label>
<span>{{ <span>{{
getDictLable(dict.timeLimit, activeModel.timeLimit) getDictLable(dict.timeLimit, activeModel.timeLimit)
}}</span> }}</span>
</div> </div>
</div>
<div class="row">
<div class="col col-8"> <div class="col col-8">
<label>下发流程</label> <label>下发流程</label>
<span>{{ <span>{{
@ -459,17 +489,16 @@
) )
}}</span> }}</span>
</div> </div>
<div class="col col-8">
<label>创建单位</label>
<span>{{ activeModel.createDepartName }}</span>
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col col-8"> <div class="col col-8">
<label>最近活跃时间</label> <label>最近活跃时间</label>
<span>{{ activeModel.updateTime }}</span> <span>{{ activeModel.updateTime }}</span>
</div> </div>
<div class="col col-8">
<label>创建单位</label>
<span>{{ activeModel.createDepartName }}</span>
</div>
</div> </div>
<div class="row mb-20"> <div class="row mb-20">
<div class="col col-24"> <div class="col col-24">
@ -477,7 +506,27 @@
<span>{{ activeModel.remarks }}</span> <span>{{ activeModel.remarks }}</span>
</div> </div>
</div> </div>
<div class="flex end mb-20"></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>
<template #icon>
<icon name="el-icon-Edit" />
</template>
线索详细信息配置</el-button
>
</div>
</el-col> </el-col>
</el-row> </el-row>
<div class="mb-10"> <div class="mb-10">
@ -485,9 +534,35 @@
<div style="min-height: 300px"> <div style="min-height: 300px">
<div class="table-container"> <div class="table-container">
<el-table :data="tableData" size="small"> <el-table :data="tableData" size="small">
<el-table-column label="同步时间" prop="createTime" /> <el-table-column
<el-table-column label="预警条数" prop="size" /> label="同步时间"
<el-table-column label="分发状态" prop="state" /> 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="error">失败</el-tag>
</el-tooltip>
</template>
</el-table-column>
</el-table> </el-table>
</div> </div>
</div> </div>
@ -501,10 +576,13 @@
> >
</footer> </footer>
</el-dialog> </el-dialog>
</template> </template>
<script setup> <script setup>
import { DistributionMethod, DistributionCycle } from "@/enums/dictEnums"; import {
DistributionMethod,
DistributionCycle,
ModelDataType,
} from "@/enums/dictEnums";
import { WEEKS } from "@/enums/appEnums"; import { WEEKS } from "@/enums/appEnums";
import { listModelClass } from "@/api/sensitivePerception/modelClass"; import { listModelClass } from "@/api/sensitivePerception/modelClass";
import { import {
@ -518,7 +596,6 @@ import useCatchStore from "@/stores/modules/catch";
import { getDictLable } from "@/utils/util"; import { getDictLable } from "@/utils/util";
import feedback from "@/utils/feedback"; import feedback from "@/utils/feedback";
const catchStore = useCatchStore(); const catchStore = useCatchStore();
const dict = catchStore.getDicts([ const dict = catchStore.getDicts([
"distributionMethod", "distributionMethod",
@ -530,6 +607,8 @@ const dict = catchStore.getDicts([
"modelDataType", "modelDataType",
]); ]);
const router = useRouter();
const query = ref({ const query = ref({
size: 9, size: 9,
current: 1, current: 1,
@ -623,8 +702,6 @@ async function openDetail(item) {
tableData.value = await listTopModelClueRecords(item.id); tableData.value = await listTopModelClueRecords(item.id);
detailShow.value = true; detailShow.value = true;
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.menu { .menu {

172
src/views/sensitivePerception/ModelClue.vue

@ -2,7 +2,7 @@
<div class="container"> <div class="container">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :span="4"> <el-col :span="4">
<model-tree /> <model-tree v-model="query.modelIds" />
</el-col> </el-col>
<el-col :span="20"> <el-col :span="20">
<header> <header>
@ -25,13 +25,24 @@
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="预警内容"> <el-form-item label="预警内容">
<el-input placeholder="请输入" v-model="query.thingDesc" clearable /> <el-input
placeholder="请输入"
v-model="query.thingDesc"
clearable
/>
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="分发状态"> <el-form-item label="分发状态">
<el-select v-model="query.distributionState" clearable> <el-select
<el-option v-for="item in dict.distributionState" :label="item.dictLabel" :value="item.dictValue" /> v-model="query.distributionState"
clearable
>
<el-option
v-for="item in dict.distributionState"
:label="item.dictLabel"
:value="item.dictValue"
/>
</el-select> </el-select>
</el-form-item> </el-form-item>
</el-col> </el-col>
@ -51,13 +62,48 @@
</header> </header>
<div class="table-container"> <div class="table-container">
<el-table :data="list"> <el-table :data="list">
<el-table-column label="预警时间" prop="createTime" width="160" /> <el-table-column
<el-table-column label="预警模型" prop="modelName" width="120" /> label="预警时间"
<el-table-column label="涉及单位" prop="involveDepartName" width="120" /> prop="createTime"
<el-table-column label="预警内容" prop="thingDesc" show-overflow-tooltip /> width="150"
<el-table-column label="分发状态" align="center" width="120"> />
<el-table-column
label="预警模型"
prop="modelName"
width="160"
show-overflow-tooltip
/>
<el-table-column
label="涉及单位"
show-overflow-tooltip
width="200"
>
<template #default="{ row }"> <template #default="{ row }">
<span>{{ getDictLable(dict.distributionState, row.distributionState) }}</span> <span>{{ row.involveParentDepartName }}</span> <span>{{ row.involveDepartName }}</span>
</template>
</el-table-column>
<el-table-column
label="涉及人员"
prop="involvePoliceName"
width="100"
/>
<el-table-column
label="预警内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column
label="分发状态"
align="center"
width="120"
>
<template #default="{ row }">
<span>{{
getDictLable(
dict.distributionState,
row.distributionState
)
}}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="操作" width="180"> <el-table-column label="操作" width="180">
@ -65,51 +111,127 @@
<el-button <el-button
type="primary" type="primary"
link link
@click="show = true" @click="handleShowDetail(row)"
>查看详情</el-button >查看详情</el-button
> >
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<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>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
<el-dialog title="预警线索数据详情" v-model="show" width="80vw">
<div class="dialog-container">
<div class="row mt-10">
<div class="col col-6">
<label>预警时间</label>
<span>{{ activeModelClue.createTime }}</span>
</div>
<div class="col col-6">
<label>预警模型</label>
<span>{{ activeModelClue.modelName }}</span>
</div>
<div class="col col-6">
<label>涉及单位</label>
<span>
<span>{{ activeModelClue.involveParentDepartName }}</span> <span>{{ activeModelClue.involveDepartName }}</span>
</span>
</div>
<div class="col col-6">
<label>涉及人员</label>
<span>{{ activeModelClue.involvePoliceName }}</span>
</div>
</div>
<div class="row mt-10">
<div class="col col-24">
<label>预警内容</label>
<span>{{ activeModelClue.thingDesc }}</span>
</div>
</div>
<div class="row mt-10">
<div class="col col-6">
<label>分发状态</label>
<span>{{
getDictLable(
dict.distributionState,
activeModelClue.distributionState
)
}}</span>
</div>
</div>
<h3>详细信息</h3>
<div style="min-height: 200px">
<el-empty description="无数据" />
</div>
</div>
</el-dialog>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { listModelClue } from '@/api/sensitivePerception/modelClue' import { listModelClue } from "@/api/sensitivePerception/modelClue";
import useCatchStore from "@/stores/modules/catch"; import useCatchStore from "@/stores/modules/catch";
import { getDictLable } from "@/utils/util"; import { getDictLable } from "@/utils/util";
const catchStore = useCatchStore(); const catchStore = useCatchStore();
const dict = catchStore.getDicts([ const dict = catchStore.getDicts(["distributionState"]);
"distributionState"
]);
const query = ref({}); const query = ref({});
const list = ref([]); const list = ref([]);
const total = ref(0) const total = ref(0);
onMounted(() => { onMounted(() => {
getList() getList();
}); });
const route = useRoute();
watch(
() => route.query.modelId,
(val) => {
query.value.modelIds = [val];
}
);
watch(
() => query.value.modelIds,
() => {
getList();
}
);
function getList() { function getList() {
listModelClue(query.value).then(data => { listModelClue(query.value).then((data) => {
list.value = data.records list.value = data.records;
total.value = data.total total.value = data.total;
}) });
} }
function reset() { function reset() {
query.value = {} query.value = {};
getList() getList();
} }
const show = ref(false);
const activeModelClue = ref({});
function handleShowDetail(row) {
activeModelClue.value = row;
show.value = true;
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>

528
src/views/sensitivePerception/ModelClueManual.vue

@ -0,0 +1,528 @@
<template>
<div class="container">
<el-row :gutter="20">
<el-col :span="4">
<model-tree v-model="query.modelIds" />
</el-col>
<el-col :span="20">
<header>
<el-form :label-width="140">
<el-row>
<el-col :span="8">
<el-form-item label="预警时间">
<date-time-range-picker-ext
v-model="query.createTime"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="涉及单位">
<depart-tree-select
v-model="query.involveDepartId"
:check-strictly="false"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预警内容">
<el-input
placeholder="请输入"
v-model="query.thingDesc"
clearable
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex between mb-20">
<el-badge :value="manualList.length">
<el-button
type="primary"
:disabled="manualList.length === 0"
@click="manualShow = true"
>问题分发</el-button
>
</el-badge>
<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="createTime"
width="150"
/>
<el-table-column
label="预警模型"
prop="modelName"
width="160"
show-overflow-tooltip
/>
<el-table-column
label="涉及单位"
show-overflow-tooltip
width="200"
>
<template #default="{ row }">
<span>{{ row.involveParentDepartName }}</span>
<span>{{ row.involveDepartName }}</span>
</template>
</el-table-column>
<el-table-column
label="涉及人员"
prop="involvePoliceName"
width="120"
/>
<el-table-column
label="预警内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column
label="分发状态"
align="center"
width="120"
>
<template #default="{ row }">
<span
:class="row.involveDepartId ? '' : 'text-warning'"
>{{
getDictLable(
dict.distributionState,
row.distributionState
)
}}</span
>
</template>
</el-table-column>
<el-table-column label="操作" width="240">
<template #default="{ row }">
<el-button
type="primary"
link
@click="handleAddManuel(row)"
v-if="
manualList.filter(
(item) => item.id === row.id
).length === 0
"
>加入分发列表</el-button
>
<el-button
link
type="info"
@click="handleRemoveManuel(row)"
v-else
>从分发列表移除</el-button
>
<el-button
type="danger"
link
@click="handleNotProcessed(row)"
v-if="
manualList.filter(
(item) => item.id === row.id
).length === 0
"
>暂不处理</el-button
>
</template>
</el-table-column>
</el-table>
</div>
<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"
>
</el-pagination>
</div>
</el-col>
</el-row>
</div>
<el-dialog title="问题分发" v-model="manualShow" width="80vw" top="5vh">
<header>
<el-form :label-width="140">
<el-row>
<el-col :span="8">
<el-form-item label="模型">
<el-select v-model="manualQuery.modelId">
<el-option
v-for="item in modelOptions"
:key="item.value"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="涉及单位">
<depart-tree-select
v-model="manualQuery.involveDepartId"
:check-strictly="false"
/>
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="预警内容">
<el-input
placeholder="请输入"
v-model="manualQuery.thingDesc"
clearable
/>
</el-form-item>
</el-col>
</el-row>
</el-form>
<div class="flex v-center end mb-20">
<span class="mr-20"
>
<span class="text-primary">{{
filterManualList.length
}}</span>
条预警线索</span
>
<el-button @click="manualReset">重置</el-button>
</div>
</header>
<div style="min-height: 500px">
<div class="table-container">
<el-table :data="filterManualList">
<el-table-column
label="预警时间"
prop="createTime"
width="160"
/>
<el-table-column
label="预警模型"
prop="modelName"
width="120"
show-overflow-tooltip
/>
<el-table-column
label="涉及单位"
show-overflow-tooltip
width="200"
>
<template #default="{ row }">
<span>{{ row.involveParentDepartName }}</span>
<span>{{ row.involveDepartName }}</span>
</template>
</el-table-column>
<el-table-column
label="涉及人员"
prop="involvePoliceName"
width="120"
/>
<el-table-column
label="预警内容"
prop="thingDesc"
show-overflow-tooltip
/>
<el-table-column label="操作" width="140">
<template #default="{ row }">
<el-button
type="info"
link
@click="handleRemoveManuel(row)"
>移除</el-button
>
</template>
</el-table-column>
</el-table>
</div>
</div>
<footer class="flex end mt-20">
<el-button
type="primary"
size="large"
@click="handleShowDistributeDialog"
:disabled="manualList.length === 0"
>确认预警线索</el-button
>
</footer>
</el-dialog>
<el-dialog title="任务分发" v-model="distributeShow" width="50vw" top="5vh">
<el-form :label-width="120" ref="formRef" :model="form">
<el-form-item
label="任务名称"
prop="taskName"
:rules="{
required: true,
message: '请输入任务名称',
}"
>
<el-input
v-model="form.taskName"
style="width: 280px"
placeholder="请输入"
/>
</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>
<div class="tips mt-10">
<p>
三级审核 在问题提交办结时需经过所队>二级机构>市局三级审核通过后方可办结
</p>
<p>
二级审核 在问题提交办结时仅需经过所队>二级机构两级审核通过后即可办结
</p>
</div>
</el-form-item>
<el-form-item label="附件说明" prop="thingFiles">
<file-upload v-model:files="form.thingFiles" />
</el-form-item>
</el-form>
<footer class="flex end mt-20">
<el-button
type="primary"
size="large"
@click="handleSubmitManuelModelClueTask"
>确认下发</el-button
>
</footer>
</el-dialog>
<el-dialog title="配置涉及单位" v-model="editDepartShow" width="500">
<el-form :label-width="120" :model="editDepartForm" ref="editDepartFormRef">
<el-form-item label="涉及单位" :rules="{
required: true,
message: '请选择涉及单位',
}">
<depart-tree-select v-model="editDepartForm.departId" @node-click="(node) => editDepartForm.name = node.shortName" />
</el-form-item>
</el-form>
<footer class="flex end mt-40">
<el-button
@click="editDepartShow = false"
>取消</el-button
>
<el-button
type="primary"
@click="handleUpdatDepartModelClue"
>确认</el-button
>
</footer>
</el-dialog>
</template>
<script lang="ts" setup>
import { DistributionMethod } from "@/enums/dictEnums";
import {
listModelClue,
manuelModelClueTask,
updateDepartModelClue
} 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([
"distributionState",
"timeLimit",
"approvalFlow",
"distributionFlow",
]);
const query = ref({
distributionMethod: DistributionMethod.MANUALLY_DISTRIBUTE,
distributionState: "0",
});
const list = ref([]);
const total = ref(0);
onMounted(() => {
getList();
});
watch(
() => query.value.modelIds,
() => {
getList();
}
);
function getList() {
listModelClue(query.value).then((data) => {
list.value = data.records;
total.value = data.total;
});
}
function reset() {
query.value = {};
getList();
}
const manualList = ref([]);
async function handleAddManuel(row) {
if (!row.involveDepartId) {
activeModelClueId = row.id
await feedback.confirm(`该数据的"涉及单位"为空,请先配置"涉及单位"再下发`, '去配置');
editDepartShow.value = true
return
}
manualList.value.push(row);
}
function handleRemoveManuel(row) {
manualList.value.splice(manualList.value.indexOf(row), 1);
}
async function handleNotProcessed(row) {
await feedback.confirm(`确认该数据暂不处理?`);
}
const manualShow = ref(false);
const manualQuery = ref({});
const filterManualList = computed(() => {
let arr = manualList.value;
if (manualQuery.value.modelId) {
arr = arr.filter((item) => item.modelId === manualQuery.value.modelId);
}
if (manualQuery.value.involveDepartId) {
arr = arr.filter(
(item) => item.involveDepartId === manualQuery.value.involveDepartId
);
}
if (manualQuery.value.thingDesc) {
arr = arr.filter((item) =>
item.thingDesc.includes(manualQuery.value.thingDesc)
);
}
return arr;
});
const modelOptions = computed(() => {
const items = filterManualList.value.map((item) => {
return {
value: item.modelId,
label: item.modelName,
};
});
const uniqueItems = [
...new Map(items.map((item) => [item.value, item])).values(),
];
return uniqueItems;
});
function manualReset() {
manualQuery.value = {};
}
function handleShowDistributeDialog() {
if (new Set(filterManualList.value.map((item) => item.modelId)).size > 1) {
feedback.msgWarning("线索数据包含两个模型,请筛选单个模型再下发");
return;
}
distributeShow.value = true;
}
const form = ref({
modelClues: [],
thingFiles: [],
});
const formRef = ref(null);
const distributeShow = ref(false);
async function handleSubmitManuelModelClueTask() {
await formRef.value.validate();
form.value.modelClues = filterManualList.value;
await manuelModelClueTask(form.value);
feedback.msgSuccess("下发成功");
form.value = {
modelClues: [],
thingFiles: [],
};
distributeShow.value = false;
manualShow.value = false;
manualList.value = [];
getList();
}
const editDepartShow = ref(false)
const editDepartForm = ref({})
const editDepartFormRef = ref()
let activeModelClueId = 0;
async function handleUpdatDepartModelClue() {
await editDepartFormRef.value.validate()
await updateDepartModelClue(activeModelClueId, editDepartForm.value)
editDepartShow.value = false
editDepartForm.value = {}
getList();
}
</script>
<style lang="scss" scoped>
</style>

100
src/views/sensitivePerception/ModelClueTask.vue

@ -9,32 +9,21 @@
<el-form :label-width="140"> <el-form :label-width="140">
<el-row> <el-row>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="预警时间"> <el-form-item label="任务名称">
<date-time-range-picker-ext <el-input
v-model="query.createTime" placeholder="请输入"
v-model="query.thingDesc"
clearable
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8"> <el-col :span="8">
<el-form-item label="涉及单位"> <el-form-item label="下发时间">
<depart-tree-select <date-time-range-picker-ext
v-model="query.involveDepartId" v-model="query.createTime"
:check-strictly="false"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
<el-col :span="8">
<el-form-item label="预警内容">
<el-input placeholder="请输入" v-model="query.thingDesc" clearable />
</el-form-item>
</el-col>
<el-col :span="8">
<el-form-item label="分发状态">
<el-select v-model="query.distributionState" clearable>
<el-option v-for="item in dict.distributionState" :label="item.dictLabel" :value="item.dictValue" />
</el-select>
</el-form-item>
</el-col>
</el-row> </el-row>
</el-form> </el-form>
<div class="flex end mb-20"> <div class="flex end mb-20">
@ -51,59 +40,76 @@
</header> </header>
<div class="table-container"> <div class="table-container">
<el-table :data="list"> <el-table :data="list">
<el-table-column label="任务名称" prop="taskName" /> <el-table-column
<el-table-column label="模型名称" prop="modelName" /> label="模型名称"
<el-table-column label="下发时间" prop="distributionTime" width="180" /> prop="modelName"
<el-table-column label="问题条数" prop="size" width="120" /> width="200"
<el-table-column label="操作" width="180"> show-overflow-tooltip
<template #default="{ row }"> />
<el-button <el-table-column
type="primary" label="下发时间"
link prop="distributionTime"
>查看详情</el-button width="200"
> />
<el-table-column
</template> label="问题条数"
prop="size"
align="center"
/>
<el-table-column label="办结数量" align="center" />
<el-table-column label="查实数量" align="center" />
<el-table-column label="涉及单位数" align="center" />
<el-table-column label="操作" width="200">
<template #default="{ row }"> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div> </div>
<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>
</el-col> </el-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { listModelClue } from '@/api/sensitivePerception/modelClue' import { listModelClueTask } from "@/api/sensitivePerception/modelClueTask";
import useCatchStore from "@/stores/modules/catch"; import useCatchStore from "@/stores/modules/catch";
import { getDictLable } from "@/utils/util"; import { getDictLable } from "@/utils/util";
const catchStore = useCatchStore(); const catchStore = useCatchStore();
const dict = catchStore.getDicts([ const dict = catchStore.getDicts(["distributionState"]);
"distributionState"
]);
const query = ref({}); const query = ref({});
const list = ref([]); const list = ref([]);
const total = ref(0) const total = ref(0);
onMounted(() => { onMounted(() => {
getList() getList();
}); });
function getList() { function getList() {
listModelClue(query.value).then(data => { listModelClueTask(query.value).then((data) => {
list.value = data.records list.value = data.records;
total.value = data.total total.value = data.total;
}) });
} }
function reset() { function reset() {
query.value = {} query.value = {};
getList() getList();
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
</style> </style>

9
src/views/sensitivePerception/Rwff.vue

@ -1,9 +0,0 @@
<template>
<img src="/imgs/lmgz/3.png" alt="">
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>

9
src/views/sensitivePerception/Sgff.vue

@ -1,9 +0,0 @@
<template>
<img src="/imgs/lmgz/2.png" alt="">
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>

9
src/views/sensitivePerception/Yjxs.vue

@ -1,9 +0,0 @@
<template>
<img src="/imgs/lmgz/4.png" alt="">
</template>
<script setup>
</script>
<style lang="scss" scoped>
</style>

8
src/views/system/Menu.vue

@ -55,7 +55,7 @@
<el-button <el-button
type="danger" type="danger"
link link
@click="handleDelete(row.id)" @click="handleDelete(row)"
>删除</el-button >删除</el-button
> >
</template> </template>
@ -347,9 +347,9 @@ function handleEdit(row) {
formData.value = {...row}; formData.value = {...row};
} }
const handleDelete = async (id: number) => { const handleDelete = async (row) => {
await feedback.confirm("确定要删除?"); await feedback.confirm(`确定要删除 ${row.menuName}`);
await delMenu(id); await delMenu(row.id);
feedback.msgSuccess("删除成功"); feedback.msgSuccess("删除成功");
getList(); getList();
}; };

20
src/views/system/Police.vue

@ -126,7 +126,7 @@
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="姓名" prop="name" width="100" /> <el-table-column label="姓名" prop="name" width="90" />
<el-table-column <el-table-column
label="警号" label="警号"
prop="empNo" prop="empNo"
@ -136,8 +136,7 @@
<el-table-column label="所属机构" show-overflow-tooltip> <el-table-column label="所属机构" show-overflow-tooltip>
<template #default="{ row }"> <template #default="{ row }">
<div class="flex gap-4"> <div class="flex gap-4">
<span>{{ row.parentDepartShortName }}</span> <span v-if="row.parentDepartShortName">{{ row.parentDepartShortName }}/</span><span>{{ row.departShortName }}</span>
<span>{{ row.departShortName }}</span>
</div> </div>
</template> </template>
</el-table-column> </el-table-column>
@ -148,11 +147,20 @@
}}</span> }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="职位" prop="position" width="120" /> <el-table-column label="职位" prop="position" width="120" align="center" >
<el-table-column label="备注" prop="job" width="140" /> <template #default="{ row }">
<span v-if="row.position">
<span v-if="row.level === 0">局领导{{ row.position }}</span>
<span v-if="row.level === 2">二级机构{{ row.position }}</span>
<span v-if="row.level === 3">三机机构{{ row.position }}</span>
<span v-if="row.level === 4">四机机构{{ row.position }}</span>
</span>
</template>
</el-table-column>
<el-table-column label="备注" prop="job" width="140" show-overflow-tooltip />
<el-table-column label="身份证" prop="idCode" width="200" /> <el-table-column label="身份证" prop="idCode" width="200" />
<el-table-column label="电话" prop="mobile" width="180" /> <el-table-column label="电话" prop="mobile" width="120" show-overflow-tooltip />
<el-table-column label="操作" width="220"> <el-table-column label="操作" width="220">
<template #default="{ row }"> <template #default="{ row }">

16
src/views/work/Query.vue

@ -374,6 +374,13 @@
@click="handleAction(row)" @click="handleAction(row)"
>详情</el-button >详情</el-button
> >
<el-button
type="danger"
link
@click="handleDel(row)"
v-perms="['negative:del']"
>删除</el-button
>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -403,7 +410,7 @@
</template> </template>
<script setup> <script setup>
import { ElLoading } from 'element-plus' import { ElLoading } from 'element-plus'
import { listNegative, negativeExport } from "@/api/work/negative"; import { listNegative, negativeExport, delNegative } from "@/api/work/negative";
import { getDictLable, formatTimeText, getInvolveProblem } from "@/utils/util"; import { getDictLable, formatTimeText, getInvolveProblem } from "@/utils/util";
import feedback from "@/utils/feedback"; import feedback from "@/utils/feedback";
@ -476,7 +483,12 @@ async function handleExport() {
router.push('/negative/export') router.push('/negative/export')
} }
async function handleDel(row) {
await feedback.confirm(`确定删除该数据?`)
await delNegative(row.id);
feedback.msgSuccess('操作成功')
getList()
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.form-row { .form-row {

Loading…
Cancel
Save