385 lines
8.5 KiB
Markdown
385 lines
8.5 KiB
Markdown
# 枚举键名生成优化方案
|
||
|
||
## 问题描述
|
||
|
||
当前生成的枚举使用通用的键名(`value1`, `value2`, `value3`...),不够语义化。
|
||
|
||
### 当前生成结果
|
||
|
||
```dart
|
||
enum SysTaskTypeEnums {
|
||
value1(1), // 实际应该是 SPOT_CHECK (抽查)
|
||
value2(2), // 实际应该是 CULTURAL (文创建设)
|
||
value3(3), // 实际应该是 CLASS_CADRE_MEETING (班干部会议)
|
||
...
|
||
}
|
||
```
|
||
|
||
### 期望结果
|
||
|
||
```dart
|
||
enum SysTaskTypeEnums {
|
||
/// 抽查
|
||
SPOT_CHECK(1),
|
||
|
||
/// 文创建设
|
||
CULTURAL(2),
|
||
|
||
/// 班干部会议
|
||
CLASS_CADRE_MEETING(3),
|
||
|
||
/// 学生谈话
|
||
STUDENT_TALK(4),
|
||
...
|
||
}
|
||
```
|
||
|
||
## 根本原因
|
||
|
||
Swagger 文档中的枚举定义只包含值(numbers),没有提供键名映射:
|
||
|
||
```json
|
||
{
|
||
"SysTaskTypeEnums": {
|
||
"enum": [1, 2, 3, 4, 5, ...],
|
||
"type": "integer",
|
||
"description": "任务类型枚举"
|
||
}
|
||
}
|
||
```
|
||
|
||
## 解决方案
|
||
|
||
### 方案 1: 使用 OpenAPI 扩展字段 (推荐)
|
||
|
||
在 Swagger 文档中添加 `x-enum-varnames` 和 `x-enum-descriptions` 扩展字段:
|
||
|
||
```json
|
||
{
|
||
"SysTaskTypeEnums": {
|
||
"enum": [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13],
|
||
"type": "integer",
|
||
"description": "任务类型枚举",
|
||
"format": "int32",
|
||
"x-enum-varnames": [
|
||
"SPOT_CHECK",
|
||
"CULTURAL",
|
||
"CLASS_CADRE_MEETING",
|
||
"STUDENT_TALK",
|
||
"FOLLOW_CLASS",
|
||
"TEACHER_BEHAVIOR_OBSERVATION",
|
||
"MEETING",
|
||
"COACH_SUBJECT",
|
||
"DATA_COLLECTION",
|
||
"CLASS_MEETING",
|
||
"TEACHER_TALK",
|
||
"OTHER_WORK",
|
||
"CLASS_ACTIVITY"
|
||
],
|
||
"x-enum-descriptions": [
|
||
"抽查",
|
||
"文创建设",
|
||
"班干部会议",
|
||
"学生谈话",
|
||
"双师跟课",
|
||
"教师行为观察",
|
||
"参加会议",
|
||
"学科辅助",
|
||
"数据采集",
|
||
"召开班会",
|
||
"教师谈话",
|
||
"其他工作",
|
||
"班级活动"
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
**优点**:
|
||
- ✅ 标准的 OpenAPI 扩展方式
|
||
- ✅ 枚举定义和键名在同一处
|
||
- ✅ 易于维护
|
||
|
||
**缺点**:
|
||
- ⚠️ 需要修改后端 Swagger 文档
|
||
- ⚠️ 需要后端配合
|
||
|
||
### 方案 2: 配置文件映射
|
||
|
||
在 `generator_config.yaml` 中添加枚举键名映射:
|
||
|
||
```yaml
|
||
# generator_config.yaml
|
||
|
||
generation:
|
||
models:
|
||
# 枚举键名映射配置
|
||
enum_key_mappings:
|
||
SysTaskTypeEnums:
|
||
1:
|
||
name: SPOT_CHECK
|
||
description: 抽查
|
||
2:
|
||
name: CULTURAL
|
||
description: 文创建设
|
||
3:
|
||
name: CLASS_CADRE_MEETING
|
||
description: 班干部会议
|
||
4:
|
||
name: STUDENT_TALK
|
||
description: 学生谈话
|
||
5:
|
||
name: FOLLOW_CLASS
|
||
description: 双师跟课
|
||
# ... 其他映射
|
||
|
||
SysRoleEnum:
|
||
1:
|
||
name: ADMIN
|
||
description: 管理员
|
||
2:
|
||
name: USER
|
||
description: 普通用户
|
||
# ... 其他映射
|
||
```
|
||
|
||
**优点**:
|
||
- ✅ 不需要修改后端
|
||
- ✅ 灵活配置
|
||
- ✅ 支持批量管理
|
||
|
||
**缺点**:
|
||
- ⚠️ 配置文件可能很大
|
||
- ⚠️ 需要手动维护映射
|
||
|
||
### 方案 3: 智能命名策略(备选)
|
||
|
||
如果 Swagger 文档中枚举的 description 字段包含中文说明,可以尝试智能转换:
|
||
|
||
```
|
||
"抽查" -> SPOT_CHECK (通过翻译API或预定义映射)
|
||
"文创建设" -> CULTURAL
|
||
"班干部会议" -> CLASS_CADRE_MEETING
|
||
```
|
||
|
||
**优点**:
|
||
- ✅ 自动化程度高
|
||
- ✅ 不需要额外配置
|
||
|
||
**缺点**:
|
||
- ⚠️ 翻译质量不稳定
|
||
- ⚠️ 需要外部服务或大量预定义映射
|
||
|
||
## 推荐实施方案
|
||
|
||
### 阶段 1: 支持 OpenAPI 扩展字段(立即实施)
|
||
|
||
修改枚举解析逻辑,支持读取 `x-enum-varnames` 和 `x-enum-descriptions`:
|
||
|
||
```dart
|
||
// lib/core/models/api_schema.dart
|
||
|
||
class ApiModel {
|
||
final List<String>? enumVarNames; // 新增
|
||
final List<String>? enumDescriptions; // 新增
|
||
|
||
factory ApiModel.fromJson(...) {
|
||
// 解析 x-enum-varnames
|
||
final enumVarNames = json['x-enum-varnames'] as List<dynamic>?;
|
||
final enumDescriptions = json['x-enum-descriptions'] as List<dynamic>?;
|
||
|
||
return ApiModel(
|
||
enumVarNames: enumVarNames?.map((e) => e.toString()).toList(),
|
||
enumDescriptions: enumDescriptions?.map((e) => e.toString()).toList(),
|
||
...
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
修改枚举生成逻辑:
|
||
|
||
```dart
|
||
// lib/pipeline/generate/impl/model/model_content_builders.dart
|
||
|
||
String _generateEnumCodeWithoutImports(ApiModel model) {
|
||
...
|
||
for (var i = 0; i < model.enumValues.length; i++) {
|
||
final value = model.enumValues[i];
|
||
|
||
// 优先使用 x-enum-varnames
|
||
final enumName = model.enumVarNames != null && i < model.enumVarNames!.length
|
||
? model.enumVarNames![i]
|
||
: StringHelper.generateEnumValueName(value, i);
|
||
|
||
// 添加描述注释
|
||
if (model.enumDescriptions != null && i < model.enumDescriptions!.length) {
|
||
buffer.writeln(' /// ${model.enumDescriptions![i]}');
|
||
}
|
||
|
||
final enumLine = enumType == 'integer' || enumType == 'number'
|
||
? ' $enumName($value),'
|
||
: " $enumName('$value'),";
|
||
|
||
buffer.writeln(enumLine);
|
||
}
|
||
...
|
||
}
|
||
```
|
||
|
||
### 阶段 2: 支持配置文件映射 ✅
|
||
|
||
已实现配置支持:
|
||
|
||
```dart
|
||
// lib/core/config_repository.dart
|
||
|
||
class EnumKeyMapping {
|
||
final String name;
|
||
final String? description;
|
||
|
||
const EnumKeyMapping({required this.name, this.description});
|
||
}
|
||
|
||
class ConfigRepository {
|
||
/// 获取枚举键名映射配置
|
||
/// 返回格式: { "EnumName": { value: { "name": "KEY_NAME", "description": "描述" } } }
|
||
Map<String, Map<dynamic, EnumKeyMapping>>? get enumKeyMappings { ... }
|
||
}
|
||
```
|
||
|
||
配置文件格式(`generator_config.yaml`):
|
||
|
||
```yaml
|
||
generation:
|
||
models:
|
||
enum_key_mappings:
|
||
SysTaskTypeEnums:
|
||
- value: 1
|
||
name: SPOT_CHECK
|
||
description: 抽查
|
||
- value: 2
|
||
name: CULTURAL
|
||
description: 文创建设
|
||
```
|
||
|
||
## 实施步骤
|
||
|
||
### Step 1: 修改数据模型 ✅
|
||
|
||
1. 在 `ApiModel` 中添加 `enumVarNames` 和 `enumDescriptions` 字段
|
||
2. 在 `fromJson` 中解析扩展字段
|
||
|
||
### Step 2: 修改生成逻辑 ✅
|
||
|
||
1. 修改 `_generateEnumCodeWithoutImports` 方法
|
||
2. 实现三级优先级:配置文件 > x-enum-varnames > 智能生成
|
||
3. 支持配置文件覆盖 Swagger 文档定义
|
||
|
||
### Step 3: 配置文件支持 ✅
|
||
|
||
1. 在 `ConfigRepository` 中添加 `enumKeyMappings` 解析
|
||
2. 在 `SwaggerConfig` 中暴露配置
|
||
3. 在枚举生成逻辑中使用配置
|
||
4. 更新配置模板文件
|
||
|
||
### Step 4: 文档和示例 ✅
|
||
|
||
1. 更新使用文档
|
||
2. 提供 Swagger 文档示例
|
||
3. 提供配置文件示例
|
||
4. 创建测试配置和测试文档
|
||
|
||
### Step 5: 测试 ✅
|
||
|
||
1. 创建测试 Swagger 文档
|
||
2. 创建测试配置文件
|
||
3. 运行生成器验证功能
|
||
4. 确认生成的枚举键名和描述正确
|
||
|
||
## 使用示例
|
||
|
||
### 后端 Swagger 文档(推荐)
|
||
|
||
```json
|
||
{
|
||
"components": {
|
||
"schemas": {
|
||
"SysTaskTypeEnums": {
|
||
"enum": [1, 2, 3],
|
||
"type": "integer",
|
||
"description": "任务类型枚举",
|
||
"x-enum-varnames": ["SPOT_CHECK", "CULTURAL", "CLASS_CADRE_MEETING"],
|
||
"x-enum-descriptions": ["抽查", "文创建设", "班干部会议"]
|
||
}
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 配置文件映射(备选)
|
||
|
||
```yaml
|
||
# generator_config.yaml
|
||
generation:
|
||
models:
|
||
enum_key_mappings:
|
||
SysTaskTypeEnums:
|
||
1: { name: "SPOT_CHECK", description: "抽查" }
|
||
2: { name: "CULTURAL", description: "文创建设" }
|
||
3: { name: "CLASS_CADRE_MEETING", description: "班干部会议" }
|
||
```
|
||
|
||
### 生成结果
|
||
|
||
```dart
|
||
/// 任务类型枚举
|
||
@JsonEnum()
|
||
enum SysTaskTypeEnums {
|
||
/// 抽查
|
||
SPOT_CHECK(1),
|
||
|
||
/// 文创建设
|
||
CULTURAL(2),
|
||
|
||
/// 班干部会议
|
||
CLASS_CADRE_MEETING(3);
|
||
|
||
const SysTaskTypeEnums(this.value);
|
||
final int value;
|
||
|
||
static SysTaskTypeEnums fromValue(dynamic value) {
|
||
for (final enumValue in SysTaskTypeEnums.values) {
|
||
if (enumValue.value == value) {
|
||
return enumValue;
|
||
}
|
||
}
|
||
throw ArgumentError('Unknown enum value: $value');
|
||
}
|
||
|
||
factory SysTaskTypeEnums.fromJson(dynamic json) {
|
||
return fromValue(json);
|
||
}
|
||
|
||
dynamic toJson() => value;
|
||
}
|
||
```
|
||
|
||
## 兼容性
|
||
|
||
- ✅ 向后兼容:如果没有提供扩展字段或配置,仍使用 `value1`, `value2` 等
|
||
- ✅ 灵活配置:支持全局配置或单个枚举配置
|
||
- ✅ 标准支持:使用标准的 OpenAPI 扩展字段
|
||
|
||
## 相关资源
|
||
|
||
- [OpenAPI Extensions](https://swagger.io/docs/specification/openapi-extensions/)
|
||
- [x-enum-varnames Extension](https://github.com/OpenAPITools/openapi-generator/blob/master/docs/templating.md#enum)
|
||
|
||
---
|
||
|
||
**提案日期**: 2025-11-24
|
||
**状态**: 待实施
|
||
**优先级**: Medium
|
||
|