409 lines
9.3 KiB
Markdown
409 lines
9.3 KiB
Markdown
# 枚举配置文件映射功能实现总结
|
||
|
||
**实现日期**: 2025-11-24
|
||
**功能状态**: ✅ 已完成并测试
|
||
|
||
## 概述
|
||
|
||
成功实现了**阶段 2:配置文件映射**功能,允许用户通过 `generator_config.yaml` 配置文件为枚举值定义有意义的键名和描述,即使后端不支持 OpenAPI 扩展字段。
|
||
|
||
## 核心特性
|
||
|
||
### 1. 三级优先级系统
|
||
|
||
```
|
||
配置文件映射 > x-enum-varnames > 智能生成
|
||
```
|
||
|
||
- **配置文件映射**(最高优先级):用户在 `generator_config.yaml` 中显式配置
|
||
- **x-enum-varnames**(中优先级):后端在 Swagger 文档中提供的扩展字段
|
||
- **智能生成**(最低优先级):自动生成 `valueN` 格式
|
||
|
||
### 2. 灵活的配置方式
|
||
|
||
支持在 `generator_config.yaml` 中配置:
|
||
|
||
```yaml
|
||
generation:
|
||
models:
|
||
enum_key_mappings:
|
||
SysTaskTypeEnums:
|
||
- value: 1
|
||
name: SPOT_CHECK
|
||
description: 抽查
|
||
- value: 2
|
||
name: CULTURAL
|
||
description: 文创建设
|
||
```
|
||
|
||
### 3. 完整的类型支持
|
||
|
||
- ✅ 整数枚举 (`integer`, `number`)
|
||
- ✅ 字符串枚举 (`string`)
|
||
- ✅ 枚举键名和描述
|
||
- ✅ 部分映射(可以只配置部分枚举值)
|
||
- ✅ 自动添加 `UNKNOWN` 枚举值(整数类型用 `-9999`,字符串类型用 `'UNKNOWN'`)
|
||
- ✅ 容错处理(未知值返回 `UNKNOWN` 而不是抛异常)
|
||
|
||
## 实现细节
|
||
|
||
### 修改的文件
|
||
|
||
#### 1. `lib/core/config_repository.dart`
|
||
|
||
新增 `EnumKeyMapping` 数据类和解析逻辑:
|
||
|
||
```dart
|
||
/// 枚举键名映射
|
||
class EnumKeyMapping {
|
||
const EnumKeyMapping({
|
||
required this.name,
|
||
this.description,
|
||
});
|
||
|
||
final String name;
|
||
final String? description;
|
||
}
|
||
|
||
class ConfigRepository {
|
||
/// 获取枚举键名映射配置
|
||
Map<String, Map<dynamic, EnumKeyMapping>>? get enumKeyMappings {
|
||
// 从配置文件解析枚举映射
|
||
// 返回格式: { "EnumName": { value: EnumKeyMapping } }
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 2. `lib/core/config.dart`
|
||
|
||
暴露枚举映射配置:
|
||
|
||
```dart
|
||
class SwaggerConfig {
|
||
/// 获取枚举键名映射配置(从配置文件读取)
|
||
static Map<String, Map<dynamic, EnumKeyMapping>>? get enumKeyMappings =>
|
||
ConfigRepository.loadSync().enumKeyMappings;
|
||
}
|
||
```
|
||
|
||
#### 3. `lib/pipeline/generate/impl/model/model_content_builders.dart`
|
||
|
||
修改枚举生成逻辑,支持三级优先级:
|
||
|
||
```dart
|
||
String _generateEnumCodeWithoutImports(ApiModel model) {
|
||
// 获取配置文件中的枚举映射
|
||
final enumMappings = SwaggerConfig.enumKeyMappings?[model.name];
|
||
|
||
for (var i = 0; i < model.enumValues.length; i++) {
|
||
final value = model.enumValues[i];
|
||
|
||
String enumName;
|
||
String? description;
|
||
|
||
// 优先级 1: 配置文件映射
|
||
if (enumMappings != null && enumMappings.containsKey(value)) {
|
||
final mapping = enumMappings[value]!;
|
||
enumName = mapping.name;
|
||
description = mapping.description;
|
||
}
|
||
// 优先级 2: x-enum-varnames
|
||
else if (model.enumVarNames != null && i < model.enumVarNames!.length) {
|
||
enumName = model.enumVarNames![i];
|
||
if (model.enumDescriptions != null && i < model.enumDescriptions!.length) {
|
||
description = model.enumDescriptions![i];
|
||
}
|
||
}
|
||
// 优先级 3: 智能生成
|
||
else {
|
||
enumName = StringHelper.generateEnumValueName(value, i);
|
||
}
|
||
|
||
// 生成枚举代码...
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4. `generator_config.template.yaml`
|
||
|
||
添加详细的配置示例和说明:
|
||
|
||
```yaml
|
||
generation:
|
||
models:
|
||
# 枚举键名映射配置(可选)
|
||
# 用于为枚举值定义有意义的键名和描述
|
||
# 优先级:配置文件映射 > x-enum-varnames > 智能生成
|
||
enum_key_mappings:
|
||
SysTaskTypeEnums:
|
||
- value: 1
|
||
name: SPOT_CHECK
|
||
description: 抽查
|
||
- value: 2
|
||
name: CULTURAL
|
||
description: 文创建设
|
||
```
|
||
|
||
### 测试文件
|
||
|
||
#### 测试 Swagger 文档
|
||
|
||
创建了 `example/swagger_config_mapping_test.json`:
|
||
|
||
```json
|
||
{
|
||
"components": {
|
||
"schemas": {
|
||
"SysTaskTypeEnums": {
|
||
"type": "integer",
|
||
"description": "任务类型枚举",
|
||
"enum": [1, 2, 3, 4, 5, 6, 7]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 测试配置文件
|
||
|
||
创建了 `example/test_config_mapping.yaml`,包含完整的枚举映射配置。
|
||
|
||
#### 测试结果
|
||
|
||
✅ 成功生成了包含有意义键名和描述的枚举代码:
|
||
|
||
```dart
|
||
/// 任务类型枚举
|
||
@JsonEnum()
|
||
enum SysTaskTypeEnums {
|
||
/// 抽查
|
||
SPOT_CHECK(1),
|
||
/// 文创建设
|
||
CULTURAL(2),
|
||
/// 班干部会议
|
||
CLASS_CADRE_MEETING(3),
|
||
/// 文创项目
|
||
CULTURAL_PROJECT(4),
|
||
/// 教工评优
|
||
TEACHER_AWARD(5),
|
||
/// 班级评比
|
||
CLASS_EVALUATION(6),
|
||
/// 组织生活
|
||
ORGANIZATION_LIFE(7),
|
||
|
||
/// 未知值
|
||
UNKNOWN(-9999);
|
||
|
||
const SysTaskTypeEnums(this.value);
|
||
final int value;
|
||
|
||
static SysTaskTypeEnums fromValue(dynamic value) {
|
||
for (final enumValue in SysTaskTypeEnums.values) {
|
||
if (enumValue.value == value) {
|
||
return enumValue;
|
||
}
|
||
}
|
||
return SysTaskTypeEnums.UNKNOWN; // 返回 UNKNOWN 而不是抛异常
|
||
}
|
||
// ... 其余代码
|
||
}
|
||
```
|
||
|
||
## 文档更新
|
||
|
||
### 1. ENUM_KEY_NAMES_PROPOSAL.md
|
||
|
||
- ✅ 标记阶段 2 已完成
|
||
- ✅ 更新实施步骤
|
||
- ✅ 添加配置文件格式说明
|
||
|
||
### 2. ENUM_KEY_NAMES_USAGE.md
|
||
|
||
- ✅ 添加"方法 2: 通过配置文件映射"章节
|
||
- ✅ 提供完整的配置示例
|
||
- ✅ 说明优先级规则
|
||
- ✅ 列出使用场景和注意事项
|
||
|
||
### 3. generator_config.template.yaml
|
||
|
||
- ✅ 添加 `enum_key_mappings` 配置节
|
||
- ✅ 提供详细的注释和示例
|
||
- ✅ 说明优先级和使用场景
|
||
|
||
## 使用示例
|
||
|
||
### 场景 1: 后端不支持扩展字段
|
||
|
||
**Swagger 文档**:
|
||
|
||
```json
|
||
{
|
||
"SysTaskTypeEnums": {
|
||
"enum": [1, 2, 3],
|
||
"type": "integer"
|
||
}
|
||
}
|
||
```
|
||
|
||
**配置文件**:
|
||
|
||
```yaml
|
||
generation:
|
||
models:
|
||
enum_key_mappings:
|
||
SysTaskTypeEnums:
|
||
- value: 1
|
||
name: SPOT_CHECK
|
||
description: 抽查
|
||
- value: 2
|
||
name: CULTURAL
|
||
description: 文创建设
|
||
- value: 3
|
||
name: CLASS_CADRE_MEETING
|
||
description: 班干部会议
|
||
```
|
||
|
||
**生成结果**: 使用配置文件中的键名和描述 ✅
|
||
|
||
### 场景 2: 覆盖 Swagger 文档定义
|
||
|
||
**Swagger 文档**:
|
||
|
||
```json
|
||
{
|
||
"SysTaskTypeEnums": {
|
||
"enum": [1, 2, 3],
|
||
"type": "integer",
|
||
"x-enum-varnames": ["TYPE_1", "TYPE_2", "TYPE_3"]
|
||
}
|
||
}
|
||
```
|
||
|
||
**配置文件**:
|
||
|
||
```yaml
|
||
generation:
|
||
models:
|
||
enum_key_mappings:
|
||
SysTaskTypeEnums:
|
||
- value: 1
|
||
name: SPOT_CHECK
|
||
description: 抽查
|
||
```
|
||
|
||
**生成结果**:
|
||
- value 1: 使用配置文件的 `SPOT_CHECK` ✅
|
||
- value 2: 使用 Swagger 的 `TYPE_2` ✅
|
||
- value 3: 使用 Swagger 的 `TYPE_3` ✅
|
||
|
||
### 场景 3: 只使用 Swagger 扩展字段
|
||
|
||
**Swagger 文档**:
|
||
|
||
```json
|
||
{
|
||
"SysTaskTypeEnums": {
|
||
"enum": [1, 2, 3],
|
||
"type": "integer",
|
||
"x-enum-varnames": ["SPOT_CHECK", "CULTURAL", "CLASS_CADRE_MEETING"]
|
||
}
|
||
}
|
||
```
|
||
|
||
**配置文件**: 无配置
|
||
|
||
**生成结果**: 使用 Swagger 的枚举键名 ✅
|
||
|
||
## UNKNOWN 枚举值
|
||
|
||
### 设计理念
|
||
|
||
每个生成的枚举都会自动添加一个 `UNKNOWN` 枚举值,用于处理未知或无效的枚举值,提供更好的容错性。
|
||
|
||
### 值的选择
|
||
|
||
- **整数枚举**: 使用 `-9999` 作为 `UNKNOWN` 的值
|
||
- **字符串枚举**: 使用 `'UNKNOWN'` 作为 `UNKNOWN` 的值
|
||
|
||
### 优势
|
||
|
||
1. **容错处理**: 当接收到未知的枚举值时,返回 `UNKNOWN` 而不是抛出异常
|
||
2. **前向兼容**: 当后端添加新的枚举值时,前端不会崩溃
|
||
3. **安全检查**: 可以在业务逻辑中检查是否为 `UNKNOWN` 值
|
||
|
||
### 使用示例
|
||
|
||
```dart
|
||
// 后端返回了一个新增的枚举值 99(前端代码还未更新)
|
||
final taskType = SysTaskTypeEnums.fromValue(99);
|
||
print(taskType); // SysTaskTypeEnums.UNKNOWN
|
||
|
||
// 业务逻辑中检查
|
||
if (taskType == SysTaskTypeEnums.UNKNOWN) {
|
||
print('遇到未知的任务类型,请更新应用版本');
|
||
}
|
||
```
|
||
|
||
## 优势
|
||
|
||
### 1. 灵活性
|
||
|
||
- ✅ 无需后端支持即可使用
|
||
- ✅ 可以快速修改枚举定义
|
||
- ✅ 支持覆盖 Swagger 文档定义
|
||
|
||
### 2. 兼容性
|
||
|
||
- ✅ 完全向后兼容
|
||
- ✅ 不影响现有功能
|
||
- ✅ 与 x-enum-varnames 共存
|
||
- ✅ 自动容错处理(UNKNOWN 枚举值)
|
||
|
||
### 3. 可维护性
|
||
|
||
- ✅ 集中式配置管理
|
||
- ✅ 易于团队协作
|
||
- ✅ 支持部分映射
|
||
|
||
## 注意事项
|
||
|
||
### 1. 维护成本
|
||
|
||
⚠️ 配置文件需要手动维护,当后端枚举值变化时需要同步更新。
|
||
|
||
**建议**: 如果后端支持,优先使用 Swagger 扩展字段,保持单一数据源。
|
||
|
||
### 2. 值匹配
|
||
|
||
⚠️ 配置文件中的 `value` 必须与 Swagger 文档中的枚举值完全匹配(类型和值都要匹配)。
|
||
|
||
### 3. 命名规范
|
||
|
||
⚠️ 枚举键名必须是有效的 Dart 标识符(大写字母+下划线)。
|
||
|
||
## 后续计划
|
||
|
||
1. ✅ 基础功能实现
|
||
2. ✅ 测试验证
|
||
3. ✅ 文档更新
|
||
4. 🔄 收集用户反馈
|
||
5. 🔄 优化用户体验
|
||
|
||
## 总结
|
||
|
||
阶段 2 的配置文件映射功能已成功实现,为用户提供了更灵活的枚举键名配置方式。用户现在可以:
|
||
|
||
1. ✅ 在后端不支持扩展字段时使用配置文件
|
||
2. ✅ 覆盖 Swagger 文档中的枚举定义
|
||
3. ✅ 快速修改枚举键名,无需等待后端
|
||
4. ✅ 为不同项目使用不同的枚举命名规范
|
||
|
||
功能已完成测试,生成的代码符合预期,文档已更新完毕。
|
||
|
||
---
|
||
|
||
**实现者**: Assistant
|
||
**日期**: 2025-11-24
|
||
**状态**: ✅ 已完成
|
||
|