Files
geg-gas-web/src/components/SecondDev/OpinionDialog.vue
‘huanghaiixia’ 9ded452de5 国际采购
2026-02-04 17:59:39 +08:00

331 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-modal :mask-closable="false" :title="dialogTitle" :visible="isOpen" :width="500" centered class="geg" @cancel="onClickCancel">
<template #footer>
<a-button :disabled="loading" @click="onClickCancel">取消</a-button>
<a-button :loading="loading" type="primary" @click="onClickOK">确定</a-button>
</template>
<div class="dialog-wrap">
<a-form :label-col="{ span: 6 }" :model="formState" autocomplete="off">
<a-form-item v-if="_action === 'agree'" label="下一节点" name="nextNodeName">
<span>{{ getNextNodesName() }}</span>
</a-form-item>
<template v-for="node in flowNextNodes" :key="node.activityId">
<div v-if="flowNextNodes.length > 1" class="node-info">
<span class="node-label">{{ node.nodeTypeLabel }}</span>
<span class="node-name">{{ node.activityName }}</span>
<a-switch :checked="node.chooseNode" v-if="!node.hiddenNode" style="margin-left: 10px" @change="agreeNodeChange(node)"></a-switch>
</div>
<a-form-item :required="flowNextNodes.length === 1 || node.chooseNode" v-if="(_action === 'agree' || _action == 'disagree') && !isEnd" :label="'审批人'">
<a-select
v-show="node.chooseAssign"
v-model:value="node.assignees"
:options="node.nextAssignees"
:disabled="loading"
:placeholder="'审批人'"
max-tag-count="responsive"
:mode="node.isChooseMulti ? 'multiple' : ''"
:filterOption="search"
></a-select>
<span v-show="!node.chooseAssign">{{ getAssigneeText(node) }}</span>
</a-form-item>
</template>
<!-- <a-form-item v-if="_action === 'reject'" label="退回至" name="rejectNode">
<a-select v-model:value="rejectNodeId" :disabled="loading">
<a-select-option v-for="(item, index) in rejectNodeList" :key="index" :value="item.activityId">{{ item.activityName }}</a-select-option>
</a-select>
</a-form-item> -->
<template v-for="node in rejectNodeList" :key="node.activityId">
<a-form-item required v-if="_action === 'reject' && rejectNodeId === node.activityId" label="审批人">
<a-select
v-show="node.chooseAssign"
v-model:value="node.assignees"
:options="node.nextAssignees"
:placeholder="'请选择' + node.activityName + '的审批人'"
max-tag-count="responsive"
:disabled="loading"
:mode="node.rejectIsChooseMulti ? 'multiple' : ''"
:filterOption="search"
></a-select>
<span v-show="!node.chooseAssign">{{ getAssigneeText(node) }}</span>
</a-form-item>
</template>
<a-form-item label="审批意见" :required="_action == 'reject'" name="opinion">
<a-textarea v-model:value="formState.opinion" :disabled="loading" :maxlength="200" :rows="3" placeholder="请输入审批意见不超过200字" />
</a-form-item>
</a-form>
</div>
</a-modal>
</template>
<script setup>
import { reactive, ref } from 'vue';
import { getRejectNodeList } from '/@/api/workflow/task';
import { message } from 'ant-design-vue';
const dialogTitle = ref('审批');
const isOpen = ref(false);
const rejectNodeList = ref([]);
const rejectNodeId = ref('');
const loading = ref(false);
const isEnd = ref(false);
let _action = ref('agree');
let _processId = '';
let _taskId = '';
let flowNextNodes = ref([]);
let _callback = null;
let _onCancel = null;
const formState = reactive({
opinion: '',
opinionList: ['同意。', '请领导审批。']
});
function getAssigneeText(node) {
// 注意这里用的是下拉框的数据结构 所以字段是value和label
return (node.nextAssignees || [])
.filter((item) => node.assignees.includes(item.value))
.map((item) => item.label)
.join('、');
}
function getNextNodesName() {
return flowNextNodes.value.length > 1 ? '多个节点,请确认流向节点' : flowNextNodes?.value[0]?.activityName;
}
function toggleDialog({ isClose, action, callback, rejectCancel, processId, taskId, nextNodes } = {}) {
if (isClose) {
isOpen.value = false;
loading.value = false;
return;
}
isOpen.value = true;
_action.value = action;
_callback = callback;
_onCancel = rejectCancel;
_processId = processId;
_taskId = taskId;
flowNextNodes.value = nextNodes;
formState.opinion = '';
dialogTitle.value = `审批`;
if (nextNodes && nextNodes.length) {
// 下一个节点唯一时(可能有并行节点)
const nNode = nextNodes[0];
//formState.nextNodeName = nNode.activityName;
isEnd.value = nNode.isEnd;
const typeCount = nextNodes.length <= 1 ? nextNodes.length : new Set(nextNodes.map((nNode) => nNode.nodeType)).size;
nextNodes.forEach((nNode) => {
if (!nNode.userList?.length) {
return;
}
const selected = [];
nNode.nextAssignees = nNode.userList.map((item) => {
if (item.checked || nNode.userList.length === 1) {
// 只有一个人的时候必须选他
selected.push(item['F_UserId']);
}
return {
value: item['F_UserId'],
label: item['F_RealName'],
item: item
};
});
nNode.assignees = selected;
if (!nNode.chooseAssign) {
// 不需要选审批人的时候 所有备选人都要放到下个节点
nNode.assignees = nNode.userList.map((item) => item['F_UserId']);
}
nNode.chooseAssign = nNode.chooseAssign;
if (nNode.nodeType === 'commitToNode') {
nNode.nodeTypeLabel = '提交到退回节点:';
}
if (nextNodes.length > 1 && nNode.nodeType === 'common') {
nNode.nodeTypeLabel = '并行节点:';
}
// 如果是必选并行节点 或者 只有一个节点,默认选中
if (nNode.isChooseParallel || nextNodes.length == 1) {
nNode.chooseNode = true;
if (typeCount == 1) {
// 如果只有一个节点类型的,默认隐藏
nNode.hiddenNode = true;
} else {
nNode.hiddenNode = false;
}
}
});
flowNextNodes.value = nextNodes;
}
if (action === 'reject') {
loadRejectNodeList();
}
}
function agreeNodeChange(node) {
if (node.chooseNode) {
// 如果是必选并行节点,取消选择时,警告并返回
if (node.isChooseParallel) {
return message.warning('并行节点必选,不能取消选择');
}
node.chooseNode = false;
// 遍历节点如果不是common类型都是false了需要遍历common类型中必填节点是否都是true
const sumNotCommonNode = flowNextNodes.value.filter((nNode) => nNode.nodeType != 'common' && nNode.chooseNode).length;
if (sumNotCommonNode === 0) {
// 如果没有非common类型的节点被选中则将遍历common类型的节点,必填节点设置为true
flowNextNodes.value.forEach((nNode) => {
if (nNode.nodeType === 'common' && nNode.isChooseParallel) {
nNode.chooseNode = true;
}
});
}
} else if (!node.chooseNode) {
node.chooseNode = true;
// 遍历节点,取消与自己不同类型的节点的选择
flowNextNodes.value.forEach((nNode) => {
if (nNode.nodeType != node.nodeType) {
nNode.chooseNode = false;
}
});
if (node.nodeType === 'common') {
// 如果是common类型的节点遍历所有common类型的节点必填节点设置为true
flowNextNodes.value.forEach((nNode) => {
if (nNode.nodeType === 'common' && nNode.isChooseParallel) {
nNode.chooseNode = true;
}
});
}
}
}
function search(inputValue, option) {
return inputValue ? option.item.F_Account.indexOf(inputValue) > -1 || option.item.F_RealName.indexOf(inputValue) > -1 : true;
}
async function loadRejectNodeList() {
rejectNodeId.value = '';
let res = await getRejectNodeList(_processId, _taskId);
if (res && Array.isArray(res) && res.length > 0) {
rejectNodeList.value = res;
dialogTitle.value = `退回`;
if (res?.length) {
res.forEach((nNode) => {
if (!nNode.userList?.length) {
return;
}
const selected = [];
nNode.nextAssignees = nNode.userList.map((item) => {
if (item.checked || nNode.userList.length === 1) {
// 只有一个人的时候必须选他
selected.push(item['F_UserId']);
}
return {
value: item['F_UserId'],
label: item['F_RealName'] + (item.remarks ? '(' + item.remarks + ')' : ''),
item: item
};
});
nNode.assignees = selected;
if (!nNode.chooseAssign) {
// 不需要选审批人的时候 所有备选人都要放到下个节点
nNode.assignees = nNode.userList.map((item) => item['F_UserId']);
}
nNode.chooseAssign = nNode.chooseAssign;
});
}
}
}
function onClickOK() {
const nextTaskUser = {};
if (_action.value === 'agree' && !isEnd.value) {
// 如果是同意,并且没有选择节点 报错
const choose = flowNextNodes.value.find((node) => node.chooseNode);
if (!choose) {
return message.error('请选择下一节点');
}
// 调整成选中的节点的被审人员
const isEmpty = flowNextNodes.value.find((node) => !node.assignees?.length && node.chooseNode);
if (isEmpty) {
return message.error('请选择审批人');
}
flowNextNodes.value
.filter((node) => node.chooseNode)
.forEach((nNode) => {
nextTaskUser[nNode.activityId] = isEnd.value ? '' : typeof nNode.assignees == 'string' ? nNode.assignees : nNode.assignees.join(',');
});
}
if (_action.value === 'reject') {
const isChoose = rejectNodeList.value.find((node) => node.activityId == rejectNodeId.value && node.assignees?.length);
// if (!isChoose) {
// return message.error('请选择审批人');
// }
if (!formState.opinion) {
return message.error('请填写审批意见');
}
rejectNodeList.value.forEach((nNode) => {
if (nNode.activityId == rejectNodeId.value) {
nextTaskUser[nNode.activityId] = isEnd.value ? '' : typeof nNode.assignees == 'string' ? nNode.assignees : nNode.assignees.join(',');
}
});
}
if (_callback && typeof _callback === 'function') {
loading.value = true;
_callback({
opinion: formState.opinion,
rejectNodeId: rejectNodeId.value,
nextTaskUser,
isEnd
});
} else {
isOpen.value = false;
}
}
function onClickCancel() {
if (_onCancel && typeof _onCancel === 'function') {
_onCancel();
}
isOpen.value = false;
}
function stopLoading() {
loading.value = false;
}
defineExpose({
toggleDialog,
stopLoading
});
</script>
<style lang="less" scoped>
.dialog-wrap {
padding: 10px 15px 0 0;
}
.node-info {
display: block;
margin: 6px 0;
line-height: 2;
padding-left: 0;
}
.node-label {
display: inline-block;
min-width: 25%;
text-align: right;
padding-right: 8px;
color: #000;
vertical-align: top;
}
.node-name {
display: inline-block;
flex: none;
text-align: left;
color: #333;
font-weight: 600;
vertical-align: top;
}
</style>