feat: 选择下一步审批人权限
This commit is contained in:
parent
e78f4e984d
commit
6170da0870
@ -1,5 +1,6 @@
|
|||||||
import type {
|
import type {
|
||||||
CompleteTaskReqData,
|
CompleteTaskReqData,
|
||||||
|
NextNodeInfo,
|
||||||
StartWorkFlowReqData,
|
StartWorkFlowReqData,
|
||||||
TaskInfo,
|
TaskInfo,
|
||||||
TaskOperationData,
|
TaskOperationData,
|
||||||
@ -156,3 +157,16 @@ export function getBackTaskNode(definitionId: string, nodeCode: string) {
|
|||||||
export function currentTaskAllUser(taskId: ID) {
|
export function currentTaskAllUser(taskId: ID) {
|
||||||
return requestClient.get<any>(`/workflow/task/currentTaskAllUser/${taskId}`);
|
return requestClient.get<any>(`/workflow/task/currentTaskAllUser/${taskId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下一节点
|
||||||
|
* @param data data
|
||||||
|
* @param data.taskId taskId
|
||||||
|
* @returns NextNodeInfo
|
||||||
|
*/
|
||||||
|
export function getNextNodeList(data: { taskId: string }) {
|
||||||
|
return requestClient.post<NextNodeInfo[]>(
|
||||||
|
'/workflow/task/getNextNodeList',
|
||||||
|
data,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
27
apps/web-antd/src/api/workflow/task/model.d.ts
vendored
27
apps/web-antd/src/api/workflow/task/model.d.ts
vendored
@ -45,6 +45,8 @@ export interface CompleteTaskReqData {
|
|||||||
variables: any;
|
variables: any;
|
||||||
// 附件ID 1,2,3,4形式
|
// 附件ID 1,2,3,4形式
|
||||||
fileId?: string;
|
fileId?: string;
|
||||||
|
// 选人 key为节点code value为用户ID join(,)
|
||||||
|
assigneeMap: { [key: string]: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StartWorkFlowReqData {
|
export interface StartWorkFlowReqData {
|
||||||
@ -79,3 +81,28 @@ export type TaskOperationType =
|
|||||||
| 'delegateTask'
|
| 'delegateTask'
|
||||||
| 'reductionSignature'
|
| 'reductionSignature'
|
||||||
| 'transferTask';
|
| 'transferTask';
|
||||||
|
|
||||||
|
export interface NextNodeInfo {
|
||||||
|
skipList: string[];
|
||||||
|
id: string;
|
||||||
|
createTime: string;
|
||||||
|
updateTime: string;
|
||||||
|
tenantId: string;
|
||||||
|
delFlag: string;
|
||||||
|
nodeType: number;
|
||||||
|
definitionId: string;
|
||||||
|
nodeCode: string;
|
||||||
|
nodeName: string;
|
||||||
|
permissionFlag: string;
|
||||||
|
nodeRatio: string;
|
||||||
|
coordinate: string;
|
||||||
|
version: string;
|
||||||
|
anyNodeSkip: any;
|
||||||
|
listenerType: any;
|
||||||
|
listenerPath: any;
|
||||||
|
handlerType: any;
|
||||||
|
handlerPath: any;
|
||||||
|
formCustom: string;
|
||||||
|
formPath: any;
|
||||||
|
ext: string;
|
||||||
|
}
|
||||||
|
@ -1,14 +1,21 @@
|
|||||||
<!-- 审批同意的弹窗 -->
|
<!-- 审批同意的弹窗 -->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { CompleteTaskReqData } from '#/api/workflow/task/model';
|
import type { User } from '#/api/system/user/model';
|
||||||
|
import type {
|
||||||
|
CompleteTaskReqData,
|
||||||
|
NextNodeInfo,
|
||||||
|
} from '#/api/workflow/task/model';
|
||||||
|
|
||||||
|
import { ref } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal } from '@vben/common-ui';
|
import { useVbenModal } from '@vben/common-ui';
|
||||||
import { cloneDeep } from '@vben/utils';
|
import { cloneDeep } from '@vben/utils';
|
||||||
|
|
||||||
|
import { message } from 'ant-design-vue';
|
||||||
import { omit } from 'lodash-es';
|
import { omit } from 'lodash-es';
|
||||||
|
|
||||||
import { useVbenForm } from '#/adapter/form';
|
import { useVbenForm } from '#/adapter/form';
|
||||||
import { completeTask } from '#/api/workflow/task';
|
import { completeTask, getNextNodeList } from '#/api/workflow/task';
|
||||||
|
|
||||||
import { CopyComponent } from '.';
|
import { CopyComponent } from '.';
|
||||||
|
|
||||||
@ -77,6 +84,11 @@ const [BasicForm, formApi] = useVbenForm({
|
|||||||
defaultValue: [],
|
defaultValue: [],
|
||||||
label: '抄送人',
|
label: '抄送人',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'assigneeMap',
|
||||||
|
component: 'Input',
|
||||||
|
label: '下一步审批人',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
fieldName: 'message',
|
fieldName: 'message',
|
||||||
component: 'Textarea',
|
component: 'Textarea',
|
||||||
@ -92,8 +104,12 @@ interface ModalProps {
|
|||||||
taskId: string;
|
taskId: string;
|
||||||
// 是否具有抄送权限
|
// 是否具有抄送权限
|
||||||
copyPermission: boolean;
|
copyPermission: boolean;
|
||||||
|
// 是有具有选人权限
|
||||||
|
assignPermission: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 自定义添加选人属性 给组件v-for绑定
|
||||||
|
const nextNodeInfo = ref<(NextNodeInfo & { selectUserList: User[] })[]>([]);
|
||||||
const [BasicModal, modalApi] = useVbenModal({
|
const [BasicModal, modalApi] = useVbenModal({
|
||||||
title: '审批通过',
|
title: '审批通过',
|
||||||
fullscreenButton: false,
|
fullscreenButton: false,
|
||||||
@ -106,18 +122,36 @@ const [BasicModal, modalApi] = useVbenModal({
|
|||||||
}
|
}
|
||||||
modalApi.modalLoading(true);
|
modalApi.modalLoading(true);
|
||||||
|
|
||||||
const { taskId, copyPermission } = modalApi.getData() as ModalProps;
|
const { taskId, copyPermission, assignPermission } =
|
||||||
|
modalApi.getData() as ModalProps;
|
||||||
// 是否显示抄送选择
|
// 是否显示抄送选择
|
||||||
formApi.updateSchema([
|
formApi.updateSchema([
|
||||||
{
|
{
|
||||||
fieldName: 'flowCopyList',
|
fieldName: 'flowCopyList',
|
||||||
dependencies: {
|
dependencies: {
|
||||||
show: copyPermission,
|
if: copyPermission,
|
||||||
|
triggerFields: [''],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fieldName: 'assigneeMap',
|
||||||
|
dependencies: {
|
||||||
|
if: assignPermission,
|
||||||
triggerFields: [''],
|
triggerFields: [''],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// 获取下一节点名称
|
||||||
|
if (assignPermission) {
|
||||||
|
const resp = await getNextNodeList({ taskId });
|
||||||
|
nextNodeInfo.value = resp.map((item) => ({
|
||||||
|
...item,
|
||||||
|
// 用于给组件绑定
|
||||||
|
selectUserList: [],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
await formApi.setFieldValue('taskId', taskId);
|
await formApi.setFieldValue('taskId', taskId);
|
||||||
|
|
||||||
modalApi.modalLoading(false);
|
modalApi.modalLoading(false);
|
||||||
@ -144,6 +178,26 @@ async function handleSubmit() {
|
|||||||
variables: {},
|
variables: {},
|
||||||
flowCopyList,
|
flowCopyList,
|
||||||
} as CompleteTaskReqData;
|
} as CompleteTaskReqData;
|
||||||
|
|
||||||
|
// 选人
|
||||||
|
if (modalApi.getData()?.assignPermission) {
|
||||||
|
// 判断是否选中
|
||||||
|
for (const item of nextNodeInfo.value) {
|
||||||
|
if (item.selectUserList.length === 0) {
|
||||||
|
message.warn(`未选择节点[${item.nodeName}]审批人`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const assigneeMap: { [key: string]: string } = {};
|
||||||
|
nextNodeInfo.value.forEach((item) => {
|
||||||
|
assigneeMap[item.nodeCode] = item.selectUserList
|
||||||
|
.map((u) => u.userId)
|
||||||
|
.join(',');
|
||||||
|
});
|
||||||
|
requestData.assigneeMap = assigneeMap;
|
||||||
|
}
|
||||||
|
|
||||||
await completeTask(requestData);
|
await completeTask(requestData);
|
||||||
modalApi.close();
|
modalApi.close();
|
||||||
emit('complete');
|
emit('complete');
|
||||||
@ -161,6 +215,24 @@ async function handleSubmit() {
|
|||||||
<template #flowCopyList="slotProps">
|
<template #flowCopyList="slotProps">
|
||||||
<CopyComponent v-model:user-list="slotProps.modelValue" />
|
<CopyComponent v-model:user-list="slotProps.modelValue" />
|
||||||
</template>
|
</template>
|
||||||
|
<template #assigneeMap>
|
||||||
|
<div
|
||||||
|
v-for="item in nextNodeInfo"
|
||||||
|
:key="item.nodeCode"
|
||||||
|
class="flex items-center gap-2"
|
||||||
|
>
|
||||||
|
<template v-if="item.permissionFlag">
|
||||||
|
<span class="opacity-70">{{ item.nodeName }}</span>
|
||||||
|
<CopyComponent
|
||||||
|
:allow-user-ids="item.permissionFlag"
|
||||||
|
v-model:user-list="item.selectUserList"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<span class="text-red-500">没有权限, 请联系管理员</span>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
</BasicForm>
|
</BasicForm>
|
||||||
</BasicModal>
|
</BasicModal>
|
||||||
</template>
|
</template>
|
||||||
|
@ -256,7 +256,13 @@ const [ApprovalModal, approvalModalApi] = useVbenModal({
|
|||||||
function handleApproval() {
|
function handleApproval() {
|
||||||
// 是否具有抄送权限
|
// 是否具有抄送权限
|
||||||
const copyPermission = buttonPermissions.value?.copy ?? false;
|
const copyPermission = buttonPermissions.value?.copy ?? false;
|
||||||
approvalModalApi.setData({ taskId: props.task?.id, copyPermission });
|
// 是否具有选人权限
|
||||||
|
const assignPermission = buttonPermissions.value?.pop ?? false;
|
||||||
|
approvalModalApi.setData({
|
||||||
|
taskId: props.task?.id,
|
||||||
|
copyPermission,
|
||||||
|
assignPermission,
|
||||||
|
});
|
||||||
approvalModalApi.open();
|
approvalModalApi.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
<!--抄送组件-->
|
<!--抄送组件-->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type { PropType } from 'vue';
|
||||||
|
|
||||||
import type { User } from '#/api/system/user/model';
|
import type { User } from '#/api/system/user/model';
|
||||||
|
|
||||||
import { computed, type PropType } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
import { useVbenModal, VbenAvatar } from '@vben/common-ui';
|
import { useVbenModal, VbenAvatar } from '@vben/common-ui';
|
||||||
|
|
||||||
@ -15,12 +17,19 @@ defineOptions({
|
|||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ ellipseNumber?: number }>(), {
|
const props = withDefaults(
|
||||||
|
defineProps<{ allowUserIds?: string; ellipseNumber?: number }>(),
|
||||||
|
{
|
||||||
/**
|
/**
|
||||||
* 最大显示的头像数量 超过显示为省略号头像
|
* 最大显示的头像数量 超过显示为省略号头像
|
||||||
*/
|
*/
|
||||||
ellipseNumber: 3,
|
ellipseNumber: 3,
|
||||||
});
|
/**
|
||||||
|
* 允许选择允许选择的人员ID 会当做参数拼接在uselist接口
|
||||||
|
*/
|
||||||
|
allowUserIds: '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const emit = defineEmits<{ cancel: []; finish: [User[]] }>();
|
const emit = defineEmits<{ cancel: []; finish: [User[]] }>();
|
||||||
|
|
||||||
@ -80,6 +89,10 @@ const displayedList = computed(() => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</AvatarGroup>
|
</AvatarGroup>
|
||||||
<a-button size="small" @click="handleOpen">选择人员</a-button>
|
<a-button size="small" @click="handleOpen">选择人员</a-button>
|
||||||
<UserSelectModal @cancel="$emit('cancel')" @finish="handleFinish" />
|
<UserSelectModal
|
||||||
|
:allow-user-ids="allowUserIds"
|
||||||
|
@cancel="$emit('cancel')"
|
||||||
|
@finish="handleFinish"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -18,9 +18,16 @@ defineOptions({
|
|||||||
inheritAttrs: false,
|
inheritAttrs: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{ mode?: 'multiple' | 'single' }>(), {
|
const props = withDefaults(
|
||||||
|
defineProps<{ allowUserIds?: string; mode?: 'multiple' | 'single' }>(),
|
||||||
|
{
|
||||||
mode: 'multiple',
|
mode: 'multiple',
|
||||||
});
|
/**
|
||||||
|
* 允许选择允许选择的人员ID 会当做参数拼接在uselist接口
|
||||||
|
*/
|
||||||
|
allowUserIds: '',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
/**
|
/**
|
||||||
@ -136,11 +143,17 @@ const gridOptions: VxeGridProps = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await userList({
|
const params: any = {
|
||||||
pageNum: page.currentPage,
|
pageNum: page.currentPage,
|
||||||
pageSize: page.pageSize,
|
pageSize: page.pageSize,
|
||||||
...formValues,
|
...formValues,
|
||||||
});
|
};
|
||||||
|
// 添加参数
|
||||||
|
if (props.allowUserIds) {
|
||||||
|
params.userIds = props.allowUserIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
return await userList(params);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -27,7 +27,7 @@ import { ApprovalCard, ApprovalPanel } from '../components';
|
|||||||
|
|
||||||
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
||||||
|
|
||||||
const taskList = ref<({ active: boolean } & TaskInfo)[]>([]);
|
const taskList = ref<(TaskInfo & { active: boolean })[]>([]);
|
||||||
const taskTotal = ref(0);
|
const taskTotal = ref(0);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
@ -29,7 +29,7 @@ import { ApprovalCard, ApprovalPanel, CopyComponent } from '../components';
|
|||||||
|
|
||||||
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
||||||
|
|
||||||
const taskList = ref<({ active: boolean } & TaskInfo)[]>([]);
|
const taskList = ref<(TaskInfo & { active: boolean })[]>([]);
|
||||||
const taskTotal = ref(0);
|
const taskTotal = ref(0);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
@ -29,7 +29,7 @@ import { ApprovalCard, ApprovalPanel, CopyComponent } from '../components';
|
|||||||
|
|
||||||
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
||||||
|
|
||||||
const taskList = ref<({ active: boolean } & TaskInfo)[]>([]);
|
const taskList = ref<(TaskInfo & { active: boolean })[]>([]);
|
||||||
const taskTotal = ref(0);
|
const taskTotal = ref(0);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
@ -30,7 +30,7 @@ import { ApprovalCard, ApprovalPanel, CopyComponent } from '../components';
|
|||||||
|
|
||||||
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
const emptyImage = Empty.PRESENTED_IMAGE_SIMPLE;
|
||||||
|
|
||||||
const taskList = ref<({ active: boolean } & TaskInfo)[]>([]);
|
const taskList = ref<(TaskInfo & { active: boolean })[]>([]);
|
||||||
const taskTotal = ref(0);
|
const taskTotal = ref(0);
|
||||||
const page = ref(1);
|
const page = ref(1);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
Loading…
Reference in New Issue
Block a user