表单设计器

This commit is contained in:
dengqichen 2025-10-23 23:26:33 +08:00
parent 00e5bf6315
commit 34a5eb0ddd
5 changed files with 157 additions and 16 deletions

View File

@ -7,6 +7,7 @@ import {
environmentProjectsConfig,
jenkinsServerViewsJobsConfig,
departmentUsersConfig,
departmentTreeConfig,
projectGroupAppsConfig
} from './presets/cascade';
@ -17,6 +18,7 @@ export const CASCADE_DATA_SOURCE_REGISTRY: CascadeDataSourceRegistry = {
[CascadeDataSourceType.ENVIRONMENT_PROJECTS]: environmentProjectsConfig,
[CascadeDataSourceType.JENKINS_SERVER_VIEWS_JOBS]: jenkinsServerViewsJobsConfig,
[CascadeDataSourceType.DEPARTMENT_USERS]: departmentUsersConfig,
[CascadeDataSourceType.DEPARTMENT_TREE]: departmentTreeConfig,
[CascadeDataSourceType.PROJECT_GROUP_APPS]: projectGroupAppsConfig
};

View File

@ -10,6 +10,13 @@ import { getCascadeDataSourceConfig } from './CascadeDataSourceRegistry';
*
*/
class CascadeDataSourceService {
/**
*
*/
private isRecursiveMode(config: any): boolean {
return !!config.recursive;
}
/**
*
* @param type
@ -18,8 +25,19 @@ class CascadeDataSourceService {
async loadFirstLevel(type: CascadeDataSourceType): Promise<CascadeOption[]> {
const config = getCascadeDataSourceConfig(type);
if (!config || config.levels.length === 0) {
console.error(`❌ 级联数据源类型 ${type} 未配置或配置为空`);
if (!config) {
console.error(`❌ 级联数据源类型 ${type} 未配置`);
return [];
}
// 递归模式
if (this.isRecursiveMode(config)) {
return this.loadRecursiveLevel(config.recursive!, null);
}
// 固定层级模式
if (!config.levels || config.levels.length === 0) {
console.error(`❌ 级联数据源类型 ${type} 未配置层级`);
return [];
}
@ -43,6 +61,18 @@ class CascadeDataSourceService {
return [];
}
// 递归模式:使用同一配置加载所有层级
if (this.isRecursiveMode(config)) {
const parentValue = selectedOptions[selectedOptions.length - 1];
return this.loadRecursiveLevel(config.recursive!, parentValue);
}
// 固定层级模式
if (!config.levels) {
console.error(`❌ 级联数据源类型 ${type} 未配置层级`);
return [];
}
const levelIndex = selectedOptions.length;
if (levelIndex >= config.levels.length) {
@ -58,7 +88,60 @@ class CascadeDataSourceService {
}
/**
*
*
* @param recursiveConfig
* @param parentValue null
* @returns
*/
private async loadRecursiveLevel(
recursiveConfig: any,
parentValue: any
): Promise<CascadeOption[]> {
try {
// 构建请求参数
const params: Record<string, any> = { ...recursiveConfig.params };
// 添加父级参数
if (parentValue !== null) {
params[recursiveConfig.parentParam] = parentValue;
}
// 发起请求
const response = await request.get(recursiveConfig.url, { params });
const data = response || [];
// 转换为级联选项格式
return data.map((item: any) => {
const option: CascadeOption = {
label: item[recursiveConfig.labelField],
value: item[recursiveConfig.valueField]
};
// 判断是否为叶子节点
if (recursiveConfig.hasChildren) {
// 使用自定义判断函数
option.isLeaf = !recursiveConfig.hasChildren(item);
} else if ('isLeaf' in item) {
// 使用后端返回的 isLeaf 字段
option.isLeaf = item.isLeaf;
} else if ('hasChildren' in item) {
// 使用后端返回的 hasChildren 字段
option.isLeaf = !item.hasChildren;
} else {
// 默认不是叶子节点(允许继续展开)
option.isLeaf = false;
}
return option;
});
} catch (error) {
console.error(`❌ 加载递归级联数据失败:`, error);
return [];
}
}
/**
*
* @param levelConfig
* @param parentValue
* @param hasNextLevel
@ -108,11 +191,18 @@ class CascadeDataSourceService {
/**
*
* @param type
* @returns
* @returns -1
*/
getLevelCount(type: CascadeDataSourceType): number {
const config = getCascadeDataSourceConfig(type);
return config?.levels.length || 0;
if (!config) return 0;
// 递归模式返回 -1 表示无限层级
if (this.isRecursiveMode(config)) {
return -1;
}
return config.levels?.length || 0;
}
/**

View File

@ -53,7 +53,7 @@ export const jenkinsServerViewsJobsConfig: CascadeDataSourceConfig = {
};
/**
*
*
*/
export const departmentUsersConfig: CascadeDataSourceConfig = {
description: '部门 → 用户',
@ -73,6 +73,23 @@ export const departmentUsersConfig: CascadeDataSourceConfig = {
]
};
/**
*
*
*/
export const departmentTreeConfig: CascadeDataSourceConfig = {
description: '部门树(无限层级)',
recursive: {
url: '/api/v1/department/tree',
parentParam: 'parentId',
labelField: 'name',
valueField: 'id',
// 可选:自定义判断是否有子节点
// hasChildren: (item) => item.hasChildren
// 如果不提供,会自动使用后端返回的 isLeaf 或 hasChildren 字段
}
};
/**
*
*/

View File

@ -21,10 +21,11 @@ export enum DataSourceType {
*
*/
export enum CascadeDataSourceType {
ENVIRONMENT_PROJECTS = 'ENVIRONMENT_PROJECTS', // 环境 → 项目
JENKINS_SERVER_VIEWS_JOBS = 'JENKINS_SERVER_VIEWS_JOBS', // Jenkins → View → Job
DEPARTMENT_USERS = 'DEPARTMENT_USERS', // 部门 → 用户
PROJECT_GROUP_APPS = 'PROJECT_GROUP_APPS' // 项目组 → 应用
ENVIRONMENT_PROJECTS = 'ENVIRONMENT_PROJECTS', // 环境 → 项目固定2级
JENKINS_SERVER_VIEWS_JOBS = 'JENKINS_SERVER_VIEWS_JOBS', // Jenkins → View → Job固定3级
DEPARTMENT_USERS = 'DEPARTMENT_USERS', // 部门 → 用户固定2级
DEPARTMENT_TREE = 'DEPARTMENT_TREE', // 部门树(递归无限层级)⭐
PROJECT_GROUP_APPS = 'PROJECT_GROUP_APPS' // 项目组 → 应用固定2级
}
/**
@ -66,12 +67,28 @@ export interface CascadeLevelConfig {
isLeaf?: (item: any) => boolean; // 判断是否为叶子节点
}
/**
*
*/
export interface RecursiveCascadeConfig {
url: string; // 接口地址
labelField: string; // 标签字段
valueField: string; // 值字段
parentParam: string; // 父级参数名(如 'parentId'
params?: Record<string, any>; // 额外参数
hasChildren?: (item: any) => boolean; // 判断是否有子节点(可选,默认根据后端 isLeaf 字段)
}
/**
*
*
* 1. - 使 levels
* 2. - 使 recursive
*/
export interface CascadeDataSourceConfig {
levels: CascadeLevelConfig[]; // 级联层级配置
description?: string; // 描述
levels?: CascadeLevelConfig[]; // 固定层级配置
recursive?: RecursiveCascadeConfig; // 递归层级配置(无限层级)
description?: string; // 描述
}
/**

View File

@ -85,20 +85,35 @@ export const useCascaderLoadData = (field: FieldConfig) => {
// 提取已选择的值
const selectedValues = selectedOptions.map(opt => opt.value);
// 获取目标选项(最后一个被选择的选项)
const targetOption = selectedOptions[selectedOptions.length - 1];
try {
// 加载子级数据
const childrenData = await cascadeDataSourceService.loadChildren(sourceType, selectedValues);
console.log(`✅ 懒加载成功,子级数据:`, childrenData);
// 转换为级联选项格式
const children = convertToCascadeFieldOption(childrenData);
// 更新最后一个选项的 children
const targetOption = selectedOptions[selectedOptions.length - 1];
// 重要:需要设置 loading: false 和 children
targetOption.loading = false;
targetOption.children = convertToCascadeFieldOption(childrenData);
// 如果有子数据,设置 children如果没有设置为 undefined 并标记为叶子节点
if (children && children.length > 0) {
targetOption.children = children;
} else {
targetOption.children = undefined;
targetOption.isLeaf = true;
}
} catch (error) {
console.error(`❌ 懒加载失败:`, error);
const targetOption = selectedOptions[selectedOptions.length - 1];
// 出错时标记为叶子节点(不再展开)
targetOption.loading = false;
targetOption.children = [];
targetOption.children = undefined;
targetOption.isLeaf = true;
}
},
[sourceType]