You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
534 lines
14 KiB
534 lines
14 KiB
<template> |
|
<h5>信访办理</h5> |
|
<el-form ref="formRef" :model="form" :label-width="146"> |
|
<el-form-item |
|
label="办理环节" |
|
prop="processingStage" |
|
:rules="[{ required: true, message: '请选择办理环节', trigger: 'change' }]" |
|
> |
|
<el-radio-group v-model="form.processingStage"> |
|
<el-radio :value="STAGE_INITIAL">初核阶段</el-radio> |
|
<el-radio :value="STAGE_COMPLETION">办结阶段</el-radio> |
|
</el-radio-group> |
|
</el-form-item> |
|
|
|
<template v-if="isInitialStage"> |
|
<h5> |
|
初核办理 |
|
<span style="color: #777; font-size: 12px; margin-left: 10px" |
|
>4个工作日内办结无需上传初核情况</span |
|
> |
|
</h5> |
|
<el-form-item |
|
label="初核工作开展情况" |
|
prop="initWorkDes" |
|
:rules="[{ required: true, message: '请输入初核工作开展情况', trigger: 'blur' }]" |
|
> |
|
<el-input v-model="form.initWorkDes" type="textarea" :autosize="{ minRows: 4 }" /> |
|
</el-form-item> |
|
<el-form-item |
|
label="初核发现的问题及下步工作计划" |
|
prop="initProblemPlan" |
|
:rules="[ |
|
{ |
|
required: true, |
|
message: '请输入初核发现的问题及下步工作计划', |
|
trigger: 'blur', |
|
}, |
|
]" |
|
> |
|
<el-input |
|
v-model="form.initProblemPlan" |
|
type="textarea" |
|
:autosize="{ minRows: 4 }" |
|
/> |
|
</el-form-item> |
|
<el-form-item |
|
label="初核结论" |
|
prop="initVerdict" |
|
:rules="[{ required: true, message: '请选择初核结论', trigger: 'change' }]" |
|
> |
|
<el-select v-model="form.initVerdict" clearable style="width: 280px"> |
|
<el-option |
|
v-for="item in dict.checkStatus" |
|
:key="item.dictCode" |
|
:label="item.dictLabel" |
|
:value="item.dictValue" |
|
/> |
|
</el-select> |
|
</el-form-item> |
|
</template> |
|
|
|
<template v-else> |
|
<el-row> |
|
<el-col :span="12"> |
|
<el-form-item |
|
label="办结情况" |
|
prop="completionStatus" |
|
:rules="[{ required: true, message: '请选择办结情况', trigger: 'change' }]" |
|
><el-radio-group v-model="form.completionStatus" |
|
><el-radio value="1">程序办结</el-radio |
|
><el-radio value="2">已解决合理诉求</el-radio></el-radio-group |
|
></el-form-item |
|
></el-col |
|
> |
|
<el-col :span="12" |
|
><el-form-item |
|
label="群众认可" |
|
prop="publicRecognition" |
|
:rules="[{ required: true, message: '请选择群众认可', trigger: 'change' }]" |
|
><el-radio-group v-model="form.publicRecognition" |
|
><el-radio value="1">认可</el-radio |
|
><el-radio value="2">不认可</el-radio></el-radio-group |
|
></el-form-item |
|
></el-col |
|
> |
|
</el-row> |
|
|
|
<el-form-item |
|
v-if="showPetitionFields" |
|
prop="handlePolices" |
|
label="经办人" |
|
:rules="[{ required: true, validator: validateHandlePolices }]" |
|
> |
|
<div |
|
v-for="(item, index) in form.handlePolices" |
|
:key="index" |
|
class="mb-8 flex gap v-center" |
|
style="width: 100%" |
|
> |
|
<police-select |
|
:depart-id="negative?.handleSecondDepartId" |
|
v-model="item.empNo" |
|
@change=" |
|
(police) => { |
|
item.name = police.name; |
|
item.mobile = police.mobile; |
|
} |
|
" |
|
/> |
|
<el-input v-model="item.mobile" placeholder="联系方式" style="width: 240px" /> |
|
<el-button |
|
v-if="index === 0" |
|
plain |
|
type="primary" |
|
@click="form.handlePolices.push({ name: '', empNo: '', mobile: '' })" |
|
>新增经办人</el-button |
|
> |
|
<el-button |
|
v-else |
|
plain |
|
type="danger" |
|
@click="form.handlePolices.splice(index, 1)" |
|
>删除</el-button |
|
> |
|
</div> |
|
</el-form-item> |
|
<template |
|
v-if=" |
|
sourceNegative.problemSourcesCode === ProblemSources.GJXFPT || |
|
sourceNegative.problemSourcesCode === ProblemSources.GABXF |
|
" |
|
> |
|
<el-form-item |
|
label="化解情况" |
|
prop="resolveSituation" |
|
:rules="{ |
|
required: true, |
|
message: '请选择信访化解情况', |
|
trigger: ['blur'], |
|
}" |
|
> |
|
<el-select |
|
v-model="form.resolveSituation" |
|
clearable |
|
style="width: 240px" |
|
placeholder="请选择信访化解情况" |
|
> |
|
<el-option |
|
v-for="item in dict.resolveSituation" |
|
:key="item.id" |
|
:label="item.dictLabel" |
|
:value="item.dictValue" |
|
/> |
|
</el-select> |
|
</el-form-item> |
|
<el-form-item |
|
prop="resolveStatus" |
|
label="当前状态" |
|
:rules="{ |
|
required: true, |
|
message: '请选择信访当前状态', |
|
trigger: ['blur'], |
|
}" |
|
> |
|
<el-select |
|
v-model="form.resolveStatus" |
|
clearable |
|
style="width: 240px" |
|
placeholder="请选择信访化当前状态" |
|
> |
|
<el-option |
|
v-for="item in dict.resolveStatus" |
|
:key="item.id" |
|
:label="item.dictLabel" |
|
:value="item.dictValue" |
|
/> |
|
</el-select> |
|
</el-form-item> |
|
</template> |
|
<negative-verify ref="negativeVerifyRef" /> |
|
</template> |
|
</el-form> |
|
</template> |
|
|
|
<script lang="ts" setup> |
|
import { ProblemSources } from "@/enums/dictEnums"; |
|
import useCatchStore from "@/stores/modules/catch"; |
|
import NegativeVerify from "@/components/negative/verify.vue"; |
|
|
|
type HandlePolice = { |
|
name: string; |
|
empNo: string; |
|
mobile: string; |
|
}; |
|
|
|
const STAGE_INITIAL = "0"; |
|
const STAGE_COMPLETION = "1"; |
|
type ProcessingStage = typeof STAGE_INITIAL | typeof STAGE_COMPLETION; |
|
|
|
type VerifySfssForm = { |
|
complaintId?: string; |
|
processingStage: ProcessingStage; |
|
caseNumber: string; |
|
accountabilityTarget: string; |
|
checkStatus: string; |
|
checkStatusCode: string; |
|
checkStatusName: string; |
|
checkStatusDesc: string; |
|
involveDepartId: string; |
|
involveDepartName: string; |
|
initWorkDes: string; |
|
initProblemPlan: string; |
|
initVerdict: string; |
|
completionStatus: string; |
|
publicRecognition: string; |
|
handlePolices: HandlePolice[]; |
|
files: any[]; |
|
blames: any[]; |
|
blameLeaders: any[]; |
|
}; |
|
|
|
const props = defineProps<{ extraDict?: Record<string, any[]> }>(); |
|
const emit = defineEmits<{ |
|
(e: "stage-change", stage: ProcessingStage): void; |
|
}>(); |
|
const catchStore = useCatchStore(); |
|
const dict = reactive<Record<string, any[]>>({}); |
|
|
|
watchEffect(() => { |
|
Object.assign( |
|
dict, |
|
catchStore.getDicts([ |
|
"accountabilityTarget", |
|
"checkStatus", |
|
"businessType", |
|
"yesNo", |
|
"handleMethodType", |
|
]) || {}, |
|
props.extraDict || {} |
|
); |
|
}); |
|
|
|
const sourceNegative = inject<any>("negative"); |
|
const formRef = ref(); |
|
const negativeVerifyRef = ref<InstanceType<typeof NegativeVerify>>(); |
|
|
|
const createHandlePolice = (): HandlePolice => ({ |
|
name: "", |
|
empNo: "", |
|
mobile: "", |
|
}); |
|
|
|
const createForm = (): VerifySfssForm => ({ |
|
complaintId: "", |
|
processingStage: STAGE_INITIAL, |
|
caseNumber: "", |
|
accountabilityTarget: "", |
|
checkStatus: "", |
|
checkStatusCode: "", |
|
checkStatusName: "", |
|
checkStatusDesc: "", |
|
involveDepartId: "", |
|
involveDepartName: "", |
|
initWorkDes: "", |
|
initProblemPlan: "", |
|
initVerdict: "", |
|
completionStatus: "", |
|
publicRecognition: "", |
|
handlePolices: [createHandlePolice()], |
|
files: [], |
|
blames: [], |
|
blameLeaders: [], |
|
}); |
|
|
|
const form = ref<VerifySfssForm>(createForm()); |
|
const currentRow = computed(() => sourceNegative?.value?.currentRow || {}); |
|
const isInitialStage = computed(() => form.value.processingStage === STAGE_INITIAL); |
|
const showPetitionFields = computed(() => |
|
[ |
|
ProblemSources.GJXFPT, |
|
ProblemSources.GABXF, |
|
ProblemSources.JZXX, |
|
ProblemSources.XF12337, |
|
].includes(sourceNegative?.value?.problemSourcesCode) |
|
); |
|
|
|
debugger |
|
const negative = computed(() => ({ |
|
...(sourceNegative?.value || {}), |
|
...clone(form.value), |
|
currentRow: currentRow.value, |
|
})); |
|
|
|
provide("negative", negative); |
|
|
|
watch( |
|
() => [sourceNegative?.value?.id, currentRow.value?.id], |
|
([negativeId, complaintId]) => { |
|
if (negativeId || complaintId) { |
|
syncFormData(); |
|
} |
|
}, |
|
{ immediate: true } |
|
); |
|
|
|
watch( |
|
() => form.value.processingStage, |
|
(stage) => { |
|
emit("stage-change", stage); |
|
}, |
|
{ immediate: true } |
|
); |
|
|
|
function clone<T>(value: T): T { |
|
return JSON.parse(JSON.stringify(value)); |
|
} |
|
|
|
function getStageBySource(row: Record<string, any>) { |
|
const hasInitialReviewData = |
|
Boolean(row?.gwf2) || |
|
Boolean(row?.initWorkDes) || |
|
Boolean(row?.initProblemPlan) || |
|
Boolean(row?.initVerdict); |
|
|
|
return sourceNegative?.value?.checkStatusCode || |
|
sourceNegative?.value?.completionStatus || |
|
row?.completionStatus || |
|
sourceNegative?.value?.publicRecognition || |
|
row?.publicRecognition || |
|
hasInitialReviewData |
|
? STAGE_COMPLETION |
|
: STAGE_INITIAL; |
|
} |
|
|
|
function getHandlePolices() { |
|
const handlePolices = clone(sourceNegative?.value?.handlePolices || []); |
|
return handlePolices.length ? handlePolices : [createHandlePolice()]; |
|
} |
|
|
|
function syncFormData() { |
|
const row = currentRow.value || {}; |
|
const fallbackInvolveDepartId = |
|
sourceNegative?.value?.involveDepartId || |
|
row?.involveDepartId || |
|
row?.thirdDepartId || |
|
row?.secondDepartId || |
|
""; |
|
const fallbackInvolveDepartName = |
|
sourceNegative?.value?.involveDepartName || |
|
row?.involveDepartName || |
|
row?.thirdDepartName || |
|
row?.secondDepartName || |
|
""; |
|
|
|
form.value = { |
|
...createForm(), |
|
...row, |
|
complaintId: row?.id || sourceNegative?.value?.complaintId || "", |
|
processingStage: getStageBySource(row), |
|
caseNumber: sourceNegative?.value?.caseNumber || row?.caseNumber || "", |
|
accountabilityTarget: |
|
sourceNegative?.value?.accountabilityTarget || row?.accountabilityTarget || "", |
|
checkStatus: sourceNegative?.value?.checkStatus || row?.checkStatus || "", |
|
checkStatusCode: sourceNegative?.value?.checkStatusCode || row?.checkStatusCode || "", |
|
checkStatusName: sourceNegative?.value?.checkStatusName || row?.checkStatusName || "", |
|
checkStatusDesc: sourceNegative?.value?.checkStatusDesc || row?.checkStatusDesc || "", |
|
involveDepartId: fallbackInvolveDepartId, |
|
involveDepartName: fallbackInvolveDepartName, |
|
initWorkDes: row?.initWorkDes || "", |
|
initProblemPlan: row?.initProblemPlan || "", |
|
initVerdict: row?.initVerdict || "", |
|
completionStatus: String( |
|
sourceNegative?.value?.completionStatus ?? row?.completionStatus ?? "" |
|
), |
|
publicRecognition: String( |
|
sourceNegative?.value?.publicRecognition ?? row?.publicRecognition ?? "" |
|
), |
|
handlePolices: getHandlePolices(), |
|
files: clone(sourceNegative?.value?.files || []), |
|
blames: clone(sourceNegative?.value?.blames || []), |
|
blameLeaders: clone(sourceNegative?.value?.blameLeaders || []), |
|
}; |
|
} |
|
|
|
function mergeVerifyForm(verifyForm: Record<string, any> = {}) { |
|
const baseForm = clone(form.value); |
|
const complaintId = |
|
verifyForm?.complaintId || |
|
baseForm?.complaintId || |
|
currentRow.value?.id || |
|
sourceNegative?.value?.complaintId || |
|
""; |
|
const involveDepartId = |
|
verifyForm?.involveDepartId || |
|
baseForm?.involveDepartId || |
|
sourceNegative?.value?.involveDepartId || |
|
currentRow.value?.involveDepartId || |
|
currentRow.value?.thirdDepartId || |
|
currentRow.value?.secondDepartId || |
|
""; |
|
const involveDepartName = |
|
verifyForm?.involveDepartName || |
|
baseForm?.involveDepartName || |
|
sourceNegative?.value?.involveDepartName || |
|
currentRow.value?.involveDepartName || |
|
currentRow.value?.thirdDepartName || |
|
currentRow.value?.secondDepartName || |
|
""; |
|
|
|
return { |
|
...verifyForm, |
|
...baseForm, |
|
complaintId, |
|
involveDepartId, |
|
involveDepartName, |
|
handlePolices: clone(baseForm.handlePolices), |
|
files: clone(verifyForm.files || baseForm.files || []), |
|
blames: clone(verifyForm.blames || baseForm.blames || []), |
|
blameLeaders: clone(verifyForm.blameLeaders || baseForm.blameLeaders || []), |
|
}; |
|
} |
|
|
|
function validateHandlePolices( |
|
_: unknown, |
|
value: HandlePolice[], |
|
callback: (error?: Error) => void |
|
) { |
|
if (!value?.length || !value[0]?.name) { |
|
callback(new Error("请选择经办人")); |
|
return; |
|
} |
|
if (!value[0]?.mobile) { |
|
callback(new Error("请输入经办人联系方式")); |
|
return; |
|
} |
|
callback(); |
|
} |
|
|
|
async function validate() { |
|
await formRef.value?.validate(); |
|
const verifyData = await validateNegativeVerify(); |
|
return mergeVerifyForm(verifyData); |
|
} |
|
|
|
function getData() { |
|
const verifyData = getNegativeVerifyData(); |
|
return mergeVerifyForm(verifyData); |
|
} |
|
|
|
function getStage() { |
|
return form.value.processingStage; |
|
} |
|
|
|
function setStage(stage: ProcessingStage) { |
|
form.value.processingStage = stage; |
|
} |
|
|
|
async function validateNegativeVerify() { |
|
if (isInitialStage.value || !negativeVerifyRef.value) { |
|
return {}; |
|
} |
|
|
|
return await negativeVerifyRef.value.validate(); |
|
} |
|
|
|
function getNegativeVerifyData() { |
|
if (isInitialStage.value || !negativeVerifyRef.value) { |
|
return {}; |
|
} |
|
|
|
return negativeVerifyRef.value.getData(); |
|
} |
|
|
|
defineExpose({ validate, getData, getStage, setStage }); |
|
</script> |
|
|
|
<style lang="scss" scoped> |
|
.info-container, |
|
.summary-box { |
|
border: 1px solid #eee; |
|
background: #fafcff; |
|
padding: 12px 16px; |
|
border-radius: 6px; |
|
margin-bottom: 12px; |
|
} |
|
|
|
.summary-title { |
|
color: var(--el-color-primary); |
|
font-weight: 600; |
|
margin-bottom: 10px; |
|
} |
|
|
|
.row { |
|
display: flex; |
|
flex-wrap: wrap; |
|
gap: 10px 0; |
|
} |
|
|
|
.col { |
|
display: flex; |
|
gap: 8px; |
|
line-height: 22px; |
|
} |
|
|
|
.col-12 { |
|
width: 50%; |
|
} |
|
|
|
.col-24 { |
|
width: 100%; |
|
} |
|
|
|
label { |
|
width: 140px; |
|
color: #666; |
|
flex: 0 0 auto; |
|
} |
|
|
|
span { |
|
color: #222; |
|
flex: 1 1 auto; |
|
word-break: break-word; |
|
} |
|
|
|
.inline-actions { |
|
display: inline-flex; |
|
align-items: center; |
|
gap: 8px; |
|
} |
|
|
|
.repeat-btn { |
|
padding: 0; |
|
} |
|
</style>
|
|
|