|
|
@@ -626,6 +626,43 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
// 流程设计列表数据(用于流程模板下拉框)
|
|
|
const [workflowTemplateList, setWorkflowTemplateList] = useState<WorkflowDesignVO[]>([]);
|
|
|
|
|
|
+ // iPad(iOS Safari) 触摸场景:点击页面空白处不会触发 Select blur,导致下拉不收起
|
|
|
+ const workflowTemplateSelectWrapRef = useRef<HTMLDivElement | null>(null);
|
|
|
+ const jobCategorySelectWrapRef = useRef<HTMLDivElement | null>(null);
|
|
|
+ const workflowTemplateSelectRef = useRef<any>(null);
|
|
|
+ const jobCategorySelectRef = useRef<any>(null);
|
|
|
+ const [workflowTemplateDropdownVisible, setWorkflowTemplateDropdownVisible] = useState(false);
|
|
|
+ const [jobCategoryDropdownVisible, setJobCategoryDropdownVisible] = useState(false);
|
|
|
+
|
|
|
+ useEffect(() => {
|
|
|
+ if (!workflowTemplateDropdownVisible && !jobCategoryDropdownVisible) return;
|
|
|
+
|
|
|
+ const closeIfPointerOutside = (evt: Event) => {
|
|
|
+ const target = (evt.target as HTMLElement | null);
|
|
|
+ if (!target) return;
|
|
|
+
|
|
|
+ const inWrap =
|
|
|
+ (workflowTemplateSelectWrapRef.current && workflowTemplateSelectWrapRef.current.contains(target)) ||
|
|
|
+ (jobCategorySelectWrapRef.current && jobCategorySelectWrapRef.current.contains(target));
|
|
|
+ const inDropdown = !!target.closest?.('.ant-select-dropdown');
|
|
|
+
|
|
|
+ if (!inWrap && !inDropdown) {
|
|
|
+ // 不控制 open,直接 blur 让 antd 自己收起下拉,避免影响 Form 取值
|
|
|
+ workflowTemplateSelectRef.current?.blur?.();
|
|
|
+ jobCategorySelectRef.current?.blur?.();
|
|
|
+ setWorkflowTemplateDropdownVisible(false);
|
|
|
+ setJobCategoryDropdownVisible(false);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ document.addEventListener('touchstart', closeIfPointerOutside, { passive: true });
|
|
|
+ document.addEventListener('mousedown', closeIfPointerOutside);
|
|
|
+ return () => {
|
|
|
+ document.removeEventListener('touchstart', closeIfPointerOutside as any);
|
|
|
+ document.removeEventListener('mousedown', closeIfPointerOutside as any);
|
|
|
+ };
|
|
|
+ }, [workflowTemplateDropdownVisible, jobCategoryDropdownVisible]);
|
|
|
+
|
|
|
// 作业管理列表数据
|
|
|
const [workJobList, setWorkJobList] = useState<WorkJobVO[]>([]);
|
|
|
const [workJobTotal, setWorkJobTotal] = useState(0);
|
|
|
@@ -4505,56 +4542,80 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
>
|
|
|
<Form.Item
|
|
|
label={t('common.workflowTemplate')}
|
|
|
- name="workflowTemplate"
|
|
|
required
|
|
|
- rules={[{ required: true, message: t('common.workflowTemplateRequired') }]}
|
|
|
- help={t('common.workflowTemplateHelp')}
|
|
|
+ extra={t('common.workflowTemplateHelp')}
|
|
|
>
|
|
|
- <Select
|
|
|
- placeholder={t('common.workflowTemplatePlaceholder')}
|
|
|
- allowClear
|
|
|
- showSearch
|
|
|
- disabled={isViewMode}
|
|
|
- filterOption={(input, option) =>
|
|
|
- (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
|
|
- }
|
|
|
- options={workflowTemplateList
|
|
|
- .filter(item => item.status === 1) // 只显示启用的
|
|
|
- .map(item => ({
|
|
|
- label: item.name,
|
|
|
- value: item.id,
|
|
|
- }))}
|
|
|
- onChange={(value) => {
|
|
|
- if (value) {
|
|
|
- // 加载流程设计JSON
|
|
|
- loadWorkflowJson(value);
|
|
|
- // 自动填充作业名称为流程模板名称
|
|
|
- const selectedTemplate = workflowTemplateList.find(item => item.id === value);
|
|
|
- if (selectedTemplate?.name) {
|
|
|
- workJobBasicForm.setFieldsValue({ jobName: selectedTemplate.name });
|
|
|
+ <div ref={workflowTemplateSelectWrapRef}>
|
|
|
+ <Form.Item
|
|
|
+ name="workflowTemplate"
|
|
|
+ noStyle
|
|
|
+ rules={[{ required: true, message: t('common.workflowTemplateRequired') }]}
|
|
|
+ >
|
|
|
+ <Select
|
|
|
+ ref={workflowTemplateSelectRef}
|
|
|
+ placeholder={t('common.workflowTemplatePlaceholder')}
|
|
|
+ allowClear
|
|
|
+ showSearch
|
|
|
+ disabled={isViewMode}
|
|
|
+ onDropdownVisibleChange={setWorkflowTemplateDropdownVisible}
|
|
|
+ onClear={() => setWorkflowTemplateDropdownVisible(false)}
|
|
|
+ filterOption={(input, option) =>
|
|
|
+ (option?.label ?? '').toLowerCase().includes(input.toLowerCase())
|
|
|
}
|
|
|
- } else {
|
|
|
- setWorkflowJson(null);
|
|
|
- // 清空作业名称
|
|
|
- workJobBasicForm.setFieldsValue({ jobName: '' });
|
|
|
- }
|
|
|
- }}
|
|
|
- />
|
|
|
+ options={workflowTemplateList
|
|
|
+ .filter(item => item.status === 1) // 只显示启用的
|
|
|
+ .map(item => ({
|
|
|
+ label: item.name,
|
|
|
+ value: item.id,
|
|
|
+ }))}
|
|
|
+ onChange={(value) => {
|
|
|
+ setWorkflowTemplateDropdownVisible(false);
|
|
|
+ if (value) {
|
|
|
+ // 加载流程设计JSON
|
|
|
+ loadWorkflowJson(value);
|
|
|
+ // 自动填充作业名称为流程模板名称
|
|
|
+ const selectedTemplate = workflowTemplateList.find(item => item.id === value);
|
|
|
+ if (selectedTemplate?.name) {
|
|
|
+ workJobBasicForm.setFieldsValue({ jobName: selectedTemplate.name });
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ setWorkflowJson(null);
|
|
|
+ // 清空作业名称
|
|
|
+ workJobBasicForm.setFieldsValue({ jobName: '' });
|
|
|
+ }
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </Form.Item>
|
|
|
+ </div>
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
label={t('common.jobCategory')}
|
|
|
- name="jobCategory"
|
|
|
required
|
|
|
- rules={[{ required: true, message: t('common.jobCategoryRequired') }]}
|
|
|
>
|
|
|
- <Select placeholder={t('common.jobCategoryPlaceholder')} allowClear disabled={isViewMode}>
|
|
|
- {workTypeDictList.map((item) => (
|
|
|
- <Select.Option key={item.id} value={item.value}>
|
|
|
- {item.label}
|
|
|
- </Select.Option>
|
|
|
- ))}
|
|
|
- </Select>
|
|
|
+ <div ref={jobCategorySelectWrapRef}>
|
|
|
+ <Form.Item
|
|
|
+ name="jobCategory"
|
|
|
+ noStyle
|
|
|
+ rules={[{ required: true, message: t('common.jobCategoryRequired') }]}
|
|
|
+ >
|
|
|
+ <Select
|
|
|
+ ref={jobCategorySelectRef}
|
|
|
+ placeholder={t('common.jobCategoryPlaceholder')}
|
|
|
+ allowClear
|
|
|
+ disabled={isViewMode}
|
|
|
+ onDropdownVisibleChange={setJobCategoryDropdownVisible}
|
|
|
+ onSelect={() => setJobCategoryDropdownVisible(false)}
|
|
|
+ onClear={() => setJobCategoryDropdownVisible(false)}
|
|
|
+ >
|
|
|
+ {workTypeDictList.map((item) => (
|
|
|
+ <Select.Option key={item.id} value={item.value}>
|
|
|
+ {item.label}
|
|
|
+ </Select.Option>
|
|
|
+ ))}
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </div>
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
@@ -4983,9 +5044,19 @@ export default function IsolationWork({ subMenu }: IsolationWorkProps) {
|
|
|
const isolationNodes = workflowNodes.filter(n => n.data?.type === 'isolation');
|
|
|
|
|
|
// 如果有连线,只显示已连线的隔离节点;否则显示所有隔离节点(兼容旧数据)
|
|
|
- const nodesToShow = connectedIsolationNodeIds.size > 0
|
|
|
+ let nodesToShow = connectedIsolationNodeIds.size > 0
|
|
|
? isolationNodes.filter(n => connectedIsolationNodeIds.has(String(n.id)))
|
|
|
: isolationNodes;
|
|
|
+
|
|
|
+ // 关键兼容:如果当前已经有选中的隔离节点,但它不在过滤结果里
|
|
|
+ // antd Select 会回显 raw value(比如 isolation-xxxx)。这里强制把它补进 options,保证回显为节点名称。
|
|
|
+ const selectedId = workflowNodeConfig.isolationNodeUuid;
|
|
|
+ if (selectedId && !nodesToShow.some(n => String(n.id) === String(selectedId))) {
|
|
|
+ const selectedNode = isolationNodes.find(n => String(n.id) === String(selectedId));
|
|
|
+ if (selectedNode) {
|
|
|
+ nodesToShow = [selectedNode, ...nodesToShow];
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
return nodesToShow.map(node => {
|
|
|
// 从 workflowWorkNodeDOList 中查找对应的节点数据,获取 nodeName
|