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.
751 lines
27 KiB
751 lines
27 KiB
<template> |
|
<el-dialog |
|
:show-close="false" |
|
width="84vw" |
|
top="2vh" |
|
class="dialog-header-nopadding" |
|
style="--el-dialog-padding-primary: 10px; margin-bottom: 2vh" |
|
:lock-scroll="false" |
|
ref="dialogRef" |
|
> |
|
<template #header="{ close }"> |
|
<header class="flex between v-center dialog-header"> |
|
<div class="ml-16"> |
|
<span class="mr-8 second">问题编号</span> |
|
<span>{{ id }}</span> |
|
</div> |
|
<div class="flex step-box"> |
|
<div |
|
class="step flex center v-center" |
|
v-for="(item, index) in dict.processingStatus" |
|
:key="index" |
|
:active="negative.processingStatus === item.dictValue" |
|
:completed=" |
|
index < |
|
dict.processingStatus.indexOf( |
|
negative.processingStatus |
|
) |
|
" |
|
> |
|
<span class="bloder">{{ index + 1 }}</span> |
|
<span>{{ item.remark }}</span> |
|
</div> |
|
</div> |
|
<div class="flex"> |
|
<el-button |
|
type="primary" |
|
size="large" |
|
:class="isFav ? 'fav-btn active' : 'fav-btn'" |
|
@click="handleFav" |
|
>{{ isFav ? "已收藏" : "收藏" }} |
|
<template #icon> |
|
<icon |
|
:name=" |
|
isFav |
|
? 'el-icon-StarFilled' |
|
: 'el-icon-star' |
|
" |
|
:size="22" |
|
/> |
|
</template> |
|
</el-button> |
|
<el-button |
|
link |
|
circle |
|
size="large" |
|
@click="close" |
|
class="close-btn" |
|
> |
|
<template #icon> |
|
<icon |
|
name="el-icon-close" |
|
:size="26" |
|
:color="'#fff'" |
|
/> |
|
</template> |
|
</el-button> |
|
</div> |
|
</header> |
|
</template> |
|
<main v-loading="loading"> |
|
<el-row style="height: 100%"> |
|
<el-col :span="5" style="height: 100%"> |
|
<div ref="leftContainerRef" class="left-container h100"> |
|
<div |
|
ref="countdownContainerRef" |
|
v-if=" |
|
negative.flowKey !== |
|
FlowNodeEnum.FIRST_DISTRIBUTE && |
|
negative.processingStatus !== |
|
ProcessingStatus.COMPLETED |
|
" |
|
> |
|
<negative-countdown |
|
v-model:time="remainingDuration" |
|
:max-time="maxDuration" |
|
:extensionDays="negative.extensionDays" |
|
/> |
|
</div> |
|
<div class="row" ref="leftRowRef"> |
|
<div |
|
class="col col-24" |
|
style="--label-width: 60px" |
|
v-if="negative.timeLimit" |
|
> |
|
<label>办理时限</label> |
|
<span>{{ |
|
getDictLable( |
|
dict.timeLimit, |
|
negative.timeLimit |
|
) |
|
}} |
|
<span v-if="negative.timeLimit === 'other'">({{negative.maxSignDuration}}个工作日签收;{{negative.maxHandleDuration}}个工作日办理;延期不超过{{negative.maxExtensionDuration}}天)</span> |
|
</span> |
|
</div> |
|
<div |
|
class="col col-24" |
|
style="--label-width: 60px" |
|
v-if="negative.hostLevel" |
|
> |
|
<label>主办层级</label> |
|
<span>{{ |
|
getDictLable( |
|
dict.hostLevel, |
|
negative.hostLevel |
|
) |
|
}}</span> |
|
</div> |
|
<div |
|
class="col col-24" |
|
style="--label-width: 60px" |
|
v-if="negative.approvalFlow" |
|
> |
|
<label>审批流程</label> |
|
<span>{{ |
|
getDictLable( |
|
dict.approvalFlow, |
|
negative.approvalFlow |
|
) |
|
}}</span> |
|
</div> |
|
</div> |
|
<div ref="actionHistoryRef"> |
|
<negative-action-history /> |
|
</div> |
|
</div> |
|
</el-col> |
|
<el-col :span="19" style="height: 100%"> |
|
<el-scrollbar max-height="100%" class="main-container"> |
|
<!--提回--> |
|
<negative-sign-return-description /> |
|
<!-- 延期--> |
|
<negative-apply-extension-description /> |
|
<!-- 问题信息--> |
|
<negative-description /> |
|
<div |
|
class="row mt-10" |
|
v-if=" |
|
negative.firstDistributeComments && |
|
negative.processingStatus === 'signing' |
|
" |
|
> |
|
<div class="col col-24"> |
|
<label>市局下发意见</label> |
|
<span class="text-wrap">{{ |
|
negative.firstDistributeComments |
|
}}</span> |
|
</div> |
|
</div> |
|
|
|
<template |
|
v-if=" |
|
(components.indexOf('negative-verify') > -1 && |
|
!disabled) || |
|
verifyEditFlag |
|
" |
|
> |
|
<!-- 核查办理--> |
|
<negative-verify |
|
ref="componentRef" |
|
@submit="handleSubmitExecute" |
|
/> |
|
</template> |
|
|
|
<template |
|
v-if=" |
|
components.indexOf( |
|
'negative-verify-description' |
|
) > -1 && !verifyEditFlag |
|
" |
|
> |
|
<!-- 核查办理(查看)--> |
|
<negative-verify-description :ConfinementData="ConfinementDataList" /> |
|
</template> |
|
<template v-if="approves.length"> |
|
<!-- 审批意见--> |
|
<negative-approve-description /> |
|
</template> |
|
<div |
|
class="mb-4 mt-8 flex end" |
|
v-if="spotCheckEditFlag" |
|
> |
|
<el-button |
|
size="small" |
|
v-if="verifyEditFlag" |
|
@click="verifyEditFlag = false" |
|
>取消</el-button |
|
> |
|
<el-button |
|
type="primary" |
|
plain |
|
size="small" |
|
@click="handleUpdateVerify" |
|
>{{ |
|
verifyEditFlag |
|
? "保存核查情况" |
|
: "修改核查情况" |
|
}}</el-button |
|
> |
|
</div> |
|
<template v-if="!disabled"> |
|
<template |
|
v-if=" |
|
components.indexOf('negative-distribute') > |
|
-1 |
|
" |
|
> |
|
<!-- 办理单位--> |
|
<negative-distribute ref="componentRef" /> |
|
</template> |
|
</template> |
|
<!-- 会签--> |
|
<negative-countersign-description /> |
|
<template |
|
v-if=" |
|
components.indexOf('negative-countersign') > -1 |
|
" |
|
> |
|
<!-- 会签意见--> |
|
<negative-countersign |
|
ref="componentRef" |
|
@submit="handleSubmitExecute" |
|
/> |
|
</template> |
|
<div |
|
v-if=" |
|
negative.processingStatus === |
|
ProcessingStatus.COMPLETED |
|
" |
|
> |
|
<h4 class="text-primary">认定办结</h4> |
|
<div class="row"> |
|
<div class="col col-6"> |
|
<label>核查办理情况</label> |
|
<span>{{ |
|
getDictLable( |
|
dict.verifySituation, |
|
negative.verifySituation |
|
) || "/" |
|
}}</span> |
|
</div> |
|
<div class="col col-6"> |
|
<label>佐证材料情况</label> |
|
<span>{{ |
|
getDictLable( |
|
dict.verifyFileSituation, |
|
negative.verifyFileSituation |
|
) || "/" |
|
}}</span> |
|
</div> |
|
</div> |
|
</div> |
|
<!-- 抽检--> |
|
<el-form |
|
class="mt-20" |
|
:model="formData" |
|
ref="formRef" |
|
v-if="spotCheckEditFlag" |
|
> |
|
<el-form-item |
|
label="抽检结果" |
|
prop="spotCheckResult" |
|
:rules="{ |
|
required: true, |
|
message: '请选择抽检结果', |
|
trigger: ['blur'], |
|
}" |
|
> |
|
<el-radio-group |
|
v-model="formData.spotCheckResult" |
|
> |
|
<el-radio value="1" size="large" border |
|
>合格</el-radio |
|
> |
|
<el-radio value="0" size="large" border |
|
>不合格</el-radio |
|
> |
|
</el-radio-group> |
|
</el-form-item> |
|
<el-form-item |
|
label="抽检情况" |
|
prop="spotCheckDesc" |
|
:rules="{ |
|
required: true, |
|
message: '请选择抽检情况', |
|
trigger: ['blur'], |
|
}" |
|
> |
|
<el-input |
|
type="textarea" |
|
:autosize="{ minRows: 5 }" |
|
placeholder="请输入" |
|
v-model="formData.spotCheckDesc" |
|
/> |
|
</el-form-item> |
|
</el-form> |
|
</el-scrollbar> |
|
</el-col> |
|
</el-row> |
|
</main> |
|
<footer class="flex between v-center"> |
|
<div style="min-height: 40px"> |
|
<!-- <el-button type="primary" plain size="large">打印</el-button> --> |
|
</div> |
|
<el-button |
|
type="primary" |
|
size="large" |
|
@click="handleSubmitSpotCheck" |
|
v-if="spotCheckEditFlag" |
|
>保存抽检结果</el-button |
|
> |
|
<div v-if="!disabled"> |
|
<template v-for="item in flowActions" :key="item.actionKey"> |
|
<template |
|
v-if=" |
|
!negative.extensionApplyFlag && |
|
(item.actionKey === |
|
FlowActionEnum.APPLY_COMPLETION || |
|
item.actionKey === |
|
FlowActionEnum.APPLY_EXTENSION || |
|
item.actionKey === |
|
FlowActionEnum.THREE_SIGN_RETURN) |
|
" |
|
> |
|
<el-tooltip |
|
effect="dark" |
|
:content="`${negative.currentProcessingObject}正在审理您提交的延期审批,请耐心等待审批通过后再操作!`" |
|
raw-content |
|
placement="top" |
|
> |
|
<span class="ml-10"> |
|
<el-button |
|
size="large" |
|
:type="item.buttonType" |
|
:plain="item.plain" |
|
:disabled="true" |
|
>{{ item.buttonLabel }}</el-button |
|
> |
|
</span> |
|
</el-tooltip> |
|
</template> |
|
<el-button |
|
v-else |
|
size="large" |
|
:type="item.buttonType" |
|
:plain="item.plain" |
|
@click="handleExecute(item)" |
|
:disabled="loading" |
|
>{{ |
|
item.actionKey === "update_verify" && verifyEditFlag |
|
? "保存核查内容" |
|
: item.buttonLabel |
|
}}</el-button |
|
> |
|
</template> |
|
</div> |
|
</footer> |
|
<template v-for="item in flowActions" :key="item.actionKey"> |
|
<template v-if="item.actionKey.includes('apply_completion')"> |
|
<negative-apply-completion |
|
:ref="(el) => setActionItemRef(item.actionKey, el)" |
|
@submit="handleSubmitExecute" |
|
/> |
|
</template> |
|
<template v-if="item.actionKey.includes('apply_extension')"> |
|
<!-- 申请延期--> |
|
<negative-apply-extension |
|
:ref="(el) => setActionItemRef(item.actionKey, el)" |
|
@submit="handleSubmitExecute" |
|
/> |
|
</template> |
|
<template v-if="item.actionKey.includes('_approve')"> |
|
<negative-approve |
|
:ref="(el) => setActionItemRef(item.actionKey, el)" |
|
@submit="handleSubmitExecute" |
|
/> |
|
</template> |
|
<template v-if="item.actionKey.includes('_return')"> |
|
<negative-return |
|
:ref="(el) => setActionItemRef(item.actionKey, el)" |
|
@submit="handleSubmitExecute" |
|
/> |
|
</template> |
|
<template v-if="item.actionKey.includes('apply_countersign')"> |
|
<negative-apply-countersign |
|
:ref="(el) => setActionItemRef(item.actionKey, el)" |
|
@submit="handleSubmitExecute" |
|
/> |
|
</template> |
|
</template> |
|
<template v-if="confirmationCompletionFlag && flowActions.length"> |
|
<negative-confirmation-completion |
|
@submit="handleSubmitExecute" |
|
ref="confirmationCompletionRef" |
|
/> |
|
</template> |
|
</el-dialog> |
|
</template> |
|
<script lang="ts" setup> |
|
import { ApprovalFlow } from "@/enums/dictEnums"; |
|
import { |
|
FlowActionEnum, |
|
FlowNodeEnum, |
|
ProcessingStatus, |
|
} from "@/enums/flowEnums"; |
|
import { |
|
getNegativeDetails, |
|
negativeExecute, |
|
spotCheckNegative, |
|
} from "@/api/work/negative"; |
|
import { addFav, delFav } from "@/api/work/fav"; |
|
import feedback from "@/utils/feedback"; |
|
import { getComponents } from "@/utils/flow"; |
|
import { getDictLable } from "@/utils/util"; |
|
|
|
import useCatchStore from "@/stores/modules/catch"; |
|
import { nextTick, onMounted } from "vue"; |
|
import {getConfinementListAll} from "@/api/work/confinement"; |
|
|
|
const dict = useCatchStore().getDicts([ |
|
"processingStatus", |
|
"timeLimit", |
|
"approvalFlow", |
|
"hostLevel", |
|
]); |
|
|
|
const props = defineProps({ |
|
id: { |
|
type: String, |
|
required: true, |
|
}, |
|
disabled: { |
|
type: Boolean, |
|
default: true, |
|
}, |
|
}); |
|
|
|
const emit = defineEmits(["close", "change"]); |
|
|
|
const work = inject("work", null); |
|
|
|
const loading = ref(false); |
|
|
|
const negative = ref({}); |
|
const actionHistory = ref([]); |
|
const signReturns = ref([]); |
|
const approves = ref([]); |
|
const extensionApply = ref({}); |
|
const countersignApplys = ref([]); |
|
const ConfinementDataList =ref([]) |
|
provide("negative", negative); |
|
provide("actionHistory", actionHistory); |
|
provide("signReturns", signReturns); |
|
provide("approves", approves); |
|
provide("extensionApply", extensionApply); |
|
provide("countersignApplys", countersignApplys); |
|
|
|
const isFav = ref(false); |
|
const remainingDuration = ref(0); |
|
const maxDuration = ref(0); |
|
const flowActions = ref([]); |
|
const components = ref([]); |
|
watch( |
|
() => props.id, |
|
() => { |
|
getDetails(); |
|
getConfinementData() |
|
verifyEditFlag.value = false; |
|
formData.value = {}; |
|
} |
|
); |
|
|
|
const confirmationCompletionFlag = ref(false); |
|
function getDetails() { |
|
loading.value = true; |
|
getNegativeDetails(props.id, work?.value.workId).then((data) => { |
|
negative.value = data.negative; |
|
flowActions.value = data.flowActions; |
|
actionHistory.value = data.actionHistory; |
|
signReturns.value = data.signReturns; |
|
approves.value = data.approves; |
|
extensionApply.value = data.extensionApply || {}; |
|
countersignApplys.value = data.countersignApplys; |
|
isFav.value = data.isFav; |
|
remainingDuration.value = data.remainingDuration; |
|
maxDuration.value = data.maxDuration; |
|
components.value = getComponents(data.flowNode?.flowKey); |
|
// 是否认定办结 |
|
confirmationCompletionFlag.value = data.confirmationCompletionFlag; |
|
loading.value = false; |
|
}); |
|
} |
|
|
|
const componentRef = ref([]); |
|
const actionItemRefs = ref({}); |
|
const setActionItemRef = (actionKey, el) => { |
|
if (el) { |
|
actionItemRefs.value[actionKey] = el; |
|
} |
|
}; |
|
|
|
const confirmationCompletionRef = ref(null); |
|
|
|
const activeAction = ref({}); |
|
const verifyEditFlag = ref(false); |
|
async function handleExecute(action, data) { |
|
if (action.actionKey === "update_verify" && !verifyEditFlag.value) { |
|
verifyEditFlag.value = true; |
|
return; |
|
} |
|
if (action.actionKey !== "update_verify" && verifyEditFlag.value) { |
|
feedback.confirm("请先“保存核查内容”再操作"); |
|
return; |
|
} |
|
if (action.validateForm) { |
|
if (action.actionKey !== FlowActionEnum.SAVE) { |
|
try { |
|
data = await componentRef.value.validate(); |
|
} catch (e) { |
|
feedback.msgWarning(e.message || "请检查输入项"); |
|
throw e; |
|
} |
|
} else { |
|
data = componentRef.value.getData(); |
|
} |
|
} |
|
if (action.openDialog) { |
|
if ( |
|
confirmationCompletionFlag.value && |
|
!action.actionKey.includes("_return") && |
|
action.actionKey !== "apply_countersign" |
|
) { |
|
confirmationCompletionRef.value.open(); |
|
activeAction.value = { |
|
actionName: "认定办结", |
|
actionKey: "confirmationCompletion", |
|
doClose: true, |
|
}; |
|
return; |
|
} |
|
actionItemRefs.value[action.actionKey].open(); |
|
activeAction.value = action; |
|
return; |
|
} |
|
loading.value = true; |
|
if (action.actionKey === "update_verify") { |
|
verifyEditFlag.value = false; |
|
} |
|
await negativeExecute(props.id, { |
|
workId: work?.value.workId, |
|
actionKey: action.actionKey, |
|
nextFlowKey: action.nextFlowKey, |
|
actionName: action.actionName, |
|
data, |
|
}); |
|
feedback.msgSuccess("操作成功"); |
|
if (action.doClose) { |
|
emit("change"); |
|
emit("close"); |
|
return; |
|
} |
|
getConfinementData(); |
|
getDetails(); |
|
} |
|
|
|
async function handleSubmitExecute(data) { |
|
activeAction.value.openDialog = false; |
|
handleExecute(activeAction.value, data); |
|
} |
|
|
|
function handleFav() { |
|
if (isFav.value) { |
|
delFav(props.id); |
|
} else { |
|
addFav(props.id); |
|
} |
|
isFav.value = !isFav.value; |
|
} |
|
|
|
const spotCheckEditFlag = ref(false); |
|
let confinementQuery = ref({ |
|
current: 1, |
|
size: 10000, |
|
departBranch: false |
|
}) |
|
|
|
|
|
|
|
/** |
|
* 获取禁闭信息 |
|
* */ |
|
async function getConfinementData(){ |
|
const res = await getConfinementListAll(confinementQuery.value); |
|
ConfinementDataList.value= res.records; |
|
|
|
} |
|
function spotCheck() { |
|
spotCheckEditFlag.value = true; |
|
} |
|
|
|
const dialogRef = ref(); |
|
|
|
const formData = ref({}); |
|
const formRef = ref(); |
|
async function handleSubmitSpotCheck() { |
|
try { |
|
await formRef.value.validate(); |
|
} catch (e) { |
|
feedback.msgWarning(e.message || "请检查输入项"); |
|
throw e; |
|
} |
|
await spotCheckNegative(props.id, formData.value); |
|
feedback.msgSuccess("抽查成功!"); |
|
emit("change"); |
|
emit("close"); |
|
formData.value = {}; |
|
} |
|
|
|
async function handleUpdateVerify() { |
|
if (verifyEditFlag.value) { |
|
try { |
|
const data = await componentRef.value.validate(); |
|
formData.value.verifyData = data; |
|
} catch (e) { |
|
feedback.msgWarning(e.message || "请检查输入项"); |
|
throw e; |
|
} |
|
} |
|
verifyEditFlag.value = !verifyEditFlag.value; |
|
} |
|
|
|
defineExpose({ |
|
spotCheck, |
|
}); |
|
|
|
// 样式 |
|
const leftContainerRef = ref(); |
|
const countdownContainerRef = ref(); |
|
const leftRowRef = ref(); |
|
const actionHistoryRef = ref(); |
|
watch( |
|
() => dialogRef.value?.visible, |
|
(val) => { |
|
if (!val) { |
|
spotCheckEditFlag.value = false; |
|
} |
|
} |
|
); |
|
|
|
watch(loading, (val) => { |
|
if (!val) { |
|
nextTick(() => { |
|
console.log("nextTick", [leftContainerRef.value.offsetHeight]); |
|
actionHistoryRef.value.style.height = `${ |
|
leftContainerRef.value.offsetHeight - |
|
(countdownContainerRef.value?.offsetHeight || 0) - |
|
leftRowRef.value.offsetHeight |
|
}px`; |
|
console.log( |
|
`${ |
|
leftContainerRef.value.offsetHeight - |
|
(countdownContainerRef.value?.offsetHeight || 0) - |
|
leftRowRef.value.offsetHeight |
|
}px` |
|
); |
|
}); |
|
} |
|
}); |
|
</script> |
|
<style lang="scss" scoped> |
|
.dialog-header { |
|
--dialog-header-font-color: #acb7ff; |
|
--dialog-header-font-size: 16px; |
|
background-color: var(--primary-color); |
|
color: #fff; |
|
padding: 1em; |
|
font-size: var(--dialog-header-font-size); |
|
.second { |
|
color: var(--dialog-header-font-color); |
|
} |
|
.step-box { |
|
.step { |
|
--setp-background-color: #3a4dc1; |
|
--setp-border-color: #4b60e4; |
|
--setp-font-color: var(--dialog-header-font-color); |
|
--setp-font-size: var(--dialog-header-font-size); |
|
padding-left: 30px; |
|
padding-right: 16px; |
|
&::after { |
|
display: none; |
|
} |
|
&:first-child { |
|
padding-left: 16px; |
|
} |
|
&[active="true"] { |
|
--setp-background-color: #ff4242; |
|
--setp-border-color: #ff7474; |
|
--setp-font-color: #fff; |
|
} |
|
.bloder { |
|
font-size: 24px; |
|
font-weight: 700; |
|
margin-right: 8px; |
|
} |
|
span { |
|
z-index: 2; |
|
} |
|
} |
|
} |
|
.fav-btn { |
|
--el-font-size-base: 18px; |
|
--el-button-bg-color: #283aac; |
|
--el-button-hover-bg-color: #c20921; |
|
--el-button-hover-border-color: #fa8695; |
|
&.active { |
|
--el-button-bg-color: #c20921; |
|
} |
|
&:focus { |
|
background-color: var(--el-button-bg-color); |
|
} |
|
} |
|
.close-btn:hover { |
|
:deep() { |
|
.el-icon { |
|
color: #c20921; |
|
} |
|
} |
|
} |
|
} |
|
main { |
|
height: calc(96vh - 180px); |
|
} |
|
.left-container { |
|
padding: 0 20px 0 40px; |
|
} |
|
.main-container { |
|
padding: 0 20px; |
|
} |
|
footer { |
|
padding: 10px 20px 0; |
|
} |
|
</style>
|
|
|