|
|
<template> |
|
|
<el-dialog |
|
|
:title="mode === 'add' ? '添加登记来件' : '修改登记来件'" |
|
|
v-model="visibleProxy" |
|
|
width="70vw" |
|
|
top="2vh" |
|
|
style="margin-bottom: 0" |
|
|
> |
|
|
<el-scrollbar max-height="76vh"> |
|
|
<el-form |
|
|
ref="formRef" |
|
|
:model="formData" |
|
|
:label-width="150" |
|
|
class="form-layout" |
|
|
style="min-height: 66vh" |
|
|
:rules="rules" |
|
|
> |
|
|
<!-- 投诉信息 --> |
|
|
<h2>投诉信息</h2> |
|
|
<div class="add-negation-container"> |
|
|
<!-- 来源 --> |
|
|
<el-row> |
|
|
<el-col :span="12"> |
|
|
<el-form-item label="来源" prop="sourcePath"> |
|
|
<el-cascader |
|
|
v-model="formData.sourcePath" |
|
|
:options="dict.sourceTableAndLevel" |
|
|
:props="{ emitPath: true, checkStrictly: false }" |
|
|
clearable |
|
|
filterable |
|
|
show-all-levels |
|
|
style="width: 100%" |
|
|
placeholder="请选择来源(一级/二级)" |
|
|
/> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
|
|
|
<el-col :span="12"> |
|
|
<el-form-item label="业务类别" prop="handleMethod"> |
|
|
<el-select |
|
|
v-model="formData.businessTypeCode" |
|
|
placeholder="业务类别" |
|
|
clearable |
|
|
> |
|
|
<el-option |
|
|
v-for="item in dict.businessType" |
|
|
:key="item.id" |
|
|
:label="item.dictLabel" |
|
|
:value="item.dictValue" |
|
|
/> |
|
|
</el-select> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
|
|
|
</el-row> |
|
|
|
|
|
<!-- 编号 + 受理时间 --> |
|
|
<el-row> |
|
|
<el-col :span="12"> |
|
|
<el-form-item label="编号" prop="originId"> |
|
|
<el-input |
|
|
v-model="formData.originId" |
|
|
:placeholder="formData.originIdSkip ? '无' : '请输入编号'" |
|
|
:disabled="mode === 'edit' || formData.originIdSkip" |
|
|
> |
|
|
<template #append> |
|
|
<el-checkbox |
|
|
v-model="formData.originIdSkip" |
|
|
@change="(v) => v && (formData.originId = '')" |
|
|
:disabled="mode=== 'edit'" |
|
|
> |
|
|
无 |
|
|
</el-checkbox> |
|
|
</template> |
|
|
</el-input> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
|
|
|
<el-col :span="12"> |
|
|
<el-form-item label="登记/受理时间" prop="discoveryTime"> |
|
|
<el-date-picker |
|
|
v-model="formData.discoveryTime" |
|
|
type="datetime" |
|
|
placeholder="请选择" |
|
|
value-format="YYYY-MM-DDTHH:mm:ss" |
|
|
format="YYYY-MM-DD HH:mm:ss" |
|
|
style="width: 100%" |
|
|
/> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
</el-row> |
|
|
|
|
|
<!-- 来件人姓名 + 身份证号码 --> |
|
|
<el-row> |
|
|
<el-col :span="12"> |
|
|
<el-form-item label="来件人姓名" prop="responderName"> |
|
|
<el-input |
|
|
v-model="formData.responderName" |
|
|
:placeholder="formData.responderNameSkip ? '无' : '请输入来件人姓名'" |
|
|
:disabled="formData.responderNameSkip" |
|
|
@blur="onAutoCheckDuplicate" |
|
|
> |
|
|
<template #append> |
|
|
<el-checkbox |
|
|
v-model="formData.responderNameSkip" |
|
|
@change="(v) => v && (formData.responderName = '')" |
|
|
> |
|
|
无 |
|
|
</el-checkbox> |
|
|
</template> |
|
|
</el-input> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
|
|
|
<el-col :span="12"> |
|
|
<div style="display: flex; align-items: flex-start; gap: 8px;"> |
|
|
<el-form-item label="身份证号码" prop="responderIdCode" style="flex: 1; margin-bottom: 0;"> |
|
|
<el-input |
|
|
v-model="formData.responderIdCode" |
|
|
:placeholder="formData.responderIdCodeSkip ? '无' : '请输入身份证号码'" |
|
|
:disabled="formData.responderIdCodeSkip" |
|
|
@blur="onAutoCheckDuplicate" |
|
|
> |
|
|
<template #append> |
|
|
<el-checkbox |
|
|
v-model="formData.responderIdCodeSkip" |
|
|
@change="(v) => v && (formData.responderIdCode = '')" |
|
|
> |
|
|
无 |
|
|
</el-checkbox> |
|
|
</template> |
|
|
</el-input> |
|
|
</el-form-item> |
|
|
|
|
|
<el-button |
|
|
type="primary" |
|
|
:loading="duplicateLoading" |
|
|
@click="onCheckDuplicate" |
|
|
> |
|
|
查看 |
|
|
</el-button> |
|
|
|
|
|
<span |
|
|
v-if="duplicateHintVisible" |
|
|
style="margin-left: 8px; font-size: 12px;" |
|
|
:style="{ color: duplicateCount > 0 ? '#fa541c' : '#8c8c8c' }" |
|
|
> |
|
|
<template v-if="autoDuplicateLoading">查重中…</template> |
|
|
<template v-else-if="duplicateCount > 0">疑似重复 {{ duplicateCount }} 条</template> |
|
|
<template v-else>未发现重复</template> |
|
|
</span> |
|
|
|
|
|
</div> |
|
|
</el-col> |
|
|
</el-row> |
|
|
|
|
|
<!-- 联系电话 + 被投诉二级机构 --> |
|
|
<el-row> |
|
|
<el-col :span="12"> |
|
|
<el-form-item label="联系电话" prop="responderPhone"> |
|
|
<el-input |
|
|
v-model="formData.responderPhone" |
|
|
:placeholder="formData.responderPhoneSkip ? '无' : '请输入联系电话'" |
|
|
:disabled="formData.responderPhoneSkip" |
|
|
@blur="onAutoCheckDuplicate" |
|
|
> |
|
|
<template #append> |
|
|
<el-checkbox |
|
|
v-model="formData.responderPhoneSkip" |
|
|
@change="(v) => v && (formData.responderPhone = '')" |
|
|
> |
|
|
无 |
|
|
</el-checkbox> |
|
|
</template> |
|
|
</el-input> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
|
|
|
<el-col :span="12"> |
|
|
<el-form-item label="被投诉二级机构" prop="secondDepartId" > |
|
|
<depart-tree-select |
|
|
v-model="formData.secondDepartId" |
|
|
:check-strictly="true" |
|
|
@node-click="(row) => (formData.secondDepartName = row.shortName)" |
|
|
/> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
</el-row> |
|
|
|
|
|
<!-- 来件内容 --> |
|
|
<el-row> |
|
|
<el-col :span="24"> |
|
|
<el-form-item label="来件内容" prop="thingDesc"> |
|
|
<el-input v-model="formData.thingDesc" type="textarea" :autosize="{ minRows: 4 }" /> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
</el-row> |
|
|
|
|
|
<!-- 涉嫌问题 + 是否重复件 --> |
|
|
<el-row> |
|
|
<el-col :span="12"> |
|
|
<el-form-item label="涉嫌问题" prop="involveProblemIdList"> |
|
|
<el-select v-model="formData.involveProblemIdList" multiple clearable style="width: 100%"> |
|
|
<el-option |
|
|
v-for="item in dict.suspectProblem" |
|
|
:key="item.dictValue" |
|
|
:value="item.dictValue" |
|
|
:label="item.dictLabel" |
|
|
> |
|
|
<!-- 复选框展示 --> |
|
|
<el-checkbox :model-value="(formData.involveProblemIdList || []).includes(item.dictValue)"> |
|
|
{{ item.dictLabel }} |
|
|
</el-checkbox> |
|
|
</el-option> |
|
|
</el-select> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
|
|
|
<el-col :span="12"> |
|
|
<el-form-item label="是否重复件" prop="repeatt"> |
|
|
<el-radio-group v-model="formData.repeatt" clearable> |
|
|
<el-radio v-for="item in dict.yesNo" :key="item.id" :label="item.dictValue"> |
|
|
{{ item.dictLabel }} |
|
|
</el-radio> |
|
|
</el-radio-group> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
</el-row> |
|
|
|
|
|
<!-- 标签 --> |
|
|
<el-row> |
|
|
<el-col :span="18"> |
|
|
<el-form-item label="标签" prop="tags"> |
|
|
<el-checkbox-group v-model="formData.tags"> |
|
|
<el-checkbox v-for="item in dict.sfssTags" :key="item.id" :label="item.dictValue"> |
|
|
{{ item.dictLabel }} |
|
|
</el-checkbox> |
|
|
</el-checkbox-group> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
</el-row> |
|
|
|
|
|
<!-- 办理方式 --> |
|
|
<el-row> |
|
|
<el-col :span="12"> |
|
|
<el-form-item label="办理方式" prop="handleMethod"> |
|
|
<el-radio-group v-model="formData.handleMethod" clearable> |
|
|
<el-radio v-for="item in dict.handleMethodType" :key="item.id" :label="item.dictValue"> |
|
|
{{ item.dictLabel }} |
|
|
</el-radio> |
|
|
</el-radio-group> |
|
|
</el-form-item> |
|
|
</el-col> |
|
|
</el-row> |
|
|
|
|
|
<el-form-item v-if="mode === 'add'" label="附件" prop="thingFiles"> |
|
|
<file-upload |
|
|
v-model:files="formData.thingFiles" |
|
|
tips="为便于“办理单位”更全面了解问题详情,请上传相关附件,如现场督察、数字督察等相关照片、视频及其他佐证材料。" |
|
|
/> |
|
|
</el-form-item> |
|
|
</div> |
|
|
|
|
|
<!-- 办理单位 --> |
|
|
<el-divider v-if="mode === 'add'" /> |
|
|
<h2 v-if="mode === 'add'">办理单位</h2> |
|
|
<div v-if="mode === 'add'" class="add-negation-container"> |
|
|
<el-form-item label="主办层级" prop="hostLevel" :rules="{ required: true, message: '请选择主办层级', trigger: ['blur'] }"> |
|
|
<el-select style="width: 280px" v-model="formData.hostLevel" @change="handleChangeHostLevel"> |
|
|
<el-option v-for="item in dict.hostLevel" :key="item.id" :label="item.dictLabel" :value="item.dictValue" /> |
|
|
</el-select> |
|
|
<div class="tips mt-10"> |
|
|
<p>如主办层级 为 市局主办, 则由<span :data-active="formData.hostLevel === HostLevel.FIRST">督察支队</span>办理;</p> |
|
|
<p>如主办层级为 二级机构主办,则由<span :data-active="formData.hostLevel === HostLevel.SECOND">督察部门</span>办理,可进一步下发;</p> |
|
|
<p>如主办层级为 三级机构主办,则由<span :data-active="formData.hostLevel === HostLevel.THREE">所队</span>办理。</p> |
|
|
</div> |
|
|
</el-form-item> |
|
|
<el-form-item label="指定办理单位" prop="departId" :rules="{ required: true, message: '请选择办理单位', trigger: ['blur'] }"> |
|
|
<div class="flex gap"> |
|
|
<div style="width: 280px"> |
|
|
<template v-if="formData.hostLevel === HostLevel.THREE"> |
|
|
<depart-tree-select v-model="formData.departId" v-loading="departLoading" /> |
|
|
</template> |
|
|
<el-tree-select v-else :data="departs" :props="{ label: 'shortName', value: 'id' }" node-key="id" clearable filterable v-model="formData.departId" @node-click="handleSelectDepart" check-strictly style="width: 280px" v-loading="departLoading" /> |
|
|
</div> |
|
|
<el-button type="primary" @click="handleLinkDepart" text v-if="formData.hostLevel !== HostLevel.FIRST">关联问题涉及单位</el-button> |
|
|
</div> |
|
|
<div class="tips mt-10"> |
|
|
<p>问题涉及单位 指与该问题相关的单位;</p> |
|
|
<p>指定办理单位 指将问题分派给哪个单位办理。</p> |
|
|
</div> |
|
|
</el-form-item> |
|
|
</div> |
|
|
|
|
|
<!-- 初核时限 --> |
|
|
<h2 v-if="mode === 'add'">初核时限</h2> |
|
|
<p v-if="mode === 'add'" style="color: #909399; font-size: 14px; line-height: 1.6; padding-left: 200px;"> |
|
|
该信件的初核时限需在<span style="color: var(--el-color-danger); font-weight: 600;"> 4个工作日 </span>之内完成初核。 |
|
|
</p> |
|
|
|
|
|
<!-- 办理时限 --> |
|
|
<h2 v-if="mode === 'add'">办理时限</h2> |
|
|
<div v-if="mode === 'add'" class="add-negation-container"> |
|
|
<el-form-item label="办理时限" prop="timeLimit" :rules="{ required: true, message: '请选择办理时限', trigger: ['blur'] }"> |
|
|
<time-limit-select :key="timeLimitKey" v-model="formData.timeLimit" v-model:maxSignDuration="formData.maxSignDuration" v-model:maxHandleDuration="formData.maxHandleDuration" v-model:maxExtensionDuration="formData.maxExtensionDuration" /> |
|
|
</el-form-item> |
|
|
</div> |
|
|
|
|
|
<!-- 审批流程 --> |
|
|
<h2 v-if="mode === 'add'">审批流程</h2> |
|
|
<div v-if="mode === 'add'" class="add-negation-container"> |
|
|
<el-form-item label="审批流程" prop="approvalFlow" :rules="{ required: true, message: '请选择审批流程', trigger: ['blur'] }"> |
|
|
<el-radio-group v-model="formData.approvalFlow" v-if="userStore.user.roleCodes.includes('admin_1')"> |
|
|
<el-radio v-for="item in dict.approvalFlow" :key="item.dictCode" :value="item.dictValue">{{ item.dictLabel }}{{ item.remark ? `(${item.remark})` : "" }}</el-radio> |
|
|
</el-radio-group> |
|
|
<el-radio-group v-model="formData.approvalFlow" v-else> |
|
|
<el-radio value="2">二级审批(所队一>二级机构)</el-radio> |
|
|
</el-radio-group> |
|
|
<div class="tips mt-10"> |
|
|
<p v-if="userStore.user.roleCodes.includes('admin_1')">三级审核 问题提交办结时,需经过"所队—>二级机构—>市局"三级审核,通过后方可办结;</p> |
|
|
<p>二级审核 问题提交办结时,仅需经过"所队—>二级机构"两级审核,通过后即可办结;</p> |
|
|
</div> |
|
|
</el-form-item> |
|
|
</div> |
|
|
</el-form> |
|
|
</el-scrollbar> |
|
|
|
|
|
<template #footer> |
|
|
<div class="dialog-footer"> |
|
|
<el-button @click="visibleProxy = false" size="large">取消</el-button> |
|
|
<el-button type="primary" @click="onSubmit" size="large" :loading="loading || submitLoading"> |
|
|
{{ mode === 'add' ? '添加' : '修改' }} |
|
|
</el-button> |
|
|
</div> |
|
|
</template> |
|
|
</el-dialog> |
|
|
|
|
|
<DuplicateDrawerWithDetail |
|
|
v-model="duplicateDrawerVisible" |
|
|
:dict="dict" |
|
|
:query="{ |
|
|
responderIdCode: formData.responderIdCode, |
|
|
responderName: formData.responderName, |
|
|
responderPhone: formData.responderPhone |
|
|
}" |
|
|
:requestFn="maileRepeatt" |
|
|
detailIdKey="negativeId" |
|
|
@opened-detail="handleDuplicateRowClick" |
|
|
/> |
|
|
|
|
|
|
|
|
<!-- 办理详情 --> |
|
|
<NegativeDialog |
|
|
v-model="detailDialogVisible" |
|
|
:id="detailNegativeId" |
|
|
@close="detailDialogVisible = false" |
|
|
/> |
|
|
|
|
|
<!-- 局长信箱办理详情 --> |
|
|
<NegativeMailboxDialog |
|
|
v-model="mailboxDetailVisible" |
|
|
:id="detailNegativeId" |
|
|
@close="mailboxDetailVisible = false" |
|
|
/> |
|
|
</template> |
|
|
|
|
|
<script setup> |
|
|
import {computed, ref, watch} from "vue"; |
|
|
import {maileRepeatt, getComplaintCollectionDetail, updateComplaintCollection, addComplaintCollection} from "@/api/data/complaintCollection.ts"; |
|
|
import dayjs from "dayjs"; |
|
|
import feedback from "@/utils/feedback.ts"; |
|
|
import DuplicateDrawerWithDetail from "@/views/data/DuplicateDrawerWithDetail.vue"; |
|
|
import useUserStore from "@/stores/modules/user.ts"; |
|
|
import {secondList, listByFirstHost} from "@/api/system/depart"; |
|
|
import useCatchStore from "@/stores/modules/catch"; |
|
|
const catchStore = useCatchStore(); |
|
|
|
|
|
// 内部表单数据 |
|
|
const formData = ref(createEmptyForm()); |
|
|
|
|
|
function createEmptyForm() { |
|
|
return { |
|
|
// 来源 |
|
|
sourcePath: [], |
|
|
sourceTable: '', |
|
|
sourceTableSubOne: '', |
|
|
// 编号 |
|
|
originId: '', |
|
|
originIdSkip: false, |
|
|
// 受理时间 |
|
|
discoveryTime: '', |
|
|
// 来件人 |
|
|
responderName: '', |
|
|
responderNameSkip: false, |
|
|
responderIdCode: '', |
|
|
responderIdCodeSkip: false, |
|
|
responderPhone: '', |
|
|
responderPhoneSkip: false, |
|
|
// 被投诉机构 |
|
|
secondDepartId: '', |
|
|
secondDepartName: '', |
|
|
// 内容 |
|
|
thingDesc: '', |
|
|
involveProblemIdList: [], |
|
|
repeatt: '', |
|
|
handleMethod: '', |
|
|
// 标签 |
|
|
tags: [], |
|
|
businessTypeCode: '', |
|
|
businessTypeName: '', |
|
|
// 附件 |
|
|
thingFiles: [], |
|
|
// 办理信息 |
|
|
hostLevel: '3', |
|
|
departId: '', |
|
|
departName: '', |
|
|
timeLimit: '', |
|
|
maxSignDuration: null, |
|
|
maxHandleDuration: null, |
|
|
maxExtensionDuration: null, |
|
|
approvalFlow: '', |
|
|
// 编辑时需要的 id |
|
|
id: '', |
|
|
negativeId: '', |
|
|
}; |
|
|
} |
|
|
|
|
|
// 内部校验规则 |
|
|
const rules = { |
|
|
sourcePath: [ |
|
|
{required: true, message: "请选择来源(一级/二级)", trigger: "change"}, |
|
|
], |
|
|
discoveryTime: [{required: true, message: '请选择受理时间', trigger: 'change'}], |
|
|
secondDepartId: [{required: true, message: '请选择被投诉二级机构', trigger: 'change'}], |
|
|
thingDesc: [{required: true, message: '请输入来件内容', trigger: 'blur'}], |
|
|
involveProblemIdList: [{required: true, message: '请选择涉嫌问题', trigger: 'change'}], |
|
|
repeatt: [{required: true, message: '请选择是否重复件', trigger: 'change'}], |
|
|
hostLevel: [{required: true, message: '请选择主办层级', trigger: 'change'}], |
|
|
departId: [{required: true, message: '请选择办理单位', trigger: 'change'}], |
|
|
timeLimit: [{required: true, message: '请选择办理时限', trigger: 'change'}], |
|
|
approvalFlow: [{required: true, message: '请选择审批流程', trigger: 'change'}], |
|
|
}; |
|
|
|
|
|
// 1. 用 computed 包装 storeDict |
|
|
const storeDict = computed(() => |
|
|
catchStore.getDicts([ |
|
|
"businessType", |
|
|
"suspectProblem", |
|
|
"specialSupervision", |
|
|
"checkStatus", |
|
|
"policeType", |
|
|
"timeLimit", |
|
|
"approvalFlow", |
|
|
"sfssSourceTable", |
|
|
"sfssTags", |
|
|
]) || {} |
|
|
); |
|
|
|
|
|
// 2. 本地静态字典 |
|
|
const localDict = { |
|
|
yesNo: [ |
|
|
{id: 1, dictLabel: "是", dictValue: "1"}, |
|
|
{id: 2, dictLabel: "否", dictValue: "0"}, |
|
|
], |
|
|
handleMethodType: [ |
|
|
{id: 1, dictLabel: "自办", dictValue: "0"}, |
|
|
{id: 2, dictLabel: "下发", dictValue: "1"}, |
|
|
], |
|
|
}; |
|
|
|
|
|
// 3. sourceTableAndLevel 依赖 storeDict.value |
|
|
const sourceTableAndLevel = computed(() => { |
|
|
const list = storeDict.value?.sfssSourceTable || []; |
|
|
if (!list || list.length === 0) return []; |
|
|
// 一级:remark 为空 |
|
|
const parents = list.filter(d => !d.remark); |
|
|
// 二级:remark 有值 |
|
|
const children = list.filter(d => d.remark); |
|
|
return parents.map(p => ({ |
|
|
label: p.dictLabel, |
|
|
value: String(p.dictValue), |
|
|
children: children |
|
|
.filter(c => String(c.remark) === String(p.dictValue)) |
|
|
.map(c => ({ |
|
|
label: c.dictLabel, |
|
|
value: String(c.dictValue), |
|
|
})), |
|
|
})); |
|
|
}); |
|
|
|
|
|
// 4. dict 合并 |
|
|
const dict = computed(() => ({ |
|
|
...storeDict.value, |
|
|
...localDict, |
|
|
sourceTableAndLevel: sourceTableAndLevel.value, |
|
|
})); |
|
|
|
|
|
const HostLevel = { |
|
|
FIRST: '1', |
|
|
SECOND: '2', |
|
|
THREE: '3' |
|
|
}; |
|
|
|
|
|
const userStore = useUserStore(); |
|
|
|
|
|
const props = defineProps({ |
|
|
modelValue: Boolean, |
|
|
mode: { type: String, default: "add" }, |
|
|
id: { type: String, default: "" }, |
|
|
negativeId: { type: String, default: "" }, |
|
|
loading: { type: Boolean, default: false }, |
|
|
}); |
|
|
|
|
|
const emit = defineEmits(["update:modelValue", "updateSuccess"]); |
|
|
|
|
|
const formRef = ref(); |
|
|
const submitLoading = ref(false); |
|
|
const timeLimitKey = ref(0); |
|
|
|
|
|
const visibleProxy = computed({ |
|
|
get: () => props.modelValue, |
|
|
set: (v) => emit("update:modelValue", v), |
|
|
}); |
|
|
|
|
|
watch( |
|
|
() => visibleProxy.value, |
|
|
async (v) => { |
|
|
if (v) { |
|
|
// 重置表单 |
|
|
timeLimitKey.value++ |
|
|
formData.value = createEmptyForm(); |
|
|
|
|
|
duplicateDrawerVisible.value = false |
|
|
duplicateLoading.value = false |
|
|
autoDuplicateLoading.value = false |
|
|
duplicateHintVisible.value = false |
|
|
duplicateCount.value = 0 |
|
|
duplicateCache.value = [] |
|
|
duplicateList.value = [] |
|
|
|
|
|
getDeparts() |
|
|
|
|
|
if (props.mode === 'edit' && (props.id || props.negativeId)) { |
|
|
try { |
|
|
const res = await getComplaintCollectionDetail({ id: props.id, negativeId: props.negativeId }); |
|
|
const r = res?.data ?? res ?? {}; |
|
|
|
|
|
formData.value.id = r.id ?? ''; |
|
|
formData.value.sourceTable = r.sourceTable ?? ''; |
|
|
formData.value.sourceTableSubOne = r.sourceTableSubOne ?? ''; |
|
|
formData.value.sourcePath = [r.sourceTable, r.sourceTableSubOne].filter(Boolean); |
|
|
formData.value.originId = r.originId ?? ''; |
|
|
formData.value.discoveryTime = r.discoveryTime ?? ''; |
|
|
formData.value.responderName = r.responderName ?? ''; |
|
|
formData.value.responderIdCode = r.responderIdCode ?? ''; |
|
|
formData.value.responderPhone = r.responderPhone ?? ''; |
|
|
formData.value.secondDepartId = r.secondDepartId ?? ''; |
|
|
formData.value.secondDepartName = r.secondDepartName ?? ''; |
|
|
formData.value.thingDesc = r.thingDesc ?? ''; |
|
|
formData.value.repeatt = r.repeatt ?? ''; |
|
|
formData.value.handleMethod = r.handleMethod ?? ''; |
|
|
formData.value.involveProblemIdList = splitToArray(r.involveProblemIdList ?? r.involveProblem); |
|
|
formData.value.tags = splitToArray(r.tags ?? r.tag); |
|
|
formData.value.businessTypeName = r.businessTypeName ?? ''; |
|
|
formData.value.businessTypeCode = r.businessTypeCode ?? ''; |
|
|
formData.value.thingFiles = normalizeThingFiles(r.thingFiles); |
|
|
formData.value.hostLevel = r.hostLevel ?? '3'; |
|
|
formData.value.departId = r.departId ?? ''; |
|
|
formData.value.departName = r.departName ?? ''; |
|
|
formData.value.timeLimit = r.timeLimit ?? ''; |
|
|
formData.value.maxSignDuration = r.maxSignDuration ?? null; |
|
|
formData.value.maxHandleDuration = r.maxHandleDuration ?? null; |
|
|
formData.value.maxExtensionDuration = r.maxExtensionDuration ?? null; |
|
|
formData.value.approvalFlow = r.approvalFlow ?? ''; |
|
|
formData.value.negativeId = r.negativeId ?? ''; |
|
|
} catch (e) { |
|
|
console.error("获取详情失败", e); |
|
|
feedback.notifyError("获取数据失败,请重试"); |
|
|
visibleProxy.value = false; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
); |
|
|
|
|
|
watch( |
|
|
() => formData.value.hostLevel, |
|
|
() => { |
|
|
getDeparts(); |
|
|
} |
|
|
); |
|
|
|
|
|
const departs = ref([]); |
|
|
const departLoading = ref(false); |
|
|
async function getDeparts() { |
|
|
if (!formData.value.hostLevel) return; |
|
|
departLoading.value = true; |
|
|
try { |
|
|
if (formData.value.hostLevel === HostLevel.FIRST) { |
|
|
departs.value = await listByFirstHost(); |
|
|
} else if (formData.value.hostLevel === HostLevel.SECOND) { |
|
|
departs.value = await secondList(); |
|
|
} else { |
|
|
departs.value = []; |
|
|
} |
|
|
} catch (e) { |
|
|
console.error(e); |
|
|
} finally { |
|
|
departLoading.value = false; |
|
|
} |
|
|
} |
|
|
|
|
|
function handleSelectDepart(row) { |
|
|
formData.value.departName = row.shortName; |
|
|
} |
|
|
|
|
|
function handleLinkDepart() { |
|
|
if (formData.value.hostLevel === HostLevel.SECOND) { |
|
|
feedback.msgWarning("当前选择二级机构主办,指定办理单位请选择二级机构!"); |
|
|
return; |
|
|
} |
|
|
formData.value.departId = formData.value.secondDepartId; |
|
|
formData.value.departName = formData.value.secondDepartName; |
|
|
} |
|
|
|
|
|
function handleChangeHostLevel(val) { |
|
|
if (val === HostLevel.FIRST) { |
|
|
formData.value.departId = ""; |
|
|
} |
|
|
if (val === HostLevel.SECOND) { |
|
|
formData.value.approvalFlow = "3"; |
|
|
} |
|
|
} |
|
|
|
|
|
watch( |
|
|
() => formData.value.sourcePath, |
|
|
(path) => { |
|
|
if (!path || path.length === 0) return; |
|
|
formData.value.sourceTable = (path && path[0]) || ""; |
|
|
formData.value.sourceTableSubOne = (path && path[1]) || ""; |
|
|
}, |
|
|
{ deep: true } |
|
|
); |
|
|
|
|
|
|
|
|
function fillFiledName() { |
|
|
const code = formData.value.businessTypeCode; |
|
|
const hit = dict.value?.businessType?.find( |
|
|
(d) => String(d.dictValue) === String(code) |
|
|
); |
|
|
formData.value.businessTypeName = hit?.dictLabel || ""; |
|
|
} |
|
|
|
|
|
function splitToArray(val) { |
|
|
if (!val) return []; |
|
|
if (Array.isArray(val)) return val; |
|
|
if (typeof val === 'string') { |
|
|
return val.split(/[,,]/).map(s => s.trim()).filter(Boolean); |
|
|
} |
|
|
return []; |
|
|
} |
|
|
|
|
|
function normalizeThingFiles(val) { |
|
|
if (!val) return []; |
|
|
if (Array.isArray(val)) return val.map(f => ({...f, loading: false, percent: 100})); |
|
|
if (typeof val === 'string' && val.trim().startsWith('[')) { |
|
|
try { |
|
|
return JSON.parse(val).map(f => ({...f, loading: false, percent: 100})); |
|
|
} catch {} |
|
|
} |
|
|
if (typeof val === 'string') { |
|
|
return val.split(/[,,]/).map(s => s.trim()).filter(Boolean).map(p => ({ |
|
|
filePath: p, |
|
|
fileName: p.split('/').pop() || p, |
|
|
loading: false, |
|
|
percent: 100, |
|
|
})); |
|
|
} |
|
|
return []; |
|
|
} |
|
|
|
|
|
async function onSubmit() { |
|
|
if (!formRef.value) return; |
|
|
try { |
|
|
await formRef.value.validate(); |
|
|
} catch { |
|
|
feedback.msgWarning("请完善必填信息"); |
|
|
return; |
|
|
} |
|
|
fillFiledName(); |
|
|
|
|
|
// 添加模式:内部调用 API |
|
|
if (props.mode === 'add') { |
|
|
submitLoading.value = true; |
|
|
try { |
|
|
await addComplaintCollection({...formData.value}); |
|
|
feedback.msgSuccess("添加成功"); |
|
|
visibleProxy.value = false; |
|
|
emit("updateSuccess"); |
|
|
} catch (e) { |
|
|
console.error("添加失败", e); |
|
|
} finally { |
|
|
submitLoading.value = false; |
|
|
} |
|
|
return; |
|
|
} |
|
|
|
|
|
// 修改模式:内部处理 API 调用 |
|
|
submitLoading.value = true; |
|
|
try { |
|
|
await updateComplaintCollection({...formData.value}); |
|
|
feedback.msgSuccess("修改成功"); |
|
|
visibleProxy.value = false; |
|
|
emit("updateSuccess"); |
|
|
} catch (e) { |
|
|
console.error("修改失败", e); |
|
|
} finally { |
|
|
submitLoading.value = false; |
|
|
} |
|
|
} |
|
|
|
|
|
// 查重 |
|
|
const duplicateDrawerVisible = ref(false) |
|
|
const duplicateList = ref([]) |
|
|
const duplicateLoading = ref(false) |
|
|
const onCheckDuplicate = async () => { |
|
|
duplicateDrawerVisible.value = true |
|
|
} |
|
|
|
|
|
const duplicateCount = ref(0) |
|
|
const duplicateCache = ref([]) |
|
|
const autoDuplicateLoading = ref(false) |
|
|
const duplicateHintVisible = ref(false) |
|
|
|
|
|
|
|
|
const fetchDuplicate = async () => { |
|
|
const body = { |
|
|
responderIdCode: formData.value.responderIdCode, |
|
|
responderName: formData.value.responderName, |
|
|
responderPhone: formData.value.responderPhone, |
|
|
} |
|
|
|
|
|
const res = await maileRepeatt(body) |
|
|
return res?.complaintCollectionRepeatDTOS || [] |
|
|
} |
|
|
|
|
|
const onAutoCheckDuplicate = async () => { |
|
|
const { responderIdCode, responderName, responderPhone } = formData.value |
|
|
|
|
|
if (!responderIdCode && !responderName && !responderPhone) { |
|
|
duplicateCount.value = 0 |
|
|
duplicateCache.value = [] |
|
|
duplicateHintVisible.value = false |
|
|
return |
|
|
} |
|
|
|
|
|
duplicateHintVisible.value = true |
|
|
autoDuplicateLoading.value = true |
|
|
try { |
|
|
const list = await fetchDuplicate() |
|
|
duplicateCount.value = list.length |
|
|
duplicateCache.value = list |
|
|
} catch (e) { |
|
|
} finally { |
|
|
autoDuplicateLoading.value = false |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// 查重结果的详情弹窗 |
|
|
const detailDialogVisible = ref(false) |
|
|
const mailboxDetailVisible = ref(false) |
|
|
const detailNegativeId = ref("") |
|
|
|
|
|
// 处理查重行点击事件 |
|
|
const handleDuplicateRowClick = (row) => { |
|
|
// 复用 ComplaintCollection.vue 中的逻辑 |
|
|
if (row.problemSources === '局长信箱') { |
|
|
mailboxDetailVisible.value = true |
|
|
detailNegativeId.value = row.originId |
|
|
} else { |
|
|
detailDialogVisible.value = true |
|
|
detailNegativeId.value = row.negativeId |
|
|
} |
|
|
} |
|
|
|
|
|
</script> |
|
|
|
|
|
<style lang="scss" scoped> |
|
|
.form-layout { |
|
|
padding: 0 34px; |
|
|
} |
|
|
|
|
|
.dialog-footer { |
|
|
padding: 16px 24px 24px; |
|
|
} |
|
|
|
|
|
.add-negation-container { |
|
|
padding: 0 60px; |
|
|
} |
|
|
|
|
|
.tips { |
|
|
margin-top: 10px; |
|
|
|
|
|
[data-active="true"] { |
|
|
color: var(--danger-color); |
|
|
} |
|
|
} |
|
|
|
|
|
:deep() { |
|
|
.el-form-item__content { |
|
|
flex-direction: column; |
|
|
align-items: flex-start; |
|
|
} |
|
|
.block.el-radio-group { |
|
|
display: block; |
|
|
} |
|
|
.block.el-radio-group .el-radio { |
|
|
display: block; |
|
|
} |
|
|
} |
|
|
|
|
|
.duplicate-drawer { |
|
|
--el-drawer-padding-primary: 20px; |
|
|
} |
|
|
|
|
|
.drawer-header { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 8px; |
|
|
font-size: 18px; |
|
|
font-weight: 600; |
|
|
color: #d46b08; |
|
|
} |
|
|
|
|
|
.drawer-body { |
|
|
padding-top: 8px; |
|
|
} |
|
|
|
|
|
.drawer-alert { |
|
|
margin-bottom: 16px; |
|
|
} |
|
|
|
|
|
.id-highlight { |
|
|
margin-bottom: 20px; |
|
|
padding: 12px 16px; |
|
|
background: #fafafa; |
|
|
border-left: 4px solid #faad14; |
|
|
font-size: 14px; |
|
|
line-height: 22px; |
|
|
} |
|
|
|
|
|
.id-highlight span { |
|
|
margin-left: 8px; |
|
|
font-weight: 600; |
|
|
color: #d4380d; |
|
|
} |
|
|
|
|
|
.drawer-header.danger { |
|
|
color: #0d73ee; |
|
|
} |
|
|
|
|
|
.drawer-header .title-group { |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
} |
|
|
|
|
|
.drawer-header .title { |
|
|
font-size: 20px; |
|
|
font-weight: 600; |
|
|
line-height: 1.2; |
|
|
} |
|
|
|
|
|
.drawer-header .sub-title { |
|
|
font-size: 13px; |
|
|
color: #8c8c8c; |
|
|
margin-top: 2px; |
|
|
} |
|
|
|
|
|
h2 { |
|
|
margin: 16px 0 8px; |
|
|
padding-left: 60px; |
|
|
font-size: 16px; |
|
|
font-weight: 600; |
|
|
} |
|
|
</style>
|
|
|
|