|
|
@@ -3,7 +3,7 @@ import { flushSync } from 'react-dom';
|
|
|
import { useNavigate } from 'react-router-dom';
|
|
|
import { useTranslation } from 'react-i18next';
|
|
|
import { Plus, Search, Edit2, Trash2, MoreVertical, FileText, Eye, Play, CheckCircle, RefreshCw, Workflow, Hand } from 'lucide-react';
|
|
|
-import { Button, Input, Space, Select, Table as AntdTable, message, Modal, Form, Row, Col, Tabs, Radio, DatePicker, Checkbox, Tooltip, Switch as AntdSwitch } from 'antd';
|
|
|
+import { Button, Input, Space, Select, TreeSelect, Table as AntdTable, message, Modal, Form, Row, Col, Tabs, Radio, DatePicker, Checkbox, Tooltip, Switch as AntdSwitch } from 'antd';
|
|
|
import { Button as UIButton } from './ui/button';
|
|
|
import type { ColumnsType } from 'antd/es/table';
|
|
|
import { workflowDesignApi, WorkflowDesignVO } from '../api/WorkflowDesign';
|
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
WarningOutlined,
|
|
|
} from '@ant-design/icons';
|
|
|
import { userApi, UserVO } from '../api/user';
|
|
|
+import { deptApi, type DeptVO } from '../api/dept';
|
|
|
import { segregationPointApi, SegregationPointVO } from '../api/spm';
|
|
|
import { getFormPage, getForm, FormVO } from '../api/bpm/form';
|
|
|
import urgecy1Icon from '../assets/urgecy1.png';
|
|
|
@@ -57,6 +58,59 @@ interface IsolationWorkProps {
|
|
|
subMenu: string;
|
|
|
}
|
|
|
|
|
|
+/** 抄送部门/人员 ID:支持数组、逗号分隔字符串、JSON 数组字符串,兼容旧 cc* 单选 */
|
|
|
+function parseWorkflowCopyIds(multi: unknown, legacySingle: unknown): string[] {
|
|
|
+ const pushValid = (out: string[], x: unknown) => {
|
|
|
+ if (x !== undefined && x !== null && x !== '') out.push(String(x));
|
|
|
+ };
|
|
|
+ if (Array.isArray(multi)) {
|
|
|
+ const out: string[] = [];
|
|
|
+ multi.forEach((x) => pushValid(out, x));
|
|
|
+ return out;
|
|
|
+ }
|
|
|
+ if (typeof multi === 'string' && multi.trim()) {
|
|
|
+ try {
|
|
|
+ const parsed = JSON.parse(multi);
|
|
|
+ if (Array.isArray(parsed)) return parseWorkflowCopyIds(parsed, undefined);
|
|
|
+ if (parsed !== null && parsed !== undefined && parsed !== '') {
|
|
|
+ return [String(parsed)];
|
|
|
+ }
|
|
|
+ } catch {
|
|
|
+ /* 非 JSON:逗号分隔 ID,如 "380,381" */
|
|
|
+ return multi
|
|
|
+ .split(',')
|
|
|
+ .map((s) => s.trim())
|
|
|
+ .filter((s) => s !== '');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (legacySingle !== undefined && legacySingle !== null && legacySingle !== '') {
|
|
|
+ return [String(legacySingle)];
|
|
|
+ }
|
|
|
+ return [];
|
|
|
+}
|
|
|
+
|
|
|
+function workflowCopyDeptIds(nodeData: any, nodeDO?: any): string[] {
|
|
|
+ return parseWorkflowCopyIds(
|
|
|
+ nodeData?.copyDeptIds ?? nodeDO?.copyDeptIds,
|
|
|
+ nodeData?.ccDeptId ?? nodeDO?.ccDeptId
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+function workflowCopyUserIds(nodeData: any, nodeDO?: any): string[] {
|
|
|
+ return parseWorkflowCopyIds(
|
|
|
+ nodeData?.copyUserIds ?? nodeDO?.copyUserIds,
|
|
|
+ nodeData?.ccUserId ?? nodeDO?.ccUserId
|
|
|
+ );
|
|
|
+}
|
|
|
+
|
|
|
+/** 更新作业节点接口要求 copyDeptIds/copyUserIds 为逗号分隔字符串,不能为 JSON 数组 */
|
|
|
+function workflowCopyIdsToApiCommaString(ids: readonly (string | number)[]): string {
|
|
|
+ return ids
|
|
|
+ .map((id) => String(id).trim())
|
|
|
+ .filter((s) => s !== '')
|
|
|
+ .join(',');
|
|
|
+}
|
|
|
+
|
|
|
// 节点配置(从ProcessDesigner复制)
|
|
|
const nodeConfigs = [
|
|
|
{
|
|
|
@@ -419,6 +473,8 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
messageTemplateCode: 'false',
|
|
|
emailTemplateCode: 'false',
|
|
|
appTemplateCode: 'false',
|
|
|
+ copyDeptIds: [] as string[],
|
|
|
+ copyUserIds: [] as string[],
|
|
|
});
|
|
|
|
|
|
// 节点配置缓存(Map<nodeId, config>)
|
|
|
@@ -458,8 +514,97 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
const [workflowDrawerUsers, setWorkflowDrawerUsers] = useState<UserVO[]>([]);
|
|
|
const [workflowLockerUsers, setWorkflowLockerUsers] = useState<UserVO[]>([]);
|
|
|
const [workflowColockerUsers, setWorkflowColockerUsers] = useState<UserVO[]>([]);
|
|
|
+ const [workflowCcDeptList, setWorkflowCcDeptList] = useState<DeptVO[]>([]);
|
|
|
+ const [workflowCcUserList, setWorkflowCcUserList] = useState<UserVO[]>([]);
|
|
|
+ const workflowCcDeptTreeData = useMemo(() => {
|
|
|
+ const nodeMap = new Map<string, any>();
|
|
|
+ const roots: any[] = [];
|
|
|
+ workflowCcDeptList.forEach((dept) => {
|
|
|
+ const id = String(dept.id);
|
|
|
+ nodeMap.set(id, {
|
|
|
+ key: `dept-${id}`,
|
|
|
+ value: id,
|
|
|
+ title: dept.name,
|
|
|
+ children: [] as any[],
|
|
|
+ });
|
|
|
+ });
|
|
|
+ workflowCcDeptList.forEach((dept) => {
|
|
|
+ const id = String(dept.id);
|
|
|
+ const parentId = String(dept.parentId ?? '');
|
|
|
+ const node = nodeMap.get(id);
|
|
|
+ const parent = nodeMap.get(parentId);
|
|
|
+ if (parent && parentId !== id) {
|
|
|
+ parent.children.push(node);
|
|
|
+ } else {
|
|
|
+ roots.push(node);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return roots;
|
|
|
+ }, [workflowCcDeptList]);
|
|
|
+ const workflowCcUserTreeData = useMemo(() => {
|
|
|
+ const buildDeptNode = (node: any): any => ({
|
|
|
+ key: node.key,
|
|
|
+ value: node.value,
|
|
|
+ title: node.title,
|
|
|
+ selectable: false,
|
|
|
+ children: (node.children || []).map((c: any) => buildDeptNode(c)),
|
|
|
+ });
|
|
|
+ const roots = workflowCcDeptTreeData.map((n: any) => buildDeptNode(n));
|
|
|
+ const deptNodeMap = new Map<string, any>();
|
|
|
+ const walk = (nodes: any[]) => {
|
|
|
+ nodes.forEach((n) => {
|
|
|
+ deptNodeMap.set(String(n.value), n);
|
|
|
+ if (Array.isArray(n.children) && n.children.length > 0) walk(n.children);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ walk(roots);
|
|
|
+ const unknownDeptNode = {
|
|
|
+ key: 'workflow-dept-unknown',
|
|
|
+ value: 'unknown',
|
|
|
+ title: '未分配部门',
|
|
|
+ selectable: false,
|
|
|
+ children: [] as any[],
|
|
|
+ };
|
|
|
+ workflowCcUserList.forEach((user) => {
|
|
|
+ const userNode = {
|
|
|
+ key: `workflow-user-${user.id}`,
|
|
|
+ value: String(user.id),
|
|
|
+ title: user.nickname || user.username,
|
|
|
+ isLeaf: true,
|
|
|
+ };
|
|
|
+ const deptKey = user.deptId !== undefined && user.deptId !== null ? String(user.deptId) : '';
|
|
|
+ const deptNode = deptNodeMap.get(deptKey);
|
|
|
+ if (deptNode) {
|
|
|
+ deptNode.children = [...(deptNode.children || []), userNode];
|
|
|
+ } else {
|
|
|
+ unknownDeptNode.children.push(userNode);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (unknownDeptNode.children.length > 0) {
|
|
|
+ roots.push(unknownDeptNode);
|
|
|
+ }
|
|
|
+ return roots;
|
|
|
+ }, [workflowCcDeptTreeData, workflowCcUserList]);
|
|
|
const [workflowIsolationPoints, setWorkflowIsolationPoints] = useState<SegregationPointVO[]>([]);
|
|
|
const [workflowFormList, setWorkflowFormList] = useState<FormVO[]>([]);
|
|
|
+
|
|
|
+ const isTemplateEnabled = useCallback((value: any): boolean => {
|
|
|
+ return value === true || value === 'true' || value === 1 || value === '1';
|
|
|
+ }, []);
|
|
|
+
|
|
|
+ const resolveNotificationMethods = useCallback((source: any, fallback?: any) => {
|
|
|
+ const methods = source?.notificationMethods || {};
|
|
|
+ const smsCode = source?.smsTemplateCode ?? fallback?.smsTemplateCode;
|
|
|
+ const messageCode = source?.messageTemplateCode ?? fallback?.messageTemplateCode;
|
|
|
+ const emailCode = source?.emailTemplateCode ?? fallback?.emailTemplateCode;
|
|
|
+ const appCode = source?.appTemplateCode ?? fallback?.appTemplateCode;
|
|
|
+ return {
|
|
|
+ sms: (methods.sms === true || methods.sms === 'true') || isTemplateEnabled(smsCode),
|
|
|
+ message: (methods.message === true || methods.message === 'true') || isTemplateEnabled(messageCode),
|
|
|
+ email: (methods.email === true || methods.email === 'true') || isTemplateEnabled(emailCode),
|
|
|
+ app: (methods.app === true || methods.app === 'true') || isTemplateEnabled(appCode),
|
|
|
+ };
|
|
|
+ }, [isTemplateEnabled]);
|
|
|
|
|
|
// 流程设计列表数据(用于流程设计页面)
|
|
|
const [processDesignList, setProcessDesignList] = useState<WorkflowDesignVO[]>([]);
|
|
|
@@ -1273,14 +1418,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: source.isolationNodeUuid || '',
|
|
|
lockPerson: source.lockPerson ? (typeof source.lockPerson === 'number' ? source.lockPerson : Number(source.lockPerson)) : undefined,
|
|
|
coLockPersons: source.coLockPersons && Array.isArray(source.coLockPersons) ? source.coLockPersons.map((id: any) => typeof id === 'number' ? id : Number(id)) : [],
|
|
|
- notificationMethods: source.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(source),
|
|
|
notificationPerson: source.notificationPerson || '',
|
|
|
notificationTime: source.notificationTime || '',
|
|
|
+ smsTemplateCode: source.smsTemplateCode || 'false',
|
|
|
+ messageTemplateCode: source.messageTemplateCode || 'false',
|
|
|
+ emailTemplateCode: source.emailTemplateCode || 'false',
|
|
|
+ appTemplateCode: source.appTemplateCode || 'false',
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source),
|
|
|
+ copyUserIds: workflowCopyUserIds(source),
|
|
|
});
|
|
|
// 高亮第一个节点
|
|
|
setWorkflowNodes((nds) =>
|
|
|
@@ -1393,6 +1539,19 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
console.error('加载表单列表失败:', error);
|
|
|
}
|
|
|
};
|
|
|
+
|
|
|
+ const loadCcOptions = async () => {
|
|
|
+ try {
|
|
|
+ const [depts, users] = await Promise.all([
|
|
|
+ deptApi.getSimpleDeptList(),
|
|
|
+ userApi.getSimpleUserList(),
|
|
|
+ ]);
|
|
|
+ setWorkflowCcDeptList(depts || []);
|
|
|
+ setWorkflowCcUserList(users || []);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('加载抄送下拉数据失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
|
|
|
// 初始化节点状态:调用 checkWorkById 和 selectWorkflowWorkById 接口
|
|
|
const initializeNodeStates = async () => {
|
|
|
@@ -1474,18 +1633,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
}
|
|
|
return coLockPersonIds.length > 0 ? coLockPersonIds : (nodeData.coLockPersons && Array.isArray(nodeData.coLockPersons) ? nodeData.coLockPersons.map((id: any) => typeof id === 'number' ? id : Number(id)) : []);
|
|
|
})(),
|
|
|
- notificationMethods: nodeData.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(nodeData, nodeDO),
|
|
|
notificationPerson: nodeData.notificationPerson || '',
|
|
|
notificationTime: nodeDO.notifyTime || nodeData.notificationTime || '',
|
|
|
smsTemplateCode: nodeData.smsTemplateCode || (nodeData.notificationMethods?.sms ? 'true' : 'false'),
|
|
|
messageTemplateCode: nodeData.messageTemplateCode || (nodeData.notificationMethods?.message ? 'true' : 'false'),
|
|
|
emailTemplateCode: nodeData.emailTemplateCode || (nodeData.notificationMethods?.email ? 'true' : 'false'),
|
|
|
appTemplateCode: nodeData.appTemplateCode || (nodeData.notificationMethods?.app ? 'true' : 'false'),
|
|
|
+ copyDeptIds: workflowCopyDeptIds(nodeData, nodeDO),
|
|
|
+ copyUserIds: workflowCopyUserIds(nodeData, nodeDO),
|
|
|
};
|
|
|
|
|
|
// 将节点配置存入缓存
|
|
|
@@ -1689,14 +1845,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
}
|
|
|
return coLockPersonIds.length > 0 ? coLockPersonIds : (nodeData.coLockPersons && Array.isArray(nodeData.coLockPersons) ? nodeData.coLockPersons.map((id: any) => typeof id === 'number' ? id : Number(id)) : []);
|
|
|
})(),
|
|
|
- notificationMethods: nodeData.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(nodeData, nodeDO),
|
|
|
notificationPerson: nodeData.notificationPerson || '',
|
|
|
notificationTime: nodeDO.notifyTime || nodeData.notificationTime || '',
|
|
|
+ smsTemplateCode: nodeData.smsTemplateCode || (nodeData.notificationMethods?.sms ? 'true' : 'false'),
|
|
|
+ messageTemplateCode: nodeData.messageTemplateCode || (nodeData.notificationMethods?.message ? 'true' : 'false'),
|
|
|
+ emailTemplateCode: nodeData.emailTemplateCode || (nodeData.notificationMethods?.email ? 'true' : 'false'),
|
|
|
+ appTemplateCode: nodeData.appTemplateCode || (nodeData.notificationMethods?.app ? 'true' : 'false'),
|
|
|
+ copyDeptIds: workflowCopyDeptIds(nodeData, nodeDO),
|
|
|
+ copyUserIds: workflowCopyUserIds(nodeData, nodeDO),
|
|
|
});
|
|
|
} else {
|
|
|
// 如果既没有缓存也没有 nodeDO,使用节点原始数据
|
|
|
@@ -1714,14 +1871,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: source.isolationNodeUuid || '',
|
|
|
lockPerson: source.lockPerson ? (typeof source.lockPerson === 'number' ? source.lockPerson : Number(source.lockPerson)) : undefined,
|
|
|
coLockPersons: source.coLockPersons && Array.isArray(source.coLockPersons) ? source.coLockPersons.map((id: any) => typeof id === 'number' ? id : Number(id)) : [],
|
|
|
- notificationMethods: source.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(source),
|
|
|
notificationPerson: source.notificationPerson || '',
|
|
|
notificationTime: source.notificationTime || '',
|
|
|
+ smsTemplateCode: source.smsTemplateCode || 'false',
|
|
|
+ messageTemplateCode: source.messageTemplateCode || 'false',
|
|
|
+ emailTemplateCode: source.emailTemplateCode || 'false',
|
|
|
+ appTemplateCode: source.appTemplateCode || 'false',
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source),
|
|
|
+ copyUserIds: workflowCopyUserIds(source),
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
@@ -1746,6 +1904,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
loadRoleUsers();
|
|
|
loadIsolationPoints();
|
|
|
loadFormList();
|
|
|
+ loadCcOptions();
|
|
|
initializeNodeStates();
|
|
|
}
|
|
|
}, [workJobStep, workflowWorkId]);
|
|
|
@@ -2033,13 +2192,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: nodeDO.isolationNodeUuid || source.isolationNodeUuid || '',
|
|
|
lockPerson: fromIsolationOnly ? (lockPersonId || undefined) : (lockPersonId || (source.lockPerson ? (typeof source.lockPerson === 'number' ? source.lockPerson : Number(source.lockPerson)) : undefined)),
|
|
|
coLockPersons: fromIsolationOnly ? coLockPersonIds : (coLockPersonIds.length > 0 ? coLockPersonIds : (source.coLockPersons && Array.isArray(source.coLockPersons) ? source.coLockPersons.map((id: any) => typeof id === 'number' ? id : Number(id)) : [])),
|
|
|
- notificationMethods: source.notificationMethods || { sms: false, message: false, email: false, app: false },
|
|
|
+ notificationMethods: resolveNotificationMethods(source, dataSource),
|
|
|
notificationPerson: source.notificationPerson || '',
|
|
|
notificationTime: fromIsolationOnly ? (dataSource.notifyTime ?? '') : (dataSource.notifyTime || source.notificationTime || ''),
|
|
|
smsTemplateCode: source.smsTemplateCode || 'false',
|
|
|
messageTemplateCode: source.messageTemplateCode || 'false',
|
|
|
emailTemplateCode: source.emailTemplateCode || 'false',
|
|
|
appTemplateCode: source.appTemplateCode || 'false',
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source, nodeDO),
|
|
|
+ copyUserIds: workflowCopyUserIds(source, nodeDO),
|
|
|
};
|
|
|
|
|
|
if (isReleaseIsolation && isolationNodeDO) {
|
|
|
@@ -2077,18 +2238,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: source.isolationNodeUuid || '',
|
|
|
lockPerson: source.lockPerson ? (typeof source.lockPerson === 'number' ? source.lockPerson : Number(source.lockPerson)) : undefined,
|
|
|
coLockPersons: source.coLockPersons && Array.isArray(source.coLockPersons) ? source.coLockPersons.map((id: any) => typeof id === 'number' ? id : Number(id)) : [],
|
|
|
- notificationMethods: source.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(source),
|
|
|
notificationPerson: source.notificationPerson || '',
|
|
|
notificationTime: source.notificationTime || '',
|
|
|
smsTemplateCode: source.smsTemplateCode || 'false',
|
|
|
messageTemplateCode: source.messageTemplateCode || 'false',
|
|
|
emailTemplateCode: source.emailTemplateCode || 'false',
|
|
|
appTemplateCode: source.appTemplateCode || 'false',
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source),
|
|
|
+ copyUserIds: workflowCopyUserIds(source),
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
@@ -2131,6 +2289,8 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
messageTemplateCode: workflowNodeConfig.messageTemplateCode,
|
|
|
emailTemplateCode: workflowNodeConfig.emailTemplateCode,
|
|
|
appTemplateCode: workflowNodeConfig.appTemplateCode,
|
|
|
+ copyDeptIds: workflowNodeConfig.copyDeptIds,
|
|
|
+ copyUserIds: workflowNodeConfig.copyUserIds,
|
|
|
// 保持 completed 状态从缓存中读取,不覆盖
|
|
|
completed: isSaved,
|
|
|
};
|
|
|
@@ -2414,14 +2574,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: firstNodeDO.isolationNodeUuid || source.isolationNodeUuid || '',
|
|
|
lockPerson: lockPersonId || source.lockPerson || '',
|
|
|
coLockPersons: coLockPersonIds.length > 0 ? coLockPersonIds : (source.coLockPersons || []),
|
|
|
- notificationMethods: source.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(source, firstNodeDO),
|
|
|
notificationPerson: source.notificationPerson || '',
|
|
|
notificationTime: firstNodeDO.notifyTime || source.notificationTime || '',
|
|
|
+ smsTemplateCode: source.smsTemplateCode || (source.notificationMethods?.sms ? 'true' : 'false'),
|
|
|
+ messageTemplateCode: source.messageTemplateCode || (source.notificationMethods?.message ? 'true' : 'false'),
|
|
|
+ emailTemplateCode: source.emailTemplateCode || (source.notificationMethods?.email ? 'true' : 'false'),
|
|
|
+ appTemplateCode: source.appTemplateCode || (source.notificationMethods?.app ? 'true' : 'false'),
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source, firstNodeDO),
|
|
|
+ copyUserIds: workflowCopyUserIds(source, firstNodeDO),
|
|
|
});
|
|
|
} else {
|
|
|
// 如果没有找到 nodeDO,使用原有逻辑
|
|
|
@@ -2439,14 +2600,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: source.isolationNodeUuid || '',
|
|
|
lockPerson: source.lockPerson || '',
|
|
|
coLockPersons: source.coLockPersons || [],
|
|
|
- notificationMethods: source.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(source),
|
|
|
notificationPerson: source.notificationPerson || '',
|
|
|
notificationTime: source.notificationTime || '',
|
|
|
+ smsTemplateCode: source.smsTemplateCode || 'false',
|
|
|
+ messageTemplateCode: source.messageTemplateCode || 'false',
|
|
|
+ emailTemplateCode: source.emailTemplateCode || 'false',
|
|
|
+ appTemplateCode: source.appTemplateCode || 'false',
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source),
|
|
|
+ copyUserIds: workflowCopyUserIds(source),
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -5037,6 +5199,63 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
+ <div>
|
|
|
+ <label className="block text-sm font-medium text-gray-700 mb-3">
|
|
|
+ 通知对象
|
|
|
+ </label>
|
|
|
+ <div className="mb-3 space-y-1 text-xs text-gray-500">
|
|
|
+ <div>1. 系统将默认发送消息给任务负责人(或上锁人\共锁人)</div>
|
|
|
+ <div>2. 请选择消息抄送对象:</div>
|
|
|
+ </div>
|
|
|
+ <div className="space-y-3 bg-gray-50 p-3 rounded-lg">
|
|
|
+ <div>
|
|
|
+ <label className="block text-sm font-medium text-gray-700 mb-2">
|
|
|
+ 抄送给部门(部门下的所有人):
|
|
|
+ </label>
|
|
|
+ <TreeSelect
|
|
|
+ multiple
|
|
|
+ value={workflowNodeConfig.copyDeptIds.length ? workflowNodeConfig.copyDeptIds : undefined}
|
|
|
+ onChange={(value) =>
|
|
|
+ setWorkflowNodeConfig({
|
|
|
+ ...workflowNodeConfig,
|
|
|
+ copyDeptIds: Array.isArray(value) ? value.map(String) : value != null && value !== '' ? [String(value)] : [],
|
|
|
+ })
|
|
|
+ }
|
|
|
+ placeholder="请选择部门(可多选)"
|
|
|
+ treeData={workflowCcDeptTreeData}
|
|
|
+ className="w-full"
|
|
|
+ allowClear
|
|
|
+ showSearch
|
|
|
+ treeNodeFilterProp="title"
|
|
|
+ treeDefaultExpandAll
|
|
|
+ disabled={isViewMode || selectedWorkflowNode.data?.type === 'releaseIsolation'}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div>
|
|
|
+ <label className="block text-sm font-medium text-gray-700 mb-2">
|
|
|
+ 抄送给人员:
|
|
|
+ </label>
|
|
|
+ <TreeSelect
|
|
|
+ multiple
|
|
|
+ value={workflowNodeConfig.copyUserIds.length ? workflowNodeConfig.copyUserIds : undefined}
|
|
|
+ onChange={(value) =>
|
|
|
+ setWorkflowNodeConfig({
|
|
|
+ ...workflowNodeConfig,
|
|
|
+ copyUserIds: Array.isArray(value) ? value.map(String) : value != null && value !== '' ? [String(value)] : [],
|
|
|
+ })
|
|
|
+ }
|
|
|
+ placeholder="请选择人员(可多选)"
|
|
|
+ treeData={workflowCcUserTreeData}
|
|
|
+ className="w-full"
|
|
|
+ allowClear
|
|
|
+ showSearch
|
|
|
+ treeNodeFilterProp="title"
|
|
|
+ treeDefaultExpandAll
|
|
|
+ disabled={isViewMode || selectedWorkflowNode.data?.type === 'releaseIsolation'}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
{/* <div>
|
|
|
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
|
通知人
|
|
|
@@ -5195,6 +5414,8 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
.map((u: any) => Number(u.userId));
|
|
|
// 共锁人:有则传 JSON 字符串,清空时传空字符串以便后端清空
|
|
|
const colockPersons = colockPersonIds.length > 0 ? JSON.stringify(colockPersonIds) : '';
|
|
|
+ const copyDeptIdsStr = workflowCopyIdsToApiCommaString(workflowNodeConfig.copyDeptIds);
|
|
|
+ const copyUserIdsStr = workflowCopyIdsToApiCommaString(workflowNodeConfig.copyUserIds);
|
|
|
|
|
|
const updateParam: UpdateWorkflowWorkNodeParam = {
|
|
|
nodeId: nodeDO.id,
|
|
|
@@ -5219,6 +5440,9 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
messageTemplateCode: workflowNodeConfig.messageTemplateCode || 'false',
|
|
|
emailTemplateCode: workflowNodeConfig.emailTemplateCode || 'false',
|
|
|
appTemplateCode: workflowNodeConfig.appTemplateCode || 'false',
|
|
|
+ // 后端要求逗号分隔字符串,禁止 JSON 数组(如 [380])
|
|
|
+ copyDeptIds: copyDeptIdsStr,
|
|
|
+ copyUserIds: copyUserIdsStr,
|
|
|
};
|
|
|
|
|
|
await workJobApi.updateWorkflowWorkNode(updateParam);
|
|
|
@@ -5292,7 +5516,7 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: nodeDO.isolationNodeUuid ?? source.isolationNodeUuid ?? '',
|
|
|
lockPerson: lockPersonVal !== undefined ? lockPersonVal : source.lockPerson,
|
|
|
coLockPersons: coLockPersonIds.length > 0 ? coLockPersonIds : (source.coLockPersons || []),
|
|
|
- notificationMethods: source.notificationMethods || { sms: false, message: false, email: false, app: false },
|
|
|
+ notificationMethods: resolveNotificationMethods(source, nodeDO),
|
|
|
notificationPerson: source.notificationPerson ?? '',
|
|
|
notificationTime: nodeDO.notifyTime ?? source.notificationTime ?? '',
|
|
|
completed: isCurrent ? true : (node.data?.completed ?? false),
|
|
|
@@ -5448,9 +5672,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: nodeDO.isolationNodeUuid ?? source.isolationNodeUuid ?? '',
|
|
|
lockPerson: lockPersonVal !== undefined ? lockPersonVal : source.lockPerson,
|
|
|
coLockPersons: coLockPersonIds.length > 0 ? coLockPersonIds : (source.coLockPersons || []),
|
|
|
- notificationMethods: source.notificationMethods || { sms: false, message: false, email: false, app: false },
|
|
|
+ notificationMethods: resolveNotificationMethods(source, nodeDO),
|
|
|
notificationPerson: source.notificationPerson ?? '',
|
|
|
notificationTime: nodeDO.notifyTime ?? source.notificationTime ?? '',
|
|
|
+ smsTemplateCode: source.smsTemplateCode ?? (source.notificationMethods?.sms ? 'true' : 'false'),
|
|
|
+ messageTemplateCode: source.messageTemplateCode ?? (source.notificationMethods?.message ? 'true' : 'false'),
|
|
|
+ emailTemplateCode: source.emailTemplateCode ?? (source.notificationMethods?.email ? 'true' : 'false'),
|
|
|
+ appTemplateCode: source.appTemplateCode ?? (source.notificationMethods?.app ? 'true' : 'false'),
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source, nodeDO),
|
|
|
+ copyUserIds: workflowCopyUserIds(source, nodeDO),
|
|
|
completed: isCurrent ? true : (node.data?.completed ?? false),
|
|
|
};
|
|
|
return { ...node, data: updatedData, selected: isCurrent ? false : node.selected };
|
|
|
@@ -5493,6 +5723,12 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
notificationMethods: workflowNodeConfig.notificationMethods,
|
|
|
notificationPerson: workflowNodeConfig.notificationPerson,
|
|
|
notificationTime: workflowNodeConfig.notificationTime,
|
|
|
+ smsTemplateCode: workflowNodeConfig.smsTemplateCode,
|
|
|
+ messageTemplateCode: workflowNodeConfig.messageTemplateCode,
|
|
|
+ emailTemplateCode: workflowNodeConfig.emailTemplateCode,
|
|
|
+ appTemplateCode: workflowNodeConfig.appTemplateCode,
|
|
|
+ copyDeptIds: workflowCopyIdsToApiCommaString(workflowNodeConfig.copyDeptIds),
|
|
|
+ copyUserIds: workflowCopyIdsToApiCommaString(workflowNodeConfig.copyUserIds),
|
|
|
};
|
|
|
})()),
|
|
|
};
|
|
|
@@ -5537,6 +5773,12 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
notificationMethods: workflowNodeConfig.notificationMethods,
|
|
|
notificationPerson: workflowNodeConfig.notificationPerson,
|
|
|
notificationTime: workflowNodeConfig.notificationTime,
|
|
|
+ smsTemplateCode: workflowNodeConfig.smsTemplateCode,
|
|
|
+ messageTemplateCode: workflowNodeConfig.messageTemplateCode,
|
|
|
+ emailTemplateCode: workflowNodeConfig.emailTemplateCode,
|
|
|
+ appTemplateCode: workflowNodeConfig.appTemplateCode,
|
|
|
+ copyDeptIds: workflowNodeConfig.copyDeptIds,
|
|
|
+ copyUserIds: workflowNodeConfig.copyUserIds,
|
|
|
completed: true,
|
|
|
};
|
|
|
setWorkflowNodes((nds) =>
|
|
|
@@ -5614,14 +5856,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
}
|
|
|
return coLockPersonIds.length > 0 ? coLockPersonIds : (source.coLockPersons && Array.isArray(source.coLockPersons) ? source.coLockPersons.map((id: any) => typeof id === 'number' ? id : Number(id)) : []);
|
|
|
})(),
|
|
|
- notificationMethods: source.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(source, nextNodeDO),
|
|
|
notificationPerson: source.notificationPerson || '',
|
|
|
notificationTime: nextNodeDO.notifyTime || source.notificationTime || '',
|
|
|
+ smsTemplateCode: source.smsTemplateCode || (source.notificationMethods?.sms ? 'true' : 'false'),
|
|
|
+ messageTemplateCode: source.messageTemplateCode || (source.notificationMethods?.message ? 'true' : 'false'),
|
|
|
+ emailTemplateCode: source.emailTemplateCode || (source.notificationMethods?.email ? 'true' : 'false'),
|
|
|
+ appTemplateCode: source.appTemplateCode || (source.notificationMethods?.app ? 'true' : 'false'),
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source, nextNodeDO),
|
|
|
+ copyUserIds: workflowCopyUserIds(source, nextNodeDO),
|
|
|
});
|
|
|
} else {
|
|
|
const source = nextNode.data || {};
|
|
|
@@ -5638,14 +5881,15 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
isolationNodeUuid: source.isolationNodeUuid || '',
|
|
|
lockPerson: source.lockPerson || '',
|
|
|
coLockPersons: source.coLockPersons || [],
|
|
|
- notificationMethods: source.notificationMethods || {
|
|
|
- sms: false,
|
|
|
- message: false,
|
|
|
- email: false,
|
|
|
- app: false,
|
|
|
- },
|
|
|
+ notificationMethods: resolveNotificationMethods(source),
|
|
|
notificationPerson: source.notificationPerson || '',
|
|
|
notificationTime: source.notificationTime || '',
|
|
|
+ smsTemplateCode: source.smsTemplateCode || 'false',
|
|
|
+ messageTemplateCode: source.messageTemplateCode || 'false',
|
|
|
+ emailTemplateCode: source.emailTemplateCode || 'false',
|
|
|
+ appTemplateCode: source.appTemplateCode || 'false',
|
|
|
+ copyDeptIds: workflowCopyDeptIds(source),
|
|
|
+ copyUserIds: workflowCopyUserIds(source),
|
|
|
});
|
|
|
}
|
|
|
}
|