表单设计器
This commit is contained in:
parent
00e5bf6315
commit
34a5eb0ddd
@ -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
|
||||
};
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -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 字段
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 项目组 → 应用
|
||||
*/
|
||||
|
||||
@ -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,11 +67,27 @@ 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[]; // 级联层级配置
|
||||
levels?: CascadeLevelConfig[]; // 固定层级配置
|
||||
recursive?: RecursiveCascadeConfig; // 递归层级配置(无限层级)
|
||||
description?: string; // 描述
|
||||
}
|
||||
|
||||
|
||||
@ -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]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user