mirror of
https://github.com/m-xlsea/ruoyi-plus-soybean.git
synced 2025-09-23 23:39:47 +08:00
feat(projects): 新增抄送、下一审批人提交功能,优化组件通用性
This commit is contained in:
@ -7,19 +7,31 @@ interface Props {
|
||||
type?: NaiveUI.ThemeColor;
|
||||
size?: 'small' | 'medium' | 'large';
|
||||
placeholder?: string;
|
||||
closable?: boolean;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
type: 'info',
|
||||
size: 'small',
|
||||
placeholder: '无'
|
||||
placeholder: '无',
|
||||
closable: false
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'close', index?: number): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
|
||||
// 统一解析 value 成数组
|
||||
const tags = computed(() => {
|
||||
if (!props.value) return [];
|
||||
return Array.isArray(props.value) ? props.value : props.value.split(',');
|
||||
});
|
||||
|
||||
function handleClose(index?: number) {
|
||||
emit('close', index);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -30,7 +42,7 @@ const tags = computed(() => {
|
||||
</template>
|
||||
|
||||
<template v-else-if="tags.length === 1">
|
||||
<NTag :type="type" :size="size">
|
||||
<NTag :type="type" :size="size" :closable="closable" @close="handleClose(0)">
|
||||
{{ tags[0] }}
|
||||
</NTag>
|
||||
</template>
|
||||
@ -41,7 +53,14 @@ const tags = computed(() => {
|
||||
<NTag :type="type" :size="size" class="cursor-pointer">{{ tags[0] }}...({{ tags.length }})</NTag>
|
||||
</template>
|
||||
<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 }}
|
||||
</NTag>
|
||||
</NSpace>
|
||||
|
@ -19,16 +19,20 @@ interface Props {
|
||||
multiple?: boolean;
|
||||
/** 禁选用户ID */
|
||||
disabledIds?: CommonType.IdType[];
|
||||
rowKeys?: CommonType.IdType[];
|
||||
searchUserIds?: string | null;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
title: '用户选择',
|
||||
multiple: false,
|
||||
disabledIds: () => []
|
||||
disabledIds: () => [],
|
||||
rowKeys: () => [],
|
||||
searchUserIds: null
|
||||
});
|
||||
|
||||
interface Emits {
|
||||
(e: 'confirm', value: CommonType.IdType[]): void;
|
||||
(e: 'confirm', value: CommonType.IdType[], rows?: Api.System.User[]): void;
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>();
|
||||
@ -128,6 +132,23 @@ const {
|
||||
|
||||
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 deptPattern = ref<string>();
|
||||
const deptData = ref<Api.Common.CommonTreeRecord>([]);
|
||||
@ -165,38 +186,64 @@ function handleResetSearch() {
|
||||
}
|
||||
|
||||
function closeModal() {
|
||||
checkedRowKeys.value = [];
|
||||
allPagesData.value = [];
|
||||
visible.value = false;
|
||||
}
|
||||
|
||||
function handleConfirm() {
|
||||
emit('confirm', checkedRowKeys.value);
|
||||
// 获取选中行对应的用户对象(从所有页面数据中筛选)
|
||||
const selectedUsers = allPagesData.value.filter(item => checkedRowKeys.value.includes(item.userId.toString()));
|
||||
emit('confirm', checkedRowKeys.value, selectedUsers);
|
||||
closeModal();
|
||||
}
|
||||
|
||||
function getRowProps(row: Api.System.User) {
|
||||
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())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 将userId转为字符串
|
||||
const userId = row.userId.toString();
|
||||
|
||||
if (props.multiple) {
|
||||
const index = checkedRowKeys.value.findIndex(key => key === row.userId);
|
||||
const index = checkedRowKeys.value.findIndex(key => key === userId);
|
||||
if (index > -1) {
|
||||
checkedRowKeys.value.splice(index, 1);
|
||||
} else {
|
||||
checkedRowKeys.value.push(row.userId);
|
||||
checkedRowKeys.value.push(userId);
|
||||
}
|
||||
} else {
|
||||
checkedRowKeys.value = [row.userId];
|
||||
checkedRowKeys.value = [userId];
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 监听数据变化(页面切换时)
|
||||
watch(
|
||||
data,
|
||||
() => {
|
||||
updateAllPagesData();
|
||||
},
|
||||
{ deep: true }
|
||||
);
|
||||
|
||||
watch(visible, () => {
|
||||
if (visible.value) {
|
||||
getTreeData();
|
||||
getData();
|
||||
if (props.searchUserIds) {
|
||||
searchParams.userIds = props.searchUserIds;
|
||||
}
|
||||
allPagesData.value = [];
|
||||
getDataByPage();
|
||||
checkedRowKeys.value = [...props.rowKeys];
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@ -273,7 +320,7 @@ watch(visible, () => {
|
||||
:loading="loading"
|
||||
:row-props="getRowProps"
|
||||
remote
|
||||
:row-key="row => row.userId"
|
||||
:row-key="row => row.userId.toString()"
|
||||
:pagination="mobilePagination"
|
||||
class="h-full lt-sm:max-h-300px"
|
||||
/>
|
||||
|
@ -64,6 +64,7 @@ function handleTransferConfirm(ids: CommonType.IdType[]) {
|
||||
return;
|
||||
}
|
||||
model.userId = ids[0];
|
||||
model.taskId = props.taskId;
|
||||
window.$dialog?.warning({
|
||||
title: '提示',
|
||||
content: '是否确认转办?',
|
||||
@ -107,6 +108,7 @@ function handleAddSignatureConfirm(ids: CommonType.IdType[]) {
|
||||
}
|
||||
|
||||
function handleTerminate() {
|
||||
terminateModel.taskId = props.taskId;
|
||||
window.$dialog?.warning({
|
||||
title: '提示',
|
||||
content: '是否确认中止?',
|
||||
|
@ -1,8 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive, ref, watch } from 'vue';
|
||||
import type { UploadFileInfo } from 'naive-ui';
|
||||
import { useBoolean, useLoading } from '@sa/hooks';
|
||||
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';
|
||||
|
||||
defineOptions({
|
||||
@ -27,6 +28,10 @@ const emit = defineEmits<Emits>();
|
||||
const visible = defineModel<boolean>('visible', {
|
||||
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', {
|
||||
default: '流程发起'
|
||||
});
|
||||
@ -45,65 +50,263 @@ function createDefaultModel(): Model {
|
||||
fileId: null,
|
||||
flowCopyList: [],
|
||||
messageType: ['1'],
|
||||
taskVariables: {},
|
||||
variables: {},
|
||||
assigneeMap: {}
|
||||
taskVariables: null,
|
||||
variables: null,
|
||||
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() {
|
||||
const { error, data } = await fetchGetTask(props.taskId);
|
||||
if (error) return;
|
||||
task.value = data;
|
||||
function initDefault() {
|
||||
selectCopyUserList.value = [];
|
||||
selectCopyUserIds.value = [];
|
||||
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() {
|
||||
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) {
|
||||
const fileIds = fileList.value.map(item => item.id);
|
||||
model.fileId = fileIds.join(',');
|
||||
}
|
||||
model.taskId = props.taskId;
|
||||
model.taskVariables = props.taskVariables;
|
||||
const { error } = await fetchCompleteTask(model);
|
||||
if (error) return;
|
||||
window.$message?.success('提交成功');
|
||||
visible.value = false;
|
||||
emit('finished');
|
||||
model.variables = props.taskVariables;
|
||||
startBtnLoading();
|
||||
startBaseFormLoading();
|
||||
try {
|
||||
const { error } = await fetchCompleteTask(model);
|
||||
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, () => {
|
||||
if (visible.value) {
|
||||
initDefault();
|
||||
getTask();
|
||||
Object.assign(model, createDefaultModel());
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<NModal v-model:show="visible" preset="card" class="w-700px" :title="title" :native-scrollbar="false" closable>
|
||||
<NForm :model="model">
|
||||
<NFormItem label="通知方式" path="messageType">
|
||||
<NCheckboxGroup v-model:value="model.messageType">
|
||||
<NSpace item-style="display: flex;">
|
||||
<NCheckbox
|
||||
v-for="item in messageTypeOptions"
|
||||
:key="item.value"
|
||||
:disabled="item.value === '1'"
|
||||
:value="item.value"
|
||||
:label="item.label"
|
||||
<NModal v-model:show="visible" preset="card" class="w-800px" :title="title" :native-scrollbar="false" closable>
|
||||
<NSpin :show="baseFormLoading">
|
||||
<NForm :model="model" label-placement="left" :label-width="100">
|
||||
<NFormItem label="通知方式" path="messageType">
|
||||
<NCheckboxGroup v-model:value="model.messageType">
|
||||
<NSpace item-style="display: flex;">
|
||||
<NCheckbox
|
||||
v-for="item in messageTypeOptions"
|
||||
:key="item.value"
|
||||
:disabled="item.value === '1'"
|
||||
: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>
|
||||
</NCheckboxGroup>
|
||||
</NFormItem>
|
||||
<NFormItem label="附件" path="fileId">
|
||||
<FileUpload v-model:file-list="fileList" :file-size="20" :max="20" upload-type="file" :accept="accept" />
|
||||
</NFormItem>
|
||||
</NForm>
|
||||
<div class="flex justify-end gap-12px">
|
||||
<NButton @click="visible = false">取消</NButton>
|
||||
<NButton type="primary" @click="handleSubmit">提交</NButton>
|
||||
</div>
|
||||
</NFormItem>
|
||||
<NFormItem
|
||||
v-if="buttonPerm.pop && nestNodeList && nestNodeList.length > 0"
|
||||
label="下一步审批人"
|
||||
path="assigneeMap"
|
||||
>
|
||||
<NSpace>
|
||||
<div v-for="(item, index) in nestNodeList" :key="index">
|
||||
<span>【{{ item.nodeName }}】:</span>
|
||||
<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>
|
||||
<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>
|
||||
|
@ -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) {
|
||||
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<
|
||||
Pick<User, 'deptId' | 'userName' | 'nickName' | 'phonenumber' | 'status'> & {
|
||||
roleId: CommonType.IdType;
|
||||
userIds: string;
|
||||
} & 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[];
|
||||
}
|
||||
>;
|
||||
type TaskNextNodeSearchParams = CommonType.RecordNullable<{
|
||||
taskId: CommonType.IdType;
|
||||
taskVariables: { [key: string]: any };
|
||||
}>;
|
||||
|
||||
/** 消息类型 */
|
||||
type MessageType = '1' | '2' | '3';
|
||||
@ -455,5 +459,48 @@ declare namespace Api {
|
||||
/** 扩展字段 */
|
||||
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[];
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user