From e9515bb6aee0ad47ed607cdbdd45c8107a67a49b Mon Sep 17 00:00:00 2001 From: cai <945260569@qq.com> Date: Thu, 4 Sep 2025 15:21:26 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E5=A4=8D=E3=80=91=E8=A1=A8?= =?UTF-8?q?=E5=8D=95=E5=88=9D=E5=A7=8B=E5=8C=96=EF=BC=8C=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=E8=8A=82=E7=82=B9=E9=9A=8F=E6=9C=BA=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/flowChart/useController.tsx | 52 +- .../src/components/flowChart/useStore.tsx | 984 ++++++++++-------- .../src/views/authApiManage/useController.tsx | 1 + .../children/workflowView/index.tsx | 91 +- .../workflowView/node/apply/model.tsx | 947 +++++++++-------- .../workflowView/node/start/model.tsx | 417 ++++---- .../src/views/autoDeploy/useController.tsx | 76 +- .../src/views/privateCaCert/index.tsx | 13 +- .../src/views/privateCaCert/useStore.tsx | 25 +- .../privateCaManage/components/AddCaModal.tsx | 421 ++++---- .../views/privateCaManage/useController.tsx | 6 +- frontend/apps/domain-official/index.html | 191 +++- .../apps/domain-official/src/api/landing.ts | 12 + .../apps/domain-official/src/pages/index.ts | 645 +++++++++++- .../apps/domain-official/src/styles/index.css | 565 +++++++++- .../src/types/api-types/flashsale.d.ts | 29 + static/build/index.html | 4 +- static/build/static/css/style-B0WIL3Dv.css | 1 - static/build/static/css/style-Cb9FPhWh.css | 1 + .../{Alert-DUy-kJ2c.js => Alert-DMmMuefE.js} | 2 +- .../{Badge-DfrTvdlT.js => Badge-WD8NTFQn.js} | 2 +- .../build/static/js/CAManageForm-Bt1zZwNW.js | 1 + .../build/static/js/CAManageForm-GJJaTkIi.js | 1 - .../static/js/CreateLeafCertForm-Be3oB_7T.js | 1 + .../static/js/CreateLeafCertForm-Rg6IRp3_.js | 1 - ...uSEpw-L.js => DownloadOutline-B1jf4tcR.js} | 2 +- .../js/{Flex-C3vnRpt4.js => Flex-B1kHIVtt.js} | 2 +- .../js/{Flow-k9mnOyTJ.js => Flow-1OX4EFf-.js} | 2 +- ...d-zdZ1feMh.js => LockOutlined-CYrJE2Jf.js} | 2 +- ...hub-C1NycjkV.js => LogoGithub-DFv9miiK.js} | 2 +- .../js/{Tabs-0RkbILPu.js => Tabs-o2SA8jXB.js} | 2 +- ...{access-Du4iSKC0.js => access-tNugO07J.js} | 2 +- ...iness-DixaSQa5.js => business-DFqzW9Fz.js} | 2 +- .../js/{ca-Btr8pAtm.js => ca-BQ6_tJiJ.js} | 2 +- .../js/{data-CbrE0j8M.js => data-BmphZhVh.js} | 2 +- .../js/{date-thPapEnX.js => date-ITQSHu_u.js} | 2 +- .../{index-BxHne39c.js => index-4YSQfPl0.js} | 2 +- .../{index-uRuYLEYM.js => index-6lmKeU8a.js} | 2 +- static/build/static/js/index-B4a0r2ZJ.js | 1 + .../{index-DxxYdr5G.js => index-BB_yIb8I.js} | 2 +- .../{index-DmFYbVGa.js => index-BCNzEgZM.js} | 2 +- .../{index-DTrXdYNR.js => index-BZGO7Gi4.js} | 2 +- .../{index-DaXJddrY.js => index-BhUxUanl.js} | 2 +- .../{index-BUMGbNUr.js => index-BrUy7zXA.js} | 2 +- static/build/static/js/index-BvWeZ1eD.js | 1 + static/build/static/js/index-ChdPdY3d.js | 1 - static/build/static/js/index-CnpBgrfM.js | 1 - .../{index-D2FOb9NC.js => index-CwfzFleR.js} | 2 +- .../{index-DDH3a4do.js => index-CyzpKyOA.js} | 2 +- .../{index-B9SDvh40.js => index-D7kMPrCO.js} | 2 +- static/build/static/js/index-DJtpEJEi.js | 1 - .../{index-D6lZ7gC3.js => index-DP4rFmDn.js} | 2 +- .../{index-DRfxREE-.js => index-DVDFeieC.js} | 2 +- .../{index-B6kauwOV.js => index-D_D2Mlc-.js} | 2 +- .../{index-BSaBEQDs.js => index-NKDn1boC.js} | 2 +- .../{index-fjy6_cH2.js => index-PcCxPxDa.js} | 2 +- .../{index-DJYSwb1D.js => index-arMgk6op.js} | 2 +- static/build/static/js/index-ediA7WBp.js | 1 - static/build/static/js/index-jFN9tlnn.js | 1 + .../{index-DOjdH0KK.js => index-leYjYcVi.js} | 2 +- .../{index-LlhX5Hs2.js => index-yTfFo-nL.js} | 2 +- static/build/static/js/index-yolAsWR-.js | 1 + .../js/{main-CVVsEoi-.js => main-BVxorWyM.js} | 2 +- ...onitor-B1_us7Y5.js => monitor-CmElP4PX.js} | 2 +- ...{public-BXkhteed.js => public-wMiYGQZ4.js} | 2 +- ...etting-Bm6X4TfA.js => setting-DkG4j-Qh.js} | 2 +- .../js/{text-DHYNx3gK.js => text-D7JJPoiP.js} | 2 +- ...ottle-DQKa2dtP.js => throttle-C61W3BCh.js} | 2 +- ...Store-D2I9NOuy.js => useStore-CPojdwSJ.js} | 2 +- ...Store-CEORux-G.js => useStore-DsgAV0BS.js} | 2 +- 70 files changed, 3083 insertions(+), 1488 deletions(-) create mode 100644 frontend/apps/domain-official/src/types/api-types/flashsale.d.ts delete mode 100644 static/build/static/css/style-B0WIL3Dv.css create mode 100644 static/build/static/css/style-Cb9FPhWh.css rename static/build/static/js/{Alert-DUy-kJ2c.js => Alert-DMmMuefE.js} (98%) rename static/build/static/js/{Badge-DfrTvdlT.js => Badge-WD8NTFQn.js} (99%) create mode 100644 static/build/static/js/CAManageForm-Bt1zZwNW.js delete mode 100644 static/build/static/js/CAManageForm-GJJaTkIi.js create mode 100644 static/build/static/js/CreateLeafCertForm-Be3oB_7T.js delete mode 100644 static/build/static/js/CreateLeafCertForm-Rg6IRp3_.js rename static/build/static/js/{DownloadOutline-BuSEpw-L.js => DownloadOutline-B1jf4tcR.js} (91%) rename static/build/static/js/{Flex-C3vnRpt4.js => Flex-B1kHIVtt.js} (94%) rename static/build/static/js/{Flow-k9mnOyTJ.js => Flow-1OX4EFf-.js} (96%) rename static/build/static/js/{LockOutlined-zdZ1feMh.js => LockOutlined-CYrJE2Jf.js} (90%) rename static/build/static/js/{LogoGithub-C1NycjkV.js => LogoGithub-DFv9miiK.js} (94%) rename static/build/static/js/{Tabs-0RkbILPu.js => Tabs-o2SA8jXB.js} (99%) rename static/build/static/js/{access-Du4iSKC0.js => access-tNugO07J.js} (88%) rename static/build/static/js/{business-DixaSQa5.js => business-DFqzW9Fz.js} (97%) rename static/build/static/js/{ca-Btr8pAtm.js => ca-BQ6_tJiJ.js} (83%) rename static/build/static/js/{data-CbrE0j8M.js => data-BmphZhVh.js} (98%) rename static/build/static/js/{date-thPapEnX.js => date-ITQSHu_u.js} (93%) rename static/build/static/js/{index-BxHne39c.js => index-4YSQfPl0.js} (98%) rename static/build/static/js/{index-uRuYLEYM.js => index-6lmKeU8a.js} (96%) create mode 100644 static/build/static/js/index-B4a0r2ZJ.js rename static/build/static/js/{index-DxxYdr5G.js => index-BB_yIb8I.js} (98%) rename static/build/static/js/{index-DmFYbVGa.js => index-BCNzEgZM.js} (95%) rename static/build/static/js/{index-DTrXdYNR.js => index-BZGO7Gi4.js} (97%) rename static/build/static/js/{index-DaXJddrY.js => index-BhUxUanl.js} (97%) rename static/build/static/js/{index-BUMGbNUr.js => index-BrUy7zXA.js} (96%) create mode 100644 static/build/static/js/index-BvWeZ1eD.js delete mode 100644 static/build/static/js/index-ChdPdY3d.js delete mode 100644 static/build/static/js/index-CnpBgrfM.js rename static/build/static/js/{index-D2FOb9NC.js => index-CwfzFleR.js} (96%) rename static/build/static/js/{index-DDH3a4do.js => index-CyzpKyOA.js} (99%) rename static/build/static/js/{index-B9SDvh40.js => index-D7kMPrCO.js} (92%) delete mode 100644 static/build/static/js/index-DJtpEJEi.js rename static/build/static/js/{index-D6lZ7gC3.js => index-DP4rFmDn.js} (98%) rename static/build/static/js/{index-DRfxREE-.js => index-DVDFeieC.js} (96%) rename static/build/static/js/{index-B6kauwOV.js => index-D_D2Mlc-.js} (84%) rename static/build/static/js/{index-BSaBEQDs.js => index-NKDn1boC.js} (88%) rename static/build/static/js/{index-fjy6_cH2.js => index-PcCxPxDa.js} (81%) rename static/build/static/js/{index-DJYSwb1D.js => index-arMgk6op.js} (93%) delete mode 100644 static/build/static/js/index-ediA7WBp.js create mode 100644 static/build/static/js/index-jFN9tlnn.js rename static/build/static/js/{index-DOjdH0KK.js => index-leYjYcVi.js} (97%) rename static/build/static/js/{index-LlhX5Hs2.js => index-yTfFo-nL.js} (99%) create mode 100644 static/build/static/js/index-yolAsWR-.js rename static/build/static/js/{main-CVVsEoi-.js => main-BVxorWyM.js} (99%) rename static/build/static/js/{monitor-B1_us7Y5.js => monitor-CmElP4PX.js} (82%) rename static/build/static/js/{public-BXkhteed.js => public-wMiYGQZ4.js} (71%) rename static/build/static/js/{setting-Bm6X4TfA.js => setting-DkG4j-Qh.js} (83%) rename static/build/static/js/{text-DHYNx3gK.js => text-D7JJPoiP.js} (97%) rename static/build/static/js/{throttle-DQKa2dtP.js => throttle-C61W3BCh.js} (96%) rename static/build/static/js/{useStore-D2I9NOuy.js => useStore-CPojdwSJ.js} (91%) rename static/build/static/js/{useStore-CEORux-G.js => useStore-DsgAV0BS.js} (82%) diff --git a/frontend/apps/allin-ssl/src/components/flowChart/useController.tsx b/frontend/apps/allin-ssl/src/components/flowChart/useController.tsx index 3fd8c44..e097e9c 100644 --- a/frontend/apps/allin-ssl/src/components/flowChart/useController.tsx +++ b/frontend/apps/allin-ssl/src/components/flowChart/useController.tsx @@ -33,6 +33,40 @@ export const useController = (props: FlowNodeProps = { type: 'quick', node: flow // 使用store获取所有需要的方法和状态 const router = useRouter() const route = useRoute() + const { startNodeSavedByUser } = useStore(); + + /** + * 生成开始节点的随机时间 + * @param {any} childNode - 子节点配置 + * @returns {any} 处理后的子节点配置 + */ + const generateStartNodeRandomTime = (childNode: any) => { + // 检查是否是开始节点 + if (childNode.type === "start") { + if (startNodeSavedByUser.value) { + return childNode; + } + const config = childNode.config; + const hasUserSetTime = + config.hour !== undefined && + config.minute !== undefined && + !(config.hour === 1 && config.minute === 0); + if (!hasUserSetTime) { + const randomHour = Math.floor(Math.random() * 4) + 1; + const randomMinute = Math.floor(Math.random() * 12) * 5; + + return { + ...childNode, + config: { + ...config, + hour: randomHour, + minute: randomMinute, + }, + }; + } + } + return childNode; + }; /** * 保存节点配置 @@ -45,14 +79,16 @@ export const useController = (props: FlowNodeProps = { type: 'quick', node: flow if (res.valid && flowData.value.name) { const { active } = workflowData.value const { id, name, childNode } = flowData.value - const { exec_type, ...exec_time } = childNode.config as unknown as StartNodeConfig - const param = { - name, - active, - content: JSON.stringify(childNode), - exec_type, - exec_time: JSON.stringify(exec_time || {}), - } + const processedChildNode = generateStartNodeRandomTime(childNode); + const { exec_type, ...exec_time } = + processedChildNode.config as unknown as StartNodeConfig; + const param = { + name, + active, + content: JSON.stringify(processedChildNode), + exec_type, + exec_time: JSON.stringify(exec_time || {}), + }; if (route.query.isEdit) { updateWorkflowData({ id, ...param }) } else { diff --git a/frontend/apps/allin-ssl/src/components/flowChart/useStore.tsx b/frontend/apps/allin-ssl/src/components/flowChart/useStore.tsx index 2bd9d63..c4d428b 100644 --- a/frontend/apps/allin-ssl/src/components/flowChart/useStore.tsx +++ b/frontend/apps/allin-ssl/src/components/flowChart/useStore.tsx @@ -42,227 +42,249 @@ export const useFlowStore = defineStore('flow-store', () => { const addNodeSelectPostion = ref(null) // 添加节点选择框位置 const selectedNodeId = ref(null) // 当前选中的节点ID const isRefreshNode = ref(null) // 是否刷新节点 + const startNodeSavedByUser = ref(false); // 开始节点是否已被用户手动保存过 - // 计算添加节点选项列表,排除的节点选项列表 - const nodeSelectList = computed(() => { - return addNodeSelectList.value.filter((item) => !excludeNodeSelectList.value.includes(item.type)) - }) + // 计算添加节点选项列表,排除的节点选项列表 + const nodeSelectList = computed(() => { + return addNodeSelectList.value.filter( + (item) => !excludeNodeSelectList.value.includes(item.type) + ); + }); - /** - * 当前选中的节点数据 - * @type {ComputedRef} - */ - const selectedNode = computed(() => { - if (!selectedNodeId.value) return null - // 使用findNodeRecursive查找节点 - return findNodeRecursive(flowData.value.childNode, selectedNodeId.value) - }) + /** + * 当前选中的节点数据 + * @type {ComputedRef} + */ + const selectedNode = computed(() => { + if (!selectedNodeId.value) return null; + // 使用findNodeRecursive查找节点 + return findNodeRecursive(flowData.value.childNode, selectedNodeId.value); + }); - /** - * 节点标题 - * @type {ComputedRef} - */ - const nodeTitle = computed(() => { - if (!selectedNode.value) return $t('t_6_1744861190121') - return selectedNode.value.name - }) + /** + * 节点标题 + * @type {ComputedRef} + */ + const nodeTitle = computed(() => { + if (!selectedNode.value) return $t("t_6_1744861190121"); + return selectedNode.value.name; + }); - /** - * 获取添加节点选项列表 - * @type {NodeSelect[]} - */ - const getAddNodeSelect = () => { - addNodeSelectList.value = [] - Object.keys(nodeOptions).forEach((key) => { - const item = nodeOptions[key as NodeNum]() - if (item.operateNode?.add) { - addNodeSelectList.value.push({ - title: { name: item.title.name } as NodeTitle, - type: key as NodeNum, - icon: { ...(item.icon || {}) } as NodeIcon, - selected: false, - }) - } - }) - } + /** + * 获取添加节点选项列表 + * @type {NodeSelect[]} + */ + const getAddNodeSelect = () => { + addNodeSelectList.value = []; + Object.keys(nodeOptions).forEach((key) => { + const item = nodeOptions[key as NodeNum](); + if (item.operateNode?.add) { + addNodeSelectList.value.push({ + title: { name: item.title.name } as NodeTitle, + type: key as NodeNum, + icon: { ...(item.icon || {}) } as NodeIcon, + selected: false, + }); + } + }); + }; - /** - * 添加排除的节点选项列表 - * @param {NodeNum[]} nodeTypes - 节点类型 - */ - const addExcludeNodeSelectList = (nodeTypes: NodeNum[]) => { - excludeNodeSelectList.value = nodeTypes - } + /** + * 添加排除的节点选项列表 + * @param {NodeNum[]} nodeTypes - 节点类型 + */ + const addExcludeNodeSelectList = (nodeTypes: NodeNum[]) => { + excludeNodeSelectList.value = nodeTypes; + }; - /** - * 清除排除的节点选项列表 - */ - const clearExcludeNodeSelectList = () => { - excludeNodeSelectList.value = [] - } + /** + * 清除排除的节点选项列表 + */ + const clearExcludeNodeSelectList = () => { + excludeNodeSelectList.value = []; + }; - /** - * 显示添加节点选择框 - * @param {boolean} flag - 是否显示添加节点选择框 - */ - const setShowAddNodeSelect = (flag: boolean, nodeType: NodeNum) => { - // 设置排除的节点选项列表 - excludeNodeSelectList.value = nodeOptions[nodeType]().operateNode?.onSupportNode || [] - // 设置添加节点选择框位置 - if (flag && addNodeSelectRef.value && addNodeBtnRef.value) { - const box = addNodeSelectRef.value.getBoundingClientRect() // 添加节点选择框 - const boxWidth = box.width // 添加节点选择框宽度 - const btn = addNodeBtnRef.value.getBoundingClientRect() // 添加节点按钮 - const btnRight = btn.right // 添加节点按钮右侧位置 - const windowWidth = window.innerWidth // 窗口宽度 - addNodeSelectPostion.value = btnRight + boxWidth > windowWidth ? 1 : 2 - } - } + /** + * 显示添加节点选择框 + * @param {boolean} flag - 是否显示添加节点选择框 + */ + const setShowAddNodeSelect = (flag: boolean, nodeType: NodeNum) => { + // 设置排除的节点选项列表 + excludeNodeSelectList.value = + nodeOptions[nodeType]().operateNode?.onSupportNode || []; + // 设置添加节点选择框位置 + if (flag && addNodeSelectRef.value && addNodeBtnRef.value) { + const box = addNodeSelectRef.value.getBoundingClientRect(); // 添加节点选择框 + const boxWidth = box.width; // 添加节点选择框宽度 + const btn = addNodeBtnRef.value.getBoundingClientRect(); // 添加节点按钮 + const btnRight = btn.right; // 添加节点按钮右侧位置 + const windowWidth = window.innerWidth; // 窗口宽度 + addNodeSelectPostion.value = btnRight + boxWidth > windowWidth ? 1 : 2; + } + }; - /** - * 初始化流程图数据 - * 创建一个默认的开始节点作为流程图的起点 - */ - const initFlowData = () => { - const deepMockData = JSON.parse(JSON.stringify(MockData)) - deepMockData.name = '工作流(' + formatDate(new Date(), 'yyyy/MM/dd HH:mm:ss') + ')' - flowData.value = deepMockData - } + /** + * 初始化流程图数据 + * 创建一个默认的开始节点作为流程图的起点 + */ + const initFlowData = () => { + const deepMockData = JSON.parse(JSON.stringify(MockData)); + deepMockData.name = + "工作流(" + formatDate(new Date(), "yyyy/MM/dd HH:mm:ss") + ")"; + flowData.value = deepMockData; + }; - /** - * 重置流程图数据 - * 清空当前流程图的所有数据 - */ - const resetFlowData = () => initFlowData() + /** + * 重置流程图数据 + * 清空当前流程图的所有数据 + */ + const resetFlowData = () => initFlowData(); - /** - * 递归查找节点 - * @param node 当前节点 - * @param targetId 目标节点ID - * @returns 找到的节点或null - */ - const findNodeRecursive = (node: BaseNodeData | BranchNodeData, targetId: string): BaseNodeData | null => { - if (node.id === targetId) return node + /** + * 递归查找节点 + * @param node 当前节点 + * @param targetId 目标节点ID + * @returns 找到的节点或null + */ + const findNodeRecursive = ( + node: BaseNodeData | BranchNodeData, + targetId: string + ): BaseNodeData | null => { + if (node.id === targetId) return node; - // 优先检查子节点 - if (node.childNode) { - const found = findNodeRecursive(node.childNode, targetId) - if (found) return found - } - // 再检查条件节点 - if ((node as BranchNodeData).conditionNodes?.length) { - for (const conditionNode of (node as BranchNodeData).conditionNodes) { - const found = findNodeRecursive(conditionNode, targetId) - if (found) return found - } - } + // 优先检查子节点 + if (node.childNode) { + const found = findNodeRecursive(node.childNode, targetId); + if (found) return found; + } + // 再检查条件节点 + if ((node as BranchNodeData).conditionNodes?.length) { + for (const conditionNode of (node as BranchNodeData).conditionNodes) { + const found = findNodeRecursive(conditionNode, targetId); + if (found) return found; + } + } - return null - } + return null; + }; - /** - * 通过节点id查找节点数据 - * @param nodeId 节点id - * @returns 节点数据或null - */ - const getFlowFindNodeData = (nodeId: string): BaseNodeData | null => { - return findNodeRecursive(flowData.value.childNode, nodeId) - } + /** + * 通过节点id查找节点数据 + * @param nodeId 节点id + * @returns 节点数据或null + */ + const getFlowFindNodeData = (nodeId: string): BaseNodeData | null => { + return findNodeRecursive(flowData.value.childNode, nodeId); + }; - /** - * 递归更新节点 - * @param node 当前节点 - * @param targetId 目标节点ID - * @param updateFn 更新函数 - * @param parent 父节点 - * @returns 是否更新成功 - */ - const updateNodeRecursive = ( - node: BaseNodeData | BranchNodeData, - targetId: string, - updateFn: (node: BaseNodeData | BranchNodeData, parent: BaseNodeData | BranchNodeData | null) => void, - parent: BaseNodeData | BranchNodeData | null = null, - ): boolean => { - if (node.id === targetId) { - updateFn(node, parent) - return true - } + /** + * 递归更新节点 + * @param node 当前节点 + * @param targetId 目标节点ID + * @param updateFn 更新函数 + * @param parent 父节点 + * @returns 是否更新成功 + */ + const updateNodeRecursive = ( + node: BaseNodeData | BranchNodeData, + targetId: string, + updateFn: ( + node: BaseNodeData | BranchNodeData, + parent: BaseNodeData | BranchNodeData | null + ) => void, + parent: BaseNodeData | BranchNodeData | null = null + ): boolean => { + if (node.id === targetId) { + updateFn(node, parent); + return true; + } - if (node.childNode) { - if (updateNodeRecursive(node.childNode, targetId, updateFn, node)) { - return true - } - } + if (node.childNode) { + if (updateNodeRecursive(node.childNode, targetId, updateFn, node)) { + return true; + } + } - if ((node as BranchNodeData).conditionNodes?.length) { - for (const conditionNode of (node as BranchNodeData).conditionNodes) { - if (updateNodeRecursive(conditionNode, targetId, updateFn, node)) { - return true - } - } - } + if ((node as BranchNodeData).conditionNodes?.length) { + for (const conditionNode of (node as BranchNodeData).conditionNodes) { + if (updateNodeRecursive(conditionNode, targetId, updateFn, node)) { + return true; + } + } + } - return false - } + return false; + }; - /** - * 添加节点 - * @param parentNodeId 父节点ID - * @param nodeType 节点类型 - * @param nodeData 节点数据 - * @param position 插入位置(对于条件节点有效) - */ - const addNode = ( - parentNodeId: string, // 父节点ID - nodeType: NodeNum, // 节点类型 - nodeData: Partial = {}, // 节点数据 - ) => { - // 获取父节点 - const parentNode = getFlowFindNodeData(parentNodeId) - if (!parentNode) { - console.warn(`Parent node with id ${parentNodeId} not found`) - return - } - // 获取支持的节点默认配置 - let newNodeData = deepMerge(nodeOptions[nodeType]().defaultNode as BaseNodeData, nodeData) as - | BaseNodeData - | BranchNodeData // 获取支持的节点默认配置 + /** + * 添加节点 + * @param parentNodeId 父节点ID + * @param nodeType 节点类型 + * @param nodeData 节点数据 + * @param position 插入位置(对于条件节点有效) + */ + const addNode = ( + parentNodeId: string, // 父节点ID + nodeType: NodeNum, // 节点类型 + nodeData: Partial = {} // 节点数据 + ) => { + // 获取父节点 + const parentNode = getFlowFindNodeData(parentNodeId); + if (!parentNode) { + console.warn(`Parent node with id ${parentNodeId} not found`); + return; + } + // 获取支持的节点默认配置 + let newNodeData = deepMerge( + nodeOptions[nodeType]().defaultNode as BaseNodeData, + nodeData + ) as BaseNodeData | BranchNodeData; // 获取支持的节点默认配置 - // 更新原始数据 - updateNodeRecursive(flowData.value.childNode, parentNodeId, (node, parent) => { - switch (nodeType) { - case CONDITION: - // console.log('条件节点', node, parent) - if ((node as BranchNodeData).conditionNodes) { - newNodeData.name = `分支${(node as BranchNodeData).conditionNodes.length + 1}` - ;(node as BranchNodeData).conditionNodes.push(newNodeData) - } - break - case BRANCH: - case EXECUTE_RESULT_BRANCH: - // 执行结果分支节点 - if (nodeType === EXECUTE_RESULT_BRANCH) { - newNodeData = { ...newNodeData, config: { fromNodeId: parentNodeId } } - } + // 更新原始数据 + updateNodeRecursive( + flowData.value.childNode, + parentNodeId, + (node, parent) => { + switch (nodeType) { + case CONDITION: + // console.log('条件节点', node, parent) + if ((node as BranchNodeData).conditionNodes) { + newNodeData.name = `分支${ + (node as BranchNodeData).conditionNodes.length + 1 + }`; + (node as BranchNodeData).conditionNodes.push(newNodeData); + } + break; + case BRANCH: + case EXECUTE_RESULT_BRANCH: + // 执行结果分支节点 + if (nodeType === EXECUTE_RESULT_BRANCH) { + newNodeData = { + ...newNodeData, + config: { fromNodeId: parentNodeId }, + }; + } - ;(newNodeData as BranchNodeData).conditionNodes[0].childNode = node.childNode - node.childNode = newNodeData - break - default: - // console.log('其他节点', node, parent) - if (node.childNode) newNodeData.childNode = node.childNode // 组件嵌套到 childNode 中 - node.childNode = newNodeData - break - } - }) - } + (newNodeData as BranchNodeData).conditionNodes[0].childNode = + node.childNode; + node.childNode = newNodeData; + break; + default: + // console.log('其他节点', node, parent) + if (node.childNode) newNodeData.childNode = node.childNode; // 组件嵌套到 childNode 中 + node.childNode = newNodeData; + break; + } + } + ); + }; - /** - * 向上查找数据类型为 apply 或 upload 的节点 - * @param nodeId 起始节点ID - * @returns 符合条件的节点数组 [{name: string, id: string}] - */ - const findApplyUploadNodesUp = ( + /** + * 向上查找数据类型为 apply 或 upload 的节点 + * @param nodeId 起始节点ID + * @returns 符合条件的节点数组 [{name: string, id: string}] + */ + const findApplyUploadNodesUp = ( nodeId: string, scanNode: string[] = ["apply", "upload", "private_ca"] ): Array<{ name: string; id: string }> => { @@ -319,284 +341,340 @@ export const useFlowStore = defineStore('flow-store', () => { return result; }; - /** - * 删除节点 - * @param nodeId 要删除的节点ID - * @param deep 是否深度删除(默认false,即子节点上移) - */ - const removeNode = (nodeId: string, deep: boolean = false) => { - const node = getFlowFindNodeData(nodeId) - if (!node) { - console.warn(`Node with id ${nodeId} not found`) - return - } + /** + * 删除节点 + * @param nodeId 要删除的节点ID + * @param deep 是否深度删除(默认false,即子节点上移) + */ + const removeNode = (nodeId: string, deep: boolean = false) => { + const node = getFlowFindNodeData(nodeId); + if (!node) { + console.warn(`Node with id ${nodeId} not found`); + return; + } - // 更新原始数据 - updateNodeRecursive(flowData.value.childNode, nodeId, (node, parent) => { - if (!parent) { - console.warn('Cannot remove root node') - return - } + // 更新原始数据 + updateNodeRecursive(flowData.value.childNode, nodeId, (node, parent) => { + if (!parent) { + console.warn("Cannot remove root node"); + return; + } - const { type, conditionNodes } = parent as BranchNodeData | ExecuteResultBranchNodeData - // 处理条件节点(分支节点、执行结果分支节点) - // console.log(type, conditionNodes, node) + const { type, conditionNodes } = parent as + | BranchNodeData + | ExecuteResultBranchNodeData; + // 处理条件节点(分支节点、执行结果分支节点) + // console.log(type, conditionNodes, node) - // 如果当前子节点存在条件节点,需要判断删除后是否支持条件节点,则需要更新 fromNodeId - if (node.childNode?.type === EXECUTE_RESULT_BRANCH && node.childNode?.config) { - node.childNode.config.fromNodeId = parent.id - } + // 如果当前子节点存在条件节点,需要判断删除后是否支持条件节点,则需要更新 fromNodeId + if ( + node.childNode?.type === EXECUTE_RESULT_BRANCH && + node.childNode?.config + ) { + node.childNode.config.fromNodeId = parent.id; + } - // console.log(node.childNode, parent) + // console.log(node.childNode, parent) - // 条件一:当前节点为普通节点 - const nodeTypeList = [CONDITION, EXECUTE_RESULT_CONDITION, BRANCH, EXECUTE_RESULT_BRANCH] - if (!nodeTypeList.includes(node.type) && parent.childNode?.id === nodeId) { - // 处理普通节点 - if (deep) { - // 深度删除,直接移除 - parent.childNode = undefined - } else { - // 非深度删除,子节点上移 - if (node.childNode) { - parent.childNode = node.childNode - } else { - parent.childNode = undefined - } - } - return - } + // 条件一:当前节点为普通节点 + const nodeTypeList = [ + CONDITION, + EXECUTE_RESULT_CONDITION, + BRANCH, + EXECUTE_RESULT_BRANCH, + ]; + if ( + !nodeTypeList.includes(node.type) && + parent.childNode?.id === nodeId + ) { + // 处理普通节点 + if (deep) { + // 深度删除,直接移除 + parent.childNode = undefined; + } else { + // 非深度删除,子节点上移 + if (node.childNode) { + parent.childNode = node.childNode; + } else { + parent.childNode = undefined; + } + } + return; + } - // 条件二:当前节点为条件节点 - if (nodeTypeList.includes(node.type)) { - // 条件节点为分支节点或执行结果分支节点 - if (conditionNodes.length === 2) { - // 条件节点为分支节点,则选定对立节点的子节点作为当前节点的子节点 - // console.log('条件节点为分支节点', parent) - if (type === BRANCH) { - updateNodeRecursive(flowData.value.childNode, parent.id as string, (nodes, parents) => { - const index = conditionNodes.findIndex((n) => n.id === nodeId) - const backNode = nodes.childNode - if (index !== -1 && parents) { - parents.childNode = conditionNodes[index === 0 ? 1 : 0].childNode // 将选定对立节点的子节点作为当前节点的子节 - const allChildNode = getNodePropertyToLast(parents, 'childNode') as BaseNodeData - allChildNode.childNode = backNode - } - }) - } else { - updateNodeRecursive(flowData.value.childNode, parent.id as string, (nodes, parents) => { - if (parents) { - if (parent?.childNode?.id) { - parents.childNode = parent.childNode - } else { - parents.childNode = undefined - } - } - }) - } - } else { - const index = (parent as BranchNodeData).conditionNodes.findIndex((n) => n.id === nodeId) - if (index !== -1) { - // if (deep) { - // // 深度删除,直接移除 - // ;(parent as BranchNodeData).conditionNodes.splice(index, 1) - // } else { - // // 非深度删除,子节点上移 - // const targetNode = (parent as BranchNodeData).conditionNodes[index] - // if (targetNode?.childNode) { - // ;(parent as BranchNodeData).conditionNodes[index] = targetNode.childNode - // } else { - // ;(parent as BranchNodeData).conditionNodes.splice(index, 1) - // } - // } - (parent as BranchNodeData).conditionNodes.splice(index, 1); - } - } - } - }) + // 条件二:当前节点为条件节点 + if (nodeTypeList.includes(node.type)) { + // 条件节点为分支节点或执行结果分支节点 + if (conditionNodes.length === 2) { + // 条件节点为分支节点,则选定对立节点的子节点作为当前节点的子节点 + // console.log('条件节点为分支节点', parent) + if (type === BRANCH) { + updateNodeRecursive( + flowData.value.childNode, + parent.id as string, + (nodes, parents) => { + const index = conditionNodes.findIndex((n) => n.id === nodeId); + const backNode = nodes.childNode; + if (index !== -1 && parents) { + parents.childNode = + conditionNodes[index === 0 ? 1 : 0].childNode; // 将选定对立节点的子节点作为当前节点的子节 + const allChildNode = getNodePropertyToLast( + parents, + "childNode" + ) as BaseNodeData; + allChildNode.childNode = backNode; + } + } + ); + } else { + updateNodeRecursive( + flowData.value.childNode, + parent.id as string, + (nodes, parents) => { + if (parents) { + if (parent?.childNode?.id) { + parents.childNode = parent.childNode; + } else { + parents.childNode = undefined; + } + } + } + ); + } + } else { + const index = (parent as BranchNodeData).conditionNodes.findIndex( + (n) => n.id === nodeId + ); + if (index !== -1) { + // if (deep) { + // // 深度删除,直接移除 + // ;(parent as BranchNodeData).conditionNodes.splice(index, 1) + // } else { + // // 非深度删除,子节点上移 + // const targetNode = (parent as BranchNodeData).conditionNodes[index] + // if (targetNode?.childNode) { + // ;(parent as BranchNodeData).conditionNodes[index] = targetNode.childNode + // } else { + // ;(parent as BranchNodeData).conditionNodes.splice(index, 1) + // } + // } + (parent as BranchNodeData).conditionNodes.splice(index, 1); + } + } + } + }); - return flowData.value - } + return flowData.value; + }; - /** - * 递归查询节点属性直到最后一层 - * @param node 当前节点 - * @param property 要查询的属性名 - * @returns 最后一层的属性值 - */ - const getNodePropertyToLast = (node: BaseNodeData, property: string) => { - if (!node) return null - const value = (node as any)[property] - if (!value) return node - // 如果属性值是一个对象,继续递归查询 - if (typeof value === 'object' && value !== null) { - return getNodePropertyToLast(value, property) - } - } + /** + * 递归查询节点属性直到最后一层 + * @param node 当前节点 + * @param property 要查询的属性名 + * @returns 最后一层的属性值 + */ + const getNodePropertyToLast = (node: BaseNodeData, property: string) => { + if (!node) return null; + const value = (node as any)[property]; + if (!value) return node; + // 如果属性值是一个对象,继续递归查询 + if (typeof value === "object" && value !== null) { + return getNodePropertyToLast(value, property); + } + }; - /** - * 更新节点配置 - * @param nodeId 节点ID - * @param config 新的配置数据 - */ - const updateNodeConfig = (nodeId: string, config: Record) => { - const node = getFlowFindNodeData(nodeId) - if (!node) { - console.warn(`Node with id ${nodeId} not found`) - return - } - // 更新原始数据 - updateNodeRecursive(flowData.value.childNode, nodeId, (node) => { - node.config = config - }) - return flowData.value - } + /** + * 更新节点配置 + * @param nodeId 节点ID + * @param config 新的配置数据 + */ + const updateNodeConfig = (nodeId: string, config: Record) => { + const node = getFlowFindNodeData(nodeId); + if (!node) { + console.warn(`Node with id ${nodeId} not found`); + return; + } + // 更新原始数据 + updateNodeRecursive(flowData.value.childNode, nodeId, (node) => { + node.config = config; + }); + return flowData.value; + }; - /** - * 更新节点数据 - * @param nodeId 要更新的节点ID - * @param newNodeData 新的节点数据 - */ - const updateNode = (nodeId: string, newNodeData: Partial, isMergeArray: boolean = true) => { - const node = getFlowFindNodeData(nodeId) - if (!node) { - console.warn(`Node with id ${nodeId} not found`) - return - } + /** + * 更新节点数据 + * @param nodeId 要更新的节点ID + * @param newNodeData 新的节点数据 + */ + const updateNode = ( + nodeId: string, + newNodeData: Partial, + isMergeArray: boolean = true + ) => { + const node = getFlowFindNodeData(nodeId); + if (!node) { + console.warn(`Node with id ${nodeId} not found`); + return; + } - // 更新原始数据 - updateNodeRecursive(flowData.value.childNode, nodeId, (node) => { - const updatedNode = deepMerge(node, newNodeData, isMergeArray) as BaseNodeData - Object.keys(updatedNode).forEach((key) => { - if (key in node) { - ;(node as any)[key] = updatedNode[key as keyof typeof updatedNode] - } - }) - }) + // 更新原始数据 + updateNodeRecursive(flowData.value.childNode, nodeId, (node) => { + const updatedNode = deepMerge( + node, + newNodeData, + isMergeArray + ) as BaseNodeData; + Object.keys(updatedNode).forEach((key) => { + if (key in node) { + (node as any)[key] = updatedNode[key as keyof typeof updatedNode]; + } + }); + }); - return flowData.value - } + return flowData.value; + }; - /** - * 检查节点是否存在子节点 - * @param nodeId 节点id - * @returns 是否存在子节点 - */ - const checkFlowNodeChild = (nodeId: string): boolean => { - const node = getFlowFindNodeData(nodeId) - return node ? !!(node.childNode || (node as BranchNodeData).conditionNodes?.length) : false - } + /** + * 检查节点是否存在子节点 + * @param nodeId 节点id + * @returns 是否存在子节点 + */ + const checkFlowNodeChild = (nodeId: string): boolean => { + const node = getFlowFindNodeData(nodeId); + return node + ? !!(node.childNode || (node as BranchNodeData).conditionNodes?.length) + : false; + }; - /** - * 检查是否存在行内节点 - * @param nodeId 节点id - */ - const checkFlowInlineNode = (nodeId: string) => { - const node = getFlowFindNodeData(nodeId) - if (!node || node.type !== 'condition') return + /** + * 检查是否存在行内节点 + * @param nodeId 节点id + */ + const checkFlowInlineNode = (nodeId: string) => { + const node = getFlowFindNodeData(nodeId); + if (!node || node.type !== "condition") return; - // 更新原始数据 - updateNodeRecursive(flowData.value.childNode, nodeId, (node) => { - if ((node as BranchNodeData).conditionNodes) { - ;(node as BranchNodeData).conditionNodes = (node as BranchNodeData).conditionNodes.filter( - (n) => n.id !== nodeId, - ) - } - }) - } + // 更新原始数据 + updateNodeRecursive(flowData.value.childNode, nodeId, (node) => { + if ((node as BranchNodeData).conditionNodes) { + (node as BranchNodeData).conditionNodes = ( + node as BranchNodeData + ).conditionNodes.filter((n) => n.id !== nodeId); + } + }); + }; - // /** - // * @description 显示节点选择 - // * @param {boolean} flag - // * @param {NodeNum} nodeData - // */ - // const showNodeSelect = (flag: boolean, nodeType?: NodeNum) => { - // if (!flag) { - // clearTimeout(timer.value as number) - // timer.value = window.setTimeout(() => { - // isShowAddNodeSelect.value = flag - // }, 1000) as unknown as null - // } else { - // isShowAddNodeSelect.value = false - // isShowAddNodeSelect.value = flag - // } - // // 设置添加节点选择状态 - // if (nodeType) { - // flowStore.setShowAddNodeSelect(flag, nodeType) - // } - // } + // /** + // * @description 显示节点选择 + // * @param {boolean} flag + // * @param {NodeNum} nodeData + // */ + // const showNodeSelect = (flag: boolean, nodeType?: NodeNum) => { + // if (!flag) { + // clearTimeout(timer.value as number) + // timer.value = window.setTimeout(() => { + // isShowAddNodeSelect.value = flag + // }, 1000) as unknown as null + // } else { + // isShowAddNodeSelect.value = false + // isShowAddNodeSelect.value = flag + // } + // // 设置添加节点选择状态 + // if (nodeType) { + // flowStore.setShowAddNodeSelect(flag, nodeType) + // } + // } - /** - * 获取流程图数据 - * 返回当前流程图数据的深拷贝,避免直接修改原始数据 - * @returns {Object} 流程图数据的副本 - */ - const getResultData = () => { - return deepMerge({}, flowData.value) - } + /** + * 获取流程图数据 + * 返回当前流程图数据的深拷贝,避免直接修改原始数据 + * @returns {Object} 流程图数据的副本 + */ + const getResultData = () => { + return deepMerge({}, flowData.value); + }; - /** - * 更新流程图数据 - * 用新的数据替换当前的流程图数据 - * @param {Object} newData - 新的流程图数据 - */ - const updateFlowData = (newData: FlowNode) => { - flowData.value = newData - } + /** + * 更新流程图数据 + * 用新的数据替换当前的流程图数据 + * @param {Object} newData - 新的流程图数据 + */ + const updateFlowData = (newData: FlowNode) => { + flowData.value = newData; + }; - /** - * 设置流程图缩放比例 - * 控制流程图的显示大小 - * @param {number} type - 缩放类型:1 表示缩小,2 表示放大 - */ - const setflowZoom = (type: number) => { - if (type === 1 && flowZoom.value > 50) { - flowZoom.value -= 10 - } else if (type === 2 && flowZoom.value < 300) { - flowZoom.value += 10 - } - } + /** + * 设置流程图缩放比例 + * 控制流程图的显示大小 + * @param {number} type - 缩放类型:1 表示缩小,2 表示放大 + */ + const setflowZoom = (type: number) => { + if (type === 1 && flowZoom.value > 50) { + flowZoom.value -= 10; + } else if (type === 2 && flowZoom.value < 300) { + flowZoom.value += 10; + } + }; + + /** + * 设置开始节点已被用户保存的状态 + * @param {boolean} saved - 是否已被保存 + */ + const setStartNodeSavedByUser = (saved: boolean) => { + startNodeSavedByUser.value = saved; + }; + + /** + * 重置开始节点保存状态 + * 在组件销毁或工作流重置时调用 + */ + const resetStartNodeSavedState = () => { + startNodeSavedByUser.value = false; + }; return { - // 数据 - flowData, // 流程图数据 - flowZoom, // 流程图缩放比例 - selectedNode, // 当前选中的节点 - nodeTitle, // 当前选中的节点标题 - selectedNodeId, // 当前选中的节点ID - isRefreshNode, // 是否刷新节点 - advancedOptions, // 高级选项 + // 数据 + flowData, // 流程图数据 + flowZoom, // 流程图缩放比例 + selectedNode, // 当前选中的节点 + nodeTitle, // 当前选中的节点标题 + selectedNodeId, // 当前选中的节点ID + isRefreshNode, // 是否刷新节点 + advancedOptions, // 高级选项 + startNodeSavedByUser, // 开始节点是否已被用户手动保存过 - // 方法 - initFlowData, // 初始化流程图数据 - resetFlowData, // 重置流程图数据 - getResultData, // 获取流程图数据 - updateFlowData, // 更新流程图数据 - setflowZoom, // 设置流程图缩放比例 + // 方法 + initFlowData, // 初始化流程图数据 + resetFlowData, // 重置流程图数据 + getResultData, // 获取流程图数据 + updateFlowData, // 更新流程图数据 + setflowZoom, // 设置流程图缩放比例 + setStartNodeSavedByUser, // 设置开始节点已被用户保存的状态 + resetStartNodeSavedState, // 重置开始节点保存状态 - // 添加节点-数据 - addNodeSelectList, // 添加节点选项列表 - nodeSelectList, // 计算添加节点选项列表,排除的节点选项列表 - excludeNodeSelectList, // 排除的节点选项列表 - addNodeBtnRef, // 添加节点按钮 - addNodeSelectRef, // 添加节点选择框 - addNodeSelectPostion, // 添加节点选择框位置 + // 添加节点-数据 + addNodeSelectList, // 添加节点选项列表 + nodeSelectList, // 计算添加节点选项列表,排除的节点选项列表 + excludeNodeSelectList, // 排除的节点选项列表 + addNodeBtnRef, // 添加节点按钮 + addNodeSelectRef, // 添加节点选择框 + addNodeSelectPostion, // 添加节点选择框位置 - // 添加节点-方法 - getAddNodeSelect, // 获取添加节点选项列表 - addExcludeNodeSelectList, // 添加排除的节点选项列表 - clearExcludeNodeSelectList, // 清除排除的节点选项列表 - setShowAddNodeSelect, // 设置显示添加节点选择框 + // 添加节点-方法 + getAddNodeSelect, // 获取添加节点选项列表 + addExcludeNodeSelectList, // 添加排除的节点选项列表 + clearExcludeNodeSelectList, // 清除排除的节点选项列表 + setShowAddNodeSelect, // 设置显示添加节点选择框 - // 节点操作 - addNode, - removeNode, - updateNodeConfig, - updateNode, - findApplyUploadNodesUp, // 向上查找 apply 和 upload 类型节点 - checkFlowNodeChild, // 检查节点是否存在子节点 - checkFlowInlineNode, // 检查是否存在行内节点 - } + // 节点操作 + addNode, + removeNode, + updateNodeConfig, + updateNode, + findApplyUploadNodesUp, // 向上查找 apply 和 upload 类型节点 + checkFlowNodeChild, // 检查节点是否存在子节点 + checkFlowInlineNode, // 检查是否存在行内节点 + }; }) /** diff --git a/frontend/apps/allin-ssl/src/views/authApiManage/useController.tsx b/frontend/apps/allin-ssl/src/views/authApiManage/useController.tsx index ac6f1e6..bbdd09e 100644 --- a/frontend/apps/allin-ssl/src/views/authApiManage/useController.tsx +++ b/frontend/apps/allin-ssl/src/views/authApiManage/useController.tsx @@ -478,6 +478,7 @@ export const useApiFormController = ( btwaf: $t("t_0_1747271295174"), safeline: $t("t_0_1747300383756"), lecdn: "请输入正确的URL地址", + webhook: "请输入回调地址", }; return callback( new Error(mapTips[param.value.type as keyof typeof mapTips]) diff --git a/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/index.tsx b/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/index.tsx index c8682e0..b6bc5a1 100644 --- a/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/index.tsx +++ b/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/index.tsx @@ -1,55 +1,62 @@ import { defineComponent, onBeforeMount, onMounted, ref } from 'vue' import type { Component } from 'vue' -import FlowChart from '@components/FlowChart' -import { useStore } from '@autoDeploy/children/workflowView/useStore' -import { useController } from './useController' +import FlowChart from "@components/FlowChart"; +import { useStore } from "@autoDeploy/children/workflowView/useStore"; +import { useController } from "./useController"; +import { useStore as useFlowStore } from "@components/FlowChart/useStore"; /** * @description 工作流视图主组件,负责加载和渲染流程图。 */ export default defineComponent({ - name: 'WorkflowView', - setup() { - const { init } = useController() - const { workflowType, workDefalutNodeData, isEdit } = useStore() + name: "WorkflowView", + setup() { + const { init } = useController(); + const { workflowType, workDefalutNodeData, isEdit } = useStore(); + const { resetStartNodeSavedState } = useFlowStore(); - // 使用import.meta.glob一次性加载所有节点组件 - const modules = import.meta.glob('./node/*/index.tsx', { eager: true }) + // 使用import.meta.glob一次性加载所有节点组件 + const modules = import.meta.glob("./node/*/index.tsx", { eager: true }); - // 创建节点组件映射 - const taskComponents = ref>({}) + // 创建节点组件映射 + const taskComponents = ref>({}); - // 初始化任务组件映射 - const initTaskComponents = () => { - const componentsMap: Record = {} - // 获取文件夹名称(对应节点类型)并映射到组件 - Object.entries(modules).forEach(([path, module]) => { - // 获取路径中的节点类型 - const match = path.match(/\/node\/([^/]+)\/index\.tsx$/) - if (match && match[1]) { - const nodeType = match[1] - const componentKey = `${nodeType}Node` - // @ts-ignore - componentsMap[componentKey] = module.default || module - } - }) - taskComponents.value = componentsMap - console.log('已加载节点组件:', Object.keys(componentsMap)) - } + // 初始化任务组件映射 + const initTaskComponents = () => { + const componentsMap: Record = {}; + // 获取文件夹名称(对应节点类型)并映射到组件 + Object.entries(modules).forEach(([path, module]) => { + // 获取路径中的节点类型 + const match = path.match(/\/node\/([^/]+)\/index\.tsx$/); + if (match && match[1]) { + const nodeType = match[1]; + const componentKey = `${nodeType}Node`; + // @ts-ignore + componentsMap[componentKey] = module.default || module; + } + }); + taskComponents.value = componentsMap; + console.log("已加载节点组件:", Object.keys(componentsMap)); + }; - // 初始化组件 - onBeforeMount(initTaskComponents) + // 初始化组件 + onBeforeMount(initTaskComponents); - // 初始化数据 - onMounted(init) + // 初始化数据 + onMounted(init); - return () => ( - - ) - }, -}) + // 组件销毁时重置开始节点保存状态 + onUnmounted(() => { + resetStartNodeSavedState(); + }); + + return () => ( + + ); + }, +}); diff --git a/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/node/apply/model.tsx b/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/node/apply/model.tsx index 4d90c34..393cc5b 100644 --- a/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/node/apply/model.tsx +++ b/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/node/apply/model.tsx @@ -53,467 +53,548 @@ export default defineComponent({ }, }, setup(props) { - const { updateNodeConfig, advancedOptions, isRefreshNode } = useStore() - // 获取路由信息 - const route = useRoute() - // 弹窗辅助 - const { confirm } = useModalHooks() - // 获取表单助手函数 - const { useFormInput, useFormSelect, useFormMore, useFormHelp, useFormSwitch } = useFormHooks() - // 表单参数 - const param = ref(deepClone(props.node.config)) + const { updateNodeConfig, advancedOptions, isRefreshNode } = useStore(); + // 获取路由信息 + const route = useRoute(); + // 弹窗辅助 + const { confirm } = useModalHooks(); + // 获取表单助手函数 + const { + useFormInput, + useFormSelect, + useFormMore, + useFormHelp, + useFormSwitch, + } = useFormHooks(); + // 表单参数 + const param = ref(deepClone(props.node.config)); - // 获取路由参数 - const isEdit = computed(() => route.query.isEdit === 'true') - const routeEmail = computed(() => (route.query.email as string) || '') + // 获取路由参数 + const isEdit = computed(() => route.query.isEdit === "true"); + const routeEmail = computed(() => (route.query.email as string) || ""); - // CA选项状态 - const caOptions = ref>([]) - const emailOptions = ref([]) - const isLoadingCA = ref(false) - const isLoadingEmails = ref(false) - const showEmailDropdown = ref(false) - const emailInputRef = ref | null>(null) + // CA选项状态 + const caOptions = ref< + Array<{ label: string; value: string; icon: string }> + >([]); + const emailOptions = ref([]); + const isLoadingCA = ref(false); + const isLoadingEmails = ref(false); + const showEmailDropdown = ref(false); + const emailInputRef = ref | null>(null); - // 加载CA选项 - const loadCAOptions = async () => { - isLoadingCA.value = true - try { - const { data } = await getEabList({ ca: '', p: 1, limit: 1000 }).fetch() - const uniqueCATypes = new Set() - const caList: Array<{ label: string; value: string; icon: string }> = [] + // 加载CA选项 + const loadCAOptions = async () => { + isLoadingCA.value = true; + try { + const { data } = await getEabList({ + ca: param.value.ca, + p: 1, + limit: 1000, + }).fetch(); + const uniqueCATypes = new Set(); + const caList: Array<{ label: string; value: string; icon: string }> = + []; - // 优先添加重要的CA类型(确保始终显示) - const priorityCATypes = ['letsencrypt', 'buypass', 'zerossl'] - priorityCATypes.forEach((caType) => { - if (!uniqueCATypes.has(caType)) { - uniqueCATypes.add(caType) - const predefinedCA = Object.values(CACertificateAuthorization).find((ca) => ca.type === caType) - caList.push({ - label: predefinedCA ? predefinedCA.name : caType.toUpperCase(), - value: caType, - icon: `cert-${caType}`, - }) - } - }) + // 优先添加重要的CA类型(确保始终显示) + const priorityCATypes = ["letsencrypt", "buypass", "zerossl"]; + priorityCATypes.forEach((caType) => { + if (!uniqueCATypes.has(caType)) { + uniqueCATypes.add(caType); + const predefinedCA = Object.values(CACertificateAuthorization).find( + (ca) => ca.type === caType + ); + caList.push({ + label: predefinedCA ? predefinedCA.name : caType.toUpperCase(), + value: caType, + icon: `cert-${caType}`, + }); + } + }); - // 添加API返回的其他CA类型(去重) - data?.forEach((item) => { - if (item.ca && !uniqueCATypes.has(item.ca)) { - uniqueCATypes.add(item.ca) + // 添加API返回的其他CA类型(去重) + data?.forEach((item) => { + if (item.ca && !uniqueCATypes.has(item.ca)) { + uniqueCATypes.add(item.ca); - // 查找预定义配置中对应的CA信息 - const predefinedCA = Object.values(CACertificateAuthorization).find((ca) => ca.type === item.ca) - caList.push({ - label: predefinedCA ? predefinedCA.name : item.ca.toUpperCase(), - value: item.ca, - icon: predefinedCA ? `cert-${item.ca}` : 'cert-custom', // 如果不在预定义配置中,使用custom图标;否则使用对应的cert图标 - }) - } - }) + // 查找预定义配置中对应的CA信息 + const predefinedCA = Object.values(CACertificateAuthorization).find( + (ca) => ca.type === item.ca + ); + caList.push({ + label: predefinedCA ? predefinedCA.name : item.ca.toUpperCase(), + value: item.ca, + icon: predefinedCA ? `cert-${item.ca}` : "cert-custom", // 如果不在预定义配置中,使用custom图标;否则使用对应的cert图标 + }); + } + }); - caOptions.value = caList - } catch (error) { - console.error('加载CA选项失败:', error) - } finally { - isLoadingCA.value = false - } - } + caOptions.value = caList; + } catch (error) { + console.error("加载CA选项失败:", error); + } finally { + isLoadingCA.value = false; + } + }; - // 加载邮件选项 - const loadEmailOptions = async (ca: string) => { - if (!ca) return - isLoadingEmails.value = true - try { - const { data } = await getEabList({ ca, p: 1, limit: 1000 }).fetch() - emailOptions.value = data?.map((item) => item.email).filter(Boolean) || [] + // 加载邮件选项 + const loadEmailOptions = async (ca: string) => { + if (!ca) return; + isLoadingEmails.value = true; + try { + const { data } = await getEabList({ ca, p: 1, limit: 1000 }).fetch(); + emailOptions.value = + data?.map((item) => item.email).filter(Boolean) || []; - // 检查是否为编辑模式且有外部传入的邮箱 - if (isEdit.value && routeEmail.value) { - // 编辑模式:使用外部传入的邮箱地址 - param.value.email = routeEmail.value - } else { - // 非编辑模式:保持原有逻辑 - if (!emailOptions.value.length) { - param.value.email = '' - } - // 如果邮箱数组有内容且当前邮箱为空,自动填充第一个邮箱地址 - if (emailOptions.value.length > 0 && emailOptions.value[0] && !param.value.email) { - param.value.email = emailOptions.value[0] - } - } - } catch (error) { - console.error('加载邮件选项失败:', error) - } finally { - isLoadingEmails.value = false - } - } + // 检查是否为编辑模式且有外部传入的邮箱 + if (isEdit.value && routeEmail.value) { + // 编辑模式:使用外部传入的邮箱地址 + param.value.email = routeEmail.value; + } else { + // 非编辑模式:保持原有逻辑 + if (!emailOptions.value.length) { + param.value.email = ""; + } + // 如果邮箱数组有内容且当前邮箱为空,自动填充第一个邮箱地址 + if ( + emailOptions.value.length > 0 && + emailOptions.value[0] && + !param.value.email + ) { + param.value.email = emailOptions.value[0]; + } + } + } catch (error) { + console.error("加载邮件选项失败:", error); + } finally { + isLoadingEmails.value = false; + } + }; - // 处理CA选择变化 - const handleCAChange = (value: string) => { - param.value.ca = value - // 移除直接调用 loadEmailOptions,让 watch 监听器统一处理 - // 这样避免了用户切换CA时的重复 API 请求 - } + // 处理CA选择变化 + const handleCAChange = (value: string) => { + param.value.ca = value; + // 移除直接调用 loadEmailOptions,让 watch 监听器统一处理 + // 这样避免了用户切换CA时的重复 API 请求 + }; - // 跳转到CA管理页面 - const goToAddCAProvider = () => { - window.open('/auto-deploy?type=caManage', '_blank') - } + // 跳转到CA管理页面 + const goToAddCAProvider = () => { + window.open("/auto-deploy?type=caManage", "_blank"); + }; - // 渲染CA选择器标签 - const renderLabel = (option: { label: string; value: string; icon: string }) => { - return ( - - - {option.label} - - ) - } + // 渲染CA选择器标签 + const renderLabel = (option: { + label: string; + value: string; + icon: string; + }) => { + return ( + + + {option.label} + + ); + }; - // 渲染CA选择器单选标签 - const renderSingleSelectTag = ({ option }: any) => { - return ( - - {option.label ? renderLabel(option) : {$t('t_0_1747990228780')}} - - ) - } + // 渲染CA选择器单选标签 + const renderSingleSelectTag = ({ option }: any) => { + return ( + + {option.label ? ( + renderLabel(option) + ) : ( + {$t("t_0_1747990228780")} + )} + + ); + }; - // 过滤函数 - const handleFilter = (pattern: string, option: any): boolean => { - return option.label.toLowerCase().includes(pattern.toLowerCase()) - } + // 过滤函数 + const handleFilter = (pattern: string, option: any): boolean => { + return option.label.toLowerCase().includes(pattern.toLowerCase()); + }; - // 处理邮箱输入框焦点 - const handleEmailFocus = () => { - if (emailOptions.value.length > 0) { - showEmailDropdown.value = true - } - } + // 处理邮箱输入框焦点 + const handleEmailFocus = () => { + if (emailOptions.value.length > 0) { + showEmailDropdown.value = true; + } + }; - // 处理邮箱输入框失焦 - const handleEmailBlur = () => { - // 延迟关闭下拉,确保点击选项有时间触发 - setTimeout(() => { - showEmailDropdown.value = false - }, 200) - } + // 处理邮箱输入框失焦 + const handleEmailBlur = () => { + // 延迟关闭下拉,确保点击选项有时间触发 + setTimeout(() => { + showEmailDropdown.value = false; + }, 200); + }; - // 选择邮箱地址 - const handleSelectEmail = (email: string) => { - param.value.email = email - showEmailDropdown.value = false - emailInputRef.value?.blur() - } + // 选择邮箱地址 + const handleSelectEmail = (email: string) => { + param.value.email = email; + showEmailDropdown.value = false; + emailInputRef.value?.blur(); + }; - // 创建邮箱下拉选项 - const emailDropdownOptions = computed(() => { - return emailOptions.value.map((email) => ({ - label: email, - key: email, - })) - }) + // 创建邮箱下拉选项 + const emailDropdownOptions = computed(() => { + return emailOptions.value.map((email) => ({ + label: email, + key: email, + })); + }); - // 判断是否需要输入框(letsencrypt、buypass、zerossl) - const shouldUseInputForEmail = computed(() => { - return ['letsencrypt', 'buypass', 'zerossl'].includes(param.value.ca) - }) + // 判断是否需要输入框(letsencrypt、buypass、zerossl) + const shouldUseInputForEmail = computed(() => { + return ["letsencrypt", "buypass", "zerossl"].includes(param.value.ca); + }); - // 表单渲染配置 - const config = computed(() => { - // 基本选项 - return [ - useFormInput($t('t_17_1745227838561'), 'domains', { - placeholder: $t('t_0_1745735774005'), - allowInput: noSideSpace, - onInput: (val: string) => { - param.value.domains = val.replace(/,/g, ',').replace(/;/g, ',') // 中文逗号分隔 - }, - }), - { - type: 'custom' as const, - render: () => { - return ( - { - param.value.provider_id = val.value - param.value.provider = val.type - }, - }} - /> - ) - }, - }, - { - type: 'custom' as const, - render: () => { - return ( - - - - { - return {$t('t_2_1747990228008')} - }, - }} - /> - - - - {$t('t_4_1747903685371')} - - - {$t('t_0_1746497662220')} - - - - - ) - }, - }, - { - type: 'custom' as const, - render: () => { - return ( - - {shouldUseInputForEmail.value ? ( - - - - ) : ( - ({ label: email, value: email }))} - placeholder={$t('t_2_1748052862259')} - clearable - filterable - loading={isLoadingEmails.value} - class="w-full" - /> - )} - - ) - }, - }, + // 表单渲染配置 + const config = computed(() => { + // 基本选项 + return [ + useFormInput($t("t_17_1745227838561"), "domains", { + placeholder: $t("t_0_1745735774005"), + allowInput: noSideSpace, + onInput: (val: string) => { + param.value.domains = val.replace(/,/g, ",").replace(/;/g, ","); // 中文逗号分隔 + }, + }), + { + type: "custom" as const, + render: () => { + return ( + { + param.value.provider_id = val.value; + param.value.provider = val.type; + }, + }} + /> + ); + }, + }, + { + type: "custom" as const, + render: () => { + return ( + + + + { + return ( + + {$t("t_2_1747990228008")} + + ); + }, + }} + /> + + + + {$t("t_4_1747903685371")} + + + {$t("t_0_1746497662220")} + + + + + ); + }, + }, + { + type: "custom" as const, + render: () => { + return ( + + {shouldUseInputForEmail.value ? ( + + + + ) : ( + ({ + label: email, + value: email, + }))} + placeholder={$t("t_2_1748052862259")} + clearable + filterable + loading={isLoadingEmails.value} + class="w-full" + /> + )} + + ); + }, + }, - { - type: 'custom' as const, - render: () => { - return ( - -
- {$t('t_5_1747990228592')} - - {$t('t_6_1747990228465')} -
-
- ) - }, - }, - useFormMore(advancedOptions), - ...(advancedOptions.value - ? [ - useFormSelect( - $t('t_0_1747647014927'), - 'algorithm', - [ - { label: 'RSA2048', value: 'RSA2048' }, - { label: 'RSA3072', value: 'RSA3072' }, - { label: 'RSA4096', value: 'RSA4096' }, - { label: 'RSA8192', value: 'RSA8192' }, - { label: 'EC256', value: 'EC256' }, - { label: 'EC384', value: 'EC384' }, - ], - {}, - { showRequireMark: false }, - ), - useFormInput( - $t('t_7_1747990227761'), - 'proxy', - { - placeholder: $t('t_8_1747990235316'), - allowInput: noSideSpace, - }, - { showRequireMark: false }, - ), - useFormSwitch( - $t('t_2_1749204567193'), - 'close_cname', - { - checkedValue: 1, - uncheckedValue: 0, - }, - { showRequireMark: false }, - ), - useFormSwitch( - $t('t_2_1747106957037'), - 'skip_check', - { - checkedValue: 1, - uncheckedValue: 0, - }, - { showRequireMark: false }, - ), - // 只有在跳过预检查关闭时才显示DNS递归服务器、预检查超时时间和忽略预检查结果 - ...(param.value.skip_check === 0 - ? [ - useFormInput( - $t('t_0_1747106957037'), - 'name_server', - { - placeholder: $t('t_1_1747106961747'), - allowInput: noSideSpace, - onInput: (val: string) => { - param.value.name_server = val.replace(/,/g, ',').replace(/;/g, ',') // 中文逗号分隔 - }, - }, - { showRequireMark: false }, - ), - { - type: 'custom' as const, - render: () => { - return ( - - - - ) - }, - }, - { - type: 'custom' as const, - render: () => { - return ( - -
- {$t('t_3_1749263104237')} - $t('t_4_1749263101853'), - unchecked: () => $t('t_5_1749263101934'), - }} - /> - {$t('t_6_1749263103891')} -
-
- ) - }, - }, - ] - : []), - ] - : []), - useFormHelp([ - { - content: $t('t_0_1747040228657'), - }, - { - content: $t('t_1_1747040226143'), - }, - ]), - ] - }) + { + type: "custom" as const, + render: () => { + return ( + +
+ + {$t("t_5_1747990228592")} + + + + {$t("t_6_1747990228465")} + +
+
+ ); + }, + }, + useFormMore(advancedOptions), + ...(advancedOptions.value + ? [ + useFormSelect( + $t("t_0_1747647014927"), + "algorithm", + [ + { label: "RSA2048", value: "RSA2048" }, + { label: "RSA3072", value: "RSA3072" }, + { label: "RSA4096", value: "RSA4096" }, + { label: "RSA8192", value: "RSA8192" }, + { label: "EC256", value: "EC256" }, + { label: "EC384", value: "EC384" }, + ], + {}, + { showRequireMark: false } + ), + useFormInput( + $t("t_7_1747990227761"), + "proxy", + { + placeholder: $t("t_8_1747990235316"), + allowInput: noSideSpace, + }, + { showRequireMark: false } + ), + useFormSwitch( + $t("t_2_1749204567193"), + "close_cname", + { + checkedValue: 1, + uncheckedValue: 0, + }, + { showRequireMark: false } + ), + useFormSwitch( + $t("t_2_1747106957037"), + "skip_check", + { + checkedValue: 1, + uncheckedValue: 0, + }, + { showRequireMark: false } + ), + // 只有在跳过预检查关闭时才显示DNS递归服务器、预检查超时时间和忽略预检查结果 + ...(param.value.skip_check === 0 + ? [ + useFormInput( + $t("t_0_1747106957037"), + "name_server", + { + placeholder: $t("t_1_1747106961747"), + allowInput: noSideSpace, + onInput: (val: string) => { + param.value.name_server = val + .replace(/,/g, ",") + .replace(/;/g, ","); // 中文逗号分隔 + }, + }, + { showRequireMark: false } + ), + { + type: "custom" as const, + render: () => { + return ( + + + + ); + }, + }, + { + type: "custom" as const, + render: () => { + return ( + +
+ + {$t("t_3_1749263104237")} + + $t("t_4_1749263101853"), + unchecked: () => $t("t_5_1749263101934"), + }} + /> + + {$t("t_6_1749263103891")} + +
+
+ ); + }, + }, + ] + : []), + ] + : []), + useFormHelp([ + { + content: $t("t_0_1747040228657"), + }, + { + content: $t("t_1_1747040226143"), + }, + ]), + ]; + }); - // 创建表单实例 - const { component: Form, data, example } = useForm({ defaultValue: param, config, rules }) + // 创建表单实例 + const { + component: Form, + data, + example, + } = useForm({ defaultValue: param, config, rules }); - // 监听CA值变化,自动加载邮箱选项 - watch( - () => param.value.ca, - async (newCA) => { - if (newCA) { - await loadEmailOptions(newCA) - } else { - emailOptions.value = [] - param.value.email = '' - showEmailDropdown.value = false - } - }, - ) + // 监听CA值变化,自动加载邮箱选项 + watch( + () => param.value.ca, + async (newCA) => { + if (newCA) { + await loadEmailOptions(newCA); + } else { + emailOptions.value = []; + param.value.email = ""; + showEmailDropdown.value = false; + } + } + ); - // 监听邮箱选项变化,如果当前下拉显示且没有选项了就关闭下拉 - watch( - () => emailOptions.value, - (newOptions) => { - if (showEmailDropdown.value && newOptions.length === 0) { - showEmailDropdown.value = false - } - }, - ) + // 监听邮箱选项变化,如果当前下拉显示且没有选项了就关闭下拉 + watch( + () => emailOptions.value, + (newOptions) => { + if (showEmailDropdown.value && newOptions.length === 0) { + showEmailDropdown.value = false; + } + } + ); - onMounted(async () => { - advancedOptions.value = false - await loadCAOptions() + onMounted(async () => { + advancedOptions.value = false; + await loadCAOptions(); - // 如果是编辑模式且有外部传入的邮箱,直接设置邮箱值 - if (isEdit.value && routeEmail.value) { - param.value.email = routeEmail.value - } + // 如果当前已经有CA值,主动加载对应的邮件选项 + if (param.value.ca) { + await loadEmailOptions(param.value.ca); + } - // 移除重复调用,让 watch 监听器处理 CA 值变化 - // 这样避免了 onMounted 和 watch 同时调用 loadEmailOptions 导致的重复请求 - }) + // 如果是编辑模式且有外部传入的邮箱,直接设置邮箱值 + if (isEdit.value && routeEmail.value) { + param.value.email = routeEmail.value; + } - // 确认事件触发 - confirm(async (close) => { - try { - await example.value?.validate() + // 移除重复调用,让 watch 监听器处理 CA 值变化 + // 这样避免了 onMounted 和 watch 同时调用 loadEmailOptions 导致的重复请求 + }); - updateNodeConfig(props.node.id, data.value) // 更新节点配置 - isRefreshNode.value = props.node.id // 刷新节点 - close() - } catch (error) { - console.log(error) - } - }) + // 确认事件触发 + confirm(async (close) => { + try { + await example.value?.validate(); - return () => ( -
-
-
- ) - }, + updateNodeConfig(props.node.id, data.value); // 更新节点配置 + isRefreshNode.value = props.node.id; // 刷新节点 + close(); + } catch (error) { + console.log(error); + } + }); + + return () => ( +
+ +
+ ); + }, }) diff --git a/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/node/start/model.tsx b/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/node/start/model.tsx index e447405..cd441de 100644 --- a/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/node/start/model.tsx +++ b/frontend/apps/allin-ssl/src/views/autoDeploy/children/workflowView/node/start/model.tsx @@ -28,208 +28,235 @@ export default defineComponent({ }, }, setup(props) { - const { updateNodeConfig, isRefreshNode, flowData } = useStore() - // 弹窗辅助 - const { confirm } = useModalHooks() - // 错误处理 - const { handleError } = useError() - // 获取表单助手函数 - const { useFormRadio, useFormCustom } = useFormHooks() - // 表单参数 - const param = ref(deepClone(props.node.config)) - - // 周期类型选项 - const cycleTypeOptions = [ - { label: $t('t_2_1744875938555'), value: 'day' }, - { label: $t('t_0_1744942117992'), value: 'week' }, - { label: $t('t_3_1744875938310'), value: 'month' }, - ] - - // 星期选项 - const weekOptions = [ - { label: $t('t_1_1744942116527'), value: 1 }, - { label: $t('t_2_1744942117890'), value: 2 }, - { label: $t('t_3_1744942117885'), value: 3 }, - { label: $t('t_4_1744942117738'), value: 4 }, - { label: $t('t_5_1744942117167'), value: 5 }, - { label: $t('t_6_1744942117815'), value: 6 }, - { label: $t('t_7_1744942117862'), value: 0 }, - ] - - // 定义默认值常量,避免重复 - const DEFAULT_AUTO_SETTINGS: Record = { - day: { exec_type: 'auto', type: 'day', hour: 1, minute: 0 }, - week: { exec_type: 'auto', type: 'week', hour: 1, minute: 0, week: 1 }, - month: { exec_type: 'auto', type: 'month', hour: 1, minute: 0, month: 1 }, - } - - // 创建时间输入input - const createTimeInput = (value: number, updateFn: (val: number) => void, max: number, label: string): VNode => ( - - { - if (val !== null) { - updateFn(val) - } - }} - max={max} - min={0} - showButton={false} - class="w-full" - /> - {label} - - ) - - // 表单渲染 - const formRender = computed(() => { - const formItems: FormConfig = [] - if (param.value.exec_type === 'auto') { - formItems.push( - useFormCustom(() => { - return ( - - - { - if (val) { - param.value.type = val - updateParamValueByType(val) - } - }} - /> - - - {param.value.type !== 'day' && ( - - {param.value.type === 'week' ? ( - { - param.value.week = val - }} - options={weekOptions} - /> - ) : ( - createTimeInput( - param.value.month || 0, - (val: number) => (param.value.month = val), - 31, - $t('t_29_1744958838904'), - ) - )} - - )} - - - {createTimeInput( - param.value.hour || 0, - (val: number) => (param.value.hour = val), - 23, - $t('t_5_1744879615277'), - )} - - - - {createTimeInput( - param.value.minute || 0, - (val: number) => (param.value.minute = val), - 59, - $t('t_3_1744879615723'), - )} - - - ) - }), - ) - } - return [ - // 运行模式选择 - useFormRadio($t('t_30_1745735764748'), 'exec_type', [ - { label: $t('t_4_1744875940750'), value: 'auto' }, - { label: $t('t_5_1744875940010'), value: 'manual' }, - ]), - ...formItems, - ] - }) - - // 创建表单实例 const { - component: Form, - data, - example, - } = useForm({ - defaultValue: param, - config: formRender, - rules, - }) + updateNodeConfig, + isRefreshNode, + flowData, + setStartNodeSavedByUser, + startNodeSavedByUser, + } = useStore(); + // 弹窗辅助 + const { confirm } = useModalHooks(); + // 错误处理 + const { handleError } = useError(); + // 获取表单助手函数 + const { useFormRadio, useFormCustom } = useFormHooks(); + // 表单参数 + const param = ref(deepClone(props.node.config)); - // 更新参数的函数 - const updateParamValue = (updates: StartNodeConfig) => { - console.log(updates) - let newParams = { ...updates } - // if (newParams.exec_type === 'manual') { - // 小时随机 1-6 - const randomHour = Math.floor(Math.random() * 4) + 1 - // 分钟每5分钟随机,0-55 - const randomMinute = Math.floor(Math.random() * 12) * 5 - newParams = { - ...newParams, - hour: randomHour, - minute: randomMinute, - } - param.value = newParams - // } - } + // 周期类型选项 + const cycleTypeOptions = [ + { label: $t("t_2_1744875938555"), value: "day" }, + { label: $t("t_0_1744942117992"), value: "week" }, + { label: $t("t_3_1744875938310"), value: "month" }, + ]; - const updateParamValueByType = (type: 'day' | 'week' | 'month') => { - updateParamValue(DEFAULT_AUTO_SETTINGS[type] as StartNodeConfig) - } + // 星期选项 + const weekOptions = [ + { label: $t("t_1_1744942116527"), value: 1 }, + { label: $t("t_2_1744942117890"), value: 2 }, + { label: $t("t_3_1744942117885"), value: 3 }, + { label: $t("t_4_1744942117738"), value: 4 }, + { label: $t("t_5_1744942117167"), value: 5 }, + { label: $t("t_6_1744942117815"), value: 6 }, + { label: $t("t_7_1744942117862"), value: 0 }, + ]; - // 监听执行类型变化 - watch( - () => param.value.exec_type, - (newVal) => { - if (newVal === 'auto') { - updateParamValue(DEFAULT_AUTO_SETTINGS.day as StartNodeConfig) - } else if (newVal === 'manual') { - updateParamValue({ exec_type: 'manual' }) - } - }, - ) + // 定义默认值常量,避免重复 + const DEFAULT_AUTO_SETTINGS: Record = { + day: { exec_type: "auto", type: "day", hour: 1, minute: 0 }, + week: { exec_type: "auto", type: "week", hour: 1, minute: 0, week: 1 }, + month: { exec_type: "auto", type: "month", hour: 1, minute: 0, month: 1 }, + }; - // 监听类型变化 - watch( - () => param.value.type, - (newVal) => { - if (newVal && param.value.exec_type === 'auto') { - updateParamValue(DEFAULT_AUTO_SETTINGS[newVal] as StartNodeConfig) - } - }, - ) + // 创建时间输入input + const createTimeInput = ( + value: number, + updateFn: (val: number) => void, + max: number, + label: string + ): VNode => ( + + { + if (val !== null) { + updateFn(val); + } + }} + max={max} + min={0} + showButton={false} + class="w-full" + /> + {label} + + ); - // 确认事件触发 - confirm(async (close) => { - try { - await example.value?.validate() - updateNodeConfig(props.node.id, data.value) // 更新节点配置 - isRefreshNode.value = props.node.id // 刷新节点 - close() - } catch (error) { - handleError(error) - } - }) + // 表单渲染 + const formRender = computed(() => { + const formItems: FormConfig = []; + if (param.value.exec_type === "auto") { + formItems.push( + useFormCustom(() => { + return ( + + + { + if (val) { + param.value.type = val; + updateParamValueByType(val); + } + }} + /> + - onMounted(() => { - if (isUndefined(flowData.value.id)) { - updateParamValueByType('day') - updateNodeConfig(props.node.id, param.value) // 更新节点配置 - } - }) + {param.value.type !== "day" && ( + + {param.value.type === "week" ? ( + { + param.value.week = val; + }} + options={weekOptions} + /> + ) : ( + createTimeInput( + param.value.month || 0, + (val: number) => (param.value.month = val), + 31, + $t("t_29_1744958838904") + ) + )} + + )} + + + {createTimeInput( + param.value.hour || 0, + (val: number) => (param.value.hour = val), + 23, + $t("t_5_1744879615277") + )} + + + + {createTimeInput( + param.value.minute || 0, + (val: number) => (param.value.minute = val), + 59, + $t("t_3_1744879615723") + )} + + + ); + }) + ); + } + return [ + // 运行模式选择 + useFormRadio($t("t_30_1745735764748"), "exec_type", [ + { label: $t("t_4_1744875940750"), value: "auto" }, + { label: $t("t_5_1744875940010"), value: "manual" }, + ]), + ...formItems, + ]; + }); + + // 创建表单实例 + const { + component: Form, + data, + example, + } = useForm({ + defaultValue: param, + config: formRender, + rules, + }); + + // 更新参数的函数 + const updateParamValue = (updates: StartNodeConfig) => { + console.log(updates); + let newParams = { ...updates }; + // if (newParams.exec_type === 'manual') { + // 小时随机 1-6 + const randomHour = Math.floor(Math.random() * 4) + 1; + // 分钟每5分钟随机,0-55 + const randomMinute = Math.floor(Math.random() * 12) * 5; + newParams = { + ...newParams, + hour: randomHour, + minute: randomMinute, + }; + param.value = newParams; + // } + }; + + const updateParamValueByType = (type: "day" | "week" | "month") => { + updateParamValue(DEFAULT_AUTO_SETTINGS[type] as StartNodeConfig); + }; + + // 监听执行类型变化 + watch( + () => param.value.exec_type, + (newVal) => { + if (newVal === "auto") { + updateParamValue(DEFAULT_AUTO_SETTINGS.day as StartNodeConfig); + } else if (newVal === "manual") { + updateParamValue({ exec_type: "manual" }); + } + } + ); + + // 监听类型变化 + watch( + () => param.value.type, + (newVal) => { + if (newVal && param.value.exec_type === "auto") { + updateParamValue(DEFAULT_AUTO_SETTINGS[newVal] as StartNodeConfig); + } + } + ); + + // 确认事件触发 + confirm(async (close) => { + try { + await example.value?.validate(); + updateNodeConfig(props.node.id, data.value); // 更新节点配置 + isRefreshNode.value = props.node.id; // 刷新节点 + setStartNodeSavedByUser(true); + close(); + } catch (error) { + handleError(error); + } + }); + + onMounted(() => { + console.log("开始节点初始化"); + if (isUndefined(flowData.value.id) && !startNodeSavedByUser.value) { + updateParamValueByType("day"); + updateNodeConfig(props.node.id, param.value); // 更新节点配置 + } + }); return () => (
diff --git a/frontend/apps/allin-ssl/src/views/autoDeploy/useController.tsx b/frontend/apps/allin-ssl/src/views/autoDeploy/useController.tsx index 767164a..656c483 100644 --- a/frontend/apps/allin-ssl/src/views/autoDeploy/useController.tsx +++ b/frontend/apps/allin-ssl/src/views/autoDeploy/useController.tsx @@ -91,6 +91,57 @@ export const useController = () => { // 判断是否为子路由 const hasChildRoutes = computed(() => route.path !== "/auto-deploy"); + /** + * @description 格式化执行周期显示 + * @param {string} execTime - 执行时间配置JSON字符串 + * @param {string} execType - 执行类型 + * @returns {string} 格式化后的执行周期文本 + */ + const formatExecTime = (execTime: string, execType: string): string => { + // 如果是手动执行,显示 -- + if (execType !== "auto") { + return "--"; + } + + // 如果没有执行时间配置,默认为每日 + if (!execTime) { + return "每日"; + } + + try { + const timeConfig = JSON.parse(execTime); + const { type = "day", hour, minute, week, month } = timeConfig; + + // 格式化时间 + const timeStr = `${hour.toString().padStart(2, "0")}:${minute + .toString() + .padStart(2, "0")}`; + + switch (type) { + case "day": + return `每日 ${timeStr}`; + case "week": + const weekDays = [ + "周日", + "周一", + "周二", + "周三", + "周四", + "周五", + "周六", + ]; + return `每周${weekDays[week] || "周" + week} ${timeStr}`; + case "month": + return `每月${month}日 ${timeStr}`; + default: + return `每日 ${timeStr}`; + } + } catch (error) { + console.error("解析执行时间配置失败:", error); + return "每日"; + } + }; + /** * @description 创建表格列配置 * @returns {DataTableColumn[]} 返回表格列配置数组 @@ -140,6 +191,14 @@ export const useController = () => { render: (row: WorkflowItem) => row.last_run_time || "-", }, statusCol("last_run_status", $t("t_2_1750129253921")), + { + title: "执行周期", + key: "exec_time", + width: 150, + render: (row: WorkflowItem) => ( + {formatExecTime(row.exec_time, row.exec_type)} + ), + }, { title: $t("t_8_1745215914610"), key: "actions", @@ -342,12 +401,17 @@ export const useController = () => { * @description 复制工作流 * @param {WorkflowItem} workflow - 工作流对象 */ - const handleCopyWorkflow = async (workflow: WorkflowItem) => { - console.log(workflow, 'workflow123123123123'); - const { name, content, exec_type, active, exec_time } = workflow; - const params = { name: `${name} - 副本`, content, exec_type, active, exec_time }; - await copyExistingWorkflow(params as WorkflowItem); - await fetch(); + const handleCopyWorkflow = async (workflow: WorkflowItem) => { + const { name, content, exec_type, active, exec_time } = workflow; + const params = { + name: `${name} - 副本`, + content, + exec_type, + active, + exec_time, + }; + await copyExistingWorkflow(params as WorkflowItem); + await fetch(); }; /** diff --git a/frontend/apps/allin-ssl/src/views/privateCaCert/index.tsx b/frontend/apps/allin-ssl/src/views/privateCaCert/index.tsx index 78ff040..71b5853 100644 --- a/frontend/apps/allin-ssl/src/views/privateCaCert/index.tsx +++ b/frontend/apps/allin-ssl/src/views/privateCaCert/index.tsx @@ -45,18 +45,21 @@ export default defineComponent({ ({ + ...(intermediateCaList.value || []).map((item) => ({ label: item.name, value: item.id, - })) + })), ]} placeholder="请选择中间证书" size="large" - style={{ width: "180px" }} - defaultValue={""} + style={{ width: "180px" }} + defaultValue={""} onUpdateValue={handleCaIdChange} /> - +
), content: () => ( diff --git a/frontend/apps/allin-ssl/src/views/privateCaCert/useStore.tsx b/frontend/apps/allin-ssl/src/views/privateCaCert/useStore.tsx index 67eb582..06efa46 100644 --- a/frontend/apps/allin-ssl/src/views/privateCaCert/useStore.tsx +++ b/frontend/apps/allin-ssl/src/views/privateCaCert/useStore.tsx @@ -38,19 +38,24 @@ export const useStore = () => { const getIntermediateCaList = async () => { try { - const { fetch, data } = getCaList({ + const { fetch, data } = getCaList({ p: "-1", limit: "-1", level: "intermediate", - }); - await fetch(); - if (data.value?.status === true) { - intermediateCaList.value = data.value.data; - return data.value.data; - } - } catch (error) { - console.error('获取中间证书列表失败:', error); - } + }); + await fetch(); + if (data.value?.status === true) { + intermediateCaList.value = data.value.data || []; + return data.value.data || []; + } else { + intermediateCaList.value = []; + return []; + } + } catch (error) { + console.error("获取中间证书列表失败:", error); + intermediateCaList.value = []; + return []; + } }; return { diff --git a/frontend/apps/allin-ssl/src/views/privateCaManage/components/AddCaModal.tsx b/frontend/apps/allin-ssl/src/views/privateCaManage/components/AddCaModal.tsx index a6044d4..5ff695d 100644 --- a/frontend/apps/allin-ssl/src/views/privateCaManage/components/AddCaModal.tsx +++ b/frontend/apps/allin-ssl/src/views/privateCaManage/components/AddCaModal.tsx @@ -1,174 +1,177 @@ import { defineComponent, ref, computed, watch } from 'vue'; -import { NForm, NFormItem, NInput, NSelect, NSpace, NButton, FormRules, useMessage } from 'naive-ui'; -import { useStore } from '../useStore'; -import { useAddCaController } from '../useController'; -import { useModalClose } from '@baota/naive-ui/hooks'; +import { + NForm, + NFormItem, + NInput, + NSelect, + NSpace, + NButton, + FormRules, + useMessage, + NDivider, + NIcon, +} from "naive-ui"; +import { useStore } from "../useStore"; +import { useAddCaController } from "../useController"; +import { useModalClose } from "@baota/naive-ui/hooks"; +import { ChevronDown } from "@vicons/ionicons5"; /** * 添加CA模态框组件 */ export default defineComponent({ - emits: ['success'], - setup(props, { emit }) { - const { addForm, resetAddForm, createType, rootCaList } = useStore(); - const message = useMessage(); - const closeModal = useModalClose(); - - // 表单引用 - const formRef = ref(); - - // 有效期单位选择 - const validityUnit = ref<'day' | 'year'>('day'); - - // 使用表单控制器 - const { handleSubmit } = useAddCaController(); - - // 表单验证规则 - const rules = computed((): FormRules => { - const baseRules: any = { - name: [ - { required: true, message: '请输入CA名称', trigger: 'blur' } - ], - cn: [ - { required: true, message: '请输入通用名称', trigger: 'blur' } - ], - o: [ - { required: true, message: '请输入组织名称', trigger: 'blur' } - ], - c: [ - { required: true, message: '请选择国家', trigger: 'change' } - ], - ou: [ - { required: true, message: '请输入组织单位', trigger: 'blur' } - ], - province: [ - { required: true, message: '请输入省份', trigger: 'blur' } - ], - locality: [ - { required: true, message: '请输入城市', trigger: 'blur' } - ], - key_length: [ - { required: true, message: '请选择密钥长度', trigger: 'change' } - ], - valid_days: [ - { required: true, message: '请选择有效期', trigger: 'change' } - ] - }; + emits: ["success"], + setup(props, { emit }) { + const { addForm, resetAddForm, createType, rootCaList } = useStore(); + const message = useMessage(); + const closeModal = useModalClose(); - if (createType.value === 'root') { - baseRules.algorithm = [ - { required: true, message: '请选择加密算法', trigger: 'change' } - ]; - } + // 表单引用 + const formRef = ref(); - if (createType.value === 'intermediate') { - baseRules.root_id = [ - { required: true, message: '请选择父级CA', trigger: 'change' } - ]; - } + // 有效期单位选择 + const validityUnit = ref<"day" | "year">("day"); - return baseRules; - }); + // 展开收起状态 + const showAdvancedConfig = ref(false); - // 算法选项 - const algorithmOptions = [ - { label: "ECDSA", value: "ecdsa" }, - { label: "RSA", value: "rsa" }, - { label: "SM2", value: "sm2" }, - ]; + // 使用表单控制器 + const { handleSubmit } = useAddCaController(); - const keyLengthOptions = computed(() => { - switch (addForm.value.algorithm) { - case 'ecdsa': - return [ - { label: "P-256 (256 bit)", value: "256" }, - { label: "P-384 (384 bit)", value: "384" }, - { label: "P-521 (521 bit)", value: "521" }, - ]; - case 'rsa': - return [ - { label: "2048 bit", value: "2048" }, - { label: "3072 bit", value: "3072" }, - { label: "4096 bit", value: "4096" }, - ]; - case 'sm2': - return [ - { label: "SM2 (256 bit)", value: "256" }, - ]; - default: - return []; - } - }); + // 表单验证规则 + const rules = computed((): FormRules => { + const baseRules: any = { + name: [{ required: true, message: "请输入CA名称", trigger: "blur" }], + cn: [{ required: true, message: "请输入通用名称", trigger: "blur" }], + c: [{ required: true, message: "请选择国家", trigger: "change" }], + key_length: [ + { required: true, message: "请选择密钥长度", trigger: "change" }, + ], + valid_days: [ + { required: true, message: "请选择有效期", trigger: "change" }, + ], + }; - // 国家选项 - const countryOptions = [ - { label: "中国", value: "CN" }, - { label: "美国", value: "US" }, - { label: "日本", value: "JP" }, - { label: "德国", value: "DE" }, - { label: "英国", value: "GB" }, - ]; + if (createType.value === "root") { + baseRules.algorithm = [ + { required: true, message: "请选择加密算法", trigger: "change" }, + ]; + } - // 监听算法变化,重置密钥长度选择 - watch(() => addForm.value.algorithm, (newAlgorithm) => { - addForm.value.key_length = ''; - if (newAlgorithm === 'ecdsa') { - addForm.value.key_length = '256'; - } else if (newAlgorithm === 'sm2') { - addForm.value.key_length = '256'; - } else if (newAlgorithm === 'rsa') { - addForm.value.key_length = '2048'; - } - }); + if (createType.value === "intermediate") { + baseRules.root_id = [ + { required: true, message: "请选择父级CA", trigger: "change" }, + ]; + } - // 监听父级CA选择,自动填充算法值 - watch(() => addForm.value.root_id, (newRootId) => { - if (createType.value === 'intermediate' && newRootId) { - const selectedRootCa = rootCaList.value.find(ca => ca.id.toString() === newRootId); - if (selectedRootCa) { - addForm.value.algorithm = selectedRootCa.algorithm; - if (selectedRootCa.algorithm === 'ecdsa') { - addForm.value.key_length = '256'; - } else if (selectedRootCa.algorithm === 'sm2') { - addForm.value.key_length = '256'; - } else if (selectedRootCa.algorithm === 'rsa') { - addForm.value.key_length = '2048'; - } - } - } - }); + return baseRules; + }); - // 处理表单提交 - const handleFormSubmit = async () => { - try { - // 先验证表单 - await formRef.value?.validate(); - const formData = { ...addForm.value }; - if (validityUnit.value === 'year' && formData.valid_days) { - const years = parseInt(formData.valid_days); - if (!isNaN(years)) { - formData.valid_days = (years * 365).toString(); - } - } - const success = await handleSubmit(formData); - if (success) { - resetAddForm(); - closeModal(); - return true; - } - } catch (error) { - console.error('表单验证失败:', error); - } - return false; - }; - - // 处理取消操作 - const handleCancel = () => { - resetAddForm(); - closeModal(); - }; + // 算法选项 + const algorithmOptions = [ + { label: "ECDSA", value: "ecdsa" }, + { label: "RSA", value: "rsa" }, + { label: "SM2", value: "sm2" }, + ]; - return () => ( + const keyLengthOptions = computed(() => { + switch (addForm.value.algorithm) { + case "ecdsa": + return [ + { label: "P-256 (256 bit)", value: "256" }, + { label: "P-384 (384 bit)", value: "384" }, + { label: "P-521 (521 bit)", value: "521" }, + ]; + case "rsa": + return [ + { label: "2048 bit", value: "2048" }, + { label: "3072 bit", value: "3072" }, + { label: "4096 bit", value: "4096" }, + ]; + case "sm2": + return [{ label: "SM2 (256 bit)", value: "256" }]; + default: + return []; + } + }); + + // 国家选项 + const countryOptions = [ + { label: "中国", value: "CN" }, + { label: "美国", value: "US" }, + { label: "日本", value: "JP" }, + { label: "德国", value: "DE" }, + { label: "英国", value: "GB" }, + ]; + + // 监听算法变化,重置密钥长度选择 + watch( + () => addForm.value.algorithm, + (newAlgorithm) => { + addForm.value.key_length = ""; + if (newAlgorithm === "ecdsa") { + addForm.value.key_length = "256"; + } else if (newAlgorithm === "sm2") { + addForm.value.key_length = "256"; + } else if (newAlgorithm === "rsa") { + addForm.value.key_length = "2048"; + } + } + ); + + // 监听父级CA选择,自动填充算法值 + watch( + () => addForm.value.root_id, + (newRootId) => { + if (createType.value === "intermediate" && newRootId) { + const selectedRootCa = rootCaList.value.find( + (ca) => ca.id.toString() === newRootId + ); + if (selectedRootCa) { + addForm.value.algorithm = selectedRootCa.algorithm; + if (selectedRootCa.algorithm === "ecdsa") { + addForm.value.key_length = "256"; + } else if (selectedRootCa.algorithm === "sm2") { + addForm.value.key_length = "256"; + } else if (selectedRootCa.algorithm === "rsa") { + addForm.value.key_length = "2048"; + } + } + } + } + ); + + // 处理表单提交 + const handleFormSubmit = async () => { + try { + // 先验证表单 + await formRef.value?.validate(); + const formData = { ...addForm.value }; + if (validityUnit.value === "year" && formData.valid_days) { + const years = parseInt(formData.valid_days); + if (!isNaN(years)) { + formData.valid_days = (years * 365).toString(); + } + } + const success = await handleSubmit(formData); + if (success) { + resetAddForm(); + closeModal(); + return true; + } + } catch (error) { + console.error("表单验证失败:", error); + } + return false; + }; + + // 处理取消操作 + const handleCancel = () => { + resetAddForm(); + closeModal(); + }; + + return () => ( - - - - - - - - - - - - - - - - - - - - {createType.value === "intermediate" && ( +
+
+ (showAdvancedConfig.value = !showAdvancedConfig.value) + } + > + +
+ 更多配置 + + + +
+
+
+ {showAdvancedConfig.value && ( +
+ + + + + + + + + + + + + + + + + + +
+ )} +
取消 @@ -286,5 +317,5 @@ export default defineComponent({
); - }, + }, }); diff --git a/frontend/apps/allin-ssl/src/views/privateCaManage/useController.tsx b/frontend/apps/allin-ssl/src/views/privateCaManage/useController.tsx index 98f2ee1..dbb0b13 100644 --- a/frontend/apps/allin-ssl/src/views/privateCaManage/useController.tsx +++ b/frontend/apps/allin-ssl/src/views/privateCaManage/useController.tsx @@ -428,11 +428,7 @@ export const useAddCaController = () => { const baseRules: any = { name: [{ required: true, message: '请输入CA名称', trigger: 'blur' }], cn: [{ required: true, message: '请输入通用名称', trigger: 'blur' }], - o: [{ required: true, message: '请输入组织名称', trigger: 'blur' }], c: [{ required: true, message: '请选择国家', trigger: 'change' }], - ou: [{ required: true, message: '请输入组织单位', trigger: 'blur' }], - province: [{ required: true, message: '请输入省份', trigger: 'blur' }], - locality: [{ required: true, message: '请输入城市', trigger: 'blur' }], key_length: [{ required: true, message: '请选择密钥长度', trigger: 'change' }], valid_days: [{ required: true, message: '请选择有效期', trigger: 'change' }], }; @@ -468,7 +464,7 @@ export const useAddCaController = () => { try { openLoad(); // 验证必填字段 - let requiredFields: string[] = ['name', 'cn', 'o', 'c', 'ou', 'province', 'locality', 'key_length', 'valid_days']; + let requiredFields: string[] = ['name', 'cn', 'c', 'key_length', 'valid_days']; if (createType.value === 'root') { requiredFields.push('algorithm'); } diff --git a/frontend/apps/domain-official/index.html b/frontend/apps/domain-official/index.html index 8901443..31490e4 100644 --- a/frontend/apps/domain-official/index.html +++ b/frontend/apps/domain-official/index.html @@ -10,21 +10,21 @@
-
+
-
+

堡塔域名注册重磅上线!
一站式搞定建站访问

- .com低至54元,.cn低至20元!部分后缀新人9.9元注册 + .com低至53.9元,.cn低至19.9元!部分后缀新人9.9元注册

- - -
-
-

域名价格一览表

-
- 透明的价格体系,无隐藏费用,让您明明白白消费,更多服务请联系客服咨询 - -