【新增】私有证书

This commit is contained in:
cai
2025-09-03 15:15:59 +08:00
parent efd052a297
commit 954cd1638d
442 changed files with 76787 additions and 7483 deletions

View File

@@ -13,11 +13,11 @@
/* 有嵌套分支的容器样式 */
.hasNestedBranch {
@apply w-full justify-around;
@apply w-full justify-center;
}
.flowNodeBranchCol {
@apply flex flex-col items-center border-t-2 border-b-2 border-[#cacaca] pt-[50px] bg-[#f8fafc] flex-1 relative max-w-[50%];
@apply flex flex-col items-center border-t-2 border-b-2 border-[#cacaca] pt-[50px] bg-[#f8fafc] flex-1 relative;
}
@@ -26,11 +26,6 @@
@apply w-full;
}
/* 多级嵌套分支样式调整 */
.flowNodeBranchCol .flowNodeBranchCol {
@apply min-w-[20rem] w-[24rem]
}
.flowNodeBranchCol::before {
@apply content-[''] absolute top-0 left-0 right-0 bottom-0 z-0 m-auto w-[2px] h-full bg-[#cacaca];

View File

@@ -1,9 +1,9 @@
.flowContainer {
@apply flex relative box-border w-full h-[calc(100vh-19rem)] overflow-x-auto overflow-y-auto p-[1rem];
@apply flex relative box-border w-full h-[calc(100vh-19rem)] overflow-x-auto overflow-y-auto p-[1rem] justify-center;
}
.flowProcess {
@apply relative h-full w-full;
@apply relative h-full;
}
.flowZoom {

View File

@@ -55,57 +55,72 @@ export default defineComponent({
onMounted(initData)
onUnmounted(resetFlowData)
return () => (
<div class="flex flex-col w-full h-full" style={cssVars.value}>
<div class="w-full h-[6rem] px-[2rem] mb-[2rem] rounded-lg flex items-center gap-2 justify-between">
<div class="flex items-center">
<NButton onClick={goBack}>
<NIcon class="mr-1">
<ArrowLeftOutlined />
</NIcon>
{$t('t_0_1744861190562')}
</NButton>
</div>
<div class="flex items-center ml-[.5rem]">
<NInput
v-model:value={flowData.value.name}
placeholder={$t('t_0_1745490735213')}
class="!w-[30rem] !border-none "
/>
</div>
<div class="flex items-center gap-2">
<NButton type="primary" onClick={handleSaveConfig} disabled={!selectedNodeId}>
<NIcon class="mr-1">
<SaveOutlined />
</NIcon>
{$t('t_2_1744861190040')}
</NButton>
</div>
</div>
<div class="w-full flex">
{/* 左侧流程容器 */}
<div class={styles.flowContainer}>
{/* 流程容器*/}
<div class={styles.flowProcess} style={{ transform: `scale(${flowZoom.value / 100})` }}>
{/* 渲染流程节点 */}
<NodeWrap node={flowData.value.childNode} />
{/* 流程结束节点 */}
<EndNode />
</div>
{/* 缩放控制区 */}
<div class={styles.flowZoom}>
<div class={styles.flowZoomIcon} onClick={() => handleZoom(1)}>
<SvgIcon icon="subtract" class={`${flowZoom.value === 50 ? styles.disabled : ''}`} color="#5a5e66" />
</div>
<span>{flowZoom.value}%</span>
<div class={styles.flowZoomIcon} onClick={() => handleZoom(2)}>
<SvgIcon icon="plus" class={`${flowZoom.value === 300 ? styles.disabled : ''}`} color="#5a5e66" />
</div>
</div>
</div>
</div>
{/* 保留原有插槽 */}
{slots.default?.()}
</div>
)
<div class="flex flex-col w-full h-full" style={cssVars.value}>
<div class="w-full h-[6rem] px-[2rem] mb-[2rem] rounded-lg flex items-center gap-2 justify-between">
<div class="flex items-center">
<NButton onClick={goBack}>
<NIcon class="mr-1">
<ArrowLeftOutlined />
</NIcon>
{$t("t_0_1744861190562")}
</NButton>
</div>
<div class="flex items-center ml-[.5rem]">
<NInput
v-model:value={flowData.value.name}
placeholder={$t("t_0_1745490735213")}
class="!w-[30rem] !border-none "
/>
</div>
<div class="flex items-center gap-2">
<NButton
type="primary"
onClick={handleSaveConfig}
disabled={!selectedNodeId}
>
<NIcon class="mr-1">
<SaveOutlined />
</NIcon>
{$t("t_2_1744861190040")}
</NButton>
</div>
</div>
<div class={styles.flowContainer}>
{/* 左侧流程容器 */}
<div class="flex min-w-0" >
{/* 流程容器*/}
<div
class={styles.flowProcess}
style={{ transform: `scale(${flowZoom.value / 100})` }}
>
{/* 渲染流程节点 */}
<NodeWrap node={flowData.value.childNode} />
{/* 流程结束节点 */}
<EndNode />
</div>
{/* 缩放控制区 */}
<div class={styles.flowZoom}>
<div class={styles.flowZoomIcon} onClick={() => handleZoom(1)}>
<SvgIcon
icon="subtract"
class={`${flowZoom.value === 50 ? styles.disabled : ""}`}
color="#5a5e66"
/>
</div>
<span>{flowZoom.value}%</span>
<div class={styles.flowZoomIcon} onClick={() => handleZoom(2)}>
<SvgIcon
icon="plus"
class={`${flowZoom.value === 300 ? styles.disabled : ""}`}
color="#5a5e66"
/>
</div>
</div>
</div>
</div>
{/* 保留原有插槽 */}
{slots.default?.()}
</div>
);
},
})

View File

@@ -9,4 +9,5 @@ export const EXECUTE_RESULT_CONDITION = 'execute_result_condition' // 执行结
export const UPLOAD = 'upload' // 上传节点
export const NOTIFY = 'notify' // 通知节点
export const APPLY = 'apply' // 申请节点
export const PRIVATE_CA = 'private_ca' // 私有CA节点
export const DEPLOY = 'deploy' // 部署节点

View File

@@ -1,53 +1,54 @@
import { deepMerge } from '@baota/utils/data'
import { v4 as uuidv4 } from 'uuid'
import {
APPLY,
BRANCH,
CONDITION,
DEPLOY,
NOTIFY,
UPLOAD,
EXECUTE_RESULT_BRANCH,
EXECUTE_RESULT_CONDITION,
START,
} from './alias'
APPLY,
BRANCH,
CONDITION,
DEPLOY,
NOTIFY,
UPLOAD,
PRIVATE_CA,
EXECUTE_RESULT_BRANCH,
EXECUTE_RESULT_CONDITION,
START,
} from "./alias";
import {
BaseRenderNodeOptions,
NodeOptions,
BaseNodeData,
ExecuteResultConditionNodeData,
ExecuteResultBranchNodeData,
} from '../types'
BaseRenderNodeOptions,
NodeOptions,
BaseNodeData,
ExecuteResultConditionNodeData,
ExecuteResultBranchNodeData,
} from "../types";
const nodeOptions = {} as NodeOptions
const nodeOptions = {} as NodeOptions;
// 基础节点配置
const baseOptions = <T extends BaseNodeData>(
options: Partial<BaseRenderNodeOptions<T>> & { defaultNode?: T },
options: Partial<BaseRenderNodeOptions<T>> & { defaultNode?: T }
): BaseRenderNodeOptions<T> => {
const defaultOptions: BaseRenderNodeOptions<T> = {
title: {
name: '', // 节点标题
color: '#FFFFFF', // 节点标题颜色
bgColor: '#3CB371', // 节点标题背景颜色
},
icon: {
name: '', // 节点图标
color: '#3CB371', // 节点图标颜色
},
operateNode: {
add: true, // 节点是否可以追加
sort: 1, // 节点排序,用于排序节点的显示优先级,主要用于配置节点的操作
addBranch: false, // 节点是否可以添加分支
edit: true, // 节点是否可以编辑
remove: true, // 节点是否可以删除
onSupportNode: [], // 节点不支持添加的节点类型
},
isHasDrawer: false, // 节点是否可以进行配置
defaultNode: {} as T,
}
return deepMerge(defaultOptions, options) as BaseRenderNodeOptions<T>
}
const defaultOptions: BaseRenderNodeOptions<T> = {
title: {
name: "", // 节点标题
color: "#FFFFFF", // 节点标题颜色
bgColor: "#3CB371", // 节点标题背景颜色
},
icon: {
name: "", // 节点图标
color: "#3CB371", // 节点图标颜色
},
operateNode: {
add: true, // 节点是否可以追加
sort: 1, // 节点排序,用于排序节点的显示优先级,主要用于配置节点的操作
addBranch: false, // 节点是否可以添加分支
edit: true, // 节点是否可以编辑
remove: true, // 节点是否可以删除
onSupportNode: [], // 节点不支持添加的节点类型
},
isHasDrawer: false, // 节点是否可以进行配置
defaultNode: {} as T,
};
return deepMerge(defaultOptions, options) as BaseRenderNodeOptions<T>;
};
// ------------------------------ 基础节点配置 ------------------------------
@@ -79,203 +80,233 @@ const baseOptions = <T extends BaseNodeData>(
// 开始节点
nodeOptions[START] = () =>
baseOptions({
title: { name: '开始' },
operateNode: { onSupportNode: [EXECUTE_RESULT_BRANCH], remove: false, edit: false, add: false },
defaultNode: {
id: uuidv4(),
name: '开始',
type: START,
config: {
exec_type: 'manual',
},
childNode: null,
},
})
baseOptions({
title: { name: "开始" },
operateNode: {
onSupportNode: [EXECUTE_RESULT_BRANCH],
remove: false,
edit: false,
add: false,
},
defaultNode: {
id: uuidv4(),
name: "开始",
type: START,
config: {
exec_type: "manual",
},
childNode: null,
},
});
// 申请节点
nodeOptions[APPLY] = () =>
baseOptions({
title: { name: '申请' },
icon: { name: APPLY },
operateNode: { sort: 1 },
defaultNode: {
id: uuidv4(),
name: '申请',
type: APPLY,
config: {
domains: '',
email: '',
eabId: '',
ca: 'letsencrypt',
proxy: '',
end_day: 30,
provider: '',
provider_id: '',
algorithm: 'RSA2048',
skip_check: 0,
close_cname: 0,
max_wait: undefined,
ignore_check: 0,
},
childNode: null,
},
})
baseOptions({
title: { name: "申请" },
icon: { name: APPLY },
operateNode: { sort: 1 },
defaultNode: {
id: uuidv4(),
name: "申请",
type: APPLY,
config: {
domains: "",
email: "",
eabId: "",
ca: "letsencrypt",
proxy: "",
end_day: 30,
provider: "",
provider_id: "",
algorithm: "RSA2048",
skip_check: 0,
close_cname: 0,
max_wait: undefined,
ignore_check: 0,
},
childNode: null,
},
});
// 上传节点
nodeOptions[UPLOAD] = () =>
baseOptions({
title: { name: '上传' },
icon: { name: UPLOAD },
operateNode: { sort: 2, onSupportNode: [EXECUTE_RESULT_BRANCH] },
defaultNode: {
id: uuidv4(),
name: '上传',
type: UPLOAD,
config: {
cert_id: '',
cert: '',
key: '',
},
childNode: null,
},
})
baseOptions({
title: { name: "上传" },
icon: { name: UPLOAD },
operateNode: { sort: 2, onSupportNode: [EXECUTE_RESULT_BRANCH] },
defaultNode: {
id: uuidv4(),
name: "上传",
type: UPLOAD,
config: {
cert_id: "",
cert: "",
key: "",
},
childNode: null,
},
});
// 部署节点
nodeOptions[DEPLOY] = () =>
baseOptions({
title: { name: '部署' },
icon: { name: DEPLOY },
operateNode: { sort: 3 },
defaultNode: {
id: uuidv4(),
name: '部署',
type: DEPLOY,
inputs: [],
config: {
provider: '',
provider_id: '',
skip: 1,
inputs: {
fromNodeId: '',
name: '',
},
},
childNode: null,
},
})
baseOptions({
title: { name: "部署" },
icon: { name: DEPLOY },
operateNode: { sort: 3 },
defaultNode: {
id: uuidv4(),
name: "部署",
type: DEPLOY,
inputs: [],
config: {
provider: "",
provider_id: "",
skip: 1,
inputs: {
fromNodeId: "",
name: "",
},
},
childNode: null,
},
});
// 通知节点
nodeOptions[NOTIFY] = () =>
baseOptions({
title: { name: '通知' },
icon: { name: NOTIFY },
operateNode: { sort: 4 },
defaultNode: {
id: uuidv4(),
name: '通知',
type: NOTIFY,
config: {
provider: '',
provider_id: '',
subject: '',
body: '',
skip: false,
},
childNode: null,
},
})
baseOptions({
title: { name: "通知" },
icon: { name: NOTIFY },
operateNode: { sort: 4 },
defaultNode: {
id: uuidv4(),
name: "通知",
type: NOTIFY,
config: {
provider: "",
provider_id: "",
subject: "",
body: "",
skip: false,
},
childNode: null,
},
});
// 自签节点
nodeOptions[PRIVATE_CA] = () =>
baseOptions({
title: { name: "自签" },
icon: { name: PRIVATE_CA },
operateNode: { sort: 4.5 },
defaultNode: {
id: uuidv4(),
name: "自签证书",
type: PRIVATE_CA,
config: {
ca_id: undefined,
name: undefined,
algorithm: undefined,
key_length: undefined,
end_day: 30,
valid_days: "",
validity_unit: "day",
cn: "",
san: "",
},
childNode: null,
},
});
// 分支节点
nodeOptions[BRANCH] = () =>
baseOptions({
title: { name: '并行分支' },
icon: { name: BRANCH },
operateNode: { sort: 5, addBranch: true },
defaultNode: {
id: uuidv4(),
name: '并行分支',
type: BRANCH,
conditionNodes: [
{
id: uuidv4(),
name: '分支1',
type: CONDITION,
config: {},
childNode: null,
},
{
id: uuidv4(),
name: '分支2',
type: CONDITION,
config: {},
childNode: null,
},
],
},
})
baseOptions({
title: { name: "并行分支" },
icon: { name: BRANCH },
operateNode: { sort: 5, addBranch: true },
defaultNode: {
id: uuidv4(),
name: "并行分支",
type: BRANCH,
conditionNodes: [
{
id: uuidv4(),
name: "分支1",
type: CONDITION,
config: {},
childNode: null,
},
{
id: uuidv4(),
name: "分支2",
type: CONDITION,
config: {},
childNode: null,
},
],
},
});
// 条件节点
nodeOptions[CONDITION] = () =>
baseOptions({
title: { name: '分支1' },
icon: { name: CONDITION },
operateNode: { add: false, onSupportNode: [EXECUTE_RESULT_BRANCH] },
defaultNode: {
id: uuidv4(),
name: '分支1',
type: CONDITION,
icon: { name: CONDITION },
config: {},
childNode: null,
},
})
baseOptions({
title: { name: "分支1" },
icon: { name: CONDITION },
operateNode: { add: false, onSupportNode: [EXECUTE_RESULT_BRANCH] },
defaultNode: {
id: uuidv4(),
name: "分支1",
type: CONDITION,
icon: { name: CONDITION },
config: {},
childNode: null,
},
});
// 执行结构分支
nodeOptions[EXECUTE_RESULT_BRANCH] = () =>
baseOptions<ExecuteResultBranchNodeData>({
title: { name: '执行结果分支' },
icon: { name: BRANCH },
operateNode: { sort: 7, onSupportNode: [EXECUTE_RESULT_BRANCH] },
defaultNode: {
id: uuidv4(),
name: '执行结果分支',
type: EXECUTE_RESULT_BRANCH,
conditionNodes: [
{
id: uuidv4(),
name: '若当前节点执行成功…',
type: EXECUTE_RESULT_CONDITION,
icon: { name: 'success' },
config: { type: 'success' },
childNode: null,
},
{
id: uuidv4(),
name: '若当前节点执行失败…',
type: EXECUTE_RESULT_CONDITION,
icon: { name: 'error' },
config: { type: 'fail' },
childNode: null,
},
],
},
})
baseOptions<ExecuteResultBranchNodeData>({
title: { name: "执行结果分支" },
icon: { name: BRANCH },
operateNode: { sort: 7, onSupportNode: [EXECUTE_RESULT_BRANCH] },
defaultNode: {
id: uuidv4(),
name: "执行结果分支",
type: EXECUTE_RESULT_BRANCH,
conditionNodes: [
{
id: uuidv4(),
name: "若当前节点执行成功…",
type: EXECUTE_RESULT_CONDITION,
icon: { name: "success" },
config: { type: "success" },
childNode: null,
},
{
id: uuidv4(),
name: "若当前节点执行失败…",
type: EXECUTE_RESULT_CONDITION,
icon: { name: "error" },
config: { type: "fail" },
childNode: null,
},
],
},
});
// 执行结构条件
nodeOptions[EXECUTE_RESULT_CONDITION] = () =>
baseOptions<ExecuteResultConditionNodeData>({
title: { name: '执行结构条件' },
icon: { name: BRANCH },
operateNode: { add: false, onSupportNode: [EXECUTE_RESULT_BRANCH] },
defaultNode: {
id: uuidv4(),
name: '若前序节点执行失败…',
type: EXECUTE_RESULT_CONDITION,
icon: { name: 'SUCCESS' },
config: { type: 'SUCCESS' },
childNode: null,
},
})
baseOptions<ExecuteResultConditionNodeData>({
title: { name: "执行结构条件" },
icon: { name: BRANCH },
operateNode: { add: false, onSupportNode: [EXECUTE_RESULT_BRANCH] },
defaultNode: {
id: uuidv4(),
name: "若前序节点执行失败…",
type: EXECUTE_RESULT_CONDITION,
icon: { name: "success" },
config: { type: "success" },
childNode: null,
},
});
export default nodeOptions

View File

@@ -1,149 +1,161 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import {
APPLY,
BRANCH,
CONDITION,
DEPLOY,
END,
EXECUTE_RESULT_BRANCH,
EXECUTE_RESULT_CONDITION,
NOTIFY,
START,
UPLOAD,
DEFAULT,
} from './lib/alias'
import type { FormRules } from 'naive-ui'
import type { Component } from 'vue'
APPLY,
BRANCH,
CONDITION,
DEPLOY,
END,
EXECUTE_RESULT_BRANCH,
EXECUTE_RESULT_CONDITION,
NOTIFY,
PRIVATE_CA,
START,
UPLOAD,
DEFAULT,
} from "./lib/alias";
import type { FormRules } from "naive-ui";
import type { Component } from "vue";
// 拖拽效果
export interface FlowNodeProps {
isEdit: boolean
type: 'quick' | 'advanced'
node: FlowNode
taskComponents?: Record<string, Component>
isEdit: boolean;
type: "quick" | "advanced";
node: FlowNode;
taskComponents?: Record<string, Component>;
}
export interface FlowNode {
id: string
name: string
childNode: BaseNodeData
id: string;
name: string;
childNode: BaseNodeData;
}
// 添加节点选项
export interface NodeSelect {
title: NodeTitle
type: NodeNum
icon: NodeIcon
selected: boolean
title: NodeTitle;
type: NodeNum;
icon: NodeIcon;
selected: boolean;
}
// 节点标题配置
export interface NodeTitle {
name: string
color?: string
bgColor?: string
name: string;
color?: string;
bgColor?: string;
}
// 节点图标配置
export interface NodeIcon {
name: string
color?: string
name: string;
color?: string;
}
// 操作节点配置,用于渲染节点的操作功能
export interface operateNodeOptions {
add?: boolean // 是否显示添加节点
sort?: number // 节点排序,用于排序节点的显示优先级,主要用于配置节点的操作
addBranch?: boolean // 是否显示添加分支节点,仅在节点类型为分支节点时有效
addBranchTitle?: string // 添加分支节点标题,仅在节点类型为分支节点时有效
edit?: boolean // 是否可编辑
remove?: boolean // 是否可删除
onSupportNode?: NodeNum[] // 不支持添加的节点类型
add?: boolean; // 是否显示添加节点
sort?: number; // 节点排序,用于排序节点的显示优先级,主要用于配置节点的操作
addBranch?: boolean; // 是否显示添加分支节点,仅在节点类型为分支节点时有效
addBranchTitle?: string; // 添加分支节点标题,仅在节点类型为分支节点时有效
edit?: boolean; // 是否可编辑
remove?: boolean; // 是否可删除
onSupportNode?: NodeNum[]; // 不支持添加的节点类型
}
// 基础节点渲染配置,用于渲染节点
export interface BaseRenderNodeOptions<T extends BaseNodeData> {
title: NodeTitle // 节点标题
icon?: NodeIcon // 节点图标
isAddNode?: boolean // 是否显示添加节点
isHasDrawer?: boolean // 是否显示抽屉
operateNode?: operateNodeOptions // 是否显示操作节点
defaultNode?: T // 默认节点数据 -- 节点数据,用于组合相应结构
title: NodeTitle; // 节点标题
icon?: NodeIcon; // 节点图标
isAddNode?: boolean; // 是否显示添加节点
isHasDrawer?: boolean; // 是否显示抽屉
operateNode?: operateNodeOptions; // 是否显示操作节点
defaultNode?: T; // 默认节点数据 -- 节点数据,用于组合相应结构
}
// 基础节点数据
export interface BaseNodeData<T = Record<string, unknown>> {
type: NodeNum // 节点类型
id?: string // 节点id用于编辑
name: string // 节点名称
icon?: NodeIcon // 节点图标
inputs?: Record<string, unknown>[] // 输入,用于连接其他节点的数据
config?: T // 参数,用于配置当前的节点
childNode?: BaseNodeData | BranchNodeData | null // 子节点
type: NodeNum; // 节点类型
id?: string; // 节点id用于编辑
name: string; // 节点名称
icon?: NodeIcon; // 节点图标
inputs?: Record<string, unknown>[]; // 输入,用于连接其他节点的数据
config?: T; // 参数,用于配置当前的节点
childNode?: BaseNodeData | BranchNodeData | null; // 子节点
}
// 分支节点数据
export interface BranchNodeData<T extends Record<string, unknown> = Record<string, unknown>> extends BaseNodeData<T> {
type: typeof BRANCH // 节点类型
conditionNodes: ConditionNodeData[] // 子节点
export interface BranchNodeData<
T extends Record<string, unknown> = Record<string, unknown>
> extends BaseNodeData<T> {
type: typeof BRANCH; // 节点类型
conditionNodes: ConditionNodeData[]; // 子节点
}
// 执行条件分支节点数据
export interface ExecuteResultBranchNodeData extends BaseNodeData {
type: typeof EXECUTE_RESULT_BRANCH // 节点类型
conditionNodes: ExecuteResultConditionNodeData[] // 子节点
type: typeof EXECUTE_RESULT_BRANCH; // 节点类型
conditionNodes: ExecuteResultConditionNodeData[]; // 子节点
}
// 执行结果条件节点数据
interface ExecuteResultCondition {
type: 'success' | 'fail'
[key: string]: unknown
type: "success" | "fail";
[key: string]: unknown;
}
// 条件节点数据
export interface ExecuteResultConditionNodeData extends BaseNodeData<ExecuteResultCondition> {
type: typeof EXECUTE_RESULT_CONDITION // 节点类型
config: ExecuteResultCondition
export interface ExecuteResultConditionNodeData
extends BaseNodeData<ExecuteResultCondition> {
type: typeof EXECUTE_RESULT_CONDITION; // 节点类型
config: ExecuteResultCondition;
}
// 节点类型
export type NodeNum =
| typeof START // 开始节点
| typeof DEFAULT // 默认节点
| typeof END // 结束节点
| typeof BRANCH // 分支节点
| typeof CONDITION // 条件节点
| typeof EXECUTE_RESULT_BRANCH // 执行结果分支节点if
| typeof EXECUTE_RESULT_CONDITION // 执行结果条件节点
| typeof UPLOAD // 上传节点(业务)
| typeof NOTIFY // 通知节点(业务)
| typeof APPLY // 申请节点(业务)
| typeof DEPLOY // 部署节点(业务)
| typeof START // 开始节点
| typeof DEFAULT // 默认节点
| typeof END // 结束节点
| typeof BRANCH // 分支节点
| typeof CONDITION // 条件节点
| typeof EXECUTE_RESULT_BRANCH // 执行结果分支节点if
| typeof EXECUTE_RESULT_CONDITION // 执行结果条件节点
| typeof UPLOAD // 上传节点(业务)
| typeof NOTIFY // 通知节点(业务)
| typeof APPLY // 申请节点(业务)
| typeof PRIVATE_CA // 私有CA节点(业务)
| typeof DEPLOY; // 部署节点(业务)
// 节点配置映射
export type NodeOptions = {
[START]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof START }>
[END]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof END }>
[DEFAULT]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof DEFAULT }>
[BRANCH]: () => BaseRenderNodeOptions<BranchNodeData>
[CONDITION]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof CONDITION }>
[EXECUTE_RESULT_BRANCH]: () => BaseRenderNodeOptions<ExecuteResultBranchNodeData>
[EXECUTE_RESULT_CONDITION]: () => BaseRenderNodeOptions<ExecuteResultConditionNodeData>
[UPLOAD]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof UPLOAD }>
[NOTIFY]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof NOTIFY }>
[APPLY]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof APPLY }>
[DEPLOY]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof DEPLOY }>
}
[START]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof START }>;
[END]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof END }>;
[DEFAULT]: () => BaseRenderNodeOptions<
BaseNodeData & { type: typeof DEFAULT }
>;
[BRANCH]: () => BaseRenderNodeOptions<BranchNodeData>;
[CONDITION]: () => BaseRenderNodeOptions<
BaseNodeData & { type: typeof CONDITION }
>;
[EXECUTE_RESULT_BRANCH]: () => BaseRenderNodeOptions<ExecuteResultBranchNodeData>;
[EXECUTE_RESULT_CONDITION]: () => BaseRenderNodeOptions<ExecuteResultConditionNodeData>;
[UPLOAD]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof UPLOAD }>;
[NOTIFY]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof NOTIFY }>;
[APPLY]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof APPLY }>;
[PRIVATE_CA]: () => BaseRenderNodeOptions<
BaseNodeData & { type: typeof PRIVATE_CA }
>;
[DEPLOY]: () => BaseRenderNodeOptions<BaseNodeData & { type: typeof DEPLOY }>;
};
// 基础节点配置
interface BaseNodeProps {
node: BaseNodeData<Record<string, unknown>>
node: BaseNodeData<Record<string, unknown>>;
}
// 定义组件包装器接受的props
export interface NodeWrapProps {
node?: BaseNodeData | BranchNodeData | ExecuteResultBranchNodeData
depth?: number
node?: BaseNodeData | BranchNodeData | ExecuteResultBranchNodeData;
depth?: number;
}
/**
@@ -152,240 +164,257 @@ export interface NodeWrapProps {
* @property message - 验证失败时的提示信息
*/
export interface ValidatorResult {
valid: boolean
message: string
valid: boolean;
message: string;
}
/**
* 验证函数类型定义
* @returns ValidatorResult - 返回验证结果对象
*/
export type ValidatorFunction = () => ValidatorResult
export type ValidatorFunction = () => ValidatorResult;
/**
* 兼容async-validator的类型定义
*/
export interface RuleItem {
type?: string
required?: boolean
pattern?: RegExp
min?: number
max?: number
len?: number
enum?: Array<any>
whitespace?: boolean
message?: string
validator?: (
rule: RuleItem,
value: any,
callback?: (error?: Error) => void,
) => boolean | Error | Error[] | Promise<void>
asyncValidator?: (rule: RuleItem, value: any, callback?: (error?: Error) => void) => Promise<void>
transform?: (value: any) => any
[key: string]: any
type?: string;
required?: boolean;
pattern?: RegExp;
min?: number;
max?: number;
len?: number;
enum?: Array<any>;
whitespace?: boolean;
message?: string;
validator?: (
rule: RuleItem,
value: any,
callback?: (error?: Error) => void
) => boolean | Error | Error[] | Promise<void>;
asyncValidator?: (
rule: RuleItem,
value: any,
callback?: (error?: Error) => void
) => Promise<void>;
transform?: (value: any) => any;
[key: string]: any;
}
/**
* 兼容async-validator的描述符类型
*/
export type ValidatorDescriptor = FormRules
export type ValidatorDescriptor = FormRules;
// 定义组件接收的参数类型(开始节点)
export interface StartNodeConfig {
// 执行模式auto-自动manual-手动
exec_type: 'auto' | 'manual'
// 执行周期类型
type?: 'month' | 'day' | 'week'
month?: number
week?: number
hour?: number
minute?: number
// 执行模式auto-自动manual-手动
exec_type: "auto" | "manual";
// 执行周期类型
type?: "month" | "day" | "week";
month?: number;
week?: number;
hour?: number;
minute?: number;
}
// 定义组件接收的参数类型(申请节点)
export interface ApplyNodeConfig {
// 基本选项
domains: string // 域名
email: string // 邮箱
eabId: string // CA授权IDEAB ID
ca: string // CA类型
proxy: string // 代理地址
provider_id: string // DNS提供商授权ID
provider: string // DNS提供商
end_day: number // 续签间隔
// 高级功能
name_server: string // DNS递归服务器
skip_check: number // 跳过检查
algorithm: string // 数字证书算法
close_cname: number // 禁用CNAME支持0关闭1开启默认0
max_wait?: number // 预检查超时时间,单位秒(可选)
ignore_check: number // 忽略预检查结果1继续0停止默认0
// 高级功能
// algorithm: 'RSA2048' | 'RSA3072' | 'RSA4096' | 'RSA8192' | 'EC256' | 'EC384' // 数字证书算法
// dnsServer?: string // 指定DNS解析服务器
// dnsTimeout?: number // DNS超时时间
// dnsTtl?: number // DNS解析TTL时间
// disableCnameFollow: boolean // 关闭CNAME跟随
// disableAutoRenew: boolean // 关闭ARI续期
// renewInterval?: number // 续签间隔
// 基本选项
domains: string; // 域名
email: string; // 邮箱
eabId: string; // CA授权IDEAB ID
ca: string; // CA类型
proxy: string; // 代理地址
provider_id: string; // DNS提供商授权ID
provider: string; // DNS提供商
end_day: number; // 续签间隔
// 高级功能
name_server: string; // DNS递归服务器
skip_check: number; // 跳过检查
algorithm: string; // 数字证书算法
close_cname: number; // 禁用CNAME支持0关闭1开启默认0
max_wait?: number; // 预检查超时时间,单位秒(可选)
ignore_check: number; // 忽略预检查结果1继续0停止默认0
// 高级功能
// algorithm: 'RSA2048' | 'RSA3072' | 'RSA4096' | 'RSA8192' | 'EC256' | 'EC384' // 数字证书算法
// dnsServer?: string // 指定DNS解析服务器
// dnsTimeout?: number // DNS超时时间
// dnsTtl?: number // DNS解析TTL时间
// disableCnameFollow: boolean // 关闭CNAME跟随
// disableAutoRenew: boolean // 关闭ARI续期
// renewInterval?: number // 续签间隔
}
// 部署节点配置
export interface DeployConfig<
Z extends Record<string, unknown>,
T extends
| 'ssh'
| 'btpanel'
| '1panel'
| 'btpanel-site'
| '1panel-site'
| 'tencentcloud-cdn'
| 'tencentcloud-cos'
| 'tencentcloud-waf'
| 'tencentcloud-teo'
| 'aliyun-cdn'
| 'aliyun-dcdn'
| 'aliyun-oss'
| 'aliyun-waf'
| 'aliyun-esa'
| 'doge-cdn'
| 'baidu-cdn'
| 'qiniu-cdn'
| 'qiniu-oss'
| 'safeline-site'
| 'safeline-panel'
| 'btpanel-dockersite'
| 'lecdn' // LeCDN 部署类型
| 'plugin', // 新增插件类型
Z extends Record<string, unknown>,
T extends
| "ssh"
| "btpanel"
| "1panel"
| "btpanel-site"
| "1panel-site"
| "tencentcloud-cdn"
| "tencentcloud-cos"
| "tencentcloud-waf"
| "tencentcloud-teo"
| "aliyun-cdn"
| "aliyun-dcdn"
| "aliyun-oss"
| "aliyun-waf"
| "aliyun-esa"
| "doge-cdn"
| "baidu-cdn"
| "qiniu-cdn"
| "qiniu-oss"
| "safeline-site"
| "safeline-panel"
| "btpanel-dockersite"
| "lecdn" // LeCDN 部署类型
| "plugin" // 新增插件类型
> {
provider: T
provider_id: string
skip: 1 | 0
type?: string // 插件类型名称,用于插件部署
provider_data?: any // 提供商数据,用于存储选择时的额外信息
[key: string]: Z
provider: T;
provider_id: string;
skip: 1 | 0;
type?: string; // 插件类型名称,用于插件部署
provider_data?: any; // 提供商数据,用于存储选择时的额外信息
[key: string]: Z;
}
// export interface DeployPanelConfig {}
// 部署节点配置ssh
export interface DeploySSHConfig {
certPath: string // 证书文件路径
keyPath: string // 私钥文件路径
beforeCmd: string // 前置命令
afterCmd?: string // 后置命令
certPath: string; // 证书文件路径
keyPath: string; // 私钥文件路径
beforeCmd: string; // 前置命令
afterCmd?: string; // 后置命令
}
// 部署本地节点配置
export interface DeployLocalConfig extends DeploySSHConfig {
[key: string]: unknown
[key: string]: unknown;
}
// 部署节点配置(宝塔面板)
export interface DeployBTPanelSiteConfig {
siteName: string
siteName: string;
}
// 部署节点配置1Panel
export interface Deploy1PanelConfig {
site_id: string
site_id: string;
}
// 部署节点配置1Panel站点
export interface Deploy1PanelSiteConfig extends Deploy1PanelConfig {
[key: string]: unknown
[key: string]: unknown;
}
// 部署腾讯云CDN/阿里云CDN
export interface DeployCDNConfig {
domain: string
domain: string;
}
// 部署阿里云WAF
export interface DeployWAFConfig {
domain: string
region: string
domain: string;
region: string;
}
// 部署腾讯云COS/阿里云OSS
export interface DeployStorageConfig {
domain: string
region: string
bucket: string
domain: string;
region: string;
bucket: string;
}
// 部署阿里云ESA
export interface DeployAliyunESAConfig {
site_id: string
site_id: string;
}
// 部署节点配置雷池WAF
export interface DeploySafelineConfig {
[key: string]: unknown
[key: string]: unknown;
}
// 部署节点配置雷池WAF站点
export interface DeploySafelineSiteConfig extends DeployBTPanelSiteConfig {
[key: string]: unknown
[key: string]: unknown;
}
// 部署宝塔docker站点
export interface DeployBTPanelDockerSiteConfig extends DeployBTPanelSiteConfig {
[key: string]: unknown
[key: string]: unknown;
}
// 部署LeCDN配置
export interface DeployLeCDNConfig {
site_id: string // 站点ID
domain: string // 域名
site_id: string; // 站点ID
domain: string; // 域名
}
// 部署插件配置
export interface DeployPluginConfig {
action: string // 插件方法名称
params: string // 用户自定义参数JSON字符串
action: string; // 插件方法名称
params: string; // 用户自定义参数JSON字符串
}
// 部署节点配置
export type DeployNodeConfig = DeployConfig<
| DeploySSHConfig // 部署节点配置ssh
| DeployLocalConfig // 部署节点配置(本地)
| DeployBTPanelConfig // 部署节点配置(宝塔面板)
| DeployBTPanelSiteConfig // 部署节点配置(宝塔面板站点)
| Deploy1PanelConfig // 部署节点配置1Panel
| Deploy1PanelSiteConfig // 部署节点配置1Panel站点
| DeployCDNConfig // 部署节点配置腾讯云CDN/阿里云CDN
| DeployWAFConfig // 部署节点配置阿里云WAF
| DeployStorageConfig // 部署节点配置腾讯云COS/阿里云OSS
| DeployAliyunESAConfig // 部署节点配置阿里云ESA
| DeploySafelineConfig // 部署节点配置雷池WAF
| DeploySafelineSiteConfig // 部署节点配置雷池WAF站点
| DeployBTPanelDockerSiteConfig // 部署节点配置宝塔docker站点
| DeployLeCDNConfig // 部署节点配置LeCDN
| DeployPluginConfig // 部署节点配置(插件)
>
| DeploySSHConfig // 部署节点配置ssh
| DeployLocalConfig // 部署节点配置(本地)
| DeployBTPanelConfig // 部署节点配置(宝塔面板)
| DeployBTPanelSiteConfig // 部署节点配置(宝塔面板站点)
| Deploy1PanelConfig // 部署节点配置1Panel
| Deploy1PanelSiteConfig // 部署节点配置1Panel站点
| DeployCDNConfig // 部署节点配置腾讯云CDN/阿里云CDN
| DeployWAFConfig // 部署节点配置阿里云WAF
| DeployStorageConfig // 部署节点配置腾讯云COS/阿里云OSS
| DeployAliyunESAConfig // 部署节点配置阿里云ESA
| DeploySafelineConfig // 部署节点配置雷池WAF
| DeploySafelineSiteConfig // 部署节点配置雷池WAF站点
| DeployBTPanelDockerSiteConfig // 部署节点配置宝塔docker站点
| DeployLeCDNConfig // 部署节点配置LeCDN
| DeployPluginConfig // 部署节点配置(插件)
>;
// 部署节点输入配置
export interface DeployNodeInputsConfig {
name: string
fromNodeId: string
name: string;
fromNodeId: string;
}
// 定义通知节点配置类型
interface NotifyNodeConfig {
provider: string
provider_id: string
subject: string
body: string
skip: boolean // 当结果来源为跳过状态时,跳过/继续发送通知true:跳过false:继续
provider: string;
provider_id: string;
subject: string;
body: string;
skip: boolean; // 当结果来源为跳过状态时,跳过/继续发送通知true:跳过false:继续
}
// 定义上传节点配置类型
interface UploadNodeConfig {
cert_id: string
cert: string
key: string
cert_id: string;
cert: string;
key: string;
}
// 定义私有CA节点配置类型
export interface PrivateCaNodeConfig {
ca_id?: string; // 中间CA ID
name?: string; // 中间CA名称
algorithm?: string; // 算法(只读显示)
key_length?: number; // 密钥长度
end_day: number; // 自动续签天数
valid_days?: string; // 有效期
validity_unit?: 'day' | 'year'; // 有效期单位
cn?: string; // 通用名称
san?: string; // 主题备用名称
}
// 部署节点配置ssh
// export type DeployNodeConfigSSH = DeployNodeConfig<'ssh', DeploySSHConfig>

View File

@@ -263,56 +263,61 @@ export const useFlowStore = defineStore('flow-store', () => {
* @returns 符合条件的节点数组 [{name: string, id: string}]
*/
const findApplyUploadNodesUp = (
nodeId: string,
scanNode: string[] = ['apply', 'upload'],
): Array<{ name: string; id: string }> => {
const result: Array<{ name: string; id: string }> = []
nodeId: string,
scanNode: string[] = ["apply", "upload", "private_ca"]
): Array<{ name: string; id: string }> => {
const result: Array<{ name: string; id: string }> = [];
// 递归查找父节点的函数
const findParentRecursive = (
currentNode: BaseNodeData | BranchNodeData,
targetId: string,
path: Array<BaseNodeData | BranchNodeData> = [],
): Array<BaseNodeData | BranchNodeData> | null => {
// 检查当前节点是否为目标节点
if (currentNode.id === targetId) {
return path
}
// 递归查找父节点的函数
const findParentRecursive = (
currentNode: BaseNodeData | BranchNodeData,
targetId: string,
path: Array<BaseNodeData | BranchNodeData> = []
): Array<BaseNodeData | BranchNodeData> | null => {
// 检查当前节点是否为目标节点
if (currentNode.id === targetId) {
return path;
}
// 检查子节点
if (currentNode.childNode) {
const newPath = [...path, currentNode]
const found = findParentRecursive(currentNode.childNode, targetId, newPath)
if (found) return found
}
// 检查子节点
if (currentNode.childNode) {
const newPath = [...path, currentNode];
const found = findParentRecursive(
currentNode.childNode,
targetId,
newPath
);
if (found) return found;
}
// 检查条件节点
if ((currentNode as BranchNodeData).conditionNodes?.length) {
for (const conditionNode of (currentNode as BranchNodeData).conditionNodes) {
const newPath = [...path, currentNode]
const found = findParentRecursive(conditionNode, targetId, newPath)
if (found) return found
}
}
// 检查条件节点
if ((currentNode as BranchNodeData).conditionNodes?.length) {
for (const conditionNode of (currentNode as BranchNodeData)
.conditionNodes) {
const newPath = [...path, currentNode];
const found = findParentRecursive(conditionNode, targetId, newPath);
if (found) return found;
}
}
return null
}
return null;
};
// 从根节点开始查找路径
const path = findParentRecursive(flowData.value.childNode, nodeId)
// 如果找到路径,筛选出 apply 和 upload 类型的节点
if (path) {
path.forEach((node) => {
if (scanNode.includes(node.type)) {
result.push({
name: node.name,
id: node.id as string,
})
}
})
}
return result
}
// 从根节点开始查找路径
const path = findParentRecursive(flowData.value.childNode, nodeId);
// 如果找到路径,筛选出 apply 和 upload 类型的节点
if (path) {
path.forEach((node) => {
if (scanNode.includes(node.type)) {
result.push({
name: node.name,
id: node.id as string,
});
}
});
}
return result;
};
/**
* 删除节点
@@ -392,18 +397,19 @@ export const useFlowStore = defineStore('flow-store', () => {
} 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)
}
}
// 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);
}
}
}