表单设计器
This commit is contained in:
parent
c033c10fb9
commit
da38d2386b
53
frontend/src/domain/dataSource/DataSourceRegistry.ts
Normal file
53
frontend/src/domain/dataSource/DataSourceRegistry.ts
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* 数据源注册表
|
||||
* 集中管理所有预设数据源配置
|
||||
*/
|
||||
import { DataSourceType, type DataSourceRegistry } from './types';
|
||||
import { jenkinsServersConfig } from './presets/jenkins';
|
||||
import { k8sClustersConfig } from './presets/k8s';
|
||||
import { gitRepositoriesConfig } from './presets/git';
|
||||
import { dockerRegistriesConfig } from './presets/docker';
|
||||
import { notificationChannelTypesConfig, notificationChannelsConfig } from './presets/notification';
|
||||
import { usersConfig, rolesConfig, departmentsConfig } from './presets/user';
|
||||
|
||||
/**
|
||||
* 数据源配置注册表
|
||||
*/
|
||||
export const DATA_SOURCE_REGISTRY: DataSourceRegistry = {
|
||||
[DataSourceType.JENKINS_SERVERS]: jenkinsServersConfig,
|
||||
[DataSourceType.K8S_CLUSTERS]: k8sClustersConfig,
|
||||
[DataSourceType.GIT_REPOSITORIES]: gitRepositoriesConfig,
|
||||
[DataSourceType.DOCKER_REGISTRIES]: dockerRegistriesConfig,
|
||||
[DataSourceType.NOTIFICATION_CHANNEL_TYPES]: notificationChannelTypesConfig,
|
||||
[DataSourceType.NOTIFICATION_CHANNELS]: notificationChannelsConfig,
|
||||
[DataSourceType.USERS]: usersConfig,
|
||||
[DataSourceType.ROLES]: rolesConfig,
|
||||
[DataSourceType.DEPARTMENTS]: departmentsConfig
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取数据源配置
|
||||
* @param type 数据源类型
|
||||
* @returns 数据源配置,如果不存在则返回 undefined
|
||||
*/
|
||||
export const getDataSourceConfig = (type: DataSourceType) => {
|
||||
return DATA_SOURCE_REGISTRY[type];
|
||||
};
|
||||
|
||||
/**
|
||||
* 检查数据源类型是否已注册
|
||||
* @param type 数据源类型
|
||||
* @returns 是否已注册
|
||||
*/
|
||||
export const hasDataSource = (type: DataSourceType): boolean => {
|
||||
return type in DATA_SOURCE_REGISTRY;
|
||||
};
|
||||
|
||||
/**
|
||||
* 获取所有已注册的数据源类型
|
||||
* @returns 数据源类型列表
|
||||
*/
|
||||
export const getAllDataSourceTypes = (): DataSourceType[] => {
|
||||
return Object.keys(DATA_SOURCE_REGISTRY) as DataSourceType[];
|
||||
};
|
||||
|
||||
74
frontend/src/domain/dataSource/DataSourceService.ts
Normal file
74
frontend/src/domain/dataSource/DataSourceService.ts
Normal file
@ -0,0 +1,74 @@
|
||||
/**
|
||||
* 数据源服务
|
||||
* 提供数据源加载和管理功能
|
||||
*/
|
||||
import request from '@/utils/request';
|
||||
import { DataSourceType, type DataSourceOption } from './types';
|
||||
import { getDataSourceConfig } from './DataSourceRegistry';
|
||||
|
||||
/**
|
||||
* 数据源服务类
|
||||
*/
|
||||
class DataSourceService {
|
||||
/**
|
||||
* 加载单个数据源
|
||||
* @param type 数据源类型
|
||||
* @returns 选项列表
|
||||
*/
|
||||
async load(type: DataSourceType): Promise<DataSourceOption[]> {
|
||||
const config = getDataSourceConfig(type);
|
||||
|
||||
if (!config) {
|
||||
console.error(`❌ 数据源类型 ${type} 未配置`);
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await request.get(config.url, { params: config.params });
|
||||
// request 拦截器已经提取了 data 字段,response 直接是数组
|
||||
return config.transform(response || []);
|
||||
} catch (error) {
|
||||
console.error(`❌ 加载数据源 ${type} 失败:`, error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量加载多个数据源(用于预加载)
|
||||
* @param types 数据源类型列表
|
||||
* @returns 数据源数据映射
|
||||
*/
|
||||
async loadMultiple(
|
||||
types: DataSourceType[]
|
||||
): Promise<Record<DataSourceType, DataSourceOption[]>> {
|
||||
const results = await Promise.all(
|
||||
types.map(type => this.load(type))
|
||||
);
|
||||
|
||||
return types.reduce((acc, type, index) => {
|
||||
acc[type] = results[index];
|
||||
return acc;
|
||||
}, {} as Record<DataSourceType, DataSourceOption[]>);
|
||||
}
|
||||
|
||||
/**
|
||||
* 预加载常用数据源(提升用户体验)
|
||||
* @returns 预加载的数据源映射
|
||||
*/
|
||||
async preload(): Promise<Record<DataSourceType, DataSourceOption[]>> {
|
||||
const commonTypes: DataSourceType[] = [
|
||||
DataSourceType.JENKINS_SERVERS,
|
||||
DataSourceType.K8S_CLUSTERS,
|
||||
DataSourceType.USERS
|
||||
];
|
||||
return this.loadMultiple(commonTypes);
|
||||
}
|
||||
}
|
||||
|
||||
// 导出单例
|
||||
export const dataSourceService = new DataSourceService();
|
||||
|
||||
// 向后兼容:导出原有的函数式API
|
||||
export const loadDataSource = (type: DataSourceType) => dataSourceService.load(type);
|
||||
export const loadMultipleDataSources = (types: DataSourceType[]) => dataSourceService.loadMultiple(types);
|
||||
|
||||
15
frontend/src/domain/dataSource/index.ts
Normal file
15
frontend/src/domain/dataSource/index.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 数据源领域模块
|
||||
* 统一导出所有公共接口
|
||||
*/
|
||||
|
||||
// 类型定义
|
||||
export { DataSourceType } from './types';
|
||||
export type { DataSourceOption, DataSourceConfig, DataSourceRegistry } from './types';
|
||||
|
||||
// 注册表
|
||||
export { DATA_SOURCE_REGISTRY, getDataSourceConfig, hasDataSource, getAllDataSourceTypes } from './DataSourceRegistry';
|
||||
|
||||
// 服务
|
||||
export { dataSourceService, loadDataSource, loadMultipleDataSources } from './DataSourceService';
|
||||
|
||||
17
frontend/src/domain/dataSource/presets/docker.ts
Normal file
17
frontend/src/domain/dataSource/presets/docker.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Docker 镜像仓库数据源
|
||||
*/
|
||||
import type { DataSourceConfig } from '../types';
|
||||
|
||||
export const dockerRegistriesConfig: DataSourceConfig = {
|
||||
url: '/api/v1/docker-registry/list',
|
||||
params: { enabled: true },
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
url: item.url
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
17
frontend/src/domain/dataSource/presets/git.ts
Normal file
17
frontend/src/domain/dataSource/presets/git.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Git 仓库数据源
|
||||
*/
|
||||
import type { DataSourceConfig } from '../types';
|
||||
|
||||
export const gitRepositoriesConfig: DataSourceConfig = {
|
||||
url: '/api/v1/git-repo/list',
|
||||
params: { enabled: true },
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.name} (${item.url})`,
|
||||
value: item.id,
|
||||
url: item.url
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
18
frontend/src/domain/dataSource/presets/jenkins.ts
Normal file
18
frontend/src/domain/dataSource/presets/jenkins.ts
Normal file
@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Jenkins 服务器数据源
|
||||
*/
|
||||
import type { DataSourceConfig } from '../types';
|
||||
|
||||
export const jenkinsServersConfig: DataSourceConfig = {
|
||||
url: '/api/v1/external-system/list',
|
||||
params: { type: 'JENKINS', enabled: true },
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.name} (${item.url})`,
|
||||
value: item.id,
|
||||
url: item.url,
|
||||
name: item.name
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
17
frontend/src/domain/dataSource/presets/k8s.ts
Normal file
17
frontend/src/domain/dataSource/presets/k8s.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Kubernetes 集群数据源
|
||||
*/
|
||||
import type { DataSourceConfig } from '../types';
|
||||
|
||||
export const k8sClustersConfig: DataSourceConfig = {
|
||||
url: '/api/v1/k8s-cluster/list',
|
||||
params: { enabled: true },
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
apiServer: item.apiServer
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
25
frontend/src/domain/dataSource/presets/notification.ts
Normal file
25
frontend/src/domain/dataSource/presets/notification.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 通知渠道数据源
|
||||
*/
|
||||
import type { DataSourceConfig } from '../types';
|
||||
|
||||
export const notificationChannelTypesConfig: DataSourceConfig = {
|
||||
url: '/api/v1/notification-channel/types',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.label}`,
|
||||
value: item.code
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
export const notificationChannelsConfig: DataSourceConfig = {
|
||||
url: '/api/v1/notification-channel/list',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `(${item.channelType})-${item.name}`,
|
||||
value: item.id
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
43
frontend/src/domain/dataSource/presets/user.ts
Normal file
43
frontend/src/domain/dataSource/presets/user.ts
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 用户、角色、部门数据源
|
||||
*/
|
||||
import type { DataSourceConfig } from '../types';
|
||||
|
||||
export const usersConfig: DataSourceConfig = {
|
||||
url: '/api/v1/user/list',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.nickname} (${item.username})`,
|
||||
value: item.username, // 后台使用 username 进行审批
|
||||
id: item.id,
|
||||
email: item.email,
|
||||
departmentName: item.departmentName
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
export const rolesConfig: DataSourceConfig = {
|
||||
url: '/api/v1/role/list',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.name} (${item.code})`,
|
||||
value: item.code, // 使用 code 作为值
|
||||
id: item.id,
|
||||
description: item.description
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
export const departmentsConfig: DataSourceConfig = {
|
||||
url: '/api/v1/department/list',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.name} (${item.code})`,
|
||||
value: item.code, // 使用 code 作为值
|
||||
id: item.id,
|
||||
description: item.description,
|
||||
parentId: item.parentId
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
42
frontend/src/domain/dataSource/types.ts
Normal file
42
frontend/src/domain/dataSource/types.ts
Normal file
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* 数据源领域 - 类型定义
|
||||
*/
|
||||
|
||||
/**
|
||||
* 数据源类型枚举
|
||||
*/
|
||||
export enum DataSourceType {
|
||||
JENKINS_SERVERS = 'JENKINS_SERVERS',
|
||||
K8S_CLUSTERS = 'K8S_CLUSTERS',
|
||||
GIT_REPOSITORIES = 'GIT_REPOSITORIES',
|
||||
DOCKER_REGISTRIES = 'DOCKER_REGISTRIES',
|
||||
NOTIFICATION_CHANNEL_TYPES = 'NOTIFICATION_CHANNEL_TYPES',
|
||||
NOTIFICATION_CHANNELS = 'NOTIFICATION_CHANNELS',
|
||||
USERS = 'USERS',
|
||||
ROLES = 'ROLES',
|
||||
DEPARTMENTS = 'DEPARTMENTS'
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源选项接口
|
||||
*/
|
||||
export interface DataSourceOption {
|
||||
label: string;
|
||||
value: any;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源配置接口
|
||||
*/
|
||||
export interface DataSourceConfig {
|
||||
url: string;
|
||||
params?: Record<string, any>;
|
||||
transform: (data: any) => DataSourceOption[];
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源注册表类型
|
||||
*/
|
||||
export type DataSourceRegistry = Record<DataSourceType, DataSourceConfig>;
|
||||
|
||||
@ -19,7 +19,7 @@ import {
|
||||
} from 'antd';
|
||||
import { PlusOutlined, DeleteOutlined } from '@ant-design/icons';
|
||||
import type { FieldConfig, FormConfig } from '../types';
|
||||
import { DataSourceType } from '@/pages/Workflow/Design/utils/dataSourceLoader';
|
||||
import { DataSourceType } from '@/domain/dataSource';
|
||||
|
||||
const { Text } = Typography;
|
||||
const { TabPane } = Tabs;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import type { FieldConfig, FieldOption } from '../types';
|
||||
import request from '../../../utils/request';
|
||||
import { loadDataSource, DataSourceType as WorkflowDataSourceType } from '@/pages/Workflow/Design/utils/dataSourceLoader';
|
||||
import { loadDataSource, DataSourceType as WorkflowDataSourceType } from '@/domain/dataSource';
|
||||
|
||||
/**
|
||||
* 从对象中根据路径提取数据
|
||||
|
||||
@ -19,7 +19,7 @@ import type { FlowNode, FlowNodeData, FlowEdge } from '../types';
|
||||
import type { WorkflowNodeDefinition, JSONSchema } from '../nodes/types';
|
||||
import { isConfigurableNode } from '../nodes/types';
|
||||
import { convertJsonSchemaToZod, extractDataSourceTypes } from '../utils/schemaConverter';
|
||||
import { loadDataSource, DataSourceType, type DataSourceOption } from '../utils/dataSourceLoader';
|
||||
import { loadDataSource, DataSourceType, type DataSourceOption } from '@/domain/dataSource';
|
||||
import { convertObjectToUUID, convertObjectToDisplayName } from '@/utils/workflow/variableConversion';
|
||||
import VariableInput from '@/components/VariableInput';
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {ConfigurableNodeDefinition, NodeType, NodeCategory, defineNodeOutputs} from './types';
|
||||
import {DataSourceType} from '../utils/dataSourceLoader';
|
||||
import { DataSourceType } from '@/domain/dataSource';
|
||||
|
||||
/**
|
||||
* 审批节点定义
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {ConfigurableNodeDefinition, NodeType, NodeCategory, defineNodeOutputs} from './types';
|
||||
import {DataSourceType} from '../utils/dataSourceLoader';
|
||||
import { DataSourceType } from '@/domain/dataSource';
|
||||
|
||||
/**
|
||||
* Jenkins构建节点定义(纯配置)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import {ConfigurableNodeDefinition, NodeType, NodeCategory, defineNodeOutputs} from './types';
|
||||
import {DataSourceType} from "@/pages/Workflow/Design/utils/dataSourceLoader.ts";
|
||||
import { DataSourceType } from "@/domain/dataSource";
|
||||
|
||||
/**
|
||||
* 通知节点定义
|
||||
|
||||
@ -1,181 +0,0 @@
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 数据源类型枚举
|
||||
*/
|
||||
export enum DataSourceType {
|
||||
JENKINS_SERVERS = 'JENKINS_SERVERS',
|
||||
K8S_CLUSTERS = 'K8S_CLUSTERS',
|
||||
GIT_REPOSITORIES = 'GIT_REPOSITORIES',
|
||||
DOCKER_REGISTRIES = 'DOCKER_REGISTRIES',
|
||||
NOTIFICATION_CHANNEL_TYPES = 'NOTIFICATION_CHANNEL_TYPES',
|
||||
NOTIFICATION_CHANNELS = 'NOTIFICATION_CHANNELS',
|
||||
USERS = 'USERS',
|
||||
ROLES = 'ROLES',
|
||||
DEPARTMENTS = 'DEPARTMENTS'
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源配置接口
|
||||
*/
|
||||
export interface DataSourceConfig {
|
||||
url: string;
|
||||
params?: Record<string, any>;
|
||||
transform: (data: any) => Array<{ label: string; value: any; [key: string]: any }>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源选项接口
|
||||
*/
|
||||
export interface DataSourceOption {
|
||||
label: string;
|
||||
value: any;
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据源配置注册表
|
||||
*/
|
||||
export const DATA_SOURCE_REGISTRY: Record<DataSourceType, DataSourceConfig> = {
|
||||
[DataSourceType.JENKINS_SERVERS]: {
|
||||
url: '/api/v1/external-system/list',
|
||||
params: {type: 'JENKINS', enabled: true},
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.name} (${item.url})`,
|
||||
value: item.id,
|
||||
url: item.url,
|
||||
name: item.name
|
||||
}));
|
||||
}
|
||||
},
|
||||
[DataSourceType.NOTIFICATION_CHANNEL_TYPES]: {
|
||||
url: '/api/v1/notification-channel/types',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.label}`,
|
||||
value: item.code
|
||||
}));
|
||||
}
|
||||
},
|
||||
[DataSourceType.NOTIFICATION_CHANNELS]: {
|
||||
url: '/api/v1/notification-channel/list',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `(${item.channelType})-${item.name}`,
|
||||
value: item.id
|
||||
}));
|
||||
}
|
||||
},
|
||||
[DataSourceType.K8S_CLUSTERS]: {
|
||||
url: '/api/v1/k8s-cluster/list',
|
||||
params: {enabled: true},
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
apiServer: item.apiServer
|
||||
}));
|
||||
}
|
||||
},
|
||||
[DataSourceType.GIT_REPOSITORIES]: {
|
||||
url: '/api/v1/git-repo/list',
|
||||
params: {enabled: true},
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.name} (${item.url})`,
|
||||
value: item.id,
|
||||
url: item.url
|
||||
}));
|
||||
}
|
||||
},
|
||||
[DataSourceType.DOCKER_REGISTRIES]: {
|
||||
url: '/api/v1/docker-registry/list',
|
||||
params: {enabled: true},
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: item.name,
|
||||
value: item.id,
|
||||
url: item.url
|
||||
}));
|
||||
}
|
||||
},
|
||||
[DataSourceType.USERS]: {
|
||||
url: '/api/v1/user/list',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.nickname} (${item.username})`,
|
||||
value: item.username, // 后台使用 username 进行审批
|
||||
id: item.id,
|
||||
email: item.email,
|
||||
departmentName: item.departmentName
|
||||
}));
|
||||
}
|
||||
},
|
||||
[DataSourceType.ROLES]: {
|
||||
url: '/api/v1/role/list',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.name} (${item.code})`,
|
||||
value: item.code, // 使用 code 作为值
|
||||
id: item.id,
|
||||
description: item.description
|
||||
}));
|
||||
}
|
||||
},
|
||||
[DataSourceType.DEPARTMENTS]: {
|
||||
url: '/api/v1/department/list',
|
||||
transform: (data: any[]) => {
|
||||
return data.map((item: any) => ({
|
||||
label: `${item.name} (${item.code})`,
|
||||
value: item.code, // 使用 code 作为值
|
||||
id: item.id,
|
||||
description: item.description,
|
||||
parentId: item.parentId
|
||||
}));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 加载数据源
|
||||
* @param type 数据源类型
|
||||
* @returns 选项列表
|
||||
*/
|
||||
export const loadDataSource = async (type: DataSourceType): Promise<DataSourceOption[]> => {
|
||||
const config = DATA_SOURCE_REGISTRY[type];
|
||||
|
||||
if (!config) {
|
||||
console.error(`数据源类型 ${type} 未配置`);
|
||||
return [];
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await request.get(config.url, {params: config.params});
|
||||
// request 拦截器已经提取了 data 字段,response 直接是数组
|
||||
return config.transform(response || []);
|
||||
} catch (error) {
|
||||
console.error(`加载数据源 ${type} 失败:`, error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 批量加载多个数据源(用于预加载)
|
||||
* @param types 数据源类型列表
|
||||
* @returns 数据源数据映射
|
||||
*/
|
||||
export const loadMultipleDataSources = async (
|
||||
types: DataSourceType[]
|
||||
): Promise<Record<DataSourceType, DataSourceOption[]>> => {
|
||||
const results = await Promise.all(
|
||||
types.map(type => loadDataSource(type))
|
||||
);
|
||||
|
||||
return types.reduce((acc, type, index) => {
|
||||
acc[type] = results[index];
|
||||
return acc;
|
||||
}, {} as Record<DataSourceType, DataSourceOption[]>);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user