@ -2,38 +2,47 @@
< el -dialog
: title = "mode === 'add' ? '添加登记来件' : '修改登记来件'"
v - model = "visibleProxy"
width = "70 vw"
width = "75 vw"
top = "2vh"
style = "margin-bottom: 0"
>
< el -scrollbar max -height = " 76vh " >
<!-- 步骤指示器 ( 仅添加模式显示 ) -- >
< el -steps v-if ="mode === 'add'" :active="currentStep" finish-status="success" align-center class="mb-20" >
< el -step title = "填写投诉信息" / >
< el -step title = "查重结果" / >
< el -step title = "完善信息" / >
< / e l - s t e p s >
< el -scrollbar max -height = " 72vh " >
< el -form
ref = "formRef"
: model = "formData"
: label - width = "150"
class = "form-layout"
style = "min-height: 66vh"
style = "min-height: 60 vh"
: 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 = "请选择来源(一级/二级)"
/ >
< / e l - f o r m - i t e m >
< / e l - c o l >
<!-- === === === === === === == 步骤1 : 投诉信息 === === === === === === == -- >
< div v-show ="mode === 'add' ? currentStep === 0 : true" >
< 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 = "请选择来源(一级/二级)"
/ >
< / e l - f o r m - i t e m >
< / e l - c o l >
< el -col :span ="12" >
< el -form -item label = "业务类别" prop = "handleMethod" >
@ -113,44 +122,22 @@
< / e l - c o l >
< 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 = '')"
>
无
< / e l - c h e c k b o x >
< / template >
< / e l - i n p u t >
< / e l - f o r m - i t e m >
< el -button
type = "primary"
: loading = "duplicateLoading"
@ click = "onCheckDuplicate"
>
查看
< / e l - b u t t o n >
< span
v - if = "duplicateHintVisible"
style = "margin-left: 8px; font-size: 12px;"
: style = "{ color: duplicateCount > 0 ? '#fa541c' : '#8c8c8c' }"
< el -form -item label = "身份证号码" prop = "responderIdCode" >
< el -input
v - model = "formData.responderIdCode"
: placeholder = "formData.responderIdCodeSkip ? '无' : '请输入身份证号码'"
: disabled = "formData.responderIdCodeSkip"
>
< template v-if ="autoDuplicateLoading" > 查重中 … < / template >
< template v -else -if = " duplicateCount > 0 " > 疑似重复 { { duplicateCount } } 条 < / template >
< template v-else > 未发现重复 < / template >
< / span >
< / div >
< template # append >
< el -checkbox
v - model = "formData.responderIdCodeSkip"
@ change = "(v) => v && (formData.responderIdCode = '')"
>
无
< / e l - c h e c k b o x >
< / template >
< / e l - i n p u t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
@ -162,22 +149,18 @@
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 = '')"
>
无
< / e l - c h e c k b o x >
> 无 < / e l - c h e c k b o x >
< / template >
< / e l - i n p u t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< el -col :span ="12" >
< el -form -item label = "被投诉二级机构" prop = "secondDepartId" >
< el -form -item label = "被投诉二级机构" prop = "secondDepartId" >
< depart -tree -select
v - model = "formData.secondDepartId"
: check - strictly = "true"
@ -196,63 +179,6 @@
< / e l - c o l >
< / e l - r o w >
<!-- 涉嫌问题 + 是否重复件 -- >
< 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 } }
< / e l - c h e c k b o x >
< / e l - o p t i o n >
< / e l - s e l e c t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< 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 } }
< / e l - r a d i o >
< / e l - r a d i o - g r o u p >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 标签 -- >
< 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 } }
< / e l - c h e c k b o x >
< / e l - c h e c k b o x - g r o u p >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 办理方式 -- >
< 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 } }
< / e l - r a d i o >
< / e l - r a d i o - g r o u p >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
< el -form -item v-if ="mode === 'add'" label="附件" prop="thingFiles" >
< file -upload
v - model : files = "formData.thingFiles"
@ -260,77 +186,397 @@
/ >
< / e l - f o r m - i t e m >
< / div >
< / 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" / >
< / e l - s e l e c t >
< 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 >
< / e l - f o r m - i t e m >
< 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 " / >
<!-- === === === === === === == 步骤2 : 查重结果 === === === === === === == -- >
< div v-if ="mode === 'add' && currentStep === 1" class="step2-container" >
< h2 > 查重结果 < / h2 >
<!-- 当前填写信息摘要 -- >
< div class = "current-info-bar" >
< el -alert type = "info" :closable ="false" show -icon >
< template # title >
< span class = "info-label" > 当前填写信息 : < / span >
< span v-if ="formData.responderName" > 姓名 : < strong > { { formData . responderName } } < / strong > < / span >
< span v-if ="formData.responderIdCode" > | 身份证 : < strong > { { formData . responderIdCode } } < / strong > < / span >
< span v-if ="formData.responderPhone" > | 电话 : < strong > { { formData . responderPhone } } < / strong > < / span >
< / template >
< / e l - a l e r t >
< / div >
<!-- 重复记录列表 -- >
< div class = "duplicate-list" v-loading ="duplicateLoading" >
< el -empty v -if = " duplicateList.length = = = 0 & & ! duplicateLoading " description = "未发现重复记录,您可以继续添加" / >
< el -result v -else -if = " duplicateList.length > 0 && ! selectedCardId " icon=" warning " title=" 发现疑似重复记录 " >
< template # sub -title >
< p style = "color: #909399;" > 请从下方列表选择一条记录进行合并 , 或选择 "不合并,继续添加" < / p >
< / template >
< / e l - r e s u l t >
< div v-if ="duplicateList.length > 0" class="card-grid" >
< div
v - for = "item in duplicateList"
: key = "item.complaintId || item.negativeId"
class = "merge-card"
: class = "{ 'is-selected': selectedCardId === (item.complaintId || item.negativeId) }"
@ click = "handleSelectCard(item)"
>
<!-- 卡片头部 -- >
< div class = "card-header" >
< el -tag size = "small" :type ="getSourceTagType(item.sourceTable)" >
{ { item . sourceTable || '未知来源' } }
< / e l - t a g >
< span class = "origin-id" > { { item . originId || '无编号' } } < / span >
< div class = "card-checkbox" >
< el -checkbox
: model - value = "selectedCardId === (item.complaintId || item.negativeId)"
@ click . stop
@ change = "handleSelectCard(item)"
/ >
< / div >
< / div >
<!-- 举报人信息 -- >
< div class = "card-info" >
< div v-if ="item.responderName" class="info-row" >
< span class = "label" > 举报人 < / span >
< span class = "value" > { { item . responderName } } < / span >
< / div >
< div v-if ="item.responderIdCode" class="info-row" >
< span class = "label" > 身份证 < / span >
< span class = "value" > { { item . responderIdCode } } < / span >
< / div >
< div v-if ="item.responderPhone" class="info-row" >
< span class = "label" > 联系电话 < / span >
< span class = "value" > { { item . responderPhone } } < / span >
< / div >
< / div >
<!-- 投诉内容 -- >
< div class = "card-content" >
< div class = "content-label" > 投诉内容 < / div >
< div class = "content-text" > { { item . thingDesc || '无内容' } } < / div >
< / div >
<!-- 卡片底部 -- >
< div class = "card-footer" >
< span class = "time" > { { formatTime ( item . discoveryTime ) } } < / span >
< el -button type = "primary" link @click.stop ="handleViewDetail(item)" >
< el -icon > < View / > < / e l - i c o n > 查 看 详 情
< / e l - b u t t o n >
< / div >
<!-- 选中标记 -- >
< div v-if ="selectedCardId === (item.complaintId || item.negativeId)" class="selected-badge" >
< el -icon > < Check / > < / e l - i c o n > 已 选 择
< / div >
< / 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 >
< / e l - f o r m - i t e m >
< / div >
< / 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" / >
< / e l - f o r m - i t e m >
< / div >
<!-- === === === === === === == 步骤3 : 完善信息 === === === === === === == -- >
< div v-if ="mode === 'add' && currentStep === 2 && !isMerging" >
<!-- 来源 + 业务类别 -- >
< 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 = "请选择来源(一级/二级)"
/ >
< / e l - f o r m - i t e m >
< / e l - c o l >
< el -col :span ="12" >
< el -form -item label = "业务类别" prop = "businessTypeCode" >
< el -select v-model ="formData.businessTypeCode" placeholder="业务类别" clearable style="width: 100%" >
< el -option
v - for = "item in dict.businessType"
: key = "item.id"
: label = "item.dictLabel"
: value = "item.dictValue"
/ >
< / e l - s e l e c t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 审批流程 -- >
< 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 >
< / e l - r a d i o - g r o u p >
< el -radio -group v -model = " formData.approvalFlow " v-else >
< el -radio value = "2" > 二级审批 ( 所队一 > 二级机构 ) < / e l - r a d i o >
< / e l - r a d i o - g r o u p >
< div class = "tips mt-10" >
< p v-if ="userStore.user.roleCodes.includes('admin_1')" > 三级审核 问题提交办结时 , 需经过 " 所队 — > 二级机构 — > 市局 " 三级审核 , 通过后方可办结 ; < / p >
< p > 二级审核 问题提交办结时 , 仅需经过 "所队—>二级机构" 两级审核 , 通过后即可办结 ; < / p >
< / div >
<!-- 编号 + 登记时间 -- >
< 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'"
> 无 < / e l - c h e c k b o x >
< / template >
< / e l - i n p u t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< 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%"
/ >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 来件人姓名 + 身份证号码 -- >
< el -row >
< el -col :span ="12" >
< el -form -item label = "来件人姓名" prop = "responderName" >
< el -input
v - model = "formData.responderName"
: placeholder = "formData.responderNameSkip ? '无' : '请输入来件人姓名'"
: disabled = "formData.responderNameSkip"
>
< template # append >
< el -checkbox
v - model = "formData.responderNameSkip"
@ change = "(v) => v && (formData.responderName = '')"
> 无 < / e l - c h e c k b o x >
< / template >
< / e l - i n p u t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< el -col :span ="12" >
< el -form -item label = "身份证号码" prop = "responderIdCode" >
< el -input
v - model = "formData.responderIdCode"
: placeholder = "formData.responderIdCodeSkip ? '无' : '请输入身份证号码'"
: disabled = "formData.responderIdCodeSkip"
>
< template # append >
< el -checkbox
v - model = "formData.responderIdCodeSkip"
@ change = "(v) => v && (formData.responderIdCode = '')"
> 无 < / e l - c h e c k b o x >
< / template >
< / e l - i n p u t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 联系电话 + 被投诉二级机构 -- >
< el -row >
< el -col :span ="12" >
< el -form -item label = "联系电话" prop = "responderPhone" >
< el -input
v - model = "formData.responderPhone"
: placeholder = "formData.responderPhoneSkip ? '无' : '请输入联系电话'"
: disabled = "formData.responderPhoneSkip"
>
< template # append >
< el -checkbox
v - model = "formData.responderPhoneSkip"
@ change = "(v) => v && (formData.responderPhone = '')"
> 无 < / e l - c h e c k b o x >
< / template >
< / e l - i n p u t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< 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)"
/ >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 来件内容 -- >
< el -row >
< el -col :span ="24" >
< el -form -item label = "来件内容" prop = "thingDesc" >
< el -input v -model = " formData.thingDesc " type = "textarea" : autosize = "{ minRows: 4 }" / >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 涉嫌问题 + 是否重复件 -- >
< 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 } }
< / e l - c h e c k b o x >
< / e l - o p t i o n >
< / e l - s e l e c t >
< / e l - f o r m - i t e m >
< / e l - c o l >
< 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 } }
< / e l - r a d i o >
< / e l - r a d i o - g r o u p >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 标签 -- >
< 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 } }
< / e l - c h e c k b o x >
< / e l - c h e c k b o x - g r o u p >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 办理方式 -- >
< 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 } }
< / e l - r a d i o >
< / e l - r a d i o - g r o u p >
< / e l - f o r m - i t e m >
< / e l - c o l >
< / e l - r o w >
<!-- 附件 -- >
< el -form -item label = "附件" prop = "thingFiles" >
< file -upload
v - model : files = "formData.thingFiles"
tips = "为便于「办理单位」更全面了解问题详情,请上传相关附件,如现场督察、数字督察等相关照片、视频及其他佐证材料。"
/ >
< / e l - f o r m - i t e m >
<!-- 办理单位 -- >
< h2 > 办理单位 < / h2 >
< div 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" / >
< / e l - s e l e c t >
< 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 >
< / e l - f o r m - i t e m >
< 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 >
< / e l - f o r m - i t e m >
< / div >
< h2 > 初核时限 < / h2 >
< p 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 > 办理时限 < / h2 >
< div 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" / >
< / e l - f o r m - i t e m >
< / div >
< h2 > 审批流程 < / h2 >
< div 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 >
< / e l - r a d i o - g r o u p >
< el -radio -group v -model = " formData.approvalFlow " v-else >
< el -radio value = "2" > 二级审批 ( 所队一 > 二级机构 ) < / e l - r a d i o >
< / e l - r a d i o - g r o u p >
< div class = "tips mt-10" >
< p v-if ="userStore.user.roleCodes.includes('admin_1')" > 三级审核 问题提交办结时 , 需经过 " 所队 — > 二级机构 — > 市局 " 三级审核 , 通过后方可办结 ; < / p >
< p > 二级审核 问题提交办结时 , 仅需经过 "所队—>二级机构" 两级审核 , 通过后即可办结 ; < / p >
< / div >
< / e l - f o r m - i t e m >
< / div >
< / div >
< / e l - f o r m >
< / e l - s c r o l l b a r >
<!-- 底部按钮 ( 根据步骤显示不同按钮 ) -- >
< template # footer >
< div class = "dialog-footer" >
< el -button @ click = "visibleProxy = false" size = "large" > 取消 < / e l - b u t t o n >
< el -button type = "primary" @click ="onSubmit" size = "large" : loading = "loading || submitLoading" >
{ { mode === 'add' ? '添加' : '修改' } }
< / e l - b u t t o n >
<!-- 修改模式 : 保持原有按钮 -- >
< template v-if ="mode === 'edit'" >
< el -button @ click = "visibleProxy = false" size = "large" > 取消 < / e l - b u t t o n >
< el -button type = "primary" @click ="onSubmit" size = "large" : loading = "loading || submitLoading" > 修改 < / e l - b u t t o n >
< / template >
<!-- 添加模式步骤1 -- >
< template v -else -if = " currentStep = = = 0 " >
< el -button @ click = "visibleProxy = false" size = "large" > 取消 < / e l - b u t t o n >
< el -button type = "primary" @click ="handleNextStep" size = "large" :loading ="duplicateLoading" >
下一步 查重
< / e l - b u t t o n >
< / template >
<!-- 添加模式步骤2 : 查重结果 -- >
< template v -else -if = " currentStep = = = 1 " >
< el -button @click ="handlePrevStep" size = "large" > 上一步 < / e l - b u t t o n >
< el -button type = "info" @click ="handleSkipMerge" size = "large" :loading ="submitLoading" >
不合并 , 继续添加
< / e l - b u t t o n >
< el -button
type = "primary"
@ click = "handleConfirmMerge"
size = "large"
: disabled = "!selectedCardId"
: loading = "mergeLoading"
>
确认合并到已选记录
< / e l - b u t t o n >
< / template >
<!-- 添加模式步骤3 : 完善信息 -- >
< template v -else -if = " currentStep = = = 2 " >
< el -button @click ="handlePrevStep" size = "large" > 上一步 < / e l - b u t t o n >
< el -button type = "primary" @click ="onSubmit" size = "large" :loading ="submitLoading" > 添加 < / e l - b u t t o n >
< / template >
< / div >
< / template >
< / e l - d i a l o g >
@ -366,7 +612,7 @@
< script setup >
import { computed , ref , watch } from "vue" ;
import { maileRepeatt , getComplaintCollectionDetail , updateComplaintCollection , addComplaintCollection } from "@/api/data/complaintCollection.ts" ;
import { maileRepeatt , getComplaintCollectionDetail , updateComplaintCollection , addComplaintCollection , mergeComplaintCollection } from "@/api/data/complaintCollection.ts" ;
import dayjs from "dayjs" ;
import feedback from "@/utils/feedback.ts" ;
import DuplicateDrawerWithDetail from "@/views/data/DuplicateDrawerWithDetail.vue" ;
@ -517,6 +763,129 @@ const formRef = ref();
const submitLoading = ref ( false ) ;
const timeLimitKey = ref ( 0 ) ;
/ / 步 骤 控 制
const currentStep = ref ( 0 )
const isMerging = ref ( false )
const selectedCardId = ref ( null )
const selectedCard = ref ( null )
const mergeLoading = ref ( false )
/ / 步 骤 切 换 方 法
const handleNextStep = async ( ) => {
try {
await formRef . value . validate ( )
} catch {
feedback . msgWarning ( "请完善必填信息" )
return
}
currentStep . value = 1
await fetchDuplicateList ( )
}
const handlePrevStep = ( ) => {
currentStep . value --
}
const handleSkipMerge = async ( ) => {
isMerging . value = false
formData . value . repeatt = '0' / / 默 认 设 置 为 " 否 "
currentStep . value = 2
}
const handleConfirmMerge = async ( ) => {
if ( ! selectedCardId . value ) {
feedback . msgWarning ( "请选择一个记录进行合并" )
return
}
mergeLoading . value = true
try {
await mergeComplaintCollection ( {
targetId : selectedCardId . value ,
sourceTable : formData . value . sourceTable ,
sourceTableSubOne : formData . value . sourceTableSubOne ,
originId : formData . value . originId ,
discoveryTime : formData . value . discoveryTime ,
businessTypeCode : formData . value . businessTypeCode ,
responderName : formData . value . responderName ,
responderIdCode : formData . value . responderIdCode ,
responderPhone : formData . value . responderPhone ,
secondDepartId : formData . value . secondDepartId ,
secondDepartName : formData . value . secondDepartName ,
thingDesc : formData . value . thingDesc ,
files : JSON . stringify ( formData . value . thingFiles || [ ] )
} )
feedback . msgSuccess ( "合并成功" )
visibleProxy . value = false
emit ( "updateSuccess" )
} catch ( e ) {
console . error ( "合并失败" , e )
feedback . notifyError ( "合并失败" )
} finally {
mergeLoading . value = false
}
}
/ / 获 取 查 重 列 表
const fetchDuplicateList = async ( ) => {
duplicateLoading . value = true
try {
const body = {
responderIdCode : formData . value . responderIdCode ,
responderName : formData . value . responderName ,
responderPhone : formData . value . responderPhone ,
}
const res = await maileRepeatt ( body )
duplicateList . value = res ? . complaintCollectionRepeatDTOS || [ ]
} catch ( e ) {
console . error ( "查重失败" , e )
} finally {
duplicateLoading . value = false
}
}
/ / 选 择 卡 片
const handleSelectCard = ( item ) => {
const id = item . complaintId || item . negativeId
if ( selectedCardId . value === id ) {
selectedCardId . value = null
selectedCard . value = null
} else {
selectedCardId . value = id
selectedCard . value = item
}
}
/ / 辅 助 函 数
const maskIdCode = ( idCode ) => {
if ( ! idCode ) return '-'
if ( idCode . length >= 10 ) {
return idCode . substring ( 0 , 6 ) + '****' + idCode . substring ( idCode . length - 4 )
}
return idCode
}
const maskPhone = ( phone ) => {
if ( ! phone ) return '-'
if ( phone . length >= 7 ) {
return phone . substring ( 0 , 3 ) + '****' + phone . substring ( phone . length - 4 )
}
return phone
}
const formatTime = ( time ) => {
if ( ! time ) return '-'
return dayjs ( time ) . format ( 'YYYY-MM-DD HH:mm' )
}
const getSourceTagType = ( source ) => {
if ( ! source ) return 'info'
if ( source . includes ( '局长信箱' ) ) return 'success'
if ( source . includes ( '12389' ) ) return 'warning'
return 'primary'
}
const visibleProxy = computed ( {
get : ( ) => props . modelValue ,
set : ( v ) => emit ( "update:modelValue" , v ) ,
@ -526,9 +895,15 @@ watch(
( ) => visibleProxy . value ,
async ( v ) => {
if ( v ) {
/ / 重 置 表 单
/ / 重 置 表 单 和 步 骤 状 态
timeLimitKey . value ++
formData . value = createEmptyForm ( ) ;
formData . value = createEmptyForm ( )
/ / 重 置 步 骤 状 态
currentStep . value = 0
isMerging . value = false
selectedCardId . value = null
selectedCard . value = null
duplicateDrawerVisible . value = false
duplicateLoading . value = false
@ -723,6 +1098,7 @@ async function onSubmit() {
const duplicateDrawerVisible = ref ( false )
const duplicateList = ref ( [ ] )
const duplicateLoading = ref ( false )
const onCheckDuplicate = async ( ) => {
duplicateDrawerVisible . value = true
}
@ -784,6 +1160,11 @@ const handleDuplicateRowClick = (row) => {
}
}
/ / 处 理 查 看 详 情
const handleViewDetail = ( item ) => {
handleDuplicateRowClick ( item )
}
< / script >
< style lang = "scss" scoped >
@ -883,4 +1264,155 @@ h2 {
font - size : 16 px ;
font - weight : 600 ;
}
/ / 步 骤 2 样 式
. mb - 20 {
margin - bottom : 20 px ;
}
. step2 - container {
min - height : 400 px ;
padding : 0 20 px ;
}
. current - info - bar {
margin - bottom : 20 px ;
padding : 0 20 px ;
. info - label {
font - weight : 600 ;
}
}
. duplicate - list {
min - height : 200 px ;
}
. card - grid {
display : grid ;
grid - template - columns : repeat ( 2 , 1 fr ) ;
gap : 16 px ;
padding : 0 20 px ;
}
. merge - card {
position : relative ;
border : 2 px solid # e8e8e8 ;
border - radius : 10 px ;
background : # fff ;
transition : all 0.25 s ease ;
overflow : hidden ;
cursor : pointer ;
& : hover {
border - color : # 409 eff ;
box - shadow : 0 4 px 12 px rgba ( 64 , 158 , 255 , 0.15 ) ;
}
& . is - selected {
border - color : # 67 c23a ;
border - width : 3 px ;
background : linear - gradient ( 135 deg , # f0f9eb 0 % , # ffffff 100 % ) ;
box - shadow : 0 6 px 20 px rgba ( 103 , 194 , 58 , 0.35 ) ;
transform : scale ( 1.02 ) ;
}
. card - header {
display : flex ;
align - items : center ;
gap : 8 px ;
padding : 12 px 14 px ;
border - bottom : 1 px solid # f0f0f0 ;
background : # fafafa ;
. origin - id {
font - weight : 600 ;
color : # 303133 ;
flex : 1 ;
}
. card - checkbox {
margin - left : auto ;
}
}
. card - info {
padding : 12 px 14 px ;
background : # f9f9f9 ;
. info - row {
display : flex ;
margin - bottom : 6 px ;
& : last - child {
margin - bottom : 0 ;
}
. label {
color : # 909399 ;
width : 70 px ;
flex - shrink : 0 ;
}
. value {
color : # 303133 ;
}
}
}
. card - content {
padding : 12 px 14 px ;
. content - label {
font - size : 12 px ;
color : # 909399 ;
margin - bottom : 4 px ;
}
. content - text {
color : # 606266 ;
font - size : 13 px ;
line - height : 1.5 ;
display : - webkit - box ;
- webkit - line - clamp : 2 ;
- webkit - box - orient : vertical ;
overflow : hidden ;
}
}
. card - footer {
display : flex ;
justify - content : space - between ;
align - items : center ;
padding : 10 px 14 px ;
border - top : 1 px solid # f0f0f0 ;
. time {
color : # 909399 ;
font - size : 12 px ;
}
}
. selected - badge {
position : absolute ;
top : 0 ;
right : 0 ;
background : linear - gradient ( 135 deg , # 67 c23a 0 % , # 5 daf34 100 % ) ;
color : # fff ;
font - size : 13 px ;
font - weight : 600 ;
padding : 6 px 14 px ;
border - radius : 0 8 px 0 8 px ;
display : flex ;
align - items : center ;
gap : 4 px ;
box - shadow : 0 2 px 8 px rgba ( 103 , 194 , 58 , 0.4 ) ;
letter - spacing : 1 px ;
text - transform : uppercase ;
. el - icon {
font - size : 14 px ;
}
}
}
< / style >