feat(projects): 新增抄送、下一审批人提交功能,优化组件通用性
This commit is contained in:
parent
3a506df9b9
commit
523aca6b75
@ -7,19 +7,31 @@ interface Props {
|
|||||||
type?: NaiveUI.ThemeColor;
|
type?: NaiveUI.ThemeColor;
|
||||||
size?: 'small' | 'medium' | 'large';
|
size?: 'small' | 'medium' | 'large';
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
|
closable?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
type: 'info',
|
type: 'info',
|
||||||
size: 'small',
|
size: 'small',
|
||||||
placeholder: '无'
|
placeholder: '无',
|
||||||
|
closable: false
|
||||||
});
|
});
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'close', index?: number): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
// 统一解析 value 成数组
|
// 统一解析 value 成数组
|
||||||
const tags = computed(() => {
|
const tags = computed(() => {
|
||||||
if (!props.value) return [];
|
if (!props.value) return [];
|
||||||
return Array.isArray(props.value) ? props.value : props.value.split(',');
|
return Array.isArray(props.value) ? props.value : props.value.split(',');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleClose(index?: number) {
|
||||||
|
emit('close', index);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -30,7 +42,7 @@ const tags = computed(() => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template v-else-if="tags.length === 1">
|
<template v-else-if="tags.length === 1">
|
||||||
<NTag :type="type" :size="size">
|
<NTag :type="type" :size="size" :closable="closable" @close="handleClose(0)">
|
||||||
{{ tags[0] }}
|
{{ tags[0] }}
|
||||||
</NTag>
|
</NTag>
|
||||||
</template>
|
</template>
|
||||||
@ -41,7 +53,14 @@ const tags = computed(() => {
|
|||||||
<NTag :type="type" :size="size" class="cursor-pointer">{{ tags[0] }}...({{ tags.length }})</NTag>
|
<NTag :type="type" :size="size" class="cursor-pointer">{{ tags[0] }}...({{ tags.length }})</NTag>
|
||||||
</template>
|
</template>
|
||||||
<NSpace vertical size="small">
|
<NSpace vertical size="small">
|
||||||
<NTag v-for="tag in tags" :key="tag" :type="type" :size="size">
|
<NTag
|
||||||
|
v-for="(tag, index) in tags"
|
||||||
|
:key="index"
|
||||||
|
:type="type"
|
||||||
|
:size="size"
|
||||||
|
:closable="closable"
|
||||||
|
@close="handleClose(index)"
|
||||||
|
>
|
||||||
{{ tag }}
|
{{ tag }}
|
||||||
</NTag>
|
</NTag>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
|
|||||||
@ -19,16 +19,20 @@ interface Props {
|
|||||||
multiple?: boolean;
|
multiple?: boolean;
|
||||||
/** 禁选用户ID */
|
/** 禁选用户ID */
|
||||||
disabledIds?: CommonType.IdType[];
|
disabledIds?: CommonType.IdType[];
|
||||||
|
rowKeys?: CommonType.IdType[];
|
||||||
|
searchUserIds?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
title: '用户选择',
|
title: '用户选择',
|
||||||
multiple: false,
|
multiple: false,
|
||||||
disabledIds: () => []
|
disabledIds: () => [],
|
||||||
|
rowKeys: () => [],
|
||||||
|
searchUserIds: null
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: 'confirm', value: CommonType.IdType[]): void;
|
(e: 'confirm', value: CommonType.IdType[], rows?: Api.System.User[]): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
const emit = defineEmits<Emits>();
|
||||||
@ -128,6 +132,23 @@ const {
|
|||||||
|
|
||||||
const { checkedRowKeys } = useTableOperate(data, getData);
|
const { checkedRowKeys } = useTableOperate(data, getData);
|
||||||
|
|
||||||
|
// 存储所有页面的用户数据,用于跨页选择
|
||||||
|
const allPagesData = ref<Api.System.User[]>([]);
|
||||||
|
|
||||||
|
// 更新allPagesData,保存当前页数据
|
||||||
|
function updateAllPagesData() {
|
||||||
|
// 将当前页数据添加到allPagesData中,避免重复
|
||||||
|
data.value.forEach(user => {
|
||||||
|
const existIndex = allPagesData.value.findIndex(item => item.userId === user.userId);
|
||||||
|
if (existIndex === -1) {
|
||||||
|
allPagesData.value.push(user);
|
||||||
|
} else {
|
||||||
|
// 更新已存在的数据
|
||||||
|
allPagesData.value[existIndex] = user;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const { loading: treeLoading, startLoading: startTreeLoading, endLoading: endTreeLoading } = useLoading();
|
const { loading: treeLoading, startLoading: startTreeLoading, endLoading: endTreeLoading } = useLoading();
|
||||||
const deptPattern = ref<string>();
|
const deptPattern = ref<string>();
|
||||||
const deptData = ref<Api.Common.CommonTreeRecord>([]);
|
const deptData = ref<Api.Common.CommonTreeRecord>([]);
|
||||||
@ -165,38 +186,64 @@ function handleResetSearch() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
|
checkedRowKeys.value = [];
|
||||||
|
allPagesData.value = [];
|
||||||
visible.value = false;
|
visible.value = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleConfirm() {
|
function handleConfirm() {
|
||||||
emit('confirm', checkedRowKeys.value);
|
// 获取选中行对应的用户对象(从所有页面数据中筛选)
|
||||||
|
const selectedUsers = allPagesData.value.filter(item => checkedRowKeys.value.includes(item.userId.toString()));
|
||||||
|
emit('confirm', checkedRowKeys.value, selectedUsers);
|
||||||
closeModal();
|
closeModal();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRowProps(row: Api.System.User) {
|
function getRowProps(row: Api.System.User) {
|
||||||
return {
|
return {
|
||||||
onClick: () => {
|
onClick: (e: MouseEvent) => {
|
||||||
|
const target = e.target as HTMLElement;
|
||||||
|
if (target.closest('.n-data-table-td--selection')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (props.disabledIds.includes(row.userId.toString())) {
|
if (props.disabledIds.includes(row.userId.toString())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将userId转为字符串
|
||||||
|
const userId = row.userId.toString();
|
||||||
|
|
||||||
if (props.multiple) {
|
if (props.multiple) {
|
||||||
const index = checkedRowKeys.value.findIndex(key => key === row.userId);
|
const index = checkedRowKeys.value.findIndex(key => key === userId);
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
checkedRowKeys.value.splice(index, 1);
|
checkedRowKeys.value.splice(index, 1);
|
||||||
} else {
|
} else {
|
||||||
checkedRowKeys.value.push(row.userId);
|
checkedRowKeys.value.push(userId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
checkedRowKeys.value = [row.userId];
|
checkedRowKeys.value = [userId];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 监听数据变化(页面切换时)
|
||||||
|
watch(
|
||||||
|
data,
|
||||||
|
() => {
|
||||||
|
updateAllPagesData();
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
watch(visible, () => {
|
watch(visible, () => {
|
||||||
if (visible.value) {
|
if (visible.value) {
|
||||||
getTreeData();
|
getTreeData();
|
||||||
getData();
|
if (props.searchUserIds) {
|
||||||
|
searchParams.userIds = props.searchUserIds;
|
||||||
|
}
|
||||||
|
allPagesData.value = [];
|
||||||
|
getDataByPage();
|
||||||
|
checkedRowKeys.value = [...props.rowKeys];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@ -273,7 +320,7 @@ watch(visible, () => {
|
|||||||
:loading="loading"
|
:loading="loading"
|
||||||
:row-props="getRowProps"
|
:row-props="getRowProps"
|
||||||
remote
|
remote
|
||||||
:row-key="row => row.userId"
|
:row-key="row => row.userId.toString()"
|
||||||
:pagination="mobilePagination"
|
:pagination="mobilePagination"
|
||||||
class="h-full lt-sm:max-h-300px"
|
class="h-full lt-sm:max-h-300px"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -64,6 +64,7 @@ function handleTransferConfirm(ids: CommonType.IdType[]) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
model.userId = ids[0];
|
model.userId = ids[0];
|
||||||
|
model.taskId = props.taskId;
|
||||||
window.$dialog?.warning({
|
window.$dialog?.warning({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
content: '是否确认转办?',
|
content: '是否确认转办?',
|
||||||
@ -107,6 +108,7 @@ function handleAddSignatureConfirm(ids: CommonType.IdType[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleTerminate() {
|
function handleTerminate() {
|
||||||
|
terminateModel.taskId = props.taskId;
|
||||||
window.$dialog?.warning({
|
window.$dialog?.warning({
|
||||||
title: '提示',
|
title: '提示',
|
||||||
content: '是否确认中止?',
|
content: '是否确认中止?',
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { reactive, ref, watch } from 'vue';
|
import { reactive, ref, watch } from 'vue';
|
||||||
import type { UploadFileInfo } from 'naive-ui';
|
import type { UploadFileInfo } from 'naive-ui';
|
||||||
|
import { useBoolean, useLoading } from '@sa/hooks';
|
||||||
import { messageTypeOptions } from '@/constants/workflow';
|
import { messageTypeOptions } from '@/constants/workflow';
|
||||||
import { fetchCompleteTask, fetchGetTask } from '@/service/api/workflow';
|
import { fetchCompleteTask, fetchGetTask, fetchGetkNextNode } from '@/service/api/workflow';
|
||||||
import FileUpload from '@/components/custom/file-upload.vue';
|
import FileUpload from '@/components/custom/file-upload.vue';
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@ -27,6 +28,10 @@ const emit = defineEmits<Emits>();
|
|||||||
const visible = defineModel<boolean>('visible', {
|
const visible = defineModel<boolean>('visible', {
|
||||||
default: false
|
default: false
|
||||||
});
|
});
|
||||||
|
const { loading: baseFormLoading, startLoading: startBaseFormLoading, endLoading: endBaseFormLoading } = useLoading();
|
||||||
|
const { loading: btnLoading, startLoading: startBtnLoading, endLoading: endBtnLoading } = useLoading();
|
||||||
|
const { bool: copyVisible, setTrue: openCopyModal } = useBoolean();
|
||||||
|
const { bool: assigneeVisible, setTrue: openAssigneeModal } = useBoolean();
|
||||||
const title = defineModel<string>('title', {
|
const title = defineModel<string>('title', {
|
||||||
default: '流程发起'
|
default: '流程发起'
|
||||||
});
|
});
|
||||||
@ -45,65 +50,263 @@ function createDefaultModel(): Model {
|
|||||||
fileId: null,
|
fileId: null,
|
||||||
flowCopyList: [],
|
flowCopyList: [],
|
||||||
messageType: ['1'],
|
messageType: ['1'],
|
||||||
taskVariables: {},
|
taskVariables: null,
|
||||||
variables: {},
|
variables: null,
|
||||||
assigneeMap: {}
|
assigneeMap: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const fileList = ref<UploadFileInfo[]>([]);
|
||||||
|
// 抄送人
|
||||||
|
const selectCopyUserList = ref<Api.System.User[]>([]);
|
||||||
|
// 抄送人id
|
||||||
|
const selectCopyUserIds = ref<CommonType.IdType[]>([]);
|
||||||
|
// 下一节点列表
|
||||||
|
const nestNodeList = ref<Api.Workflow.FlowNode[]>([]);
|
||||||
|
|
||||||
|
const nickNameMap = ref<{ [key: string]: string }>({});
|
||||||
|
|
||||||
|
const assigneeSearchUserIds = ref<string | null>(null);
|
||||||
|
|
||||||
|
const selectAssigneeIds = ref<string[]>([]);
|
||||||
|
|
||||||
|
// 节点编码
|
||||||
|
const nodeCode = ref<string>('');
|
||||||
|
// 按钮权限
|
||||||
|
interface ButtonPerm {
|
||||||
|
pop: boolean;
|
||||||
|
trust: boolean;
|
||||||
|
transfer: boolean;
|
||||||
|
addSign: boolean;
|
||||||
|
subSign: boolean;
|
||||||
|
termination: boolean;
|
||||||
|
back: boolean;
|
||||||
|
copy: boolean;
|
||||||
|
}
|
||||||
|
const buttonPerm = reactive<ButtonPerm>(createDefaultButtonPerm());
|
||||||
|
|
||||||
|
function createDefaultButtonPerm(): ButtonPerm {
|
||||||
|
return {
|
||||||
|
pop: false,
|
||||||
|
trust: false,
|
||||||
|
transfer: false,
|
||||||
|
addSign: false,
|
||||||
|
subSign: false,
|
||||||
|
termination: false,
|
||||||
|
back: false,
|
||||||
|
copy: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTask() {
|
function initDefault() {
|
||||||
const { error, data } = await fetchGetTask(props.taskId);
|
selectCopyUserList.value = [];
|
||||||
if (error) return;
|
selectCopyUserIds.value = [];
|
||||||
task.value = data;
|
nickNameMap.value = {};
|
||||||
|
assigneeSearchUserIds.value = null;
|
||||||
|
selectAssigneeIds.value = [];
|
||||||
|
nodeCode.value = '';
|
||||||
|
Object.assign(model, createDefaultModel());
|
||||||
|
Object.assign(buttonPerm, createDefaultButtonPerm());
|
||||||
}
|
}
|
||||||
|
|
||||||
const fileList = ref<UploadFileInfo[]>([]);
|
async function getTask() {
|
||||||
|
startBtnLoading();
|
||||||
|
startBaseFormLoading();
|
||||||
|
const { error, data } = await fetchGetTask(props.taskId);
|
||||||
|
if (error) {
|
||||||
|
endBtnLoading();
|
||||||
|
endBaseFormLoading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
task.value = data;
|
||||||
|
task.value.buttonList.forEach(item => {
|
||||||
|
buttonPerm[item.code as keyof ButtonPerm] = !item.show;
|
||||||
|
});
|
||||||
|
endBtnLoading();
|
||||||
|
const { error: nextNodeError, data: nextNodeData } = await fetchGetkNextNode({
|
||||||
|
taskId: props.taskId,
|
||||||
|
taskVariables: props.taskVariables
|
||||||
|
});
|
||||||
|
if (nextNodeError) {
|
||||||
|
endBaseFormLoading();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
nestNodeList.value = nextNodeData;
|
||||||
|
endBaseFormLoading();
|
||||||
|
}
|
||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
|
if (buttonPerm.pop && nestNodeList.value?.length) {
|
||||||
|
const hasEmptyAssignee = nestNodeList.value.some(e => !model.assigneeMap || !model.assigneeMap[e.nodeCode]);
|
||||||
|
if (hasEmptyAssignee) {
|
||||||
|
window.$message?.error('请选择审批人!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
model.assigneeMap = {};
|
||||||
|
}
|
||||||
|
if (selectCopyUserList.value?.length) {
|
||||||
|
model.flowCopyList = selectCopyUserList.value.map(e => ({
|
||||||
|
userId: e.userId,
|
||||||
|
userName: e.nickName
|
||||||
|
}));
|
||||||
|
}
|
||||||
if (fileList.value?.length) {
|
if (fileList.value?.length) {
|
||||||
const fileIds = fileList.value.map(item => item.id);
|
const fileIds = fileList.value.map(item => item.id);
|
||||||
model.fileId = fileIds.join(',');
|
model.fileId = fileIds.join(',');
|
||||||
}
|
}
|
||||||
model.taskId = props.taskId;
|
model.taskId = props.taskId;
|
||||||
model.taskVariables = props.taskVariables;
|
model.variables = props.taskVariables;
|
||||||
const { error } = await fetchCompleteTask(model);
|
startBtnLoading();
|
||||||
if (error) return;
|
startBaseFormLoading();
|
||||||
window.$message?.success('提交成功');
|
try {
|
||||||
visible.value = false;
|
const { error } = await fetchCompleteTask(model);
|
||||||
emit('finished');
|
if (error) return;
|
||||||
|
window.$message?.success('提交成功');
|
||||||
|
visible.value = false;
|
||||||
|
emit('finished');
|
||||||
|
} catch (error) {
|
||||||
|
window.$message?.error(`提交失败,请稍后重试,${error}`);
|
||||||
|
} finally {
|
||||||
|
endBtnLoading();
|
||||||
|
endBaseFormLoading();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCopyConfirm(userIds: CommonType.IdType[], users?: Api.System.User[]) {
|
||||||
|
selectCopyUserList.value = users || [];
|
||||||
|
selectCopyUserIds.value = userIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAssigneeOpen(item: Api.Workflow.FlowNode) {
|
||||||
|
if (!item.permissionFlag) {
|
||||||
|
window.$message?.error('没有可选人员,请联系管理员!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assigneeSearchUserIds.value = item.permissionFlag;
|
||||||
|
nodeCode.value = item.nodeCode;
|
||||||
|
selectAssigneeIds.value = model.assigneeMap?.[item.nodeCode]?.split(',') || [];
|
||||||
|
openAssigneeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAssigneeConfirm(userIds: CommonType.IdType[], users?: Api.System.User[]) {
|
||||||
|
// 更新当前节点的审批人
|
||||||
|
if (!model.assigneeMap) model.assigneeMap = {};
|
||||||
|
model.assigneeMap[nodeCode.value] = userIds.join(',');
|
||||||
|
nickNameMap.value[nodeCode.value] = users?.map(item => item.nickName).join(',') || '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleCopyTagClose(index?: number) {
|
||||||
|
if (index !== undefined) {
|
||||||
|
// 删除指定索引的用户
|
||||||
|
selectCopyUserIds.value = selectCopyUserIds.value.filter((_, i) => i !== index);
|
||||||
|
selectCopyUserList.value = selectCopyUserList.value.filter((_, i) => i !== index);
|
||||||
|
} else {
|
||||||
|
// 清空所有用户
|
||||||
|
selectCopyUserList.value = [];
|
||||||
|
selectCopyUserIds.value = [];
|
||||||
|
model.flowCopyList = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleAssigneeTagClose(code: string, index?: number) {
|
||||||
|
if (!model.assigneeMap?.[code]) return;
|
||||||
|
|
||||||
|
// 获取当前节点的用户ID列表和名称列表
|
||||||
|
const userIds = model.assigneeMap[code].split(',');
|
||||||
|
const nickNames = nickNameMap.value[code]?.split(',') || [];
|
||||||
|
|
||||||
|
if (index !== undefined) {
|
||||||
|
// 删除指定索引的用户
|
||||||
|
// 使用filter方式移除指定索引的元素
|
||||||
|
const newUserIds = userIds.filter((_, i) => i !== index);
|
||||||
|
const newNickNames = nickNames.filter((_, i) => i !== index);
|
||||||
|
|
||||||
|
// 更新数据
|
||||||
|
model.assigneeMap[code] = newUserIds.join(',');
|
||||||
|
nickNameMap.value[code] = newNickNames.join(',');
|
||||||
|
} else {
|
||||||
|
// 清空所有用户
|
||||||
|
model.assigneeMap[code] = '';
|
||||||
|
nickNameMap.value[code] = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(visible, () => {
|
watch(visible, () => {
|
||||||
if (visible.value) {
|
if (visible.value) {
|
||||||
|
initDefault();
|
||||||
getTask();
|
getTask();
|
||||||
Object.assign(model, createDefaultModel());
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NModal v-model:show="visible" preset="card" class="w-700px" :title="title" :native-scrollbar="false" closable>
|
<NModal v-model:show="visible" preset="card" class="w-800px" :title="title" :native-scrollbar="false" closable>
|
||||||
<NForm :model="model">
|
<NSpin :show="baseFormLoading">
|
||||||
<NFormItem label="通知方式" path="messageType">
|
<NForm :model="model" label-placement="left" :label-width="100">
|
||||||
<NCheckboxGroup v-model:value="model.messageType">
|
<NFormItem label="通知方式" path="messageType">
|
||||||
<NSpace item-style="display: flex;">
|
<NCheckboxGroup v-model:value="model.messageType">
|
||||||
<NCheckbox
|
<NSpace item-style="display: flex;">
|
||||||
v-for="item in messageTypeOptions"
|
<NCheckbox
|
||||||
:key="item.value"
|
v-for="item in messageTypeOptions"
|
||||||
:disabled="item.value === '1'"
|
:key="item.value"
|
||||||
:value="item.value"
|
:disabled="item.value === '1'"
|
||||||
:label="item.label"
|
:value="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
/>
|
||||||
|
</NSpace>
|
||||||
|
</NCheckboxGroup>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="附件" path="fileId">
|
||||||
|
<FileUpload v-model:file-list="fileList" :file-size="20" :max="20" upload-type="file" :accept="accept" />
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem v-if="buttonPerm.copy" label="抄送人员">
|
||||||
|
<NSpace>
|
||||||
|
<NButton ghost type="primary" @click="openCopyModal">选择抄送人员</NButton>
|
||||||
|
<GroupTag
|
||||||
|
size="large"
|
||||||
|
:value="selectCopyUserList.map(item => item.nickName)"
|
||||||
|
:closable="true"
|
||||||
|
@close="handleCopyTagClose"
|
||||||
/>
|
/>
|
||||||
</NSpace>
|
</NSpace>
|
||||||
</NCheckboxGroup>
|
</NFormItem>
|
||||||
</NFormItem>
|
<NFormItem
|
||||||
<NFormItem label="附件" path="fileId">
|
v-if="buttonPerm.pop && nestNodeList && nestNodeList.length > 0"
|
||||||
<FileUpload v-model:file-list="fileList" :file-size="20" :max="20" upload-type="file" :accept="accept" />
|
label="下一步审批人"
|
||||||
</NFormItem>
|
path="assigneeMap"
|
||||||
</NForm>
|
>
|
||||||
<div class="flex justify-end gap-12px">
|
<NSpace>
|
||||||
<NButton @click="visible = false">取消</NButton>
|
<div v-for="(item, index) in nestNodeList" :key="index">
|
||||||
<NButton type="primary" @click="handleSubmit">提交</NButton>
|
<span>【{{ item.nodeName }}】:</span>
|
||||||
</div>
|
<NSpace>
|
||||||
|
<NButton ghost type="primary" @click="handleAssigneeOpen(item)">选择审批人员</NButton>
|
||||||
|
<NInput v-if="false" v-model:value="model.assigneeMap![item.nodeCode]" />
|
||||||
|
<GroupTag
|
||||||
|
size="large"
|
||||||
|
:value="nickNameMap[item.nodeCode]"
|
||||||
|
:closable="true"
|
||||||
|
@close="index => handleAssigneeTagClose(item.nodeCode, index)"
|
||||||
|
/>
|
||||||
|
</NSpace>
|
||||||
|
</div>
|
||||||
|
</NSpace>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem v-if="task?.flowStatus === 'waiting'" label="审批意见" path="message">
|
||||||
|
<NInput v-model:value="model.message" type="textarea" />
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
<div class="flex justify-end gap-12px">
|
||||||
|
<NButton @click="visible = false">取消</NButton>
|
||||||
|
<NButton :loading="btnLoading" type="primary" @click="handleSubmit">提交</NButton>
|
||||||
|
</div>
|
||||||
|
</NSpin>
|
||||||
</NModal>
|
</NModal>
|
||||||
|
<UserSelectModal v-model:visible="copyVisible" :row-keys="selectCopyUserIds" multiple @confirm="handleCopyConfirm" />
|
||||||
|
<UserSelectModal
|
||||||
|
v-model:visible="assigneeVisible"
|
||||||
|
:row-keys="selectAssigneeIds"
|
||||||
|
:search-user-ids="assigneeSearchUserIds"
|
||||||
|
multiple
|
||||||
|
@confirm="handleAssigneeConfirm"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -17,6 +17,15 @@ export function fetchGetTask(taskId: CommonType.IdType) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 获取任务下一个节点 */
|
||||||
|
export function fetchGetkNextNode(data: Api.Workflow.TaskNextNodeSearchParams) {
|
||||||
|
return request<Api.Workflow.FlowNodeList>({
|
||||||
|
url: '/workflow/task/getNextNodeList',
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/** 完成任务 */
|
/** 完成任务 */
|
||||||
export function fetchCompleteTask(data: Api.Workflow.CompleteTaskOperateParams) {
|
export function fetchCompleteTask(data: Api.Workflow.CompleteTaskOperateParams) {
|
||||||
return request<Api.Workflow.Task>({
|
return request<Api.Workflow.Task>({
|
||||||
|
|||||||
1
src/typings/api/system.api.d.ts
vendored
1
src/typings/api/system.api.d.ts
vendored
@ -128,6 +128,7 @@ declare namespace Api {
|
|||||||
type UserSearchParams = CommonType.RecordNullable<
|
type UserSearchParams = CommonType.RecordNullable<
|
||||||
Pick<User, 'deptId' | 'userName' | 'nickName' | 'phonenumber' | 'status'> & {
|
Pick<User, 'deptId' | 'userName' | 'nickName' | 'phonenumber' | 'status'> & {
|
||||||
roleId: CommonType.IdType;
|
roleId: CommonType.IdType;
|
||||||
|
userIds: string;
|
||||||
} & Common.CommonSearchParams
|
} & Common.CommonSearchParams
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|||||||
47
src/typings/api/workflow.api.d.ts
vendored
47
src/typings/api/workflow.api.d.ts
vendored
@ -428,6 +428,10 @@ declare namespace Api {
|
|||||||
createByIds: CommonType.IdType[];
|
createByIds: CommonType.IdType[];
|
||||||
}
|
}
|
||||||
>;
|
>;
|
||||||
|
type TaskNextNodeSearchParams = CommonType.RecordNullable<{
|
||||||
|
taskId: CommonType.IdType;
|
||||||
|
taskVariables: { [key: string]: any };
|
||||||
|
}>;
|
||||||
|
|
||||||
/** 消息类型 */
|
/** 消息类型 */
|
||||||
type MessageType = '1' | '2' | '3';
|
type MessageType = '1' | '2' | '3';
|
||||||
@ -455,5 +459,48 @@ declare namespace Api {
|
|||||||
/** 扩展字段 */
|
/** 扩展字段 */
|
||||||
ext: string;
|
ext: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
/** 工作流节点 */
|
||||||
|
type FlowNode = Common.CommonRecord<{
|
||||||
|
/** 节点ID */
|
||||||
|
id: CommonType.IdType;
|
||||||
|
/** 删除标志 */
|
||||||
|
delFlag: string;
|
||||||
|
/** 节点类型(0开始节点 1中间节点 2结束节点 3互斥网关 4并行网关) */
|
||||||
|
nodeType: WorkflowNodeType;
|
||||||
|
/** 流程定义ID */
|
||||||
|
definitionId: CommonType.IdType;
|
||||||
|
/** 节点编码 */
|
||||||
|
nodeCode: string;
|
||||||
|
/** 节点名称 */
|
||||||
|
nodeName: string;
|
||||||
|
/** 权限标识 */
|
||||||
|
permissionFlag: string;
|
||||||
|
/** 流程签署比例值 */
|
||||||
|
nodeRatio: string;
|
||||||
|
/** 节点坐标 */
|
||||||
|
coordinate: string;
|
||||||
|
/** 流程版本号 */
|
||||||
|
version: string;
|
||||||
|
/** 是否允许任意节点跳转 */
|
||||||
|
anyNodeSkip: string;
|
||||||
|
/** 监听器类型 */
|
||||||
|
listenerType: string;
|
||||||
|
/** 监听器路径 */
|
||||||
|
listenerPath: string;
|
||||||
|
/** 处理器类型 */
|
||||||
|
handlerType: string;
|
||||||
|
/** 处理器路径 */
|
||||||
|
handlerPath: string;
|
||||||
|
/** 审批表单是否自定义(Y是 N否) */
|
||||||
|
formCustom: Api.Common.YesOrNoStatus;
|
||||||
|
/** 审批表单路径 */
|
||||||
|
formPath: string;
|
||||||
|
/** 扩展字段 */
|
||||||
|
ext: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
/** 工作流节点列表 */
|
||||||
|
type FlowNodeList = FlowNode[];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user