数字督察一体化平台-前端
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

<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>