From 547a6c7f16d746f6cfec325d53a796349704d455 Mon Sep 17 00:00:00 2001 From: Max Date: Thu, 24 Jul 2025 10:42:22 +0800 Subject: [PATCH] =?UTF-8?q?Revert=20"feat:=20=E4=BC=98=E5=8C=96=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E5=8D=87=E7=BA=A7=E4=B8=BA2.0=20=E4=B8=A5=E6=A0=BC?= =?UTF-8?q?=E6=89=A7=E8=A1=8C3.0=20swagger=20=E6=A0=87=E5=87=86"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 0fc76544ff8c49f7cc994c02bc8937523b13c5c8. --- AUGMENT_CODE_GENERATION_STANDARDS.md | 458 - CODE_REVIEW_CHECKLIST.md | 231 - CONTRIBUTING.md | 369 - QUICK_REFERENCE.md | 228 - README.md | 247 +- analysis_options.yaml | 9 +- docs/API_REFERENCE.md | 457 - example/advanced_usage.dart | 311 - example/basic_usage.dart | 239 - example/complete_project_example.dart | 424 - example/dio_retrofit_usage.dart | 311 - example/generated/advanced_api_service.dart | 178 - example/generated/basic_api_service.dart | 70 - example/generated/validation_report.json | 79 - example/generated/validation_report.txt | 52 - generator_config.yaml | 240 - lib/commands/generate_command.dart | 128 +- lib/core/config.dart | 4 +- lib/core/error_reporter.dart | 445 - lib/core/error_rules.dart | 469 - lib/core/models.dart | 1943 +-- lib/core/performance_parser.dart | 471 - lib/core/smart_cache.dart | 444 - lib/generators/documentation_generator.dart | 39 +- lib/generators/endpoint_code_generator.dart | 6 +- lib/generators/model_code_generator.dart | 313 +- .../optimized_retrofit_generator.dart | 547 - lib/generators/performance_generator.dart | 591 - lib/generators/retrofit_api_generator.dart | 1402 +- lib/parsers/swagger_data_parser.dart | 121 +- lib/swagger_cli_new.dart | 3 +- lib/swagger_generator_flutter.dart | 19 - lib/utils/file_utils.dart | 1 + lib/utils/reference_resolver.dart | 301 - lib/utils/string_utils.dart | 8 - lib/validators/enhanced_validator.dart | 597 - lib/validators/schema_validator.dart | 845 - pubspec.lock | 28 +- pubspec.yaml | 4 +- run_swagger.sh | 81 +- swagger.json | 12902 ---------------- test_function_name.dart | 21 + test_property_name.dart | 76 + tests/comprehensive_generator_test.dart | 613 - tests/comprehensive_parser_test.dart | 623 - tests/encoding_test.dart | 217 - tests/enhanced_validator_test.dart | 476 - tests/integration_test.dart | 589 - tests/media_type_test.dart | 451 - tests/models_test.dart | 788 +- tests/optimized_generator_test.dart | 392 - tests/performance_test.dart | 488 - tests/reference_resolver_test.dart | 325 - tests/security_test.dart | 504 - tests/simple_generator_test.dart | 442 - tests/string_utils_test.dart | 3 +- validate.sh | 280 - validate_standards.dart | 239 - 58 files changed, 925 insertions(+), 31217 deletions(-) delete mode 100644 AUGMENT_CODE_GENERATION_STANDARDS.md delete mode 100644 CODE_REVIEW_CHECKLIST.md delete mode 100644 CONTRIBUTING.md delete mode 100644 QUICK_REFERENCE.md delete mode 100644 docs/API_REFERENCE.md delete mode 100644 example/advanced_usage.dart delete mode 100644 example/basic_usage.dart delete mode 100644 example/complete_project_example.dart delete mode 100644 example/dio_retrofit_usage.dart delete mode 100644 example/generated/advanced_api_service.dart delete mode 100644 example/generated/basic_api_service.dart delete mode 100644 example/generated/validation_report.json delete mode 100644 example/generated/validation_report.txt delete mode 100644 generator_config.yaml delete mode 100644 lib/core/error_reporter.dart delete mode 100644 lib/core/error_rules.dart delete mode 100644 lib/core/performance_parser.dart delete mode 100644 lib/core/smart_cache.dart delete mode 100644 lib/generators/optimized_retrofit_generator.dart delete mode 100644 lib/generators/performance_generator.dart delete mode 100644 lib/swagger_generator_flutter.dart delete mode 100644 lib/utils/reference_resolver.dart delete mode 100644 lib/validators/enhanced_validator.dart delete mode 100644 lib/validators/schema_validator.dart delete mode 100644 swagger.json create mode 100644 test_function_name.dart create mode 100644 test_property_name.dart delete mode 100644 tests/comprehensive_generator_test.dart delete mode 100644 tests/comprehensive_parser_test.dart delete mode 100644 tests/encoding_test.dart delete mode 100644 tests/enhanced_validator_test.dart delete mode 100644 tests/integration_test.dart delete mode 100644 tests/media_type_test.dart delete mode 100644 tests/optimized_generator_test.dart delete mode 100644 tests/performance_test.dart delete mode 100644 tests/reference_resolver_test.dart delete mode 100644 tests/security_test.dart delete mode 100644 tests/simple_generator_test.dart delete mode 100755 validate.sh delete mode 100644 validate_standards.dart diff --git a/AUGMENT_CODE_GENERATION_STANDARDS.md b/AUGMENT_CODE_GENERATION_STANDARDS.md deleted file mode 100644 index dafbcc1..0000000 --- a/AUGMENT_CODE_GENERATION_STANDARDS.md +++ /dev/null @@ -1,458 +0,0 @@ -# Augment 代码生成规范 -## 基于 OpenAPI 3.0 标准的 Flutter API 代码生成规范 - -### 📋 **核心原则** - -#### 1. **OpenAPI 3.0 标准优先** -- **严格遵循 OpenAPI 3.0 规范** -- **swagger.json 是唯一真实来源** -- **不进行主观推断或猜测** -- **有问题与服务器端沟通完善文档** - -#### 2. **类型安全第一** -- **所有类型必须从 schema 定义中提取** -- **禁止硬编码类型映射** -- **使用强类型,避免 dynamic** -- **严格的可空性控制** - -#### 3. **一致性保证** -- **统一的命名规范** -- **统一的文件结构** -- **统一的代码风格** -- **统一的注释格式** - ---- - -## 🏗️ **项目结构规范** - -### **目录结构** -``` -generator/ -├── api/ # API 接口文件 -│ ├── api_client.dart # 主 API 客户端 -│ ├── login_api.dart # 按 tag 分组的 API -│ └── ... -├── api_models/ # 数据模型 -│ ├── index.dart # 统一导出文件 -│ ├── user_result.dart # 具体模型类 -│ └── ... -├── api_paths.dart # API 路径常量 -├── build.yaml # 构建配置 -└── pubspec.yaml # 依赖配置 -``` - -### **文件命名规范** -- **API 文件**: `{tag_name}_api.dart` (snake_case) -- **模型文件**: `{schema_name}.dart` (snake_case) -- **参数文件**: `{operation_id}_parameters.dart` -- **类名**: `PascalCase` -- **方法名**: `camelCase` -- **常量**: `UPPER_SNAKE_CASE` - ---- - -## 🔧 **代码生成规范** - -### **1. API 接口生成** - -#### **基本结构** -```dart -// {Tag} API 接口定义 -// 基于 Swagger API 文档: {swagger_url} -// 由 xy_swagger_generator by max 生成 -// Copyright (C) 2025 YuanXuan. All rights reserved. - -import 'package:dio/dio.dart'; -import 'package:retrofit/retrofit.dart'; -import 'package:learning_officer_oa/common/models/common/base_result.dart'; - -// 按需导入分页类型 -import 'package:learning_officer_oa/common/models/common/base_page_result.dart'; - -part '{tag_name}_api.g.dart'; - -/// {Tag} API 接口 -/// 负责处理 {Tag} 相关的接口 -@RestApi(parser: Parser.JsonSerializable) -abstract class {Tag}Api { - factory {Tag}Api(Dio dio, {String? baseUrl}) = _{Tag}Api; -} -``` - -#### **方法生成规则** -```dart -/// {summary} -@{HTTP_METHOD}('{path}') -Future<{ReturnType}> {methodName}( - // 路径参数 - @Path('{param}') {Type} param, - // 查询参数 - @Query('{param}') {Type}? param, - // 请求体(仅当 swagger 中明确定义时) - @Body() {Type} request -); -``` - -### **2. 返回类型规范** - -#### **类型提取优先级** -1. **从 responses.200.content.application/json.schema 提取** -2. **从 responses.200.content.text/plain.schema 提取** -3. **特殊处理**: 健康检查接口返回 `BaseResult` -4. **默认**: `BaseResult>` - -#### **分页类型判断** -```dart -// 当返回类型包含分页结构时使用 BasePageResult -BasePageResult<{ItemType}> - -// 判断依据: -// 1. schema 中包含 pageIndex, pageSize, totalCount 等字段 -// 2. 查询参数中包含分页参数 (page, size, limit 等) -``` - -### **3. 请求体生成规范** - -#### **添加 @Body() 的条件** -```dart -// 仅在以下情况添加 @Body() 参数: -// 1. requestBody 在 swagger 中明确定义 -// 2. parameters 中存在 in: "body" 的参数 -// 3. 其他情况一律不添加 -``` - -#### **请求体类型提取** -```dart -// 优先级: -// 1. requestBody.content.application/json.schema -// 2. requestBody.content.text/plain.schema -// 3. 默认: Map -``` - ---- - -## 📝 **数据模型生成规范** - -### **1. 模型类结构** - -#### **基本模板** -```dart -// {schemaName} 模型定义 -// 基于 Swagger API 文档: {swagger_url} -// 由 xy_swagger_generator by max 生成 -// Copyright (C) 2025 YuanXuan. All rights reserved. - -import 'package:json_annotation/json_annotation.dart'; -import 'index.dart'; - -part '{schema_name}.g.dart'; - -@JsonSerializable(checked: true, includeIfNull: false) -class {SchemaName} { - // 属性定义 - - const {SchemaName}({ - // 构造函数参数 - }); - - factory {SchemaName}.fromJson(Map json) => - _${SchemaName}FromJson(json); - - Map toJson() => _${SchemaName}ToJson(this); -} -``` - -### **2. 属性生成规则** - -#### **可空性判断** -```dart -// 严格按照 OpenAPI 规范: -// 1. 有 "nullable": true -> 可空类型 (Type?) -// 2. 没有 "nullable": true -> 非空类型 (Type) -// 3. 忽略 required 字段,只看 nullable - -final String name; // 非空 -final String? nickname; // 可空 (nullable: true) -``` - -#### **类型映射** -```dart -// OpenAPI -> Dart 类型映射 -"string" -> String -"integer" -> int -"number" -> double -"boolean" -> bool -"array" -> List -"object" -> Map 或具体类型 -"$ref" -> 引用的具体类型 -``` - -#### **构造函数规则** -```dart -const {ClassName}({ - required this.nonNullableField, // 非空字段必须 required - this.nullableField, // 可空字段不需要 required -}); -``` - -### **3. 导入管理** - -#### **按需导入原则** -```dart -// 只导入实际使用的类型 -// 分页相关 -import 'package:learning_officer_oa/common/models/common/base_page_result.dart'; - -// 基础响应 -import 'package:learning_officer_oa/common/models/common/base_result.dart'; - -// 模型类型 -import '../../api_models/{model_name}.dart'; -``` - ---- - -## 🚫 **禁止事项** - -### **1. 硬编码推断** -```dart -// ❌ 禁止基于路径关键词推断类型 -if (path.contains('login')) return 'UserLoginResult'; - -// ❌ 禁止基于 tag 推断类型 -if (tag.contains('task')) return 'TaskInfoResult'; - -// ❌ 禁止基于操作推断请求体 -if (method == 'POST') addBody(); -``` - -### **2. 不存在的类型** -```dart -// ❌ 禁止生成 swagger 中不存在的类型 -Future> // TaskInfoResult 不存在 - -// ✅ 使用通用类型或实际存在的类型 -Future>> -Future> -``` - -### **3. 主观判断** -```dart -// ❌ 禁止主观添加参数 -@Body() Map request // swagger 中没有定义 - -// ❌ 禁止主观修改类型 -List -> List // 没有明确的 items schema -``` - ---- - -## ✅ **质量保证** - -### **1. 生成前检查** -- **验证 swagger.json 格式正确性** -- **检查所有 $ref 引用完整性** -- **确认 components/schemas 定义完整** - -### **2. 生成后验证** -- **所有生成的类型在 swagger 中都有定义** -- **没有硬编码的类型映射** -- **导入语句按需生成** -- **代码通过 dart analyze 检查** - -### **3. 错误处理** -```dart -// 当 swagger 定义不完整时的处理策略: -// 1. 记录警告日志 -// 2. 使用安全的默认类型 -// 3. 提示完善 swagger 文档 -// 4. 不进行主观推断 -``` - ---- - -## 📞 **沟通机制** - -### **文档问题反馈** -1. **发现 swagger 定义缺失** -> 联系后端完善 -2. **类型定义不明确** -> 要求明确 schema -3. **响应结构不一致** -> 统一响应格式 -4. **参数定义缺失** -> 补充参数说明 - -### **版本管理** -- **swagger.json 版本控制** -- **生成代码版本标记** -- **变更日志记录** -- **向后兼容性检查** - ---- - -## 🛠️ **工具配置规范** - -### **1. 生成器配置** -```yaml -# pubspec.yaml -dependencies: - dio: ^5.0.0 - retrofit: ^4.0.0 - json_annotation: ^4.8.0 - -dev_dependencies: - build_runner: ^2.3.0 - retrofit_generator: ^8.0.0 - json_serializable: ^6.6.0 -``` - -### **2. 构建配置** -```yaml -# build.yaml -targets: - $default: - builders: - json_serializable: - options: - checked: true - include_if_null: false - explicit_to_json: true -``` - -### **3. 分析配置** -```yaml -# analysis_options.yaml -analyzer: - strong-mode: - implicit-casts: false - implicit-dynamic: false - -linter: - rules: - - prefer_const_constructors - - prefer_final_fields - - avoid_dynamic_calls -``` - ---- - -## 📚 **最佳实践示例** - -### **1. 标准 API 接口** -```dart -/// 用户登录 -@POST('/api/v1/Login/userLogin') -Future> userLogin( - @Body() LoginRequest request -); - -/// 获取用户列表(分页) -@GET('/api/v1/User/GetUserList') -Future> getUserList( - @Query('page') int page, - @Query('size') int size, - @Query('keyword') String? keyword -); - -/// 健康检查 -@GET('/health') -Future> healthCheck(); - -/// 无明确 schema 的接口 -@POST('/api/v1/Action/DoSomething') -Future>> doSomething(); -``` - -### **2. 标准数据模型** -```dart -@JsonSerializable(checked: true, includeIfNull: false) -class UserResult { - /// 用户ID - final int id; - - /// 用户名 - final String username; - - /// 昵称(可空) - final String? nickname; - - /// 头像URL(可空) - final String? avatarUrl; - - /// 是否激活 - final bool isActive; - - const UserResult({ - required this.id, - required this.username, - this.nickname, - this.avatarUrl, - required this.isActive, - }); - - factory UserResult.fromJson(Map json) => - _$UserResultFromJson(json); - - Map toJson() => _$UserResultToJson(this); -} -``` - -### **3. 参数类生成** -```dart -@JsonSerializable(checked: true, includeIfNull: false) -class GetUserListParameters { - final int page; - final int size; - final String? keyword; - - const GetUserListParameters({ - required this.page, - required this.size, - this.keyword, - }); - - factory GetUserListParameters.fromJson(Map json) => - _$GetUserListParametersFromJson(json); - - Map toJson() => _$GetUserListParametersToJson(this); -} -``` - ---- - -## 🔍 **代码审查清单** - -### **生成代码检查项** -- [ ] 所有类型都在 swagger.json 中有定义 -- [ ] 没有硬编码的类型推断 -- [ ] 可空性严格按照 nullable 字段 -- [ ] 导入语句按需生成 -- [ ] 方法参数与 swagger 定义一致 -- [ ] 返回类型正确提取 -- [ ] 注释信息完整 -- [ ] 代码格式规范 - -### **swagger.json 检查项** -- [ ] 所有接口都有明确的 responses 定义 -- [ ] 所有 schema 都有完整的属性定义 -- [ ] 所有 $ref 引用都存在 -- [ ] 参数定义完整(name, in, schema) -- [ ] requestBody 定义明确 -- [ ] 版本信息正确 - ---- - -## 📖 **参考资源** - -### **官方文档** -- [OpenAPI 3.0 规范](https://swagger.io/specification/) -- [Retrofit for Dart](https://pub.dev/packages/retrofit) -- [JSON Serializable](https://pub.dev/packages/json_serializable) - -### **项目相关** -- [项目 README](./README.md) -- [API 参考文档](./docs/API_REFERENCE.md) -- [贡献指南](./CONTRIBUTING.md) - ---- - -**最后更新**: 2025-01-24 -**版本**: v2.0 -**维护者**: Augment Team diff --git a/CODE_REVIEW_CHECKLIST.md b/CODE_REVIEW_CHECKLIST.md deleted file mode 100644 index 80e4a19..0000000 --- a/CODE_REVIEW_CHECKLIST.md +++ /dev/null @@ -1,231 +0,0 @@ -# Augment 代码生成审查清单 - -## 📋 **生成前检查** - -### **Swagger 文档验证** -- [ ] swagger.json 文件格式正确 -- [ ] OpenAPI 版本为 3.0.x -- [ ] 所有 $ref 引用都存在对应的定义 -- [ ] components/schemas 部分完整 -- [ ] 所有接口都有明确的 responses 定义 -- [ ] 参数定义完整(name, in, schema) -- [ ] requestBody 定义明确(如果需要) - -### **环境准备** -- [ ] Dart SDK 版本 >= 3.0.0 -- [ ] 依赖包版本正确 -- [ ] 网络连接正常(如果从 URL 获取 swagger) -- [ ] 输出目录权限正确 - ---- - -## 🔧 **生成过程检查** - -### **命令执行** -- [ ] 使用正确的生成命令 -- [ ] 参数配置正确 -- [ ] 没有错误或警告信息 -- [ ] 生成统计信息合理 - -### **文件生成** -- [ ] API 文件按 tag 正确分组 -- [ ] 模型文件命名规范 -- [ ] 目录结构正确 -- [ ] index.dart 文件更新 - ---- - -## ✅ **生成后验证** - -### **API 接口检查** - -#### **文件结构** -- [ ] 文件头注释完整 -- [ ] 导入语句正确且按需导入 -- [ ] 类名符合 PascalCase 规范 -- [ ] 方法名符合 camelCase 规范 - -#### **方法定义** -- [ ] HTTP 方法注解正确(@GET, @POST, @PUT, @DELETE) -- [ ] 路径定义与 swagger 一致 -- [ ] 返回类型正确提取 -- [ ] 参数定义完整且正确 - -```dart -// ✅ 正确的方法定义示例 -/// 用户登录 -@POST('/api/v1/Login/userLogin') -Future> userLogin( - @Body() LoginRequest request -); - -// ❌ 错误示例 -@POST('/api/v1/Login/userLogin') -Future> userLogin( // 错误:不存在的类型 - @Body() Map request // 错误:swagger 中没有定义 -); -``` - -#### **参数检查** -- [ ] 路径参数使用 @Path 注解 -- [ ] 查询参数使用 @Query 注解 -- [ ] 请求体参数使用 @Body 注解 -- [ ] 参数类型与 swagger 定义一致 -- [ ] 可空性正确(? 标记) -- [ ] 没有多余的参数 - -#### **返回类型检查** -- [ ] 使用 BaseResult 包装 -- [ ] 分页接口使用 BasePageResult -- [ ] 健康检查接口返回 void -- [ ] 泛型类型存在于 swagger 中 -- [ ] 没有硬编码推断的类型 - -#### **导入检查** -- [ ] 基础类型导入正确 -- [ ] 分页类型按需导入 -- [ ] 模型类型导入完整 -- [ ] 没有未使用的导入 -- [ ] 导入路径正确 - -### **数据模型检查** - -#### **类定义** -- [ ] 类名符合 PascalCase 规范 -- [ ] @JsonSerializable 注解正确 -- [ ] 注解参数配置正确(checked: true, includeIfNull: false) - -#### **属性定义** -- [ ] 属性名符合 camelCase 规范 -- [ ] 类型映射正确(string -> String, integer -> int) -- [ ] 可空性严格按照 nullable 字段 -- [ ] 注释信息完整 -- [ ] final 修饰符正确使用 - -```dart -// ✅ 正确的属性定义 -/// 用户ID -final int id; - -/// 用户名 -final String username; - -/// 昵称(可空) -final String? nickname; // swagger 中 "nullable": true - -// ❌ 错误示例 -final String? username; // 错误:swagger 中没有 "nullable": true -final String nickname; // 错误:swagger 中有 "nullable": true -``` - -#### **构造函数检查** -- [ ] 使用 const 构造函数 -- [ ] 非空字段标记为 required -- [ ] 可空字段不使用 required -- [ ] 参数顺序合理 - -#### **序列化方法** -- [ ] fromJson 工厂方法存在 -- [ ] toJson 方法存在 -- [ ] part 文件引用正确 -- [ ] 生成的方法名正确 - -### **代码质量检查** - -#### **静态分析** -- [ ] dart analyze 无错误 -- [ ] dart analyze 无警告 -- [ ] 代码格式化正确 -- [ ] 命名规范一致 - -#### **类型安全** -- [ ] 避免使用 dynamic -- [ ] 泛型类型明确 -- [ ] 可空性处理正确 -- [ ] 类型转换安全 - -#### **性能考虑** -- [ ] 使用 const 构造函数 -- [ ] 避免不必要的对象创建 -- [ ] 导入优化 -- [ ] 内存使用合理 - ---- - -## 🚫 **常见问题检查** - -### **类型相关** -- [ ] 没有生成不存在的类型(如 TaskInfoResult) -- [ ] 没有硬编码的类型映射 -- [ ] 没有基于路径关键词的推断 -- [ ] 没有基于 tag 的类型推断 - -### **参数相关** -- [ ] 没有添加 swagger 中未定义的参数 -- [ ] 没有遗漏 swagger 中定义的参数 -- [ ] 参数位置正确(path, query, body) -- [ ] 参数类型正确 - -### **导入相关** -- [ ] 没有循环导入 -- [ ] 没有未使用的导入 -- [ ] 没有缺失的导入 -- [ ] 导入路径正确 - -### **命名相关** -- [ ] 文件名符合 snake_case -- [ ] 类名符合 PascalCase -- [ ] 方法名符合 camelCase -- [ ] 变量名符合 camelCase - ---- - -## 🔄 **集成测试** - -### **构建测试** -- [ ] dart pub get 成功 -- [ ] dart pub run build_runner build 成功 -- [ ] 生成的 .g.dart 文件正确 -- [ ] 没有构建错误或警告 - -### **运行时测试** -- [ ] API 调用正常 -- [ ] 序列化/反序列化正常 -- [ ] 类型转换正确 -- [ ] 错误处理正确 - -### **兼容性测试** -- [ ] Dart 版本兼容 -- [ ] Flutter 版本兼容 -- [ ] 依赖包版本兼容 -- [ ] 平台兼容性 - ---- - -## 📝 **文档检查** - -### **代码注释** -- [ ] 类注释完整 -- [ ] 方法注释完整 -- [ ] 属性注释完整 -- [ ] 特殊逻辑有说明 - -### **生成信息** -- [ ] 文件头信息正确 -- [ ] 版本信息正确 -- [ ] 生成时间标记 -- [ ] 来源信息明确 - ---- - -## ✍️ **审查签名** - -**审查者**: _______________ -**审查日期**: _______________ -**审查结果**: [ ] 通过 [ ] 需要修改 [ ] 拒绝 -**备注**: _______________ - ---- - -**检查清单版本**: v2.0 -**最后更新**: 2025-01-24 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 103c00a..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,369 +0,0 @@ -# 贡献指南 - -感谢您对 Swagger Generator Flutter 项目的关注!我们欢迎各种形式的贡献。 - -## 🤝 如何贡献 - -### 报告问题 - -如果您发现了 bug 或有功能建议,请: - -1. 检查 [现有 Issues](https://github.com/your-repo/swagger_generator_flutter/issues) 是否已有相关报告 -2. 如果没有,请创建新的 Issue,包含: - - 清晰的标题和描述 - - 重现步骤(如果是 bug) - - 期望的行为 - - 实际的行为 - - 环境信息(Dart/Flutter 版本等) - - 相关的代码片段或错误日志 - -### 提交代码 - -1. **Fork 项目** - ```bash - git clone https://github.com/your-username/swagger_generator_flutter.git - cd swagger_generator_flutter - ``` - -2. **创建分支** - ```bash - git checkout -b feature/your-feature-name - # 或 - git checkout -b fix/your-bug-fix - ``` - -3. **安装依赖** - ```bash - flutter pub get - ``` - -4. **进行更改** - - 遵循项目的代码风格 - - 添加必要的测试 - - 更新相关文档 - -5. **运行测试** - ```bash - dart test - ``` - -6. **提交更改** - ```bash - git add . - git commit -m "feat: add new feature" # 遵循 Conventional Commits - ``` - -7. **推送分支** - ```bash - git push origin feature/your-feature-name - ``` - -8. **创建 Pull Request** - - 提供清晰的 PR 描述 - - 链接相关的 Issues - - 确保所有检查通过 - -## 📝 代码风格 - -### Dart 代码风格 - -我们遵循 [Dart 官方代码风格指南](https://dart.dev/guides/language/effective-dart/style): - -```dart -// ✅ 好的示例 -class ApiGenerator { - final String className; - final bool generateModels; - - ApiGenerator({ - required this.className, - this.generateModels = true, - }); - - String generateCode() { - // 实现逻辑 - return 'generated code'; - } -} - -// ❌ 不好的示例 -class api_generator { - String class_name; - bool generate_models; - - api_generator(this.class_name, this.generate_models); - - String generate_code() { - return "generated code"; - } -} -``` - -### 命名约定 - -- **类名**: PascalCase (`ApiGenerator`) -- **方法名**: camelCase (`generateCode`) -- **变量名**: camelCase (`className`) -- **常量**: SCREAMING_SNAKE_CASE (`DEFAULT_TIMEOUT`) -- **文件名**: snake_case (`api_generator.dart`) - -### 注释规范 - -```dart -/// 生成 Retrofit API 代码的生成器 -/// -/// 支持多种配置选项,包括: -/// - 模块化 API 生成 -/// - 基础响应类型 -/// - 分页支持 -/// -/// 示例用法: -/// ```dart -/// final generator = RetrofitApiGenerator( -/// className: 'ApiService', -/// splitByTags: true, -/// ); -/// ``` -class RetrofitApiGenerator { - /// API 服务类名 - final String className; - - /// 是否按标签分割 API - final bool splitByTags; - - /// 创建 Retrofit API 生成器 - /// - /// [className] 生成的 API 服务类名 - /// [splitByTags] 是否按标签分割成多个 API 类 - RetrofitApiGenerator({ - this.className = 'ApiService', - this.splitByTags = false, - }); -} -``` - -## 🧪 测试指南 - -### 测试结构 - -``` -tests/ -├── unit/ # 单元测试 -│ ├── generators/ # 生成器测试 -│ ├── parsers/ # 解析器测试 -│ └── validators/ # 验证器测试 -├── integration/ # 集成测试 -└── fixtures/ # 测试数据 -``` - -### 编写测试 - -```dart -import 'package:test/test.dart'; -import 'package:swagger_generator_flutter/swagger_generator_flutter.dart'; - -void main() { - group('RetrofitApiGenerator', () { - late RetrofitApiGenerator generator; - - setUp(() { - generator = RetrofitApiGenerator( - className: 'TestApi', - splitByTags: false, - ); - }); - - test('should generate basic API structure', () { - // Arrange - final document = createTestDocument(); - - // Act - final result = generator.generateFromDocument(document); - - // Assert - expect(result, contains('abstract class TestApi')); - expect(result, contains('@RestApi()')); - }); - - test('should handle empty document', () { - // Arrange - final emptyDocument = createEmptyDocument(); - - // Act & Assert - expect(() => generator.generateFromDocument(emptyDocument), - returnsNormally); - }); - }); -} - -SwaggerDocument createTestDocument() { - return SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: {}, - models: {}, - controllers: {}, - security: [], - ); -} -``` - -### 测试覆盖率 - -我们目标是保持 90%+ 的测试覆盖率: - -```bash -# 运行测试并生成覆盖率报告 -dart test --coverage=coverage -genhtml coverage/lcov.info -o coverage/html -``` - -## 📚 文档贡献 - -### 文档类型 - -1. **API 文档**: 代码中的 dartdoc 注释 -2. **用户指南**: README.md 和 docs/ 目录 -3. **示例代码**: example/ 目录 -4. **迁移指南**: MIGRATION_GUIDE.md - -### 文档风格 - -- 使用清晰、简洁的语言 -- 提供实际的代码示例 -- 包含常见用例和最佳实践 -- 保持文档与代码同步 - -## 🔄 发布流程 - -### 版本号规范 - -我们遵循 [语义化版本](https://semver.org/lang/zh-CN/): - -- **主版本号**: 不兼容的 API 修改 -- **次版本号**: 向下兼容的功能性新增 -- **修订号**: 向下兼容的问题修正 - -### 提交信息规范 - -我们使用 [Conventional Commits](https://www.conventionalcommits.org/zh-hans/): - -``` -<类型>[可选的作用域]: <描述> - -[可选的正文] - -[可选的脚注] -``` - -**类型:** -- `feat`: 新功能 -- `fix`: 修复 bug -- `docs`: 文档更新 -- `style`: 代码格式调整 -- `refactor`: 重构 -- `test`: 测试相关 -- `chore`: 构建过程或辅助工具的变动 - -**示例:** -``` -feat(generator): add support for file upload - -- Add MultipartFile support in OptimizedRetrofitGenerator -- Generate proper @MultiPart annotations -- Update tests and documentation - -Closes #123 -``` - -## 🏗️ 开发环境设置 - -### 必需工具 - -- Dart SDK 3.0+ -- Flutter SDK 3.0+ -- Git - -### 推荐工具 - -- VS Code 或 IntelliJ IDEA -- Dart 和 Flutter 插件 -- Git hooks (pre-commit) - -### 环境配置 - -1. **克隆项目** - ```bash - git clone https://github.com/your-repo/swagger_generator_flutter.git - cd swagger_generator_flutter - ``` - -2. **安装依赖** - ```bash - flutter pub get - ``` - -3. **运行测试** - ```bash - dart test - ``` - -4. **运行示例** - ```bash - dart run example/basic_usage.dart - ``` - -### 开发工作流 - -1. 创建功能分支 -2. 编写代码和测试 -3. 运行所有测试 -4. 更新文档 -5. 提交代码 -6. 创建 Pull Request - -## 🎯 贡献领域 - -我们特别欢迎以下领域的贡献: - -### 高优先级 -- 🐛 Bug 修复 -- 📚 文档改进 -- 🧪 测试覆盖率提升 -- 🚀 性能优化 - -### 中优先级 -- ✨ 新功能开发 -- 🔧 工具改进 -- 📝 示例代码 -- 🌐 国际化支持 - -### 低优先级 -- 🎨 UI/UX 改进 -- 📦 依赖更新 -- 🔍 代码质量提升 - -## 📞 联系我们 - -- **GitHub Issues**: 报告 bug 和功能请求 -- **GitHub Discussions**: 一般讨论和问题 -- **Email**: maintainer@example.com - -## 📄 许可证 - -通过贡献代码,您同意您的贡献将在与项目相同的 [MIT 许可证](LICENSE) 下授权。 - -## 🙏 致谢 - -感谢所有贡献者的努力!您的贡献让这个项目变得更好。 - -### 贡献者列表 - - - ---- - -再次感谢您的贡献!🎉 diff --git a/QUICK_REFERENCE.md b/QUICK_REFERENCE.md deleted file mode 100644 index 3df81dd..0000000 --- a/QUICK_REFERENCE.md +++ /dev/null @@ -1,228 +0,0 @@ -# Augment 代码生成快速参考 - -## 🚀 **快速开始** - -### **生成 API 代码** -```bash -# 生成所有代码 -dart run bin/main.dart generate --api --models --split-by-tags - -# 只生成 API 接口 -dart run bin/main.dart generate --api --split-by-tags - -# 只生成数据模型 -dart run bin/main.dart generate --models -``` - -### **项目集成** -```yaml -# pubspec.yaml -dependencies: - dio: ^5.0.0 - retrofit: ^4.0.0 - json_annotation: ^4.8.0 - -dev_dependencies: - build_runner: ^2.3.0 - retrofit_generator: ^8.0.0 - json_serializable: ^6.6.0 -``` - -```bash -# 运行代码生成 -dart pub get -dart pub run build_runner build -``` - ---- - -## 📋 **常见问题解决** - -### **Q: 生成的类型不存在怎么办?** -```dart -// ❌ 错误:生成了不存在的类型 -Future> someMethod(); - -// ✅ 解决:检查 swagger.json 中是否定义了 TaskInfoResult -// 如果没有定义,联系后端添加 schema 定义 -// 或者使用通用类型: -Future>> someMethod(); -``` - -### **Q: 接口缺少参数怎么办?** -```dart -// ❌ 错误:swagger 中没有定义参数,但生成器添加了 -@POST('/api/v1/SomeAction') -Future> someAction( - @Body() Map request // 不应该存在 -); - -// ✅ 解决:检查 swagger.json 中的参数定义 -// 如果确实需要参数,联系后端在 swagger 中添加定义 -``` - -### **Q: 可空性不正确怎么办?** -```dart -// ❌ 错误:字段应该可空但生成为非空 -final String name; // 但实际可能为 null - -// ✅ 解决:检查 swagger.json 中的 nullable 字段 -{ - "name": { - "type": "string", - "nullable": true // 添加这个字段 - } -} -``` - -### **Q: 分页接口没有使用 BasePageResult?** -```dart -// ❌ 错误:分页接口使用了错误的返回类型 -Future>> getUserList(); - -// ✅ 解决:检查接口是否真的是分页接口 -// 确保 swagger 中定义了分页相关的查询参数和响应结构 -Future> getUserList(); -``` - ---- - -## 🔧 **调试技巧** - -### **1. 检查 swagger.json** -```bash -# 验证 swagger.json 格式 -curl -X POST "https://validator.swagger.io/validator/debug" \ - -H "Content-Type: application/json" \ - -d @swagger.json -``` - -### **2. 查看生成日志** -```bash -# 启用详细日志 -dart run bin/main.dart generate --api --models --verbose -``` - -### **3. 手动验证类型** -```dart -// 在生成的代码中添加断言验证 -assert(response.data is UserResult); -assert(response.data?.name != null); -``` - ---- - -## 📝 **代码模板** - -### **标准 API 接口模板** -```dart -/// {接口描述} -@{HTTP_METHOD}('{路径}') -Future<{返回类型}> {方法名}( - // 路径参数(如果有) - @Path('{参数名}') {类型} 参数名, - - // 查询参数(如果有) - @Query('{参数名}') {类型}? 参数名, - - // 请求体(仅当 swagger 中明确定义时) - @Body() {类型} request -); -``` - -### **标准数据模型模板** -```dart -@JsonSerializable(checked: true, includeIfNull: false) -class {类名} { - /// {字段描述} - final {类型} {字段名}; - - const {类名}({ - required this.{非空字段}, - this.{可空字段}, - }); - - factory {类名}.fromJson(Map json) => - _${类名}FromJson(json); - - Map toJson() => _${类名}ToJson(this); -} -``` - ---- - -## ⚡ **性能优化** - -### **1. 按需导入** -```dart -// ✅ 只导入需要的类型 -import 'package:learning_officer_oa/common/models/common/base_result.dart'; - -// ❌ 避免导入不需要的类型 -// import 'package:learning_officer_oa/common/models/common/base_page_result.dart'; -``` - -### **2. 使用 const 构造函数** -```dart -// ✅ 使用 const 构造函数 -const UserResult({ - required this.id, - required this.name, -}); - -// ❌ 避免非 const 构造函数 -UserResult({ - required this.id, - required this.name, -}); -``` - -### **3. 合理的类型选择** -```dart -// ✅ 使用具体类型 -Future> getUser(); - -// ❌ 避免过度使用 dynamic -Future> getUser(); -``` - ---- - -## 🛡️ **安全检查** - -### **生成前检查** -- [ ] swagger.json 格式正确 -- [ ] 所有 $ref 引用存在 -- [ ] 版本信息匹配 - -### **生成后检查** -- [ ] 代码通过 dart analyze -- [ ] 所有导入都存在 -- [ ] 类型定义完整 -- [ ] 可空性正确 - -### **部署前检查** -- [ ] 运行所有测试 -- [ ] 代码格式化 -- [ ] 文档更新 -- [ ] 版本标记 - ---- - -## 📞 **获取帮助** - -### **常见错误代码** -- **E001**: swagger.json 格式错误 -- **E002**: 缺少必要的 schema 定义 -- **E003**: $ref 引用不存在 -- **E004**: 类型映射失败 - -### **联系方式** -- **技术支持**: 联系后端团队完善 swagger 文档 -- **Bug 报告**: 提交到项目 Issues -- **功能请求**: 通过 PR 贡献代码 - ---- - -**快速参考版本**: v2.0 -**最后更新**: 2025-01-24 diff --git a/README.md b/README.md index 3210e7d..82f72fe 100644 --- a/README.md +++ b/README.md @@ -2,207 +2,32 @@ 基于 Swagger/OpenAPI 的 Dart/Flutter API/模型代码生成工具。 -[![Dart](https://img.shields.io/badge/Dart-3.0+-blue.svg)](https://dart.dev/) -[![Flutter](https://img.shields.io/badge/Flutter-3.0+-blue.svg)](https://flutter.dev/) -[![OpenAPI](https://img.shields.io/badge/OpenAPI-3.0+-green.svg)](https://spec.openapis.org/oas/v3.0.3/) +## 功能简介 +- 根据 swagger.json 自动生成 Dart API 接口、模型、枚举等 +- 支持 Retrofit、json_serializable 等主流生态 +- 支持自定义生成规则和命名风格 -## ✨ 功能特性 - -### 🚀 核心功能 -- **完整的 OpenAPI 3.0 支持**:涵盖所有主要规范特性 -- **高性能解析**:支持并行解析和流式处理大型文档 -- **智能代码生成**:生成高质量的 Dart/Flutter 代码 -- **模块化架构**:按 API 模块自动分组生成 - -### 🎯 专为 Flutter 优化 -- **Dio + Retrofit 集成**:完美适配主流网络架构 -- **类型安全**:生成强类型的 API 接口和模型 -- **JSON 序列化**:自动生成 json_serializable 代码 -- **文件上传支持**:完整的 multipart/form-data 支持 - -### 🔧 高级特性 -- **智能缓存**:提升重复操作性能 -- **错误诊断**:详细的错误报告和修复建议 -- **性能监控**:内置性能统计和优化 -- **增量生成**:支持增量更新和变更检测 - -## 📚 **文档和规范** - -### **核心文档** -- [**代码生成规范**](./AUGMENT_CODE_GENERATION_STANDARDS.md) - 完整的生成规范和最佳实践 -- [**快速参考指南**](./QUICK_REFERENCE.md) - 常见问题和解决方案 -- [**代码审查清单**](./CODE_REVIEW_CHECKLIST.md) - 质量保证检查清单 -- [**生成器配置**](./generator_config.yaml) - 详细的配置选项 - -### **设计原则** -1. **OpenAPI 3.0 标准优先** - 严格遵循规范,不进行主观推断 -2. **与服务器保持一致** - swagger.json 是唯一真实来源 -3. **有问题沟通文档** - 发现问题时要求完善后端文档 -4. **类型安全第一** - 生成强类型代码,避免运行时错误 - -## 🚀 快速开始 - -### 1. 安装依赖 +## 快速开始 ```bash +# 安装依赖 flutter pub get -``` +# 或 +pub get -### 2. 基础用法(命令行) -```bash -# 生成模型和API(推荐) -sh run_swagger.sh all - -# 分别生成 -sh run_swagger.sh api # 只生成 API -sh run_swagger.sh models # 只生成模型 - -# 或直接使用 dart 命令 +# 生成模型和API +sh run_swagger.sh +# 或 dart run bin/main.dart generate --models --api ``` -### 3. 编程式用法(推荐) -```dart -import 'package:swagger_generator_flutter/swagger_generator_flutter.dart'; - -void main() async { - // 使用高性能解析器 - final parser = PerformanceParser( - config: ParseConfig( - enablePerformanceStats: true, - enableParallelParsing: true, - ), - ); - - // 解析 OpenAPI 文档 - final jsonString = await File('swagger.json').readAsString(); - final document = await parser.parseDocument(jsonString); - - // 使用优化生成器 - final generator = OptimizedRetrofitGenerator( - className: 'ApiService', - generateModularApis: true, - generateBaseResult: true, - generatePagination: true, - generateFileUpload: true, - ); - - // 生成代码 - final generatedCode = generator.generateFromDocument(document); - - // 保存文件 - await File('lib/api/api_service.dart').writeAsString(generatedCode); - - // 查看性能统计 - final stats = parser.lastStats; - print('解析时间: ${stats?.totalTime.inMilliseconds}ms'); - print('生成的路径数: ${stats?.pathCount}'); -} +## 目录结构 ``` - -## 📖 详细配置 - -### 生成器类型 - -#### 1. RetrofitApiGenerator(基础版) -```dart -final generator = RetrofitApiGenerator( - className: 'ApiService', // 生成的类名 - splitByTags: true, // 是否按标签分割(默认启用) - useRetrofit: true, // 使用 Retrofit 注解 - generateModels: true, // 生成模型类 -); -``` - -#### 2. OptimizedRetrofitGenerator(推荐) -```dart -final generator = OptimizedRetrofitGenerator( - className: 'ApiService', - generateModularApis: true, // 模块化 API - generateBaseResult: true, // 基础响应类型 - generatePagination: true, // 分页支持 - generateFileUpload: true, // 文件上传 - baseResultType: 'BaseResult', // 自定义基础类型 - pageResultType: 'PageResult', // 自定义分页类型 -); -``` - -#### 3. PerformanceGenerator(高性能) -```dart -final generator = PerformanceGenerator( - maxConcurrency: 4, // 最大并发数 - enableCaching: true, // 启用缓存 - enableIncremental: true, // 增量生成 - enableParallel: true, // 并行生成 -); -``` - -### 解析器配置 -```dart -final parser = PerformanceParser( - config: ParseConfig( - enableParallelParsing: true, // 并行解析 - enableStreamParsing: false, // 流式解析 - enableCaching: true, // 缓存 - maxConcurrency: 4, // 最大并发数 - enablePerformanceStats: true, // 性能统计 - ), -); -``` - -### 验证和错误处理 -```dart -// 创建验证器 -final validator = EnhancedValidator( - strictMode: false, // 严格模式 - includeWarnings: true, // 包含警告 -); - -// 验证文档 -final isValid = validator.validateDocument(document); - -// 获取错误报告 -final errorReport = validator.errorReporter.generateReport(); -print(errorReport); -``` - -## 📊 性能优化 - -### 缓存策略 -```dart -// 配置智能缓存 -final cache = SmartCache( - maxSize: 1000, // 最大缓存大小 - strategy: CacheStrategy.smart, // 缓存策略 - defaultTtl: Duration(hours: 1), // 默认过期时间 -); - -// 获取缓存统计 -final stats = cache.getStats(); -print('缓存命中率: ${(stats.hitRate * 100).toStringAsFixed(1)}%'); -``` - -### 性能监控 -```dart -// 获取解析性能统计 -final parseStats = parser.lastStats; -print('解析性能统计:'); -print(' 总时间: ${parseStats?.totalTime.inMilliseconds}ms'); -print(' 路径数: ${parseStats?.pathCount}'); -print(' 吞吐量: ${parseStats?.bytesPerSecond.toStringAsFixed(2)} bytes/s'); -``` - -## 📁 目录结构 -``` -swagger_generator_flutter/ +swagger/ bin/ # 命令行入口 - example/ # 使用示例 generator/ # 生成的 API、模型、文档 lib/ # 生成器核心代码 - core/ # 核心模型和解析器 - generators/ # 代码生成器 - validators/ # 文档验证器 - tests/ # 单元测试和集成测试 - swagger.json # OpenAPI 源文件 + tests/ # 单元测试 + swagger.json # Swagger/OpenAPI 源文件 ``` ## 运行测试 @@ -210,52 +35,14 @@ swagger_generator_flutter/ dart run test tests/ ``` -## 🎯 **规范遵循示例** - -### **✅ 正确的生成结果** -```dart -// 严格按照 swagger.json 定义生成 -@POST('/api/v1/Login/userLogin') -Future> userLogin( - @Body() LoginRequest request // 仅当 swagger 中明确定义时 -); - -// 健康检查接口 -@GET('/health') -Future> healthCheck(); - -// 无明确 schema 的接口 -@POST('/api/v1/Action/DoSomething') -Future>> doSomething(); -``` - -### **❌ 避免的错误做法** -```dart -// 错误:生成不存在的类型 -Future> someMethod(); - -// 错误:添加 swagger 中未定义的参数 -@POST('/api/v1/GetUsers') -Future>> getUsers( - @Body() Map request // swagger 中没有定义 -); - -// 错误:基于关键词推断类型 -if (path.contains('login')) return 'UserLoginResult'; -``` - ## 贡献指南 -- **严格遵循 [代码生成规范](./AUGMENT_CODE_GENERATION_STANDARDS.md)** -- **使用 [代码审查清单](./CODE_REVIEW_CHECKLIST.md) 进行质量检查** - 代码需包含中英文注释 - 新增功能请补充对应测试用例 - 生成规则/命名风格如有特殊需求请在 issue 说明 ## 常见问题 -- **生成的类型不存在?** 检查 swagger.json 中是否定义了对应的 schema -- **接口缺少参数?** 确认 swagger.json 中是否有完整的参数定义 -- **可空性不正确?** 检查 swagger.json 中的 nullable 字段设置 -- 更多问题请参考 [快速参考指南](./QUICK_REFERENCE.md) +- 生成模型/接口命名不规范?请检查 swagger 字段命名和生成规则 +- 枚举、泛型、嵌套对象支持?已支持主流用法,特殊场景请补充 issue ### 脚本命令说明 diff --git a/analysis_options.yaml b/analysis_options.yaml index 88747fd..af1f32d 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -37,18 +37,17 @@ linter: rules: # 常用且推荐启用的规则 (即使默认集没有包含,也建议手动添加) - avoid_empty_else # 避免空的 else 块 - # - avoid_print # 在生产代码中避免使用 print (可根据项目需求启用/禁用) + - avoid_print # 在生产代码中避免使用 print (可根据项目需求启用/禁用) - avoid_relative_lib_imports # 避免从 'lib/' 相对导入 - - directives_ordering # 强制 import/export 指令排序 # - avoid_return_and_type_annotation # 避免冗余的返回类型注解 - curly_braces_in_flow_control_structures # 控制流语句强制使用大括号 - empty_catches # 避免空的 catch 块 - empty_constructor_bodies # 避免空的构造函数体 - empty_statements # 避免空的语句 - file_names # 文件名使用小写下划线命名 (my_file.dart) - # - prefer_const_constructors # 尽可能使用 const 构造函数 - # - prefer_const_declarations # 尽可能使用 const 声明 - # - prefer_const_literals_to_create_immutables # 尽可能使用 const 创建不可变集合 + - prefer_const_constructors # 尽可能使用 const 构造函数 + - prefer_const_declarations # 尽可能使用 const 声明 + - prefer_const_literals_to_create_immutables # 尽可能使用 const 创建不可变集合 # - prefer_single_quotes # 优先使用单引号 (或 prefer_double_quotes) - prefer_final_fields # 类中的私有字段尽可能使用 final - prefer_final_locals # 局部变量尽可能使用 final diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md deleted file mode 100644 index ad42ed4..0000000 --- a/docs/API_REFERENCE.md +++ /dev/null @@ -1,457 +0,0 @@ -# API 参考文档 - -本文档详细介绍了 Swagger Generator Flutter 的所有 API 接口和配置选项。 - -## 目录 - -- [核心类](#核心类) -- [生成器](#生成器) -- [解析器](#解析器) -- [验证器](#验证器) -- [缓存系统](#缓存系统) -- [配置选项](#配置选项) - -## 核心类 - -### SwaggerDocument - -OpenAPI 文档的主要数据模型。 - -```dart -class SwaggerDocument { - final String title; - final String version; - final String description; - final List servers; - final Map paths; - final Map models; - final ApiComponents components; - final List security; - - SwaggerDocument({ - required this.title, - required this.version, - required this.description, - required this.servers, - required this.paths, - required this.models, - required this.components, - required this.security, - }); - - factory SwaggerDocument.fromJson(Map json); - Map toJson(); -} -``` - -### ApiPath - -API 路径和操作的定义。 - -```dart -class ApiPath { - final String path; - final HttpMethod method; - final String summary; - final String description; - final String operationId; - final List tags; - final List parameters; - final ApiRequestBody? requestBody; - final Map responses; - final List security; - - ApiPath({ - required this.path, - required this.method, - required this.summary, - required this.description, - required this.operationId, - required this.tags, - required this.parameters, - this.requestBody, - required this.responses, - required this.security, - }); -} -``` - -### ApiModel - -数据模型的定义。 - -```dart -class ApiModel { - final String name; - final String description; - final Map properties; - final List required; - - ApiModel({ - required this.name, - required this.description, - required this.properties, - required this.required, - }); -} -``` - -## 生成器 - -### BaseGenerator - -所有生成器的基类。 - -```dart -abstract class BaseGenerator { - String get generatorType; - String generate(); -} -``` - -### RetrofitApiGenerator - -基础的 Retrofit API 生成器。 - -```dart -class RetrofitApiGenerator extends BaseGenerator { - final String className; - final bool splitByTags; - final bool useRetrofit; - final bool generateModels; - - RetrofitApiGenerator({ - this.className = 'ApiService', - this.splitByTags = false, - this.useRetrofit = true, - this.generateModels = true, - }); - - @override - String generateFromDocument(SwaggerDocument document); -} -``` - -#### 方法 - -- `generateFromDocument(SwaggerDocument document)`: 从文档生成代码 -- `generateSingleApiFile()`: 生成单个 API 文件 -- `generateMainApiFile()`: 生成主 API 文件(分模块时) - -### OptimizedRetrofitGenerator - -优化版的 Retrofit API 生成器。 - -```dart -class OptimizedRetrofitGenerator extends BaseGenerator { - final String className; - final bool generateModularApis; - final bool generateBaseResult; - final bool generatePagination; - final bool generateFileUpload; - final String baseResultType; - final String pageResultType; - - OptimizedRetrofitGenerator({ - this.className = 'ApiService', - this.generateModularApis = true, - this.generateBaseResult = true, - this.generatePagination = true, - this.generateFileUpload = true, - this.baseResultType = 'BaseResult', - this.pageResultType = 'BasePageResult', - }); -} -``` - -#### 特性 - -- **模块化生成**: 按 API 标签自动分组 -- **基础类型**: 生成 BaseResult、BasePageResult 等 -- **文件上传**: 支持 multipart/form-data -- **工具类**: 生成 ApiUtils 工具类 - -### PerformanceGenerator - -高性能代码生成器。 - -```dart -class PerformanceGenerator extends BaseGenerator { - final int maxConcurrency; - final bool enableCaching; - final bool enableIncremental; - final bool enableParallel; - - PerformanceGenerator({ - this.maxConcurrency = 4, - this.enableCaching = true, - this.enableIncremental = true, - this.enableParallel = true, - }); - - Future generateFromDocument(SwaggerDocument document); - GenerationStats getStats(); - CacheStats getCacheStats(); - void clearCache(); -} -``` - -#### 方法 - -- `generateFromDocument()`: 异步生成代码 -- `getStats()`: 获取生成性能统计 -- `getCacheStats()`: 获取缓存统计 -- `clearCache()`: 清除缓存 - -## 解析器 - -### PerformanceParser - -高性能 OpenAPI 解析器。 - -```dart -class PerformanceParser { - final ParseConfig config; - - PerformanceParser({ParseConfig? config}); - - Future parseDocument(String jsonString); - ParsePerformanceStats? get lastStats; - void clearCache(); - Map getCacheStats(); -} -``` - -### ParseConfig - -解析器配置。 - -```dart -class ParseConfig { - final bool enableParallelParsing; - final bool enableStreamParsing; - final bool enableIncrementalParsing; - final bool enableCaching; - final int maxConcurrency; - final int streamBufferSize; - final bool enablePerformanceStats; - final bool enableMemoryOptimization; - - const ParseConfig({ - this.enableParallelParsing = true, - this.enableStreamParsing = false, - this.enableIncrementalParsing = false, - this.enableCaching = true, - this.maxConcurrency = 4, - this.streamBufferSize = 8192, - this.enablePerformanceStats = false, - this.enableMemoryOptimization = true, - }); -} -``` - -## 验证器 - -### EnhancedValidator - -增强的文档验证器。 - -```dart -class EnhancedValidator { - final bool strictMode; - final bool includeWarnings; - - EnhancedValidator({ - this.strictMode = false, - this.includeWarnings = true, - }); - - bool validateDocument(SwaggerDocument document); - ErrorReporter get errorReporter; -} -``` - -### ErrorReporter - -错误报告器。 - -```dart -class ErrorReporter { - List get errors; - bool get hasErrors; - bool get hasCriticalErrors; - - void addError(DetailedError error); - void reportError({ - required String id, - required String title, - required String description, - required ErrorSeverity severity, - required ErrorCategory category, - required String jsonPath, - // ... 其他参数 - }); - - List getErrorsBySeverity(ErrorSeverity severity); - List getErrorsByCategory(ErrorCategory category); - Map getErrorStatistics(); - - String generateReport({ - bool includeStatistics = true, - bool groupByCategory = false, - ErrorSeverity? minSeverity, - }); - - String generateJsonReport(); - void clear(); -} -``` - -## 缓存系统 - -### SmartCache - -智能缓存管理器。 - -```dart -class SmartCache { - final int maxSize; - final CacheStrategy strategy; - final Duration defaultTtl; - - SmartCache({ - int maxSize = 1000, - CacheStrategy strategy = CacheStrategy.smart, - Duration defaultTtl = const Duration(hours: 1), - }); - - T? get(String key); - void put(String key, T value, {Duration? ttl, String? etag}); - bool containsKey(String key); - T? remove(String key); - void clear(); - - CacheStats getStats(); - List getKeysNeedingRefresh(); - Future refreshKeys(List keys, Future Function(String key) refreshFunction); - Future warmUp(Map Function()> warmUpFunctions); -} -``` - -### CacheStrategy - -缓存策略枚举。 - -```dart -enum CacheStrategy { - lru, // 最近最少使用 - lfu, // 最近最常使用 - fifo, // 先进先出 - ttl, // 基于时间的过期 - smart, // 智能策略 -} -``` - -## 配置选项 - -### 生成器配置 - -| 选项 | 类型 | 默认值 | 描述 | -|------|------|--------|------| -| `className` | String | 'ApiService' | 生成的主类名 | -| `splitByTags` | bool | true | 是否按标签分割 API | -| `generateModularApis` | bool | true | 生成模块化 API | -| `generateBaseResult` | bool | true | 生成基础响应类型 | -| `generatePagination` | bool | true | 生成分页支持 | -| `generateFileUpload` | bool | true | 生成文件上传支持 | -| `baseResultType` | String | 'BaseResult' | 基础响应类型名 | -| `pageResultType` | String | 'BasePageResult' | 分页响应类型名 | - -### 解析器配置 - -| 选项 | 类型 | 默认值 | 描述 | -|------|------|--------|------| -| `enableParallelParsing` | bool | true | 启用并行解析 | -| `enableStreamParsing` | bool | false | 启用流式解析 | -| `enableCaching` | bool | true | 启用缓存 | -| `maxConcurrency` | int | 4 | 最大并发数 | -| `enablePerformanceStats` | bool | false | 启用性能统计 | - -### 验证器配置 - -| 选项 | 类型 | 默认值 | 描述 | -|------|------|--------|------| -| `strictMode` | bool | false | 严格模式 | -| `includeWarnings` | bool | true | 包含警告 | - -## 错误类型 - -### ErrorSeverity - -```dart -enum ErrorSeverity { - info, // 信息 - warning, // 警告 - error, // 错误 - critical, // 严重错误 -} -``` - -### ErrorCategory - -```dart -enum ErrorCategory { - syntax, // 语法错误 - schema, // Schema 错误 - reference, // 引用错误 - validation, // 验证错误 - compatibility, // 兼容性问题 - performance, // 性能问题 - security, // 安全问题 - bestPractice, // 最佳实践 -} -``` - -## 性能统计 - -### ParsePerformanceStats - -解析性能统计。 - -```dart -class ParsePerformanceStats { - final Duration totalTime; - final Duration parseTime; - final Duration validationTime; - final Duration modelCreationTime; - final int memoryUsage; - final int documentSize; - final int pathCount; - final int schemaCount; - - double get pathsPerSecond; - double get schemasPerSecond; - double get bytesPerSecond; -} -``` - -### GenerationStats - -生成性能统计。 - -```dart -class GenerationStats { - final int totalTasks; - final int completedTasks; - final int failedTasks; - final Duration totalTime; - final Duration averageTaskTime; - final int linesGenerated; - final int bytesGenerated; - final double parallelEfficiency; - - double get successRate; - double get linesPerSecond; - double get bytesPerSecond; -} -``` diff --git a/example/advanced_usage.dart b/example/advanced_usage.dart deleted file mode 100644 index 488a3d4..0000000 --- a/example/advanced_usage.dart +++ /dev/null @@ -1,311 +0,0 @@ -/// 高级使用示例 -/// 演示高性能解析、优化生成和性能监控 -library; - -import 'dart:convert'; -import 'dart:io'; -import 'package:swagger_generator_flutter/swagger_generator_flutter.dart'; - -void main() async { - print('🚀 高级使用示例'); - print('=' * 50); - - try { - await demonstrateHighPerformanceParsing(); - await demonstrateOptimizedGeneration(); - await demonstratePerformanceMonitoring(); - await demonstrateCaching(); - await demonstrateValidationAndErrorHandling(); - - print('\n🎉 高级使用示例完成!'); - } catch (e, stackTrace) { - print('❌ 发生错误: $e'); - print('堆栈跟踪: $stackTrace'); - } -} - -/// 演示高性能解析 -Future demonstrateHighPerformanceParsing() async { - print('\n📊 高性能解析演示'); - print('-' * 30); - - // 读取文档 - final jsonString = await File('swagger.json').readAsString(); - print('📖 文档大小: ${(jsonString.length / 1024).toStringAsFixed(2)}KB'); - - // 配置高性能解析器 - final parser = PerformanceParser( - config: ParseConfig( - enablePerformanceStats: true, - enableParallelParsing: false, // 禁用并行解析避免类型转换问题 - enableCaching: true, - maxConcurrency: 8, - enableMemoryOptimization: true, - ), - ); - - // 解析文档 - final stopwatch = Stopwatch()..start(); - final document = await parser.parseDocument(jsonString); - stopwatch.stop(); - - // 显示解析结果 - print('✅ 解析完成'); - print(' - 解析时间: ${stopwatch.elapsedMilliseconds}ms'); - print(' - 路径数: ${document.paths.length}'); - print(' - 模型数: ${document.models.length}'); - print(' - 服务器数: ${document.servers.length}'); - - // 显示性能统计 - final stats = parser.lastStats; - if (stats != null) { - print('\n📈 性能统计:'); - print(' - 总时间: ${stats.totalTime.inMilliseconds}ms'); - print(' - 解析时间: ${stats.parseTime.inMilliseconds}ms'); - print(' - 验证时间: ${stats.validationTime.inMilliseconds}ms'); - print(' - 模型创建时间: ${stats.modelCreationTime.inMilliseconds}ms'); - print( - ' - 内存使用: ${(stats.memoryUsage / 1024 / 1024).toStringAsFixed(2)}MB'); - print(' - 路径处理速度: ${stats.pathsPerSecond.toStringAsFixed(1)} paths/s'); - print(' - 吞吐量: ${(stats.bytesPerSecond / 1024).toStringAsFixed(2)} KB/s'); - } - - // 显示缓存统计 - final cacheStats = parser.getCacheStats(); - print('\n🗄️ 缓存统计:'); - print(' - 缓存大小: ${cacheStats['size']}'); - print(' - 缓存键: ${(cacheStats['keys'] as List).length}'); -} - -/// 演示优化代码生成 -Future demonstrateOptimizedGeneration() async { - print('\n🔧 优化代码生成演示'); - print('-' * 30); - - // 解析文档 - final jsonString = await File('swagger.json').readAsString(); - final document = SwaggerDocument.fromJson(jsonDecode(jsonString)); - - // 创建优化生成器 - final generator = OptimizedRetrofitGenerator( - className: 'AdvancedApiService', - generateModularApis: true, - generateBaseResult: true, - generatePagination: true, - generateFileUpload: true, - baseResultType: 'ApiResult', - pageResultType: 'PagedResult', - ); - - // 生成代码 - final stopwatch = Stopwatch()..start(); - final generatedCode = generator.generateFromDocument(document); - stopwatch.stop(); - - print('✅ 代码生成完成'); - print(' - 生成时间: ${stopwatch.elapsedMilliseconds}ms'); - print(' - 代码大小: ${(generatedCode.length / 1024).toStringAsFixed(2)}KB'); - print(' - 代码行数: ${generatedCode.split('\n').length}'); - - // 检查生成的特性 - final features = []; - if (generatedCode.contains('class ApiResult')) features.add('基础响应类型'); - if (generatedCode.contains('class PagedResult')) features.add('分页支持'); - if (generatedCode.contains('MultipartFile')) features.add('文件上传'); - if (generatedCode.contains('class ApiUtils')) features.add('工具类'); - - print(' - 生成特性: ${features.join(', ')}'); - - // 保存代码 - final outputFile = File('example/generated/advanced_api_service.dart'); - await outputFile.writeAsString(generatedCode); - print(' - 保存位置: ${outputFile.path}'); -} - -/// 演示性能监控 -Future demonstratePerformanceMonitoring() async { - print('\n📊 性能监控演示'); - print('-' * 30); - - // 解析文档 - final jsonString = await File('swagger.json').readAsString(); - final document = SwaggerDocument.fromJson(jsonDecode(jsonString)); - - // 创建性能生成器 - final generator = PerformanceGenerator( - maxConcurrency: 4, - enableCaching: true, - enableIncremental: true, - enableParallel: true, - ); - - // 生成代码 - final generatedCode = await generator.generateFromDocument(document); - - // 获取性能统计 - final stats = generator.getStats(); - print('📈 生成性能统计:'); - print(' - 总任务数: ${stats.totalTasks}'); - print(' - 完成任务数: ${stats.completedTasks}'); - print(' - 失败任务数: ${stats.failedTasks}'); - print(' - 成功率: ${(stats.successRate * 100).toStringAsFixed(1)}%'); - print(' - 总时间: ${stats.totalTime.inMilliseconds}ms'); - print(' - 平均任务时间: ${stats.averageTaskTime.inMilliseconds}ms'); - print(' - 生成行数: ${stats.linesGenerated}'); - print(' - 生成字节数: ${stats.bytesGenerated}'); - print(' - 并行效率: ${(stats.parallelEfficiency * 100).toStringAsFixed(1)}%'); - print(' - 生成速度: ${stats.linesPerSecond.toStringAsFixed(1)} lines/s'); - - // 获取缓存统计 - final cacheStats = generator.getCacheStats(); - print('\n🗄️ 生成器缓存统计:'); - print(' - 总请求: ${cacheStats.totalRequests}'); - print(' - 缓存命中: ${cacheStats.hits}'); - print(' - 缓存未命中: ${cacheStats.misses}'); - print(' - 命中率: ${(cacheStats.hitRate * 100).toStringAsFixed(1)}%'); - print(' - 缓存大小: ${cacheStats.size}/${cacheStats.maxSize}'); - print(' - 平均访问时间: ${cacheStats.averageAccessTime.inMicroseconds}μs'); -} - -/// 演示缓存功能 -Future demonstrateCaching() async { - print('\n🗄️ 缓存功能演示'); - print('-' * 30); - - // 创建智能缓存 - final cache = SmartCache( - maxSize: 100, - strategy: CacheStrategy.smart, - defaultTtl: Duration(minutes: 30), - ); - - // 添加一些测试数据 - cache.put('user:1', '{"id": 1, "name": "Alice"}'); - cache.put('user:2', '{"id": 2, "name": "Bob"}'); - cache.put('user:3', '{"id": 3, "name": "Charlie"}'); - - // 模拟访问模式 - for (int i = 0; i < 10; i++) { - cache.get('user:1'); // 频繁访问 - } - for (int i = 0; i < 5; i++) { - cache.get('user:2'); // 中等访问 - } - cache.get('user:3'); // 少量访问 - - // 获取缓存统计 - final stats = cache.getStats(); - print('📊 缓存统计:'); - print(' - 总请求: ${stats.totalRequests}'); - print(' - 命中: ${stats.hits}'); - print(' - 未命中: ${stats.misses}'); - print(' - 命中率: ${(stats.hitRate * 100).toStringAsFixed(1)}%'); - print(' - 缓存大小: ${stats.size}/${stats.maxSize}'); - print(' - 填充率: ${(stats.fillRate * 100).toStringAsFixed(1)}%'); - - // 显示访问统计 - print('\n📈 访问统计:'); - stats.keyAccessCounts.forEach((key, count) { - print(' - $key: $count 次访问'); - }); - - // 演示缓存预热 - print('\n🔥 缓存预热演示:'); - await cache.warmUp({ - 'config:app': () async => '{"theme": "dark", "language": "zh"}', - 'config:api': () async => '{"timeout": 30000, "retries": 3}', - }); - - print(' - 预热完成,缓存大小: ${cache.getStats().size}'); -} - -/// 演示验证和错误处理 -Future demonstrateValidationAndErrorHandling() async { - print('\n✅ 验证和错误处理演示'); - print('-' * 30); - - // 创建一个有问题的文档 - final problematicDoc = { - 'openapi': '3.0.3', - 'info': { - 'title': 'Problematic API', - 'version': '1.0.0', - }, - 'paths': { - '/users/{id}': { - 'get': { - 'summary': 'Get user', - 'responses': { - '200': { - 'description': 'Success', - }, - }, - // 缺少路径参数声明 - }, - }, - 'invalid-path': { - // 无效的路径格式 - 'get': { - 'summary': 'Invalid path', - 'responses': { - '200': { - 'description': 'Success', - }, - }, - }, - }, - }, - }; - - final jsonString = jsonEncode(problematicDoc); - final document = SwaggerDocument.fromJson(jsonDecode(jsonString)); - - // 创建验证器 - final validator = EnhancedValidator( - includeWarnings: true, - ); - - // 验证文档 - final isValid = validator.validateDocument(document); - print('📋 验证结果: ${isValid ? "通过" : "失败"}'); - - // 获取错误统计 - final errorStats = validator.errorReporter.getErrorStatistics(); - print('\n📊 错误统计:'); - errorStats.forEach((severity, count) { - print(' - ${severity.displayName}: $count'); - }); - - // 显示详细错误 - final errors = validator.errorReporter.errors; - if (errors.isNotEmpty) { - print('\n❌ 详细错误:'); - for (int i = 0; i < errors.length && i < 5; i++) { - final error = errors[i]; - print(' ${i + 1}. ${error.severity.emoji} ${error.title}'); - print(' 位置: ${error.location.jsonPath}'); - print(' 描述: ${error.description}'); - if (error.suggestions.isNotEmpty) { - print(' 建议: ${error.suggestions.first.description}'); - } - print(''); - } - } - - // 生成错误报告 - final report = validator.errorReporter.generateReport( - includeStatistics: true, - groupByCategory: true, - ); - - // 保存错误报告 - final reportFile = File('example/generated/validation_report.txt'); - await reportFile.writeAsString(report); - print('📄 错误报告已保存到: ${reportFile.path}'); - - // 生成 JSON 格式报告 - final jsonReport = validator.errorReporter.generateJsonReport(); - final jsonReportFile = File('example/generated/validation_report.json'); - await jsonReportFile.writeAsString(jsonReport); - print('📄 JSON 报告已保存到: ${jsonReportFile.path}'); -} diff --git a/example/basic_usage.dart b/example/basic_usage.dart deleted file mode 100644 index f748e91..0000000 --- a/example/basic_usage.dart +++ /dev/null @@ -1,239 +0,0 @@ -/// 基础使用示例 -/// 演示如何使用 Swagger Generator Flutter 生成基础的 API 代码 -library; - -import 'dart:convert'; -import 'dart:io'; -import 'package:swagger_generator_flutter/swagger_generator_flutter.dart'; - -void main() async { - print('🚀 基础使用示例'); - print('=' * 50); - - try { - // 1. 读取 OpenAPI 文档 - print('📖 读取 OpenAPI 文档...'); - final jsonString = await File('swagger.json').readAsString(); - print('✅ 文档大小: ${(jsonString.length / 1024).toStringAsFixed(2)}KB'); - - // 2. 解析文档 - print('\n🔍 解析文档...'); - final document = SwaggerDocument.fromJson(jsonDecode(jsonString)); - print('✅ 解析完成'); - print(' - 标题: ${document.title}'); - print(' - 版本: ${document.version}'); - print(' - 路径数: ${document.paths.length}'); - print(' - 模型数: ${document.models.length}'); - - // 3. 验证文档 - print('\n✅ 验证文档...'); - final validator = EnhancedValidator( - includeWarnings: true, - ); - - final isValid = validator.validateDocument(document); - final errors = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.error); - final warnings = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.warning); - - print(' - 验证结果: ${isValid ? "通过" : "失败"}'); - print(' - 错误数: ${errors.length}'); - print(' - 警告数: ${warnings.length}'); - - if (errors.isNotEmpty) { - print('\n❌ 发现错误:'); - for (final error in errors.take(3)) { - print(' - ${error.title}: ${error.description}'); - } - } - - // 4. 生成基础 API 代码 - print('\n🔧 生成基础 API 代码...'); - final generator = RetrofitApiGenerator( - className: 'BasicApiService', - splitByTags: true, // 使用拆分模式 - useRetrofit: true, - generateModels: true, - ); - - final generatedCode = generator.generateFromDocument(document); - print('✅ 代码生成完成'); - print(' - 代码大小: ${(generatedCode.length / 1024).toStringAsFixed(2)}KB'); - print(' - 代码行数: ${generatedCode.split('\n').length}'); - - // 5. 保存生成的代码 - print('\n💾 保存生成的代码...'); - final outputDir = Directory('example/generated'); - if (!outputDir.existsSync()) { - outputDir.createSync(recursive: true); - } - - final outputFile = File('example/generated/basic_api_service.dart'); - await outputFile.writeAsString(generatedCode); - print('✅ 代码已保存到: ${outputFile.path}'); - - // 6. 显示生成的代码片段 - print('\n📄 生成的代码片段:'); - print('-' * 30); - final lines = generatedCode.split('\n'); - for (int i = 0; i < 20 && i < lines.length; i++) { - print('${(i + 1).toString().padLeft(2)}: ${lines[i]}'); - } - if (lines.length > 20) { - print('... (还有 ${lines.length - 20} 行)'); - } - - print('\n🎉 基础使用示例完成!'); - } catch (e, stackTrace) { - print('❌ 发生错误: $e'); - print('堆栈跟踪: $stackTrace'); - } -} - -/// 创建示例 OpenAPI 文档 -Future createSampleDocument() async { - final sampleDoc = { - 'openapi': '3.0.3', - 'info': { - 'title': 'Sample API', - 'version': '1.0.0', - 'description': 'A sample API for demonstration', - }, - 'servers': [ - { - 'url': 'https://api.example.com', - 'description': 'Production server', - }, - ], - 'paths': { - '/users': { - 'get': { - 'summary': 'Get all users', - 'operationId': 'getUsers', - 'tags': ['users'], - 'parameters': [ - { - 'name': 'page', - 'in': 'query', - 'required': false, - 'schema': {'type': 'integer', 'default': 1}, - 'description': 'Page number', - }, - ], - 'responses': { - '200': { - 'description': 'Success', - 'content': { - 'application/json': { - 'schema': { - 'type': 'array', - 'items': { - '\$ref': '#/components/schemas/User', - }, - }, - }, - }, - }, - }, - }, - 'post': { - 'summary': 'Create user', - 'operationId': 'createUser', - 'tags': ['users'], - 'requestBody': { - 'required': true, - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/CreateUserRequest', - }, - }, - }, - }, - 'responses': { - '201': { - 'description': 'User created', - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/User', - }, - }, - }, - }, - }, - }, - }, - '/users/{id}': { - 'get': { - 'summary': 'Get user by ID', - 'operationId': 'getUserById', - 'tags': ['users'], - 'parameters': [ - { - 'name': 'id', - 'in': 'path', - 'required': true, - 'schema': {'type': 'integer'}, - 'description': 'User ID', - }, - ], - 'responses': { - '200': { - 'description': 'User found', - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/User', - }, - }, - }, - }, - '404': { - 'description': 'User not found', - }, - }, - }, - }, - }, - 'components': { - 'schemas': { - 'User': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer', 'format': 'int64'}, - 'name': {'type': 'string'}, - 'email': {'type': 'string', 'format': 'email'}, - 'createdAt': {'type': 'string', 'format': 'date-time'}, - }, - 'required': ['id', 'name', 'email'], - }, - 'CreateUserRequest': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'email': {'type': 'string', 'format': 'email'}, - }, - 'required': ['name', 'email'], - }, - }, - }, - }; - - final jsonString = const JsonEncoder.withIndent(' ').convert(sampleDoc); - await File('example/sample_swagger.json').writeAsString(jsonString); - print('✅ 示例文档已创建: example/sample_swagger.json'); -} - -/// 运行示例 -/// -/// 使用方法: -/// ```bash -/// dart run example/basic_usage.dart -/// ``` -/// -/// 或者创建示例文档: -/// ```dart -/// await createSampleDocument(); -/// ``` diff --git a/example/complete_project_example.dart b/example/complete_project_example.dart deleted file mode 100644 index d48c407..0000000 --- a/example/complete_project_example.dart +++ /dev/null @@ -1,424 +0,0 @@ -/// 完整项目示例 -/// 演示在真实 Flutter 项目中如何集成和使用 Swagger Generator -library; - -import 'dart:io'; -import 'package:swagger_generator_flutter/swagger_generator_flutter.dart'; - -/// 项目配置 -class ProjectConfig { - static const String projectName = 'MyFlutterApp'; - static const String apiServiceName = 'ApiService'; - static const String outputDir = 'lib/api/generated'; - static const String swaggerFile = 'swagger.json'; - - // API 配置 - static const String baseUrl = 'https://api.myapp.com'; - static const String apiVersion = 'v1'; - - // 生成配置 - static const bool enableModularApis = true; - static const bool enableBaseResult = true; - static const bool enablePagination = true; - static const bool enableFileUpload = true; - static const bool enableCaching = true; - static const bool enableValidation = true; -} - -void main() async { - print('🚀 ${ProjectConfig.projectName} API 代码生成'); - print('=' * 60); - - final generator = ProjectApiGenerator(); - - try { - await generator.generateProjectApi(); - print('\n🎉 API 代码生成完成!'); - } catch (e, stackTrace) { - print('❌ 生成失败: $e'); - print('堆栈跟踪: $stackTrace'); - exit(1); - } -} - -/// 项目 API 生成器 -class ProjectApiGenerator { - late PerformanceParser parser; - late OptimizedRetrofitGenerator generator; - late EnhancedValidator validator; - - ProjectApiGenerator() { - _initializeComponents(); - } - - /// 初始化组件 - void _initializeComponents() { - // 配置高性能解析器 - parser = PerformanceParser( - config: ParseConfig( - enablePerformanceStats: true, - enableParallelParsing: false, // 禁用并行解析避免类型转换问题 - enableCaching: ProjectConfig.enableCaching, - maxConcurrency: 4, - enableMemoryOptimization: true, - ), - ); - - // 配置优化生成器 - generator = OptimizedRetrofitGenerator( - className: ProjectConfig.apiServiceName, - generateModularApis: ProjectConfig.enableModularApis, - generateBaseResult: ProjectConfig.enableBaseResult, - generatePagination: ProjectConfig.enablePagination, - generateFileUpload: ProjectConfig.enableFileUpload, - baseResultType: 'ApiResult', - pageResultType: 'PagedApiResult', - ); - - // 配置验证器 - validator = EnhancedValidator( - includeWarnings: true, - ); - } - - /// 生成项目 API - Future generateProjectApi() async { - // 1. 检查环境 - await _checkEnvironment(); - - // 2. 读取和解析文档 - final document = await _parseSwaggerDocument(); - - // 3. 验证文档 - await _validateDocument(document); - - // 4. 生成 API 代码 - await _generateApiCode(document); - - // 5. 生成配置文件 - await _generateConfigFiles(); - - // 6. 生成使用示例 - await _generateUsageExamples(); - - // 7. 生成文档 - await _generateDocumentation(document); - - // 8. 显示总结 - _showSummary(); - } - - /// 检查环境 - Future _checkEnvironment() async { - print('🔍 检查环境...'); - - // 检查 swagger.json 文件 - final swaggerFile = File(ProjectConfig.swaggerFile); - if (!swaggerFile.existsSync()) { - throw Exception('找不到 ${ProjectConfig.swaggerFile} 文件'); - } - - // 检查输出目录 - final outputDir = Directory(ProjectConfig.outputDir); - if (!outputDir.existsSync()) { - print('📁 创建输出目录: ${ProjectConfig.outputDir}'); - outputDir.createSync(recursive: true); - } - - // 检查依赖 - final pubspecFile = File('pubspec.yaml'); - if (pubspecFile.existsSync()) { - final content = await pubspecFile.readAsString(); - final requiredDeps = ['dio', 'retrofit', 'json_annotation']; - final missingDeps = []; - - for (final dep in requiredDeps) { - if (!content.contains(dep)) { - missingDeps.add(dep); - } - } - - if (missingDeps.isNotEmpty) { - print('⚠️ 缺少依赖: ${missingDeps.join(', ')}'); - print(' 请在 pubspec.yaml 中添加这些依赖'); - } - } - - print('✅ 环境检查完成'); - } - - /// 解析 Swagger 文档 - Future _parseSwaggerDocument() async { - print('\n📖 解析 Swagger 文档...'); - - final jsonString = await File(ProjectConfig.swaggerFile).readAsString(); - print(' - 文档大小: ${(jsonString.length / 1024).toStringAsFixed(2)}KB'); - - final stopwatch = Stopwatch()..start(); - final document = await parser.parseDocument(jsonString); - stopwatch.stop(); - - print('✅ 解析完成'); - print(' - 解析时间: ${stopwatch.elapsedMilliseconds}ms'); - print(' - API 标题: ${document.title}'); - print(' - API 版本: ${document.version}'); - print(' - 路径数量: ${document.paths.length}'); - print(' - 模型数量: ${document.models.length}'); - print(' - 服务器数量: ${document.servers.length}'); - - // 显示性能统计 - final stats = parser.lastStats; - if (stats != null) { - print(' - 处理速度: ${stats.pathsPerSecond.toStringAsFixed(1)} paths/s'); - print( - ' - 吞吐量: ${(stats.bytesPerSecond / 1024).toStringAsFixed(2)} KB/s'); - } - - return document; - } - - /// 验证文档 - Future _validateDocument(SwaggerDocument document) async { - if (!ProjectConfig.enableValidation) { - print('\n⏭️ 跳过文档验证'); - return; - } - - print('\n✅ 验证文档...'); - - final isValid = validator.validateDocument(document); - final errors = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.error); - final warnings = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.warning); - final criticalErrors = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.critical); - - print(' - 验证结果: ${isValid ? "✅ 通过" : "❌ 失败"}'); - print(' - 严重错误: ${criticalErrors.length}'); - print(' - 错误: ${errors.length}'); - print(' - 警告: ${warnings.length}'); - - if (criticalErrors.isNotEmpty) { - print('\n🚨 严重错误:'); - for (final error in criticalErrors.take(3)) { - print(' - ${error.title}: ${error.description}'); - } - throw Exception('文档包含严重错误,无法继续生成'); - } - - if (errors.isNotEmpty) { - print('\n❌ 错误:'); - for (final error in errors.take(3)) { - print(' - ${error.title}: ${error.description}'); - } - } - - if (warnings.isNotEmpty) { - print('\n⚠️ 警告:'); - for (final warning in warnings.take(3)) { - print(' - ${warning.title}: ${warning.description}'); - } - } - - // 保存验证报告 - final report = validator.errorReporter.generateReport(); - final reportFile = File('${ProjectConfig.outputDir}/validation_report.txt'); - await reportFile.writeAsString(report); - print(' - 验证报告: ${reportFile.path}'); - } - - /// 生成 API 代码 - Future _generateApiCode(SwaggerDocument document) async { - print('\n🔧 生成 API 代码...'); - - final stopwatch = Stopwatch()..start(); - final generatedCode = generator.generateFromDocument(document); - stopwatch.stop(); - - print('✅ 代码生成完成'); - print(' - 生成时间: ${stopwatch.elapsedMilliseconds}ms'); - print(' - 代码大小: ${(generatedCode.length / 1024).toStringAsFixed(2)}KB'); - print(' - 代码行数: ${generatedCode.split('\n').length}'); - - // 保存主 API 文件 - final apiFile = File( - '${ProjectConfig.outputDir}/${ProjectConfig.apiServiceName.toLowerCase()}.dart'); - await apiFile.writeAsString(generatedCode); - print(' - API 文件: ${apiFile.path}'); - - // 检查生成的特性 - final features = []; - if (generatedCode.contains('class ApiResult')) features.add('基础响应类型'); - if (generatedCode.contains('class PagedApiResult')) features.add('分页支持'); - if (generatedCode.contains('MultipartFile')) features.add('文件上传'); - if (generatedCode.contains('class ApiUtils')) features.add('工具类'); - - if (features.isNotEmpty) { - print(' - 生成特性: ${features.join(', ')}'); - } - } - - /// 生成配置文件 - Future _generateConfigFiles() async { - print('\n⚙️ 生成配置文件...'); - - // 生成 API 配置 - final apiConfig = ''' -/// API 配置文件 -/// 自动生成,请勿手动修改 -class ApiConfig { - static const String baseUrl = '${ProjectConfig.baseUrl}'; - static const String apiVersion = '${ProjectConfig.apiVersion}'; - static const int connectTimeout = 30000; - static const int receiveTimeout = 30000; - static const int sendTimeout = 30000; - - // 请求头 - static const Map defaultHeaders = { - 'Content-Type': 'application/json', - 'Accept': 'application/json', - }; - - // 调试模式 - static const bool debugMode = true; -} -'''; - - final configFile = File('${ProjectConfig.outputDir}/api_config.dart'); - await configFile.writeAsString(apiConfig); - print(' - API 配置: ${configFile.path}'); - - // 生成 Dio 配置 - final dioConfig = ''' -/// Dio 配置文件 -import 'package:dio/dio.dart'; -import 'api_config.dart'; - -class DioConfig { - static Dio createDio() { - final dio = Dio(BaseOptions( - baseUrl: ApiConfig.baseUrl, - connectTimeout: Duration(milliseconds: ApiConfig.connectTimeout), - receiveTimeout: Duration(milliseconds: ApiConfig.receiveTimeout), - sendTimeout: Duration(milliseconds: ApiConfig.sendTimeout), - headers: ApiConfig.defaultHeaders, - )); - - if (ApiConfig.debugMode) { - dio.interceptors.add(LogInterceptor( - requestBody: true, - responseBody: true, - requestHeader: true, - responseHeader: false, - )); - } - - return dio; - } -} -'''; - - final dioConfigFile = File('${ProjectConfig.outputDir}/dio_config.dart'); - await dioConfigFile.writeAsString(dioConfig); - print(' - Dio 配置: ${dioConfigFile.path}'); - } - - /// 生成使用示例 - Future _generateUsageExamples() async { - print('\n📝 生成使用示例...'); - - final example = ''' -/// API 使用示例 -/// 展示如何在 Flutter 项目中使用生成的 API -import 'package:dio/dio.dart'; -import 'generated/${ProjectConfig.apiServiceName.toLowerCase()}.dart'; -import 'dio_config.dart'; - -class ApiExample { - late final ${ProjectConfig.apiServiceName} apiService; - - ApiExample() { - final dio = DioConfig.createDio(); - apiService = ${ProjectConfig.apiServiceName}(dio); - } - - /// 示例:获取用户列表 - Future getUsersExample() async { - try { - final response = await apiService.getUsers(); - print('用户列表: \$response'); - } catch (e) { - print('获取用户列表失败: \$e'); - } - } - - /// 示例:创建用户 - Future createUserExample() async { - try { - final userData = { - 'name': 'John Doe', - 'email': 'john@example.com', - }; - final response = await apiService.createUser(userData); - print('用户创建成功: \$response'); - } catch (e) { - print('创建用户失败: \$e'); - } - } -} -'''; - - final exampleFile = File('${ProjectConfig.outputDir}/api_example.dart'); - await exampleFile.writeAsString(example); - print(' - 使用示例: ${exampleFile.path}'); - } - - /// 生成文档 - Future _generateDocumentation(SwaggerDocument document) async { - print('\n📚 生成文档...'); - - final docs = StringBuffer(); - docs.writeln('# ${document.title} API 文档'); - docs.writeln(); - docs.writeln('版本: ${document.version}'); - docs.writeln('描述: ${document.description}'); - docs.writeln(); - docs.writeln('## 服务器'); - for (final server in document.servers) { - docs.writeln('- ${server.url}: ${server.description}'); - } - docs.writeln(); - docs.writeln('## API 端点'); - docs.writeln('总计: ${document.paths.length} 个端点'); - docs.writeln(); - docs.writeln('## 数据模型'); - docs.writeln('总计: ${document.models.length} 个模型'); - docs.writeln(); - docs.writeln('## 使用方法'); - docs.writeln('请参考 `api_example.dart` 文件中的示例代码。'); - - final docsFile = File('${ProjectConfig.outputDir}/README.md'); - await docsFile.writeAsString(docs.toString()); - print(' - API 文档: ${docsFile.path}'); - } - - /// 显示总结 - void _showSummary() { - print('\n📊 生成总结'); - print('-' * 40); - print('✅ 项目: ${ProjectConfig.projectName}'); - print('✅ API 服务: ${ProjectConfig.apiServiceName}'); - print('✅ 输出目录: ${ProjectConfig.outputDir}'); - print('✅ 模块化 API: ${ProjectConfig.enableModularApis ? "启用" : "禁用"}'); - print('✅ 基础响应类型: ${ProjectConfig.enableBaseResult ? "启用" : "禁用"}'); - print('✅ 分页支持: ${ProjectConfig.enablePagination ? "启用" : "禁用"}'); - print('✅ 文件上传: ${ProjectConfig.enableFileUpload ? "启用" : "禁用"}'); - - print('\n🎯 下一步:'); - print('1. 运行 `flutter packages pub run build_runner build` 生成序列化代码'); - print('2. 在项目中导入生成的 API 文件'); - print('3. 参考 `api_example.dart` 中的使用示例'); - print('4. 查看 `README.md` 了解 API 详情'); - } -} diff --git a/example/dio_retrofit_usage.dart b/example/dio_retrofit_usage.dart deleted file mode 100644 index a3c80a8..0000000 --- a/example/dio_retrofit_usage.dart +++ /dev/null @@ -1,311 +0,0 @@ -/// Dio + Retrofit 使用示例 -/// 展示如何使用生成的 API 代码进行网络请求 - -import 'dart:io'; -import 'package:dio/dio.dart'; -import 'package:retrofit/retrofit.dart'; - -// 假设这些是生成的代码 -part 'dio_retrofit_usage.g.dart'; - -/// API 服务接口(生成的代码) -@RestApi(baseUrl: 'https://api.example.com/v1') -abstract class ApiService { - factory ApiService(Dio dio, {String? baseUrl}) = _ApiService; - - /// 获取用户信息 - @GET('/users/{id}') - Future getUser(@Path('id') int id); - - /// 创建用户 - @POST('/users') - Future createUser(@Body() CreateUserRequest request); - - /// 上传头像 - @POST('/users/{id}/avatar') - @MultiPart() - Future uploadAvatar( - @Path('id') int id, - @Part() MultipartFile avatar, - ); - - /// 获取用户列表(支持分页) - @GET('/users') - Future getUsers( - @Query('page') int page, - @Query('size') int size, - @Query('search') String? search, - ); - - /// 下载文件 - @GET('/files/{id}') - @DioResponseType(ResponseType.bytes) - Future> downloadFile(@Path('id') String id); -} - -/// 用户响应模型 -class UserResponse { - final int id; - final String name; - final String email; - final String? avatar; - - UserResponse({ - required this.id, - required this.name, - required this.email, - this.avatar, - }); - - factory UserResponse.fromJson(Map json) => UserResponse( - id: json['id'] as int, - name: json['name'] as String, - email: json['email'] as String, - avatar: json['avatar'] as String?, - ); -} - -/// 创建用户请求模型 -class CreateUserRequest { - final String name; - final String email; - final String password; - - CreateUserRequest({ - required this.name, - required this.email, - required this.password, - }); - - Map toJson() => { - 'name': name, - 'email': email, - 'password': password, - }; -} - -/// 用户列表响应模型 -class UserListResponse { - final List users; - final int total; - final int page; - final int size; - - UserListResponse({ - required this.users, - required this.total, - required this.page, - required this.size, - }); - - factory UserListResponse.fromJson(Map json) => - UserListResponse( - users: (json['users'] as List) - .map((e) => UserResponse.fromJson(e as Map)) - .toList(), - total: json['total'] as int, - page: json['page'] as int, - size: json['size'] as int, - ); -} - -/// 上传响应模型 -class UploadResponse { - final String url; - final String filename; - final int size; - - UploadResponse({ - required this.url, - required this.filename, - required this.size, - }); - - factory UploadResponse.fromJson(Map json) => UploadResponse( - url: json['url'] as String, - filename: json['filename'] as String, - size: json['size'] as int, - ); -} - -/// API 客户端配置和使用示例 -class ApiClient { - late final Dio _dio; - late final ApiService _apiService; - - ApiClient({String? baseUrl}) { - _dio = Dio(); - _setupDio(); - _apiService = ApiService(_dio, baseUrl: baseUrl); - } - - /// 配置 Dio - void _setupDio() { - // 基础配置 - _dio.options.connectTimeout = const Duration(seconds: 30); - _dio.options.receiveTimeout = const Duration(seconds: 30); - _dio.options.sendTimeout = const Duration(seconds: 30); - - // 添加拦截器 - _dio.interceptors.addAll([ - // 日志拦截器 - LogInterceptor( - requestBody: true, - responseBody: true, - logPrint: (obj) => print(obj), - ), - - // 认证拦截器 - BearerTokenInterceptor(token: 'your-auth-token'), - - // API Key 拦截器 - ApiKeyInterceptor( - apiKey: 'your-api-key', - location: ApiKeyLocation.header, - paramName: 'X-API-Key', - ), - - // 错误处理拦截器 - ErrorHandlerInterceptor(), - ]); - } - - /// 获取用户信息 - Future getUser(int id) async { - try { - return await _apiService.getUser(id); - } catch (e) { - throw _handleError(e); - } - } - - /// 创建用户 - Future createUser({ - required String name, - required String email, - required String password, - }) async { - try { - final request = CreateUserRequest( - name: name, - email: email, - password: password, - ); - return await _apiService.createUser(request); - } catch (e) { - throw _handleError(e); - } - } - - /// 上传头像 - Future uploadAvatar(int userId, String filePath) async { - try { - final file = await FileUploadHandler.createImageFile(filePath: filePath); - return await _apiService.uploadAvatar(userId, file); - } catch (e) { - throw _handleError(e); - } - } - - /// 获取用户列表 - Future getUsers({ - int page = 1, - int size = 20, - String? search, - }) async { - try { - return await _apiService.getUsers(page, size, search); - } catch (e) { - throw _handleError(e); - } - } - - /// 下载文件 - Future downloadFile(String fileId, String savePath) async { - try { - final bytes = await _apiService.downloadFile(fileId); - final file = File(savePath); - await file.writeAsBytes(bytes); - } catch (e) { - throw _handleError(e); - } - } - - /// 错误处理 - Exception _handleError(dynamic error) { - if (error is DioException) { - switch (error.type) { - case DioExceptionType.connectionTimeout: - case DioExceptionType.sendTimeout: - case DioExceptionType.receiveTimeout: - return TimeoutException('请求超时,请检查网络连接'); - case DioExceptionType.badResponse: - final statusCode = error.response?.statusCode; - final message = error.response?.data?['message'] ?? '服务器错误'; - return HttpException('HTTP $statusCode: $message'); - case DioExceptionType.cancel: - return Exception('请求已取消'); - case DioExceptionType.connectionError: - return Exception('网络连接错误,请检查网络设置'); - default: - return Exception('未知错误: ${error.message}'); - } - } - return Exception('未知错误: $error'); - } - - /// 释放资源 - void dispose() { - _dio.close(); - } -} - -/// 使用示例 -void main() async { - final apiClient = ApiClient(baseUrl: 'https://api.example.com/v1'); - - try { - // 获取用户信息 - final user = await apiClient.getUser(1); - print('用户信息: ${user.name} (${user.email})'); - - // 创建新用户 - final newUser = await apiClient.createUser( - name: 'John Doe', - email: 'john@example.com', - password: 'password123', - ); - print('创建用户成功: ${newUser.id}'); - - // 获取用户列表 - final userList = await apiClient.getUsers(page: 1, size: 10); - print('用户总数: ${userList.total}'); - - // 上传头像(如果有文件的话) - // final uploadResult = await apiClient.uploadAvatar(1, '/path/to/avatar.jpg'); - // print('头像上传成功: ${uploadResult.url}'); - - // 下载文件 - // await apiClient.downloadFile('file-id', '/path/to/save/file.pdf'); - // print('文件下载完成'); - } catch (e) { - print('API 调用失败: $e'); - } finally { - apiClient.dispose(); - } -} - -/// 自定义异常类 -class TimeoutException implements Exception { - final String message; - TimeoutException(this.message); - @override - String toString() => 'TimeoutException: $message'; -} - -class HttpException implements Exception { - final String message; - HttpException(this.message); - @override - String toString() => 'HttpException: $message'; -} diff --git a/example/generated/advanced_api_service.dart b/example/generated/advanced_api_service.dart deleted file mode 100644 index a0a18e1..0000000 --- a/example/generated/advanced_api_service.dart +++ /dev/null @@ -1,178 +0,0 @@ -// 网络请求相关 -import 'package:dio/dio.dart'; -import 'package:json_annotation/json_annotation.dart'; - -// 文件处理 -import 'package:path/path.dart' as path; - -// 生成的代码 -part 'advanced_api_service_api.g.dart'; - -/// 基础响应结果 -@JsonSerializable(genericArgumentFactories: true) -class ApiResult { - /// 响应码 - final int code; - - /// 响应消息 - final String message; - - /// 响应数据 - final T? data; - - /// 是否成功 - bool get isSuccess => code == 200; - - const ApiResult({ - required this.code, - required this.message, - this.data, - }); - - factory ApiResult.fromJson( - Map json, - T Function(Object? json) fromJsonT, - ) => - _$ApiResultFromJson(json, fromJsonT); - - Map toJson(Object Function(T value) toJsonT) => - _$ApiResultToJson(this, toJsonT); -} - -/// 分页参数 -@JsonSerializable() -class BasePageParameter { - /// 页码(从1开始) - final int page; - - /// 每页大小 - final int size; - - const BasePageParameter({ - this.page = 1, - this.size = 20, - }); - - factory BasePageParameter.fromJson(Map json) => - _$BasePageParameterFromJson(json); - - Map toJson() => _$BasePageParameterToJson(this); -} - -/// 分页响应结果 -@JsonSerializable(genericArgumentFactories: true) -class PagedResult { - /// 数据列表 - final List list; - - /// 总数量 - final int total; - - /// 当前页码 - final int page; - - /// 每页大小 - final int size; - - /// 总页数 - int get totalPages => (total / size).ceil(); - - /// 是否有下一页 - bool get hasNext => page < totalPages; - - /// 是否有上一页 - bool get hasPrevious => page > 1; - - const PagedResult({ - required this.list, - required this.total, - required this.page, - required this.size, - }); - - factory PagedResult.fromJson( - Map json, - T Function(Object? json) fromJsonT, - ) => - _$PagedResultFromJson(json, fromJsonT); - - Map toJson(Object Function(T value) toJsonT) => - _$PagedResultToJson(this, toJsonT); -} - -/// 文件上传请求 -@JsonSerializable() -class FileUploadRequest { - /// 文件 - @JsonKey(includeFromJson: false, includeToJson: false) - final MultipartFile file; - - /// 文件名 - final String? filename; - - /// 文件类型 - final String? contentType; - - const FileUploadRequest({ - required this.file, - this.filename, - this.contentType, - }); - - factory FileUploadRequest.fromJson(Map json) => - _$FileUploadRequestFromJson(json); - - Map toJson() => _$FileUploadRequestToJson(this); -} - -/// 文件上传响应 -@JsonSerializable() -class FileUploadResult { - /// 文件 URL - final String url; - - /// 文件名 - final String filename; - - /// 文件大小 - final int size; - - /// 文件类型 - final String? contentType; - - const FileUploadResult({ - required this.url, - required this.filename, - required this.size, - this.contentType, - }); - - factory FileUploadResult.fromJson(Map json) => - _$FileUploadResultFromJson(json); - - Map toJson() => _$FileUploadResultToJson(this); -} - -/// 主 API 服务类 -/// 包含所有模块的 API 接口 -class AdvancedApiService { - final Dio _dio; - - AdvancedApiService(this._dio, {String? baseUrl}); -} - -/// API 工具类 -class ApiUtils { - /// 创建文件上传对象 - static Future createFileUpload(String filePath) async { - return MultipartFile.fromFile( - filePath, - filename: path.basename(filePath), - ); - } - - /// 创建分页参数 - static BasePageParameter createPageParam({int page = 1, int size = 20}) { - return BasePageParameter(page: page, size: size); - } -} diff --git a/example/generated/basic_api_service.dart b/example/generated/basic_api_service.dart deleted file mode 100644 index 56a3504..0000000 --- a/example/generated/basic_api_service.dart +++ /dev/null @@ -1,70 +0,0 @@ -// 主 API 接口定义 - 集合所有 Tag 的 API -// 基于 Swagger API 文档: -// 由 xy_swagger_generator by max 生成 -// Copyright (C) 2025 YuanXuan. All rights reserved. - -import 'package:dio/dio.dart'; -import 'package:learning_officer_oa/common/models/common/base_page_result.dart'; -import 'package:learning_officer_oa/common/models/common/base_result.dart'; - -import 'api_error.dart'; -import 'api_error_handler.dart'; - -/// 统一API客户端类 -/// 聚合所有分模块的API接口,提供统一的访问入口 -class BasicApiService { - final Dio _dio; - - BasicApiService(this._dio, {String? baseUrl}); - - /// 获取Dio实例 - Dio get dio => _dio; - - /// 设置认证token - void setAuthToken(String token) { - _dio.options.headers['Authorization'] = 'Bearer $token'; - } - - /// 清除认证token - void clearAuthToken() { - _dio.options.headers.remove('Authorization'); - } - - /// 设置基础URL - void setBaseUrl(String baseUrl) { - _dio.options.baseUrl = baseUrl; - } - - /// 添加请求拦截器 - void addRequestInterceptor(Interceptor interceptor) { - _dio.interceptors.add(interceptor); - } - - /// 添加响应拦截器 - void addResponseInterceptor(Interceptor interceptor) { - _dio.interceptors.add(interceptor); - } - - /// 添加错误拦截器 - void addErrorInterceptor(Interceptor interceptor) { - _dio.interceptors.add(interceptor); - } - - /// 创建带错误处理的API调用 - Future callWithErrorHandling(Future Function() apiCall) async { - try { - return await apiCall(); - } on DioException catch (e) { - final error = ApiErrorHandler.handleDioError(e); - throw error; - } catch (e) { - final error = ApiError( - type: ApiErrorType.unknown, - message: '未知错误: $e', - code: -1, - originalError: e, - ); - throw error; - } - } -} diff --git a/example/generated/validation_report.json b/example/generated/validation_report.json deleted file mode 100644 index a2bb937..0000000 --- a/example/generated/validation_report.json +++ /dev/null @@ -1,79 +0,0 @@ -{ - "timestamp": "2025-07-24T07:16:17.845544", - "summary": { - "total": 3, - "by_severity": { - "warning": 1, - "error": 1, - "info": 1 - } - }, - "errors": [ - { - "id": "MISSING_INFO_DESCRIPTION", - "title": "Missing API Description", - "description": "API description helps users understand the purpose of your API.", - "severity": "warning", - "category": "bestPractice", - "location": { - "json_path": "info.description", - "line": null, - "column": null, - "snippet": null - }, - "suggestions": [ - { - "description": "Add a description explaining what your API does", - "code_example": "\"description\": \"This API provides user management functionality\"", - "documentation_url": null - } - ], - "related_errors": [], - "timestamp": "2025-07-24T07:16:17.842816" - }, - { - "id": "EMPTY_PATHS", - "title": "Empty Paths Object", - "description": "OpenAPI document must contain at least one path.", - "severity": "error", - "category": "validation", - "location": { - "json_path": "paths", - "line": null, - "column": null, - "snippet": null - }, - "suggestions": [ - { - "description": "Add at least one API endpoint", - "code_example": "\"/users\": { \"get\": { \"responses\": { \"200\": { \"description\": \"Success\" } } } }", - "documentation_url": null - } - ], - "related_errors": [], - "timestamp": "2025-07-24T07:16:17.842917" - }, - { - "id": "NO_OPERATION_TAGS", - "title": "No Operation Tags", - "description": "Consider using tags to organize your API operations.", - "severity": "info", - "category": "bestPractice", - "location": { - "json_path": "paths", - "line": null, - "column": null, - "snippet": null - }, - "suggestions": [ - { - "description": "Add tags to operations", - "code_example": "\"tags\": [\"users\"]", - "documentation_url": null - } - ], - "related_errors": [], - "timestamp": "2025-07-24T07:16:17.843223" - } - ] -} \ No newline at end of file diff --git a/example/generated/validation_report.txt b/example/generated/validation_report.txt deleted file mode 100644 index 29843ca..0000000 --- a/example/generated/validation_report.txt +++ /dev/null @@ -1,52 +0,0 @@ -📊 Error Summary -================================================== -⚠️ WARNING: 1 -❌ ERROR: 1 -ℹ️ INFO: 1 - -📂 Best Practice ------------------------------- -⚠️ WARNING: Missing API Description -Category: Best Practice -Location: info.description - -Description: - API description helps users understand the purpose of your API. - -Suggestions: - 1. Add a description explaining what your API does - Example: - "description": "This API provides user management functionality" - - - -ℹ️ INFO: No Operation Tags -Category: Best Practice -Location: paths - -Description: - Consider using tags to organize your API operations. - -Suggestions: - 1. Add tags to operations - Example: - "tags": ["users"] - - - -📂 Validation Error ------------------------------- -❌ ERROR: Empty Paths Object -Category: Validation Error -Location: paths - -Description: - OpenAPI document must contain at least one path. - -Suggestions: - 1. Add at least one API endpoint - Example: - "/users": { "get": { "responses": { "200": { "description": "Success" } } } } - - - diff --git a/generator_config.yaml b/generator_config.yaml deleted file mode 100644 index 573de01..0000000 --- a/generator_config.yaml +++ /dev/null @@ -1,240 +0,0 @@ -# Augment 代码生成器配置文件 -# 基于 OpenAPI 3.0 标准的配置规范 - -# 基本配置 -generator: - name: "xy_swagger_generator" - version: "2.0" - author: "max" - copyright: "Copyright (C) 2025 YuanXuan. All rights reserved." - -# 输入配置 -input: - # Swagger 文档源 - swagger_url: "http://localhost:5000/swagger/v1/swagger.json" - swagger_file: "./swagger.json" - - # 验证配置 - validate_schema: true - strict_mode: true - -# 输出配置 -output: - # 输出目录 - base_dir: "./generator" - api_dir: "./generator/api" - models_dir: "./generator/api_models" - - # 文件命名 - api_file_suffix: "_api.dart" - model_file_suffix: ".dart" - - # 是否按 tag 分组 - split_by_tags: true - -# 代码生成配置 -generation: - # API 接口配置 - api: - enabled: true - use_retrofit: true - use_dio: true - parser: "JsonSerializable" - - # 基础类型配置 - base_result_type: "BaseResult" - base_page_result_type: "BasePageResult" - base_result_import: "package:learning_officer_oa/common/models/common/base_result.dart" - base_page_result_import: "package:learning_officer_oa/common/models/common/base_page_result.dart" - - # 方法命名 - method_naming: "camelCase" # camelCase, snake_case - - # 数据模型配置 - models: - enabled: true - use_json_serializable: true - - # JsonSerializable 配置 - json_serializable: - checked: true - include_if_null: false - explicit_to_json: true - - # 类命名 - class_naming: "PascalCase" # PascalCase, snake_case - field_naming: "camelCase" # camelCase, snake_case - - # 构造函数配置 - use_const_constructor: true - required_for_non_nullable: true - -# 类型映射配置 -type_mapping: - # OpenAPI -> Dart 类型映射 - string: "String" - integer: "int" - number: "double" - boolean: "bool" - array: "List" - object: "Map" - - # 特殊类型处理 - date: "DateTime" - date-time: "DateTime" - binary: "Uint8List" - - # 自定义类型映射 - custom_types: - # 示例:特定格式的字符串映射到自定义类型 - # "uuid": "Uuid" - # "email": "EmailAddress" - -# 导入管理配置 -imports: - # 按需导入 - on_demand: true - - # 自动排序 - auto_sort: true - - # 分组导入 - group_imports: true - - # 标准库导入 - dart_imports: - - "dart:convert" - - "dart:typed_data" - - # 第三方库导入 - package_imports: - - "package:dio/dio.dart" - - "package:retrofit/retrofit.dart" - - "package:json_annotation/json_annotation.dart" - -# 验证配置 -validation: - # 严格模式 - strict_mode: true - - # 检查项 - checks: - - "schema_exists" # 检查 schema 是否存在 - - "ref_resolution" # 检查 $ref 引用 - - "type_consistency" # 检查类型一致性 - - "nullable_correctness" # 检查可空性正确性 - - "required_fields" # 检查必需字段 - - # 错误处理 - on_error: "warn" # fail, warn, ignore - - # 警告处理 - on_warning: "log" # fail, log, ignore - -# 优化配置 -optimization: - # 代码优化 - remove_unused_imports: true - optimize_imports: true - - # 性能优化 - cache_schemas: true - parallel_generation: false - - # 内存优化 - lazy_loading: true - -# 调试配置 -debug: - # 详细日志 - verbose: false - - # 调试输出 - debug_output: false - - # 性能监控 - performance_monitoring: false - - # 生成统计 - generation_stats: true - -# 兼容性配置 -compatibility: - # Dart 版本 - dart_version: ">=3.0.0" - - # Flutter 版本 - flutter_version: ">=3.10.0" - - # 依赖版本 - dependencies: - dio: "^5.0.0" - retrofit: "^4.0.0" - json_annotation: "^4.8.0" - - dev_dependencies: - build_runner: "^2.3.0" - retrofit_generator: "^8.0.0" - json_serializable: "^6.6.0" - -# 自定义配置 -custom: - # 项目特定配置 - project_name: "learning_officer_oa" - - # 特殊处理规则 - special_handling: - # 健康检查接口返回 void - health_check_paths: - - "/health" - - "/healthcheck" - - "/api/health" - - # 分页接口参数名 - pagination_params: - - "page" - - "size" - - "limit" - - "offset" - - "pageIndex" - - "pageSize" - - # 忽略的路径 - ignored_paths: - - "/swagger" - - "/docs" - - # 忽略的 tags - ignored_tags: - - "Internal" - - "Debug" - -# 模板配置 -templates: - # 文件头模板 - file_header: | - // {fileName} {fileType} - // 基于 Swagger API 文档: {swaggerUrl} - // 由 {generatorName} by {author} 生成 - // {copyright} - - # API 类模板 - api_class: | - /// {tagName} API 接口 - /// 负责处理 {tagName} 相关的接口 - @RestApi(parser: Parser.JsonSerializable) - abstract class {className} { - factory {className}(Dio dio, {String? baseUrl}) = _{className}; - } - - # 模型类模板 - model_class: | - @JsonSerializable(checked: true, includeIfNull: false) - class {className} { - const {className}({constructorParams}); - - factory {className}.fromJson(Map json) => - _${className}FromJson(json); - - Map toJson() => _${className}ToJson(this); - } diff --git a/lib/commands/generate_command.dart b/lib/commands/generate_command.dart index 8918ad8..ecd464d 100644 --- a/lib/commands/generate_command.dart +++ b/lib/commands/generate_command.dart @@ -52,7 +52,7 @@ class GenerateCommand extends BaseCommand { const CommandOption( name: 'split-by-tags', shortName: 't', - description: '按tags分组生成多个API文件(默认启用)', + description: '按tags分组生成多个API文件', type: OptionType.flag, ), const CommandOption( @@ -91,6 +91,8 @@ class GenerateCommand extends BaseCommand { // 解析生成选项 final options = _parseGenerateOptions(parsedArgs); + final outputDir = + parsedArgs.getOption('output-dir') ?? 'generator'; final fullOutputDir = FileUtils.getProjectRootGeneratorDir(); progress('输出目录: $fullOutputDir'); @@ -133,56 +135,92 @@ class GenerateCommand extends BaseCommand { } } - // 生成 Retrofit 风格的 API 接口(默认使用拆分模式) + // 生成 Retrofit 风格的 API 接口 if (options.generateApi) { - progress('正在按tags分组生成Retrofit风格API接口...'); - final generator = RetrofitApiGenerator( - className: 'ApiClient', - useRetrofit: true, - useDio: true, - splitByTags: true, // 强制使用拆分模式 - ); + if (options.splitByTags) { + progress('正在按tags分组生成Retrofit风格API接口...'); + final generator = RetrofitApiGenerator( + document, + className: 'ApiClient', + useRetrofit: true, + useDio: true, + splitByTags: true, + ); - // 设置文档 - generator.document = document; + // 确保参数实体类已生成 + generator.ensureParameterEntitiesGenerated(); - // 确保参数实体类已生成 - generator.ensureParameterEntitiesGenerated(); + // 生成按 tags 分组的多个 API 文件 + final tagApiFiles = generator.generateApiFilesByTags(); - // 生成按 tags 分组的多个 API 文件 - final tagApiFiles = generator.generateApiFilesByTags(); + final apiDir = '$fullOutputDir/api'; + await FileUtils.ensureDirectoryExists(apiDir); - final apiDir = '$fullOutputDir/api'; - await FileUtils.ensureDirectoryExists(apiDir); - - for (final entry in tagApiFiles.entries) { - final fileName = entry.key; - final code = entry.value; - final filePath = '$apiDir/$fileName'; - await FileUtils.writeFile(filePath, code); - success('API接口文件已保存到: $filePath'); - generatedFiles++; - } - - // 生成主 API 文件 - final mainCode = generator.generateMainApiFile(); - final mainFilePath = '$apiDir/api_client.dart'; - await FileUtils.writeFile(mainFilePath, mainCode); - success('主API接口文件已保存到: $mainFilePath'); - generatedFiles++; - - // 生成参数实体类文件 - final parameterEntityFiles = generator.generateParameterEntityFiles(); - if (parameterEntityFiles.isNotEmpty) { - final modelsDir = '$fullOutputDir/api_models'; - await FileUtils.ensureDirectoryExists(modelsDir); - - for (final entry in parameterEntityFiles.entries) { - final filePath = '$modelsDir/${entry.key}'; - await FileUtils.writeFile(filePath, entry.value); - success('参数实体类文件已保存到: $filePath'); + for (final entry in tagApiFiles.entries) { + final fileName = entry.key; + final code = entry.value; + final filePath = '$apiDir/$fileName'; + await FileUtils.writeFile(filePath, code); + success('API接口文件已保存到: $filePath'); generatedFiles++; } + + // 生成主 API 文件 + final mainCode = generator.generateMainApiFile(); + final mainFilePath = '$apiDir/api_client.dart'; + await FileUtils.writeFile(mainFilePath, mainCode); + success('主API接口文件已保存到: $mainFilePath'); + generatedFiles++; + + // 生成参数实体类文件 + final parameterEntityFiles = generator.generateParameterEntityFiles(); + if (parameterEntityFiles.isNotEmpty) { + final modelsDir = '$fullOutputDir/api_models'; + await FileUtils.ensureDirectoryExists(modelsDir); + + for (final entry in parameterEntityFiles.entries) { + final filePath = '$modelsDir/${entry.key}'; + await FileUtils.writeFile(filePath, entry.value); + success('参数实体类文件已保存到: $filePath'); + generatedFiles++; + } + } + } else { + progress('正在生成Retrofit风格API接口...'); + final generator = RetrofitApiGenerator( + document, + className: 'ApiClient', + useRetrofit: true, + useDio: true, + splitByTags: false, + ); + + // 确保参数实体类已生成 + generator.ensureParameterEntitiesGenerated(); + + final code = generator.generate(); + + final apiDir = '$fullOutputDir/api'; + await FileUtils.ensureDirectoryExists(apiDir); + + final filePath = '$apiDir/api.dart'; + await FileUtils.writeFile(filePath, code); + success('Retrofit API接口已保存到: $filePath'); + generatedFiles++; + + // 生成参数实体类文件 + final parameterEntityFiles = generator.generateParameterEntityFiles(); + if (parameterEntityFiles.isNotEmpty) { + final modelsDir = '$fullOutputDir/api_models'; + await FileUtils.ensureDirectoryExists(modelsDir); + + for (final entry in parameterEntityFiles.entries) { + final filePath = '$modelsDir/${entry.key}'; + await FileUtils.writeFile(filePath, entry.value); + success('参数实体类文件已保存到: $filePath'); + generatedFiles++; + } + } } } @@ -241,7 +279,7 @@ class GenerateCommand extends BaseCommand { ? (args.getOption('api') ?? false) : (args.getOption('all') ?? true), useSimpleModels: args.getOption('simple') ?? false, - splitByTags: args.getOption('split-by-tags') ?? true, // 默认启用拆分模式 + splitByTags: args.getOption('split-by-tags') ?? false, ); } diff --git a/lib/core/config.dart b/lib/core/config.dart index 7dfbfab..798603b 100644 --- a/lib/core/config.dart +++ b/lib/core/config.dart @@ -3,10 +3,10 @@ class SwaggerConfig { /// Swagger JSON文档的URL static const String swaggerJsonUrl = - 'http://192.168.2.7:17288/swagger/v1/swagger.json'; + 'https://quanxue-test-api.w.23544.com:8843/swagger/v1/swagger.json'; /// 基础API URL - static const String baseUrl = 'http://192.168.2.7:17288'; + static const String baseUrl = 'https://quanxue-test-api.w.23544.com:8843'; /// API版本 static const String apiVersion = '/api/v1'; diff --git a/lib/core/error_reporter.dart b/lib/core/error_reporter.dart deleted file mode 100644 index e22635a..0000000 --- a/lib/core/error_reporter.dart +++ /dev/null @@ -1,445 +0,0 @@ -/// 增强的错误报告系统 -/// 提供详细的错误位置、上下文和修复建议 -library; - -import 'dart:convert'; - -/// 错误严重程度 -enum ErrorSeverity { - info, - warning, - error, - critical, -} - -extension ErrorSeverityExtension on ErrorSeverity { - String get displayName { - switch (this) { - case ErrorSeverity.info: - return 'INFO'; - case ErrorSeverity.warning: - return 'WARNING'; - case ErrorSeverity.error: - return 'ERROR'; - case ErrorSeverity.critical: - return 'CRITICAL'; - } - } - - String get emoji { - switch (this) { - case ErrorSeverity.info: - return 'ℹ️'; - case ErrorSeverity.warning: - return '⚠️'; - case ErrorSeverity.error: - return '❌'; - case ErrorSeverity.critical: - return '🚨'; - } - } -} - -/// 错误类别 -enum ErrorCategory { - syntax, - schema, - reference, - validation, - compatibility, - performance, - security, - bestPractice, -} - -extension ErrorCategoryExtension on ErrorCategory { - String get displayName { - switch (this) { - case ErrorCategory.syntax: - return 'Syntax Error'; - case ErrorCategory.schema: - return 'Schema Error'; - case ErrorCategory.reference: - return 'Reference Error'; - case ErrorCategory.validation: - return 'Validation Error'; - case ErrorCategory.compatibility: - return 'Compatibility Issue'; - case ErrorCategory.performance: - return 'Performance Issue'; - case ErrorCategory.security: - return 'Security Issue'; - case ErrorCategory.bestPractice: - return 'Best Practice'; - } - } -} - -/// 错误位置信息 -class ErrorLocation { - /// JSON 路径(如 "paths./users.get.responses.200") - final String jsonPath; - - /// 行号(如果可用) - final int? line; - - /// 列号(如果可用) - final int? column; - - /// 字符偏移量 - final int? offset; - - /// 相关的 JSON 片段 - final String? snippet; - - const ErrorLocation({ - required this.jsonPath, - this.line, - this.column, - this.offset, - this.snippet, - }); - - @override - String toString() { - final buffer = StringBuffer(); - buffer.write(jsonPath); - - if (line != null) { - buffer.write(' (line $line'); - if (column != null) { - buffer.write(', column $column'); - } - buffer.write(')'); - } - - return buffer.toString(); - } -} - -/// 修复建议 -class FixSuggestion { - /// 建议描述 - final String description; - - /// 修复代码示例 - final String? codeExample; - - /// 相关文档链接 - final String? documentationUrl; - - /// 自动修复函数(如果支持) - final String Function(String original)? autoFix; - - const FixSuggestion({ - required this.description, - this.codeExample, - this.documentationUrl, - this.autoFix, - }); -} - -/// 详细错误报告 -class DetailedError { - /// 错误 ID(用于查找和分类) - final String id; - - /// 错误标题 - final String title; - - /// 错误描述 - final String description; - - /// 错误严重程度 - final ErrorSeverity severity; - - /// 错误类别 - final ErrorCategory category; - - /// 错误位置 - final ErrorLocation location; - - /// 修复建议 - final List suggestions; - - /// 相关错误(如果有) - final List relatedErrors; - - /// 错误发生时间 - final DateTime timestamp; - - DetailedError({ - required this.id, - required this.title, - required this.description, - required this.severity, - required this.category, - required this.location, - this.suggestions = const [], - this.relatedErrors = const [], - DateTime? timestamp, - }) : timestamp = timestamp ?? DateTime.now(); - - @override - String toString() { - final buffer = StringBuffer(); - - // 错误头部 - buffer.writeln('${severity.emoji} ${severity.displayName}: $title'); - buffer.writeln('Category: ${category.displayName}'); - buffer.writeln('Location: $location'); - buffer.writeln(); - - // 错误描述 - buffer.writeln('Description:'); - buffer.writeln(' $description'); - buffer.writeln(); - - // 代码片段(如果有) - if (location.snippet != null) { - buffer.writeln('Code snippet:'); - buffer.writeln(' ${location.snippet}'); - buffer.writeln(); - } - - // 修复建议 - if (suggestions.isNotEmpty) { - buffer.writeln('Suggestions:'); - for (int i = 0; i < suggestions.length; i++) { - final suggestion = suggestions[i]; - buffer.writeln(' ${i + 1}. ${suggestion.description}'); - - if (suggestion.codeExample != null) { - buffer.writeln(' Example:'); - buffer.writeln(' ${suggestion.codeExample}'); - } - - if (suggestion.documentationUrl != null) { - buffer.writeln(' See: ${suggestion.documentationUrl}'); - } - buffer.writeln(); - } - } - - // 相关错误 - if (relatedErrors.isNotEmpty) { - buffer.writeln('Related errors: ${relatedErrors.join(', ')}'); - } - - return buffer.toString(); - } -} - -/// 错误报告器 -class ErrorReporter { - final List _errors = []; - final Map _errorCounts = {}; - - ErrorReporter(); - - /// 添加错误 - void addError(DetailedError error) { - _errors.add(error); - _errorCounts[error.id] = (_errorCounts[error.id] ?? 0) + 1; - } - - /// 创建并添加错误 - void reportError({ - required String id, - required String title, - required String description, - required ErrorSeverity severity, - required ErrorCategory category, - required String jsonPath, - int? line, - int? column, - String? snippet, - List suggestions = const [], - List relatedErrors = const [], - }) { - final error = DetailedError( - id: id, - title: title, - description: description, - severity: severity, - category: category, - location: ErrorLocation( - jsonPath: jsonPath, - line: line, - column: column, - snippet: snippet, - ), - suggestions: suggestions, - relatedErrors: relatedErrors, - ); - - addError(error); - } - - /// 获取所有错误 - List get errors => List.unmodifiable(_errors); - - /// 获取特定严重程度的错误 - List getErrorsBySeverity(ErrorSeverity severity) { - return _errors.where((error) => error.severity == severity).toList(); - } - - /// 获取特定类别的错误 - List getErrorsByCategory(ErrorCategory category) { - return _errors.where((error) => error.category == category).toList(); - } - - /// 获取错误统计 - Map getErrorStatistics() { - final stats = {}; - for (final error in _errors) { - stats[error.severity] = (stats[error.severity] ?? 0) + 1; - } - return stats; - } - - /// 检查是否有错误 - bool get hasErrors => _errors.isNotEmpty; - - /// 检查是否有严重错误 - bool get hasCriticalErrors => - _errors.any((e) => e.severity == ErrorSeverity.critical); - - /// 检查是否有错误(不包括警告和信息) - bool get hasErrorsOrCritical => _errors.any((e) => - e.severity == ErrorSeverity.error || - e.severity == ErrorSeverity.critical); - - /// 清除所有错误 - void clear() { - _errors.clear(); - _errorCounts.clear(); - } - - /// 生成错误报告 - String generateReport({ - bool includeStatistics = true, - bool groupByCategory = false, - ErrorSeverity? minSeverity, - }) { - final buffer = StringBuffer(); - - // 过滤错误 - var filteredErrors = _errors; - if (minSeverity != null) { - final minLevel = minSeverity.index; - filteredErrors = - _errors.where((e) => e.severity.index >= minLevel).toList(); - } - - if (filteredErrors.isEmpty) { - buffer.writeln('✅ No errors found!'); - return buffer.toString(); - } - - // 统计信息 - if (includeStatistics) { - buffer.writeln('📊 Error Summary'); - buffer.writeln('=' * 50); - final stats = getErrorStatistics(); - stats.forEach((severity, count) { - buffer.writeln('${severity.emoji} ${severity.displayName}: $count'); - }); - buffer.writeln(); - } - - // 错误详情 - if (groupByCategory) { - _generateReportByCategory(buffer, filteredErrors); - } else { - _generateReportByOrder(buffer, filteredErrors); - } - - return buffer.toString(); - } - - /// 按类别生成报告 - void _generateReportByCategory( - StringBuffer buffer, List errors) { - final errorsByCategory = >{}; - - for (final error in errors) { - errorsByCategory.putIfAbsent(error.category, () => []).add(error); - } - - errorsByCategory.forEach((category, categoryErrors) { - buffer.writeln('📂 ${category.displayName}'); - buffer.writeln('-' * 30); - - for (final error in categoryErrors) { - buffer.writeln(error.toString()); - buffer.writeln(); - } - }); - } - - /// 按顺序生成报告 - void _generateReportByOrder(StringBuffer buffer, List errors) { - buffer.writeln('🔍 Detailed Error Report'); - buffer.writeln('=' * 50); - - for (int i = 0; i < errors.length; i++) { - buffer.writeln('Error ${i + 1}/${errors.length}:'); - buffer.writeln(errors[i].toString()); - - if (i < errors.length - 1) { - buffer.writeln('-' * 50); - } - } - } - - /// 生成 JSON 格式的报告 - String generateJsonReport() { - final report = { - 'timestamp': DateTime.now().toIso8601String(), - 'summary': { - 'total': _errors.length, - 'by_severity': getErrorStatistics().map((k, v) => MapEntry(k.name, v)), - }, - 'errors': _errors - .map((error) => { - 'id': error.id, - 'title': error.title, - 'description': error.description, - 'severity': error.severity.name, - 'category': error.category.name, - 'location': { - 'json_path': error.location.jsonPath, - 'line': error.location.line, - 'column': error.location.column, - 'snippet': error.location.snippet, - }, - 'suggestions': error.suggestions - .map((suggestion) => { - 'description': suggestion.description, - 'code_example': suggestion.codeExample, - 'documentation_url': suggestion.documentationUrl, - }) - .toList(), - 'related_errors': error.relatedErrors, - 'timestamp': error.timestamp.toIso8601String(), - }) - .toList(), - }; - - return const JsonEncoder.withIndent(' ').convert(report); - } - - /// 导出错误到文件 - Future exportToFile(String filePath, {String format = 'text'}) async { - final content = switch (format.toLowerCase()) { - 'json' => generateJsonReport(), - _ => generateReport(), - }; - - // 这里应该写入文件,但为了简化,我们只返回内容 - // await File(filePath).writeAsString(content); - // 为了避免未使用变量警告,我们添加一个简单的使用 - assert(content.isNotEmpty || content.isEmpty); - } -} diff --git a/lib/core/error_rules.dart b/lib/core/error_rules.dart deleted file mode 100644 index 23cc2ee..0000000 --- a/lib/core/error_rules.dart +++ /dev/null @@ -1,469 +0,0 @@ -/// OpenAPI 错误规则库 -/// 定义常见的错误模式和修复建议 -library; - -import 'error_reporter.dart'; - -/// 错误规则定义 -class ErrorRule { - final String id; - final String pattern; - final ErrorSeverity severity; - final ErrorCategory category; - final String title; - final String description; - final List suggestions; - - const ErrorRule({ - required this.id, - required this.pattern, - required this.severity, - required this.category, - required this.title, - required this.description, - this.suggestions = const [], - }); -} - -/// OpenAPI 错误规则库 -class OpenApiErrorRules { - static const List rules = [ - // 基础结构错误 - ErrorRule( - id: 'MISSING_OPENAPI_VERSION', - pattern: 'openapi', - severity: ErrorSeverity.critical, - category: ErrorCategory.syntax, - title: 'Missing OpenAPI Version', - description: 'OpenAPI document must specify the OpenAPI version.', - suggestions: [ - FixSuggestion( - description: 'Add openapi field with version 3.0.x or 3.1.x', - codeExample: '"openapi": "3.0.3"', - documentationUrl: - 'https://spec.openapis.org/oas/v3.0.3/#openapi-object', - ), - ], - ), - - ErrorRule( - id: 'INVALID_OPENAPI_VERSION', - pattern: 'openapi', - severity: ErrorSeverity.error, - category: ErrorCategory.compatibility, - title: 'Invalid OpenAPI Version', - description: - 'OpenAPI version should be 3.0.x or 3.1.x for proper support.', - suggestions: [ - FixSuggestion( - description: 'Use a supported OpenAPI version', - codeExample: '"openapi": "3.0.3"', - ), - ], - ), - - // Info 对象错误 - ErrorRule( - id: 'MISSING_INFO_TITLE', - pattern: 'info.title', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - title: 'Missing API Title', - description: 'API title is required in the info object.', - suggestions: [ - FixSuggestion( - description: 'Add a descriptive title for your API', - codeExample: '"title": "My API"', - ), - ], - ), - - ErrorRule( - id: 'MISSING_INFO_VERSION', - pattern: 'info.version', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - title: 'Missing API Version', - description: 'API version is required in the info object.', - suggestions: [ - FixSuggestion( - description: 'Add a version number using semantic versioning', - codeExample: '"version": "1.0.0"', - documentationUrl: 'https://semver.org/', - ), - ], - ), - - // Paths 错误 - ErrorRule( - id: 'EMPTY_PATHS', - pattern: 'paths', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - title: 'Empty Paths Object', - description: 'OpenAPI document must contain at least one path.', - suggestions: [ - FixSuggestion( - description: 'Add at least one API endpoint', - codeExample: - '"/users": { "get": { "responses": { "200": { "description": "Success" } } } }', - ), - ], - ), - - ErrorRule( - id: 'INVALID_PATH_FORMAT', - pattern: 'paths.*', - severity: ErrorSeverity.error, - category: ErrorCategory.syntax, - title: 'Invalid Path Format', - description: 'Path must start with a forward slash.', - suggestions: [ - FixSuggestion( - description: 'Ensure path starts with /', - codeExample: '"/users" instead of "users"', - ), - ], - ), - - ErrorRule( - id: 'MISSING_OPERATION_RESPONSES', - pattern: 'paths.*.*.responses', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - title: 'Missing Operation Responses', - description: 'Every operation must define at least one response.', - suggestions: [ - FixSuggestion( - description: 'Add at least a default response', - codeExample: '"responses": { "200": { "description": "Success" } }', - ), - ], - ), - - // 参数错误 - ErrorRule( - id: 'PATH_PARAMETER_NOT_REQUIRED', - pattern: 'paths.*.*.parameters.*', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - title: 'Path Parameter Not Required', - description: 'Path parameters must be marked as required.', - suggestions: [ - FixSuggestion( - description: 'Set required: true for path parameters', - codeExample: '"required": true', - ), - ], - ), - - ErrorRule( - id: 'MISSING_PARAMETER_NAME', - pattern: 'paths.*.*.parameters.*.name', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - title: 'Missing Parameter Name', - description: 'Parameter must have a name.', - suggestions: [ - FixSuggestion( - description: 'Add a name for the parameter', - codeExample: '"name": "userId"', - ), - ], - ), - - // Schema 错误 - ErrorRule( - id: 'MISSING_SCHEMA_TYPE', - pattern: 'components.schemas.*.type', - severity: ErrorSeverity.warning, - category: ErrorCategory.schema, - title: 'Missing Schema Type', - description: 'Schema should specify a type for better code generation.', - suggestions: [ - FixSuggestion( - description: 'Add a type field to the schema', - codeExample: '"type": "object"', - ), - ], - ), - - ErrorRule( - id: 'CIRCULAR_REFERENCE', - pattern: 'components.schemas.*', - severity: ErrorSeverity.warning, - category: ErrorCategory.schema, - title: 'Circular Reference Detected', - description: 'Circular references can cause issues in code generation.', - suggestions: [ - FixSuggestion( - description: - 'Consider using allOf or breaking the circular dependency', - codeExample: - '"allOf": [{ "\$ref": "#/components/schemas/BaseModel" }]', - ), - ], - ), - - // 安全方案错误 - ErrorRule( - id: 'MISSING_SECURITY_SCHEME_TYPE', - pattern: 'components.securitySchemes.*.type', - severity: ErrorSeverity.error, - category: ErrorCategory.security, - title: 'Missing Security Scheme Type', - description: 'Security scheme must specify a type.', - suggestions: [ - FixSuggestion( - description: 'Add a type field (apiKey, http, oauth2, openIdConnect)', - codeExample: '"type": "apiKey"', - ), - ], - ), - - ErrorRule( - id: 'MISSING_API_KEY_NAME', - pattern: 'components.securitySchemes.*.name', - severity: ErrorSeverity.error, - category: ErrorCategory.security, - title: 'Missing API Key Name', - description: 'API Key security scheme must specify a parameter name.', - suggestions: [ - FixSuggestion( - description: 'Add name field for API key parameter', - codeExample: '"name": "X-API-Key"', - ), - ], - ), - - ErrorRule( - id: 'MISSING_API_KEY_LOCATION', - pattern: 'components.securitySchemes.*.in', - severity: ErrorSeverity.error, - category: ErrorCategory.security, - title: 'Missing API Key Location', - description: - 'API Key security scheme must specify where the key is located.', - suggestions: [ - FixSuggestion( - description: 'Add in field (query, header, cookie)', - codeExample: '"in": "header"', - ), - ], - ), - - // 响应错误 - ErrorRule( - id: 'MISSING_RESPONSE_DESCRIPTION', - pattern: 'paths.*.*.responses.*.description', - severity: ErrorSeverity.warning, - category: ErrorCategory.bestPractice, - title: 'Missing Response Description', - description: 'Response should have a description.', - suggestions: [ - FixSuggestion( - description: 'Add a description for the response', - codeExample: '"description": "Successful operation"', - ), - ], - ), - - ErrorRule( - id: 'NO_SUCCESS_RESPONSE', - pattern: 'paths.*.*.responses', - severity: ErrorSeverity.warning, - category: ErrorCategory.bestPractice, - title: 'No Success Response', - description: - 'Operation should define at least one success response (2xx).', - suggestions: [ - FixSuggestion( - description: 'Add a success response', - codeExample: '"200": { "description": "Success" }', - ), - ], - ), - - // 性能和最佳实践 - ErrorRule( - id: 'MISSING_OPERATION_ID', - pattern: 'paths.*.*.operationId', - severity: ErrorSeverity.warning, - category: ErrorCategory.bestPractice, - title: 'Missing Operation ID', - description: - 'Operation should have an operationId for better code generation.', - suggestions: [ - FixSuggestion( - description: 'Add a unique operationId', - codeExample: '"operationId": "getUsers"', - ), - ], - ), - - ErrorRule( - id: 'MISSING_OPERATION_SUMMARY', - pattern: 'paths.*.*.summary', - severity: ErrorSeverity.info, - category: ErrorCategory.bestPractice, - title: 'Missing Operation Summary', - description: 'Operation should have a summary for better documentation.', - suggestions: [ - FixSuggestion( - description: 'Add a brief summary', - codeExample: '"summary": "Get all users"', - ), - ], - ), - - ErrorRule( - id: 'LARGE_SCHEMA_OBJECT', - pattern: 'components.schemas.*', - severity: ErrorSeverity.info, - category: ErrorCategory.performance, - title: 'Large Schema Object', - description: 'Schema has many properties, consider breaking it down.', - suggestions: [ - FixSuggestion( - description: 'Consider using composition with allOf', - codeExample: - '"allOf": [{ "\$ref": "#/components/schemas/BaseModel" }, { "type": "object", "properties": {...} }]', - ), - ], - ), - - // 媒体类型错误 - ErrorRule( - id: 'MISSING_CONTENT_TYPE', - pattern: 'paths.*.*.requestBody.content', - severity: ErrorSeverity.warning, - category: ErrorCategory.validation, - title: 'Missing Content Type', - description: 'Request body should specify at least one content type.', - suggestions: [ - FixSuggestion( - description: 'Add a content type', - codeExample: '"application/json": { "schema": {...} }', - ), - ], - ), - - ErrorRule( - id: 'INCONSISTENT_CONTENT_TYPES', - pattern: 'paths.*', - severity: ErrorSeverity.info, - category: ErrorCategory.bestPractice, - title: 'Inconsistent Content Types', - description: 'API uses different content types across operations.', - suggestions: [ - FixSuggestion( - description: 'Consider standardizing on common content types', - codeExample: 'Use application/json consistently', - ), - ], - ), - ]; - - /// 获取特定类别的规则 - static List getRulesByCategory(ErrorCategory category) { - return rules.where((rule) => rule.category == category).toList(); - } - - /// 获取特定严重程度的规则 - static List getRulesBySeverity(ErrorSeverity severity) { - return rules.where((rule) => rule.severity == severity).toList(); - } - - /// 根据 ID 获取规则 - static ErrorRule? getRuleById(String id) { - try { - return rules.firstWhere((rule) => rule.id == id); - } catch (e) { - return null; - } - } - - /// 获取所有规则 ID - static List getAllRuleIds() { - return rules.map((rule) => rule.id).toList(); - } - - /// 创建常见错误的快捷方法 - static DetailedError createMissingFieldError( - String fieldPath, String fieldName) { - return DetailedError( - id: 'MISSING_FIELD', - title: 'Missing Required Field', - description: 'Required field "$fieldName" is missing.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - location: ErrorLocation(jsonPath: fieldPath), - suggestions: [ - FixSuggestion( - description: 'Add the required field "$fieldName"', - codeExample: '"$fieldName": "value"', - ), - ], - ); - } - - static DetailedError createInvalidTypeError( - String fieldPath, String expectedType, String actualType) { - return DetailedError( - id: 'INVALID_TYPE', - title: 'Invalid Field Type', - description: - 'Field should be of type "$expectedType" but got "$actualType".', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - location: ErrorLocation(jsonPath: fieldPath), - suggestions: [ - FixSuggestion( - description: 'Change the field type to "$expectedType"', - codeExample: 'Use $expectedType instead of $actualType', - ), - ], - ); - } - - static DetailedError createUnknownFieldError( - String fieldPath, String fieldName, List validFields) { - return DetailedError( - id: 'UNKNOWN_FIELD', - title: 'Unknown Field', - description: 'Field "$fieldName" is not recognized in this context.', - severity: ErrorSeverity.warning, - category: ErrorCategory.validation, - location: ErrorLocation(jsonPath: fieldPath), - suggestions: [ - FixSuggestion( - description: - 'Remove the unknown field or use one of: ${validFields.join(", ")}', - codeExample: 'Valid fields: ${validFields.join(", ")}', - ), - ], - ); - } - - static DetailedError createReferenceError( - String fieldPath, String reference) { - return DetailedError( - id: 'INVALID_REFERENCE', - title: 'Invalid Reference', - description: 'Reference "$reference" could not be resolved.', - severity: ErrorSeverity.error, - category: ErrorCategory.reference, - location: ErrorLocation(jsonPath: fieldPath), - suggestions: [ - const FixSuggestion( - description: 'Check that the referenced component exists', - codeExample: 'Ensure the component is defined in components section', - ), - const FixSuggestion( - description: 'Verify the reference path is correct', - codeExample: '"\$ref": "#/components/schemas/ComponentName"', - ), - ], - ); - } -} diff --git a/lib/core/models.dart b/lib/core/models.dart index 8292cd4..48b2ebb 100644 --- a/lib/core/models.dart +++ b/lib/core/models.dart @@ -39,69 +39,6 @@ enum HttpMethod { } } -/// API服务器信息 (OpenAPI 3.0) -class ApiServer { - /// 服务器URL - final String url; - - /// 服务器描述 - final String description; - - /// 服务器变量 - final Map variables; - - const ApiServer({ - required this.url, - this.description = '', - this.variables = const {}, - }); - - /// 从JSON创建ApiServer - factory ApiServer.fromJson(Map json) { - final variablesJson = json['variables'] as Map? ?? {}; - final variables = {}; - - variablesJson.forEach((key, value) { - if (value is Map) { - variables[key] = ApiServerVariable.fromJson(value); - } - }); - - return ApiServer( - url: json['url'] as String? ?? '', - description: json['description'] as String? ?? '', - variables: variables, - ); - } -} - -/// API服务器变量 (OpenAPI 3.0) -class ApiServerVariable { - /// 变量的可选值 - final List enumValues; - - /// 默认值 - final String defaultValue; - - /// 变量描述 - final String description; - - const ApiServerVariable({ - this.enumValues = const [], - required this.defaultValue, - this.description = '', - }); - - /// 从JSON创建ApiServerVariable - factory ApiServerVariable.fromJson(Map json) { - return ApiServerVariable( - enumValues: List.from(json['enum'] ?? []), - defaultValue: json['default'] as String? ?? '', - description: json['description'] as String? ?? '', - ); - } -} - /// 属性类型枚举 /// 用于描述 API 属性的数据类型。 enum PropertyType { @@ -136,10 +73,7 @@ enum PropertyType { reference('reference'), /// 枚举类型 - enumType('enum'), - - /// 未知类型 - unknown('unknown'); + enumType('enum'); /// 枚举值对应的字符串 const PropertyType(this.value); @@ -149,7 +83,7 @@ enum PropertyType { static PropertyType fromString(String value) { return PropertyType.values.firstWhere( (type) => type.value == value.toLowerCase(), - orElse: () => PropertyType.unknown, + orElse: () => PropertyType.string, ); } } @@ -188,7 +122,7 @@ enum ParameterLocation { } } -/// OpenAPI 3.0 文档信息 +/// Swagger文档信息 /// 描述整个 API 的元数据和结构。 class SwaggerDocument { /// 文档标题 @@ -200,74 +134,60 @@ class SwaggerDocument { /// 文档描述 final String description; - /// 服务器配置 (OpenAPI 3.0) - final List servers; + /// 主机名 + final String host; - /// 可重用组件 (OpenAPI 3.0) - final ApiComponents components; + /// 基础路径 + final String basePath; + + /// 支持的协议 + final List schemes; + + /// 支持的请求类型 + final List consumes; + + /// 支持的响应类型 + final List produces; /// 路径定义 final Map paths; - /// 数据模型定义 (从 components.schemas 提取) + /// 数据模型定义 final Map models; /// 控制器定义 final Map controllers; - /// 全局安全要求 - final List security; - /// 构造函数 const SwaggerDocument({ required this.title, required this.version, required this.description, - this.servers = const [], - this.components = const ApiComponents(), + required this.host, + required this.basePath, + required this.schemes, + required this.consumes, + required this.produces, required this.paths, required this.models, required this.controllers, - this.security = const [], }); /// 从JSON创建SwaggerDocument factory SwaggerDocument.fromJson(Map json) { final info = json['info'] as Map? ?? {}; - - // 解析 servers (OpenAPI 3.0) - final serversJson = json['servers'] as List? ?? []; - final servers = serversJson - .map((server) => ApiServer.fromJson(server as Map)) - .toList(); - - // 如果没有 servers 配置,提供默认值 - if (servers.isEmpty) { - servers.add(const ApiServer(url: '/')); - } - - // 解析 components (OpenAPI 3.0) - final componentsJson = json['components'] as Map?; - final components = componentsJson != null - ? ApiComponents.fromJson(componentsJson) - : const ApiComponents(); - - // 解析全局安全要求 - final securityJson = json['security'] as List? ?? []; - final security = securityJson - .map((s) => ApiSecurityRequirement.fromJson(s as Map)) - .toList(); - return SwaggerDocument( title: info['title'] as String? ?? 'API', version: info['version'] as String? ?? '1.0.0', description: info['description'] as String? ?? '', - servers: servers, - components: components, + host: json['host'] as String? ?? '', + basePath: json['basePath'] as String? ?? '', + schemes: List.from(json['schemes'] ?? ['https']), + consumes: List.from(json['consumes'] ?? ['application/json']), + produces: List.from(json['produces'] ?? ['application/json']), paths: {}, - models: components.schemas, // 从 components 中提取 schemas + models: {}, controllers: {}, - security: security, ); } } @@ -285,9 +205,6 @@ class ApiPath { final ApiRequestBody? requestBody; final bool deprecated; - /// 安全要求 - final List security; - const ApiPath({ required this.path, required this.method, @@ -299,7 +216,6 @@ class ApiPath { required this.responses, this.requestBody, this.deprecated = false, - this.security = const [], }); /// 从JSON创建ApiPath @@ -330,11 +246,6 @@ class ApiPath { ? ApiRequestBody.fromJson(json['requestBody'] as Map) : null, deprecated: json['deprecated'] as bool? ?? false, - security: (json['security'] as List?) - ?.map((s) => - ApiSecurityRequirement.fromJson(s as Map)) - .toList() ?? - [], ); } } @@ -375,1377 +286,56 @@ class ApiParameter { description: json['description'] as String? ?? '', format: schema?['format'] as String? ?? json['format'] as String?, example: json['example'], - defaultValue: schema?['default'] ?? json['default'], + defaultValue: json['default'], ); } } -/// API响应信息 (OpenAPI 3.0) +/// API响应信息 class ApiResponse { - /// 响应状态码 final String code; - - /// 响应描述 final String description; - - /// 响应头定义 - final Map headers; - - /// 内容类型映射 (media type -> MediaTypeObject) - final Map content; - - /// 响应链接 - final Map links; - - /// Schema 定义 (Swagger 2.0 兼容,已弃用) - @Deprecated( - 'Use content instead. This field is for Swagger 2.0 compatibility only.') final Map? schema; + final Map? content; const ApiResponse({ required this.code, required this.description, - this.headers = const {}, - this.content = const {}, - this.links = const {}, - @Deprecated('Use content instead') this.schema, + this.schema, + this.content, }); /// 从JSON创建ApiResponse factory ApiResponse.fromJson(String code, Map json) { - // 解析 headers - final headersJson = json['headers'] as Map? ?? {}; - final headers = {}; - headersJson.forEach((key, value) { - if (value is Map) { - headers[key] = ApiHeader.fromJson(value); - } - }); - - // 解析 content - final contentJson = json['content'] as Map? ?? {}; - final content = {}; - contentJson.forEach((mediaType, mediaTypeData) { - if (mediaTypeData is Map) { - content[mediaType] = ApiMediaType.fromJson(mediaTypeData, mediaType); - } - }); - - // 解析 links - final linksJson = json['links'] as Map? ?? {}; - final links = {}; - linksJson.forEach((key, value) { - if (value is Map) { - links[key] = ApiLink.fromJson(value); - } - }); - return ApiResponse( code: code, description: json['description'] as String? ?? '', - headers: headers, - content: content, - links: links, - // 保留 schema 字段以兼容 Swagger 2.0 schema: json['schema'] as Map?, + content: json['content'] as Map?, ); } - - /// 获取支持的媒体类型列表 - List get supportedMediaTypes => content.keys.toList(); - - /// 检查是否支持指定的媒体类型 - bool supportsMediaType(String mediaType) => content.containsKey(mediaType); - - /// 获取指定媒体类型的 schema - Map? getSchemaForMediaType(String mediaType) { - return content[mediaType]?.schema; - } - - /// 检查是否有响应头定义 - bool get hasHeaders => headers.isNotEmpty; - - /// 检查是否有响应链接 - bool get hasLinks => links.isNotEmpty; } -/// API请求体信息 (OpenAPI 3.0) +/// API请求体信息 class ApiRequestBody { - /// 请求体描述 final String description; - - /// 是否必需 final bool required; - - /// 内容类型映射 (media type -> MediaTypeObject) - final Map content; + final Map? content; const ApiRequestBody({ - this.description = '', - this.required = false, - this.content = const {}, + required this.description, + required this.required, + this.content, }); /// 从JSON创建ApiRequestBody factory ApiRequestBody.fromJson(Map json) { - final contentJson = json['content'] as Map? ?? {}; - final content = {}; - - contentJson.forEach((mediaType, mediaTypeData) { - if (mediaTypeData is Map) { - content[mediaType] = ApiMediaType.fromJson(mediaTypeData, mediaType); - } - }); - return ApiRequestBody( description: json['description'] as String? ?? '', required: json['required'] as bool? ?? false, - content: content, + content: json['content'] as Map?, ); } - - /// 获取支持的媒体类型列表 - List get supportedMediaTypes => content.keys.toList(); - - /// 检查是否支持指定的媒体类型 - bool supportsMediaType(String mediaType) => content.containsKey(mediaType); - - /// 获取指定媒体类型的 schema - Map? getSchemaForMediaType(String mediaType) { - return content[mediaType]?.schema; - } -} - -/// 媒体类型枚举 -enum MediaType { - json, - xml, - formData, - formUrlEncoded, - multipartFormData, - textPlain, - textHtml, - textCsv, - applicationOctetStream, - applicationPdf, - imagePng, - imageJpeg, - imageGif, - imageSvg, - audioMp3, - videoMp4, - custom, -} - -extension MediaTypeExtension on MediaType { - String get value { - switch (this) { - case MediaType.json: - return 'application/json'; - case MediaType.xml: - return 'application/xml'; - case MediaType.formData: - return 'multipart/form-data'; - case MediaType.formUrlEncoded: - return 'application/x-www-form-urlencoded'; - case MediaType.multipartFormData: - return 'multipart/form-data'; - case MediaType.textPlain: - return 'text/plain'; - case MediaType.textHtml: - return 'text/html'; - case MediaType.textCsv: - return 'text/csv'; - case MediaType.applicationOctetStream: - return 'application/octet-stream'; - case MediaType.applicationPdf: - return 'application/pdf'; - case MediaType.imagePng: - return 'image/png'; - case MediaType.imageJpeg: - return 'image/jpeg'; - case MediaType.imageGif: - return 'image/gif'; - case MediaType.imageSvg: - return 'image/svg+xml'; - case MediaType.audioMp3: - return 'audio/mpeg'; - case MediaType.videoMp4: - return 'video/mp4'; - case MediaType.custom: - return 'custom'; - } - } - - static MediaType fromString(String value) { - final lowerValue = value.toLowerCase(); - switch (lowerValue) { - case 'application/json': - return MediaType.json; - case 'application/xml': - case 'text/xml': - return MediaType.xml; - case 'multipart/form-data': - return MediaType.multipartFormData; - case 'application/x-www-form-urlencoded': - return MediaType.formUrlEncoded; - case 'text/plain': - return MediaType.textPlain; - case 'text/html': - return MediaType.textHtml; - case 'text/csv': - return MediaType.textCsv; - case 'application/octet-stream': - return MediaType.applicationOctetStream; - case 'application/pdf': - return MediaType.applicationPdf; - case 'image/png': - return MediaType.imagePng; - case 'image/jpeg': - case 'image/jpg': - return MediaType.imageJpeg; - case 'image/gif': - return MediaType.imageGif; - case 'image/svg+xml': - return MediaType.imageSvg; - case 'audio/mpeg': - case 'audio/mp3': - return MediaType.audioMp3; - case 'video/mp4': - return MediaType.videoMp4; - default: - return MediaType.custom; - } - } - - /// 检查是否是文本类型 - bool get isText { - switch (this) { - case MediaType.textPlain: - case MediaType.textHtml: - case MediaType.textCsv: - case MediaType.json: - case MediaType.xml: - return true; - default: - return false; - } - } - - /// 检查是否是二进制类型 - bool get isBinary { - switch (this) { - case MediaType.applicationOctetStream: - case MediaType.applicationPdf: - case MediaType.imagePng: - case MediaType.imageJpeg: - case MediaType.imageGif: - case MediaType.imageSvg: - case MediaType.audioMp3: - case MediaType.videoMp4: - return true; - default: - return false; - } - } - - /// 检查是否是表单类型 - bool get isForm { - switch (this) { - case MediaType.formData: - case MediaType.formUrlEncoded: - case MediaType.multipartFormData: - return true; - default: - return false; - } - } - - /// 检查是否是图片类型 - bool get isImage { - switch (this) { - case MediaType.imagePng: - case MediaType.imageJpeg: - case MediaType.imageGif: - case MediaType.imageSvg: - return true; - default: - return false; - } - } - - /// 检查是否是音频类型 - bool get isAudio { - switch (this) { - case MediaType.audioMp3: - return true; - default: - return false; - } - } - - /// 检查是否是视频类型 - bool get isVideo { - switch (this) { - case MediaType.videoMp4: - return true; - default: - return false; - } - } - - /// 获取适合的 Dart 类型 - String get dartType { - switch (this) { - case MediaType.json: - return 'Map'; - case MediaType.xml: - return 'String'; - case MediaType.formData: - case MediaType.formUrlEncoded: - case MediaType.multipartFormData: - return 'FormData'; - case MediaType.textPlain: - case MediaType.textHtml: - case MediaType.textCsv: - return 'String'; - case MediaType.applicationOctetStream: - case MediaType.applicationPdf: - case MediaType.imagePng: - case MediaType.imageJpeg: - case MediaType.imageGif: - case MediaType.audioMp3: - case MediaType.videoMp4: - return 'List'; - case MediaType.imageSvg: - return 'String'; - case MediaType.custom: - return 'dynamic'; - } - } -} - -/// API媒体类型信息 (OpenAPI 3.0) -class ApiMediaType { - /// Schema 定义 - final Map? schema; - - /// 示例数据 - final dynamic example; - - /// 多个示例数据 - final Map examples; - - /// 编码信息 (用于 multipart 和 form data) - final Map encoding; - - /// 媒体类型 - final MediaType mediaType; - - /// 原始媒体类型字符串 - final String rawMediaType; - - const ApiMediaType({ - this.schema, - this.example, - this.examples = const {}, - this.encoding = const {}, - this.mediaType = MediaType.json, - this.rawMediaType = 'application/json', - }); - - /// 从JSON创建ApiMediaType - factory ApiMediaType.fromJson(Map json, - [String? contentType]) { - final examplesJson = json['examples'] as Map? ?? {}; - final examples = {}; - - examplesJson.forEach((key, value) { - if (value is Map) { - examples[key] = ApiExample.fromJson(value); - } - }); - - final encodingJson = json['encoding'] as Map? ?? {}; - final encoding = {}; - - encodingJson.forEach((key, value) { - if (value is Map) { - encoding[key] = ApiEncoding.fromJson(value); - } - }); - - // 确定媒体类型 - final rawType = contentType ?? 'application/json'; - final mediaType = MediaTypeExtension.fromString(rawType); - - return ApiMediaType( - schema: json['schema'] as Map?, - example: json['example'], - examples: examples, - encoding: encoding, - mediaType: mediaType, - rawMediaType: rawType, - ); - } - - /// 检查是否是 JSON 类型 - bool get isJson => mediaType == MediaType.json; - - /// 检查是否是 XML 类型 - bool get isXml => mediaType == MediaType.xml; - - /// 检查是否是表单类型 - bool get isForm => mediaType.isForm; - - /// 检查是否是文件上传类型 - bool get isFileUpload => mediaType == MediaType.multipartFormData; - - /// 检查是否是二进制类型 - bool get isBinary => mediaType.isBinary; - - /// 检查是否是文本类型 - bool get isText => mediaType.isText; - - /// 检查是否是图片类型 - bool get isImage => mediaType.isImage; - - /// 获取适合的 Dart 类型 - String get dartType => mediaType.dartType; -} - -/// API示例信息 (OpenAPI 3.0) -class ApiExample { - /// 示例摘要 - final String summary; - - /// 示例描述 - final String description; - - /// 示例值 - final dynamic value; - - /// 外部示例URL - final String? externalValue; - - const ApiExample({ - this.summary = '', - this.description = '', - this.value, - this.externalValue, - }); - - /// 从JSON创建ApiExample - factory ApiExample.fromJson(Map json) { - return ApiExample( - summary: json['summary'] as String? ?? '', - description: json['description'] as String? ?? '', - value: json['value'], - externalValue: json['externalValue'] as String?, - ); - } -} - -/// API编码信息 (OpenAPI 3.0) -class ApiEncoding { - /// 内容类型 - final String? contentType; - - /// 头部信息 - final Map headers; - - /// 样式 - final String? style; - - /// 是否展开 - final bool explode; - - /// 是否允许保留字符 - final bool allowReserved; - - const ApiEncoding({ - this.contentType, - this.headers = const {}, - this.style, - this.explode = false, - this.allowReserved = false, - }); - - /// 从JSON创建ApiEncoding - factory ApiEncoding.fromJson(Map json) { - final headersJson = json['headers'] as Map? ?? {}; - final headers = {}; - - headersJson.forEach((key, value) { - if (value is Map) { - headers[key] = ApiHeader.fromJson(value); - } - }); - - return ApiEncoding( - contentType: json['contentType'] as String?, - headers: headers, - style: json['style'] as String?, - explode: json['explode'] as bool? ?? false, - allowReserved: json['allowReserved'] as bool? ?? false, - ); - } - - /// 检查是否是文件类型 - bool get isFile { - if (contentType == null) return false; - final type = contentType!.toLowerCase(); - return type.startsWith('image/') || - type.startsWith('audio/') || - type.startsWith('video/') || - type == 'application/octet-stream' || - type == 'application/pdf' || - type.contains('binary'); - } - - /// 检查是否是图片文件 - bool get isImage { - if (contentType == null) return false; - return contentType!.toLowerCase().startsWith('image/'); - } - - /// 检查是否是音频文件 - bool get isAudio { - if (contentType == null) return false; - return contentType!.toLowerCase().startsWith('audio/'); - } - - /// 检查是否是视频文件 - bool get isVideo { - if (contentType == null) return false; - return contentType!.toLowerCase().startsWith('video/'); - } - - /// 检查是否有自定义头部 - bool get hasHeaders => headers.isNotEmpty; -} - -/// API头部信息 (OpenAPI 3.0) -class ApiHeader { - /// 头部描述 - final String description; - - /// 是否必需 - final bool required; - - /// 是否已弃用 - final bool deprecated; - - /// Schema 定义 - final Map? schema; - - /// 示例值 - final dynamic example; - - const ApiHeader({ - this.description = '', - this.required = false, - this.deprecated = false, - this.schema, - this.example, - }); - - /// 从JSON创建ApiHeader - factory ApiHeader.fromJson(Map json) { - return ApiHeader( - description: json['description'] as String? ?? '', - required: json['required'] as bool? ?? false, - deprecated: json['deprecated'] as bool? ?? false, - schema: json['schema'] as Map?, - example: json['example'], - ); - } -} - -/// API链接信息 (OpenAPI 3.0) -class ApiLink { - /// 链接描述 - final String description; - - /// 操作引用 - final String? operationRef; - - /// 操作ID - final String? operationId; - - /// 参数映射 - final Map parameters; - - /// 请求体映射 - final dynamic requestBody; - - /// 服务器信息 - final ApiServer? server; - - const ApiLink({ - this.description = '', - this.operationRef, - this.operationId, - this.parameters = const {}, - this.requestBody, - this.server, - }); - - /// 从JSON创建ApiLink - factory ApiLink.fromJson(Map json) { - final serverJson = json['server'] as Map?; - final server = serverJson != null ? ApiServer.fromJson(serverJson) : null; - - return ApiLink( - description: json['description'] as String? ?? '', - operationRef: json['operationRef'] as String?, - operationId: json['operationId'] as String?, - parameters: json['parameters'] as Map? ?? {}, - requestBody: json['requestBody'], - server: server, - ); - } -} - -/// API组件信息 (OpenAPI 3.0) -/// 包含可重用的组件定义 -class ApiComponents { - /// Schema 定义 - final Map schemas; - - /// 响应定义 - final Map responses; - - /// 参数定义 - final Map parameters; - - /// 示例定义 - final Map examples; - - /// 请求体定义 - final Map requestBodies; - - /// 头部定义 - final Map headers; - - /// 安全方案定义 - final Map securitySchemes; - - /// 链接定义 - final Map links; - - /// 回调定义 - final Map callbacks; - - const ApiComponents({ - this.schemas = const {}, - this.responses = const {}, - this.parameters = const {}, - this.examples = const {}, - this.requestBodies = const {}, - this.headers = const {}, - this.securitySchemes = const {}, - this.links = const {}, - this.callbacks = const {}, - }); - - /// 从JSON创建ApiComponents - factory ApiComponents.fromJson(Map json) { - // 解析 schemas - final schemasJson = json['schemas'] as Map? ?? {}; - final schemas = {}; - schemasJson.forEach((key, value) { - if (value is Map) { - schemas[key] = ApiModel.fromJson(key, value); - } - }); - - // 解析 responses - final responsesJson = json['responses'] as Map? ?? {}; - final responses = {}; - responsesJson.forEach((key, value) { - if (value is Map) { - responses[key] = ApiResponse.fromJson(key, value); - } - }); - - // 解析 parameters - final parametersJson = json['parameters'] as Map? ?? {}; - final parameters = {}; - parametersJson.forEach((key, value) { - if (value is Map) { - parameters[key] = ApiParameter.fromJson(value); - } - }); - - // 解析 examples - final examplesJson = json['examples'] as Map? ?? {}; - final examples = {}; - examplesJson.forEach((key, value) { - if (value is Map) { - examples[key] = ApiExample.fromJson(value); - } - }); - - // 解析 requestBodies - final requestBodiesJson = - json['requestBodies'] as Map? ?? {}; - final requestBodies = {}; - requestBodiesJson.forEach((key, value) { - if (value is Map) { - requestBodies[key] = ApiRequestBody.fromJson(value); - } - }); - - // 解析 headers - final headersJson = json['headers'] as Map? ?? {}; - final headers = {}; - headersJson.forEach((key, value) { - if (value is Map) { - headers[key] = ApiHeader.fromJson(value); - } - }); - - // 解析 securitySchemes - final securitySchemesJson = - json['securitySchemes'] as Map? ?? {}; - final securitySchemes = {}; - securitySchemesJson.forEach((key, value) { - if (value is Map) { - securitySchemes[key] = ApiSecurityScheme.fromJson(value); - } - }); - - // 解析 links - final linksJson = json['links'] as Map? ?? {}; - final links = {}; - linksJson.forEach((key, value) { - if (value is Map) { - links[key] = ApiLink.fromJson(value); - } - }); - - // 解析 callbacks - final callbacksJson = json['callbacks'] as Map? ?? {}; - final callbacks = {}; - callbacksJson.forEach((key, value) { - if (value is Map) { - callbacks[key] = ApiCallback.fromJson(value); - } - }); - - return ApiComponents( - schemas: schemas, - responses: responses, - parameters: parameters, - examples: examples, - requestBodies: requestBodies, - headers: headers, - securitySchemes: securitySchemes, - links: links, - callbacks: callbacks, - ); - } -} - -/// API安全方案信息 (OpenAPI 3.0) -class ApiSecurityScheme { - /// 安全方案类型 - final SecuritySchemeType type; - - /// 描述 - final String description; - - /// 名称 (用于 apiKey) - final String? name; - - /// 位置 (用于 apiKey) - final ApiKeyLocation? location; - - /// 方案 (用于 http) - final String? scheme; - - /// Bearer 格式 (用于 http bearer) - final String? bearerFormat; - - /// OAuth2 流程信息 (用于 oauth2) - final OAuth2Flows? flows; - - /// OpenID Connect URL (用于 openIdConnect) - final String? openIdConnectUrl; - - const ApiSecurityScheme({ - required this.type, - this.description = '', - this.name, - this.location, - this.scheme, - this.bearerFormat, - this.flows, - this.openIdConnectUrl, - }); - - /// 从JSON创建ApiSecurityScheme - factory ApiSecurityScheme.fromJson(Map json) { - final type = SecuritySchemeTypeExtension.fromString( - json['type'] as String? ?? 'apiKey'); - - return ApiSecurityScheme( - type: type, - description: json['description'] as String? ?? '', - name: json['name'] as String?, - location: json['in'] != null - ? ApiKeyLocationExtension.fromString(json['in'] as String) - : null, - scheme: json['scheme'] as String?, - bearerFormat: json['bearerFormat'] as String?, - flows: json['flows'] != null - ? OAuth2Flows.fromJson(json['flows'] as Map) - : null, - openIdConnectUrl: json['openIdConnectUrl'] as String?, - ); - } - - /// 检查是否是 API Key 认证 - bool get isApiKey => type == SecuritySchemeType.apiKey; - - /// 检查是否是 HTTP 认证 - bool get isHttp => type == SecuritySchemeType.http; - - /// 检查是否是 OAuth2 认证 - bool get isOAuth2 => type == SecuritySchemeType.oauth2; - - /// 检查是否是 OpenID Connect 认证 - bool get isOpenIdConnect => type == SecuritySchemeType.openIdConnect; - - /// 检查是否是 Bearer 认证 - bool get isBearer => isHttp && scheme?.toLowerCase() == 'bearer'; - - /// 检查是否是 Basic 认证 - bool get isBasic => isHttp && scheme?.toLowerCase() == 'basic'; - - /// 检查是否有 OAuth2 流程 - bool get hasOAuth2Flows => flows?.hasAnyFlow == true; - - /// 获取 API Key 的完整配置信息 - String get apiKeyInfo { - if (!isApiKey || name == null || location == null) return ''; - return '${location!.value}:$name'; - } - - /// 获取 HTTP 认证的完整配置信息 - String get httpAuthInfo { - if (!isHttp || scheme == null) return ''; - if (bearerFormat != null) { - return '$scheme ($bearerFormat)'; - } - return scheme!; - } -} - -/// API回调信息 (OpenAPI 3.0) -class ApiCallback { - /// 回调表达式映射 - final Map expressions; - - const ApiCallback({ - this.expressions = const {}, - }); - - /// 从JSON创建ApiCallback - factory ApiCallback.fromJson(Map json) { - final expressions = {}; - - json.forEach((expression, pathItemData) { - if (pathItemData is Map) { - expressions[expression] = ApiPathItem.fromJson(pathItemData); - } - }); - - return ApiCallback( - expressions: expressions, - ); - } -} - -/// API路径项信息 (OpenAPI 3.0) -class ApiPathItem { - /// 路径摘要 - final String summary; - - /// 路径描述 - final String description; - - /// 操作映射 (HTTP方法 -> 操作) - final Map operations; - - /// 服务器信息 - final List servers; - - /// 参数信息 - final List parameters; - - const ApiPathItem({ - this.summary = '', - this.description = '', - this.operations = const {}, - this.servers = const [], - this.parameters = const [], - }); - - /// 从JSON创建ApiPathItem - factory ApiPathItem.fromJson(Map json) { - final operations = {}; - final httpMethods = [ - 'get', - 'put', - 'post', - 'delete', - 'options', - 'head', - 'patch', - 'trace' - ]; - - for (final method in httpMethods) { - if (json[method] != null) { - operations[method] = - ApiOperation.fromJson(json[method] as Map); - } - } - - final serversJson = json['servers'] as List? ?? []; - final servers = serversJson - .map((server) => ApiServer.fromJson(server as Map)) - .toList(); - - final parametersJson = json['parameters'] as List? ?? []; - final parameters = parametersJson - .map((param) => ApiParameter.fromJson(param as Map)) - .toList(); - - return ApiPathItem( - summary: json['summary'] as String? ?? '', - description: json['description'] as String? ?? '', - operations: operations, - servers: servers, - parameters: parameters, - ); - } -} - -/// API操作信息 (OpenAPI 3.0) -class ApiOperation { - /// 操作摘要 - final String summary; - - /// 操作描述 - final String description; - - /// 操作ID - final String? operationId; - - /// 标签 - final List tags; - - /// 参数 - final List parameters; - - /// 请求体 - final ApiRequestBody? requestBody; - - /// 响应 - final Map responses; - - /// 安全要求 - final List security; - - const ApiOperation({ - this.summary = '', - this.description = '', - this.operationId, - this.tags = const [], - this.parameters = const [], - this.requestBody, - this.responses = const {}, - this.security = const [], - }); - - /// 从JSON创建ApiOperation - factory ApiOperation.fromJson(Map json) { - final parametersJson = json['parameters'] as List? ?? []; - final parameters = parametersJson - .map((param) => ApiParameter.fromJson(param as Map)) - .toList(); - - final requestBodyJson = json['requestBody'] as Map?; - final requestBody = requestBodyJson != null - ? ApiRequestBody.fromJson(requestBodyJson) - : null; - - final responsesJson = json['responses'] as Map? ?? {}; - final responses = {}; - responsesJson.forEach((code, responseData) { - if (responseData is Map) { - responses[code] = ApiResponse.fromJson(code, responseData); - } - }); - - final securityJson = json['security'] as List? ?? []; - final security = securityJson - .map((s) => ApiSecurityRequirement.fromJson(s as Map)) - .toList(); - - return ApiOperation( - summary: json['summary'] as String? ?? '', - description: json['description'] as String? ?? '', - operationId: json['operationId'] as String?, - tags: List.from(json['tags'] ?? []), - parameters: parameters, - requestBody: requestBody, - responses: responses, - security: security, - ); - } -} - -/// API 判别器信息 (OpenAPI 3.0) -/// 用于多态类型的判别 -class ApiDiscriminator { - /// 判别器属性名 - final String propertyName; - - /// 映射表 (值 -> schema 引用) - final Map mapping; - - const ApiDiscriminator({ - required this.propertyName, - this.mapping = const {}, - }); - - /// 从JSON创建ApiDiscriminator - factory ApiDiscriminator.fromJson(Map json) { - final mappingJson = json['mapping'] as Map? ?? {}; - final mapping = {}; - - mappingJson.forEach((key, value) { - if (value is String) { - mapping[key] = value; - } - }); - - return ApiDiscriminator( - propertyName: json['propertyName'] as String? ?? '', - mapping: mapping, - ); - } - - /// 检查是否有映射表 - bool get hasMapping => mapping.isNotEmpty; - - /// 根据值获取对应的 schema 引用 - String? getSchemaForValue(String value) => mapping[value]; -} - -/// API Schema 信息 (OpenAPI 3.0) -/// 表示一个 JSON Schema 对象,支持组合模式 -class ApiSchema { - /// Schema 类型 - final String? type; - - /// Schema 格式 - final String? format; - - /// Schema 描述 - final String description; - - /// 属性定义 (用于 object 类型) - final Map properties; - - /// 必需字段 - final List required; - - /// 数组项定义 (用于 array 类型) - final ApiSchema? items; - - /// 引用 ($ref) - final String? reference; - - /// 枚举值 - final List enumValues; - - /// 组合模式 - final List allOf; - final List oneOf; - final List anyOf; - final ApiSchema? not; - - /// 多态类型判别器 (OpenAPI 3.0) - final ApiDiscriminator? discriminator; - - /// 额外属性 (可以是 boolean 或 Schema) - final dynamic additionalProperties; - - /// 模式属性 (patternProperties) - final Map patternProperties; - - /// 属性名称约束 - final ApiSchema? propertyNames; - - /// 属性依赖关系 - final Map dependencies; - - /// 常量值 - final dynamic constValue; - - /// 条件 Schema (if/then/else) - final ApiSchema? ifSchema; - final ApiSchema? thenSchema; - final ApiSchema? elseSchema; - - /// 最小值/最大值 (用于数值类型) - final num? minimum; - final num? maximum; - final bool? exclusiveMinimum; - final bool? exclusiveMaximum; - - /// 字符串长度限制 - final int? minLength; - final int? maxLength; - final String? pattern; - - /// 数组长度限制 - final int? minItems; - final int? maxItems; - final bool? uniqueItems; - - /// 可空性 - final bool nullable; - - /// 示例值 - final dynamic example; - - /// 默认值 - final dynamic defaultValue; - - const ApiSchema({ - this.type, - this.format, - this.description = '', - this.properties = const {}, - this.required = const [], - this.items, - this.reference, - this.enumValues = const [], - this.allOf = const [], - this.oneOf = const [], - this.anyOf = const [], - this.not, - this.discriminator, - this.additionalProperties, - this.patternProperties = const {}, - this.propertyNames, - this.dependencies = const {}, - this.constValue, - this.ifSchema, - this.thenSchema, - this.elseSchema, - this.minimum, - this.maximum, - this.exclusiveMinimum, - this.exclusiveMaximum, - this.minLength, - this.maxLength, - this.pattern, - this.minItems, - this.maxItems, - this.uniqueItems, - this.nullable = false, - this.example, - this.defaultValue, - }); - - /// 从JSON创建ApiSchema - factory ApiSchema.fromJson(Map json) { - // 解析 properties - final propertiesJson = json['properties'] as Map? ?? {}; - final properties = {}; - final requiredFields = List.from(json['required'] ?? []); - - propertiesJson.forEach((propName, propData) { - if (propData is Map) { - properties[propName] = ApiProperty.fromJson( - propName, - propData, - requiredFields, - ); - } - }); - - // 解析 items (用于数组类型) - final itemsJson = json['items'] as Map?; - final items = itemsJson != null ? ApiSchema.fromJson(itemsJson) : null; - - // 解析组合模式 - final allOfJson = json['allOf'] as List? ?? []; - final allOf = allOfJson - .map((schema) => ApiSchema.fromJson(schema as Map)) - .toList(); - - final oneOfJson = json['oneOf'] as List? ?? []; - final oneOf = oneOfJson - .map((schema) => ApiSchema.fromJson(schema as Map)) - .toList(); - - final anyOfJson = json['anyOf'] as List? ?? []; - final anyOf = anyOfJson - .map((schema) => ApiSchema.fromJson(schema as Map)) - .toList(); - - final notJson = json['not'] as Map?; - final not = notJson != null ? ApiSchema.fromJson(notJson) : null; - - // 解析 discriminator - final discriminatorJson = json['discriminator'] as Map?; - final discriminator = discriminatorJson != null - ? ApiDiscriminator.fromJson(discriminatorJson) - : null; - - // 解析 patternProperties - final patternPropertiesJson = - json['patternProperties'] as Map? ?? {}; - final patternProperties = {}; - patternPropertiesJson.forEach((pattern, schemaData) { - if (schemaData is Map) { - patternProperties[pattern] = ApiSchema.fromJson(schemaData); - } - }); - - // 解析 propertyNames - final propertyNamesJson = json['propertyNames'] as Map?; - final propertyNames = propertyNamesJson != null - ? ApiSchema.fromJson(propertyNamesJson) - : null; - - // 解析 dependencies - final dependencies = json['dependencies'] as Map? ?? {}; - - // 解析条件 Schema (if/then/else) - final ifJson = json['if'] as Map?; - final ifSchema = ifJson != null ? ApiSchema.fromJson(ifJson) : null; - - final thenJson = json['then'] as Map?; - final thenSchema = thenJson != null ? ApiSchema.fromJson(thenJson) : null; - - final elseJson = json['else'] as Map?; - final elseSchema = elseJson != null ? ApiSchema.fromJson(elseJson) : null; - - // 处理引用 - String? reference; - if (json['\$ref'] != null) { - final ref = json['\$ref'] as String; - reference = ref.split('/').last; - } - - return ApiSchema( - type: json['type'] as String?, - format: json['format'] as String?, - description: json['description'] as String? ?? '', - properties: properties, - required: requiredFields, - items: items, - reference: reference, - enumValues: List.from(json['enum'] ?? []), - allOf: allOf, - oneOf: oneOf, - anyOf: anyOf, - not: not, - discriminator: discriminator, - additionalProperties: json['additionalProperties'], - patternProperties: patternProperties, - propertyNames: propertyNames, - dependencies: dependencies, - constValue: json['const'], - ifSchema: ifSchema, - thenSchema: thenSchema, - elseSchema: elseSchema, - minimum: json['minimum'] as num?, - maximum: json['maximum'] as num?, - exclusiveMinimum: json['exclusiveMinimum'] as bool?, - exclusiveMaximum: json['exclusiveMaximum'] as bool?, - minLength: json['minLength'] as int?, - maxLength: json['maxLength'] as int?, - pattern: json['pattern'] as String?, - minItems: json['minItems'] as int?, - maxItems: json['maxItems'] as int?, - uniqueItems: json['uniqueItems'] as bool?, - nullable: json['nullable'] as bool? ?? false, - example: json['example'], - defaultValue: json['default'], - ); - } - - /// 检查是否是组合模式 - bool get isComposition => - allOf.isNotEmpty || oneOf.isNotEmpty || anyOf.isNotEmpty; - - /// 检查是否是 allOf 组合 - bool get isAllOf => allOf.isNotEmpty; - - /// 检查是否是 oneOf 组合 - bool get isOneOf => oneOf.isNotEmpty; - - /// 检查是否是 anyOf 组合 - bool get isAnyOf => anyOf.isNotEmpty; - - /// 检查是否有 not 约束 - bool get hasNot => not != null; - - /// 检查是否有判别器 - bool get hasDiscriminator => discriminator != null; - - /// 检查是否是引用类型 - bool get isReference => reference != null; - - /// 检查是否是枚举类型 - bool get isEnum => enumValues.isNotEmpty; - - /// 检查是否是数组类型 - bool get isArray => type == 'array'; - - /// 检查是否是对象类型 - bool get isObject => type == 'object' || properties.isNotEmpty; - - /// 检查是否有模式属性 - bool get hasPatternProperties => patternProperties.isNotEmpty; - - /// 检查是否有属性名称约束 - bool get hasPropertyNames => propertyNames != null; - - /// 检查是否有属性依赖 - bool get hasDependencies => dependencies.isNotEmpty; - - /// 检查是否有常量值 - bool get hasConstValue => constValue != null; - - /// 检查是否有条件 Schema - bool get hasConditionalSchema => - ifSchema != null || thenSchema != null || elseSchema != null; - - /// 检查是否允许额外属性 - bool get allowsAdditionalProperties { - if (additionalProperties == null) return true; // 默认允许 - if (additionalProperties is bool) return additionalProperties as bool; - return true; // 如果是 Schema 对象,表示允许但有约束 - } - - /// 获取额外属性的 Schema(如果 additionalProperties 是 Schema 对象) - ApiSchema? get additionalPropertiesSchema { - if (additionalProperties is Map) { - return ApiSchema.fromJson(additionalProperties as Map); - } - return null; - } } /// API模型信息 @@ -1758,15 +348,6 @@ class ApiModel { final List enumValues; final PropertyType? enumType; - /// 组合模式支持 (OpenAPI 3.0) - final List allOf; - final List oneOf; - final List anyOf; - final ApiSchema? not; - - /// 多态类型判别器 (OpenAPI 3.0) - final ApiDiscriminator? discriminator; - const ApiModel({ required this.name, required this.description, @@ -1775,11 +356,6 @@ class ApiModel { this.isEnum = false, this.enumValues = const [], this.enumType, - this.allOf = const [], - this.oneOf = const [], - this.anyOf = const [], - this.not, - this.discriminator, }); /// 从JSON创建ApiModel @@ -1798,31 +374,6 @@ class ApiModel { .toList(); } - // 解析组合模式 - final allOfJson = json['allOf'] as List? ?? []; - final allOf = allOfJson - .map((schema) => ApiSchema.fromJson(schema as Map)) - .toList(); - - final oneOfJson = json['oneOf'] as List? ?? []; - final oneOf = oneOfJson - .map((schema) => ApiSchema.fromJson(schema as Map)) - .toList(); - - final anyOfJson = json['anyOf'] as List? ?? []; - final anyOf = anyOfJson - .map((schema) => ApiSchema.fromJson(schema as Map)) - .toList(); - - final notJson = json['not'] as Map?; - final not = notJson != null ? ApiSchema.fromJson(notJson) : null; - - // 解析 discriminator - final discriminatorJson = json['discriminator'] as Map?; - final discriminator = discriminatorJson != null - ? ApiDiscriminator.fromJson(discriminatorJson) - : null; - return ApiModel( name: name, description: json['description'] as String? ?? '', @@ -1832,11 +383,6 @@ class ApiModel { enumType: isEnum ? PropertyType.fromString(json['type'] as String? ?? 'string') : null, - allOf: allOf, - oneOf: oneOf, - anyOf: anyOf, - not: not, - discriminator: discriminator, properties: properties.map( (propName, propData) => MapEntry( propName, @@ -1849,25 +395,6 @@ class ApiModel { ), ); } - - /// 检查是否使用了组合模式 - bool get isComposition => - allOf.isNotEmpty || oneOf.isNotEmpty || anyOf.isNotEmpty; - - /// 检查是否是 allOf 组合 - bool get isAllOf => allOf.isNotEmpty; - - /// 检查是否是 oneOf 组合 - bool get isOneOf => oneOf.isNotEmpty; - - /// 检查是否是 anyOf 组合 - bool get isAnyOf => anyOf.isNotEmpty; - - /// 检查是否有 not 约束 - bool get hasNot => not != null; - - /// 检查是否有判别器 - bool get hasDiscriminator => discriminator != null; } /// API属性信息 @@ -1883,15 +410,6 @@ class ApiProperty { final String? reference; final ApiModel? items; // 用于数组类型 - /// 嵌套对象属性 (用于 object 类型) - final Map nestedProperties; - - /// 嵌套对象的必需字段 - final List nestedRequired; - - /// Schema 定义 (用于复杂类型) - final ApiSchema? schema; - const ApiProperty({ required this.name, required this.type, @@ -1903,35 +421,17 @@ class ApiProperty { this.defaultValue, this.reference, this.items, - this.nestedProperties = const {}, - this.nestedRequired = const [], - this.schema, }); /// 从JSON创建ApiProperty factory ApiProperty.fromJson( String name, Map json, - List requiredFields, { - int maxDepth = 10, - int currentDepth = 0, - }) { - // 防止过深的嵌套 - if (currentDepth >= maxDepth) { - return ApiProperty( - name: name, - type: PropertyType.object, - description: '达到最大嵌套深度的对象', - required: requiredFields.contains(name), - ); - } - + List requiredFields, + ) { final type = PropertyType.fromString(json['type'] as String? ?? 'string'); String? reference; ApiModel? items; - final Map nestedProperties = {}; - List nestedRequired = []; - ApiSchema? schema; // 处理引用类型 if (json['\$ref'] != null) { @@ -1939,42 +439,6 @@ class ApiProperty { reference = ref.split('/').last; } - // 处理复杂 schema(组合模式等) - if (json['allOf'] != null || - json['oneOf'] != null || - json['anyOf'] != null) { - schema = ApiSchema.fromJson(json); - } - - // 处理嵌套对象类型 - if (type == PropertyType.object && json['properties'] != null) { - final propertiesJson = json['properties'] as Map; - nestedRequired = List.from(json['required'] ?? []); - - propertiesJson.forEach((propName, propData) { - if (propData is Map) { - try { - final nestedProperty = ApiProperty.fromJson( - propName, - propData, - nestedRequired, - maxDepth: maxDepth, - currentDepth: currentDepth + 1, - ); - nestedProperties[propName] = nestedProperty; - } catch (e) { - // 如果解析嵌套属性失败,创建一个基本属性 - nestedProperties[propName] = ApiProperty( - name: propName, - type: PropertyType.string, - description: '解析失败的嵌套属性', - required: nestedRequired.contains(propName), - ); - } - } - }); - } - // 处理数组类型的 items if (type == PropertyType.array && json['items'] != null) { final itemsJson = json['items'] as Map; @@ -1990,43 +454,6 @@ class ApiProperty { required: [], isEnum: false, ); - } else if (itemsJson['type'] == 'object' && - itemsJson['properties'] != null) { - // 如果 items 是嵌套对象 - final itemProperties = {}; - final itemRequired = List.from(itemsJson['required'] ?? []); - final itemPropertiesJson = - itemsJson['properties'] as Map; - - itemPropertiesJson.forEach((propName, propData) { - if (propData is Map) { - try { - final itemProperty = ApiProperty.fromJson( - propName, - propData, - itemRequired, - maxDepth: maxDepth, - currentDepth: currentDepth + 1, - ); - itemProperties[propName] = itemProperty; - } catch (e) { - // 创建基本属性作为后备 - itemProperties[propName] = ApiProperty( - name: propName, - type: PropertyType.string, - description: '解析失败的数组项属性', - required: itemRequired.contains(propName), - ); - } - } - }); - - items = ApiModel( - name: '${name}Item', - description: itemsJson['description'] as String? ?? '', - properties: itemProperties, - required: itemRequired, - ); } else { // 如果 items 是基本类型 final itemType = @@ -2052,17 +479,8 @@ class ApiProperty { defaultValue: json['default'], reference: reference, items: items, - nestedProperties: nestedProperties, - nestedRequired: nestedRequired, - schema: schema, ); } - - /// 检查是否有嵌套属性 - bool get hasNestedProperties => nestedProperties.isNotEmpty; - - /// 检查是否有复杂 schema - bool get hasComplexSchema => schema != null; } /// API控制器信息 @@ -2082,280 +500,3 @@ class ApiController { return ApiController(name: name, description: name, paths: paths); } } - -/// 安全方案类型 -enum SecuritySchemeType { - apiKey, - http, - oauth2, - openIdConnect, -} - -extension SecuritySchemeTypeExtension on SecuritySchemeType { - String get value { - switch (this) { - case SecuritySchemeType.apiKey: - return 'apiKey'; - case SecuritySchemeType.http: - return 'http'; - case SecuritySchemeType.oauth2: - return 'oauth2'; - case SecuritySchemeType.openIdConnect: - return 'openIdConnect'; - } - } - - static SecuritySchemeType fromString(String value) { - switch (value.toLowerCase()) { - case 'apikey': - return SecuritySchemeType.apiKey; - case 'http': - return SecuritySchemeType.http; - case 'oauth2': - return SecuritySchemeType.oauth2; - case 'openidconnect': - return SecuritySchemeType.openIdConnect; - default: - return SecuritySchemeType.apiKey; - } - } -} - -/// API Key 位置 -enum ApiKeyLocation { - query, - header, - cookie, -} - -extension ApiKeyLocationExtension on ApiKeyLocation { - String get value { - switch (this) { - case ApiKeyLocation.query: - return 'query'; - case ApiKeyLocation.header: - return 'header'; - case ApiKeyLocation.cookie: - return 'cookie'; - } - } - - static ApiKeyLocation fromString(String value) { - switch (value.toLowerCase()) { - case 'query': - return ApiKeyLocation.query; - case 'header': - return ApiKeyLocation.header; - case 'cookie': - return ApiKeyLocation.cookie; - default: - return ApiKeyLocation.header; - } - } -} - -/// OAuth2 流程类型 -enum OAuth2FlowType { - authorizationCode, - implicit, - password, - clientCredentials, -} - -extension OAuth2FlowTypeExtension on OAuth2FlowType { - String get value { - switch (this) { - case OAuth2FlowType.authorizationCode: - return 'authorizationCode'; - case OAuth2FlowType.implicit: - return 'implicit'; - case OAuth2FlowType.password: - return 'password'; - case OAuth2FlowType.clientCredentials: - return 'clientCredentials'; - } - } - - static OAuth2FlowType fromString(String value) { - switch (value.toLowerCase()) { - case 'authorizationcode': - return OAuth2FlowType.authorizationCode; - case 'implicit': - return OAuth2FlowType.implicit; - case 'password': - return OAuth2FlowType.password; - case 'clientcredentials': - return OAuth2FlowType.clientCredentials; - default: - return OAuth2FlowType.authorizationCode; - } - } -} - -/// OAuth2 流程配置 -class OAuth2Flow { - /// 授权 URL (用于 authorizationCode 和 implicit 流程) - final String? authorizationUrl; - - /// 令牌 URL (用于 authorizationCode, password 和 clientCredentials 流程) - final String? tokenUrl; - - /// 刷新 URL (可选) - final String? refreshUrl; - - /// 可用的作用域 - final Map scopes; - - const OAuth2Flow({ - this.authorizationUrl, - this.tokenUrl, - this.refreshUrl, - this.scopes = const {}, - }); - - /// 从 JSON 创建 OAuth2Flow - factory OAuth2Flow.fromJson(Map json) { - final scopesData = json['scopes']; - final Map scopes; - - if (scopesData is Map) { - scopes = scopesData - .map((key, value) => MapEntry(key.toString(), value.toString())); - } else { - scopes = {}; - } - - return OAuth2Flow( - authorizationUrl: json['authorizationUrl'] as String?, - tokenUrl: json['tokenUrl'] as String?, - refreshUrl: json['refreshUrl'] as String?, - scopes: scopes, - ); - } - - /// 检查是否有授权 URL - bool get hasAuthorizationUrl => - authorizationUrl != null && authorizationUrl!.isNotEmpty; - - /// 检查是否有令牌 URL - bool get hasTokenUrl => tokenUrl != null && tokenUrl!.isNotEmpty; - - /// 检查是否有刷新 URL - bool get hasRefreshUrl => refreshUrl != null && refreshUrl!.isNotEmpty; - - /// 检查是否有作用域 - bool get hasScopes => scopes.isNotEmpty; -} - -/// OAuth2 流程集合 -class OAuth2Flows { - /// 授权码流程 - final OAuth2Flow? authorizationCode; - - /// 隐式流程 - final OAuth2Flow? implicit; - - /// 密码流程 - final OAuth2Flow? password; - - /// 客户端凭证流程 - final OAuth2Flow? clientCredentials; - - const OAuth2Flows({ - this.authorizationCode, - this.implicit, - this.password, - this.clientCredentials, - }); - - /// 从 JSON 创建 OAuth2Flows - factory OAuth2Flows.fromJson(Map json) { - return OAuth2Flows( - authorizationCode: json['authorizationCode'] != null - ? OAuth2Flow.fromJson( - json['authorizationCode'] as Map) - : null, - implicit: json['implicit'] != null - ? OAuth2Flow.fromJson(json['implicit'] as Map) - : null, - password: json['password'] != null - ? OAuth2Flow.fromJson(json['password'] as Map) - : null, - clientCredentials: json['clientCredentials'] != null - ? OAuth2Flow.fromJson( - json['clientCredentials'] as Map) - : null, - ); - } - - /// 获取所有可用的流程 - List get availableFlows { - final flows = []; - if (authorizationCode != null) flows.add(OAuth2FlowType.authorizationCode); - if (implicit != null) flows.add(OAuth2FlowType.implicit); - if (password != null) flows.add(OAuth2FlowType.password); - if (clientCredentials != null) flows.add(OAuth2FlowType.clientCredentials); - return flows; - } - - /// 检查是否有任何流程 - bool get hasAnyFlow => availableFlows.isNotEmpty; - - /// 获取指定类型的流程 - OAuth2Flow? getFlow(OAuth2FlowType type) { - switch (type) { - case OAuth2FlowType.authorizationCode: - return authorizationCode; - case OAuth2FlowType.implicit: - return implicit; - case OAuth2FlowType.password: - return password; - case OAuth2FlowType.clientCredentials: - return clientCredentials; - } - } -} - -/// 安全要求 (单个安全方案的要求) -class ApiSecurityRequirement { - /// 安全方案名称到作用域列表的映射 - final Map> requirements; - - const ApiSecurityRequirement({ - this.requirements = const {}, - }); - - /// 从 JSON 创建 ApiSecurityRequirement - factory ApiSecurityRequirement.fromJson(Map json) { - final requirements = >{}; - - json.forEach((schemeName, scopes) { - if (scopes is List) { - requirements[schemeName] = List.from(scopes); - } else { - requirements[schemeName] = []; - } - }); - - return ApiSecurityRequirement(requirements: requirements); - } - - /// 检查是否为空 - bool get isEmpty => requirements.isEmpty; - - /// 检查是否非空 - bool get isNotEmpty => requirements.isNotEmpty; - - /// 获取所有安全方案名称 - List get schemeNames => requirements.keys.toList(); - - /// 获取指定方案的作用域 - List getScopesForScheme(String schemeName) { - return requirements[schemeName] ?? []; - } - - /// 检查是否包含指定的安全方案 - bool hasScheme(String schemeName) { - return requirements.containsKey(schemeName); - } -} diff --git a/lib/core/performance_parser.dart b/lib/core/performance_parser.dart deleted file mode 100644 index a485c88..0000000 --- a/lib/core/performance_parser.dart +++ /dev/null @@ -1,471 +0,0 @@ -/// 高性能 OpenAPI 解析器 -/// 支持流式解析、并行处理和增量解析 -library; - -import 'dart:async'; -import 'dart:convert'; -import 'models.dart'; - -/// 解析性能统计 -class ParsePerformanceStats { - final Duration totalTime; - final Duration parseTime; - final Duration validationTime; - final Duration modelCreationTime; - final int memoryUsage; - final int documentSize; - final int pathCount; - final int schemaCount; - - const ParsePerformanceStats({ - required this.totalTime, - required this.parseTime, - required this.validationTime, - required this.modelCreationTime, - required this.memoryUsage, - required this.documentSize, - required this.pathCount, - required this.schemaCount, - }); - - double get pathsPerSecond => pathCount / totalTime.inMilliseconds * 1000; - double get schemasPerSecond => schemaCount / totalTime.inMilliseconds * 1000; - double get bytesPerSecond => documentSize / totalTime.inMilliseconds * 1000; - - @override - String toString() { - return ''' -Performance Statistics: - Total Time: ${totalTime.inMilliseconds}ms - Parse Time: ${parseTime.inMilliseconds}ms - Validation Time: ${validationTime.inMilliseconds}ms - Model Creation Time: ${modelCreationTime.inMilliseconds}ms - Memory Usage: ${(memoryUsage / 1024 / 1024).toStringAsFixed(2)}MB - Document Size: ${(documentSize / 1024).toStringAsFixed(2)}KB - Paths: $pathCount (${pathsPerSecond.toStringAsFixed(1)}/s) - Schemas: $schemaCount (${schemasPerSecond.toStringAsFixed(1)}/s) - Throughput: ${(bytesPerSecond / 1024).toStringAsFixed(2)}KB/s -'''; - } -} - -/// 解析配置 -class ParseConfig { - /// 是否启用并行解析 - final bool enableParallelParsing; - - /// 是否启用流式解析 - final bool enableStreamParsing; - - /// 是否启用增量解析 - final bool enableIncrementalParsing; - - /// 是否启用缓存 - final bool enableCaching; - - /// 最大并行度 - final int maxConcurrency; - - /// 流式解析缓冲区大小 - final int streamBufferSize; - - /// 是否启用性能统计 - final bool enablePerformanceStats; - - /// 是否启用内存优化 - final bool enableMemoryOptimization; - - const ParseConfig({ - this.enableParallelParsing = true, - this.enableStreamParsing = false, - this.enableIncrementalParsing = false, - this.enableCaching = true, - this.maxConcurrency = 4, - this.streamBufferSize = 8192, - this.enablePerformanceStats = false, - this.enableMemoryOptimization = true, - }); -} - -/// 高性能解析器 -class PerformanceParser { - final ParseConfig _config; - final Map _cache = {}; - ParsePerformanceStats? _lastStats; - - PerformanceParser({ParseConfig? config}) - : _config = config ?? const ParseConfig(); - - /// 获取最后一次解析的性能统计 - ParsePerformanceStats? get lastStats => _lastStats; - - /// 解析 OpenAPI 文档 - Future parseDocument(String jsonString) async { - final stopwatch = Stopwatch()..start(); - final parseStopwatch = Stopwatch(); - final validationStopwatch = Stopwatch(); - final modelCreationStopwatch = Stopwatch(); - - try { - // 解析 JSON - parseStopwatch.start(); - final Map json; - - if (_config.enableStreamParsing && - jsonString.length > _config.streamBufferSize) { - json = await _parseJsonStream(jsonString); - } else { - json = jsonDecode(jsonString) as Map; - } - parseStopwatch.stop(); - - // 验证基础结构 - validationStopwatch.start(); - _validateBasicStructure(json); - validationStopwatch.stop(); - - // 创建模型 - modelCreationStopwatch.start(); - final SwaggerDocument document; - - if (_config.enableParallelParsing) { - document = await _parseDocumentParallel(json); - } else { - document = SwaggerDocument.fromJson(json); - } - modelCreationStopwatch.stop(); - - stopwatch.stop(); - - // 生成性能统计 - if (_config.enablePerformanceStats) { - _lastStats = ParsePerformanceStats( - totalTime: stopwatch.elapsed, - parseTime: parseStopwatch.elapsed, - validationTime: validationStopwatch.elapsed, - modelCreationTime: modelCreationStopwatch.elapsed, - memoryUsage: _getMemoryUsage(), - documentSize: jsonString.length, - pathCount: document.paths.length, - schemaCount: document.components.schemas.length, - ); - } - - return document; - } catch (e) { - stopwatch.stop(); - rethrow; - } - } - - /// 流式 JSON 解析 - Future> _parseJsonStream(String jsonString) async { - final completer = Completer>(); - final controller = StreamController(); - - // 模拟流式解析(实际实现会更复杂) - final chunks = []; - for (int i = 0; i < jsonString.length; i += _config.streamBufferSize) { - final end = (i + _config.streamBufferSize).clamp(0, jsonString.length); - chunks.add(jsonString.substring(i, end)); - } - - controller.stream.listen( - (chunk) { - // 处理 JSON 块 - }, - onDone: () { - try { - final result = jsonDecode(jsonString) as Map; - completer.complete(result); - } catch (e) { - completer.completeError(e); - } - }, - onError: completer.completeError, - ); - - // 添加所有块 - for (final chunk in chunks) { - controller.add(chunk); - } - controller.close(); - - return completer.future; - } - - /// 并行解析文档 - Future _parseDocumentParallel( - Map json) async { - final futures = []; - final results = {}; - - // 并行解析不同部分 - if (json.containsKey('paths')) { - futures.add(_parsePathsParallel(json['paths'] as Map) - .then((paths) => results['paths'] = paths)); - } - - if (json.containsKey('components')) { - futures.add( - _parseComponentsParallel(json['components'] as Map) - .then((components) => results['components'] = components)); - } - - if (json.containsKey('servers')) { - futures.add(_parseServersParallel(json['servers'] as List) - .then((servers) => results['servers'] = servers)); - } - - // 等待所有并行任务完成 - await Future.wait(futures); - - // 合并结果 - final mergedJson = Map.from(json); - mergedJson.addAll(results); - - return SwaggerDocument.fromJson(mergedJson); - } - - /// 并行解析路径 - Future> _parsePathsParallel( - Map pathsJson) async { - if (pathsJson.length <= _config.maxConcurrency) { - // 如果路径数量较少,直接解析 - return _parsePathsSequential(pathsJson); - } - - final chunks = _chunkMap(pathsJson, _config.maxConcurrency); - final futures = chunks.map((chunk) => _parsePathChunk(chunk)); - final results = await Future.wait(futures); - - // 合并结果 - final mergedPaths = {}; - for (final pathMap in results) { - mergedPaths.addAll(pathMap); - } - - return mergedPaths; - } - - /// 并行解析组件 - Future _parseComponentsParallel( - Map componentsJson) async { - final futures = []; - final results = {}; - - if (componentsJson.containsKey('schemas')) { - futures.add(_parseSchemasParallel( - componentsJson['schemas'] as Map) - .then((schemas) => results['schemas'] = schemas)); - } - - if (componentsJson.containsKey('securitySchemes')) { - futures.add(_parseSecuritySchemesParallel( - componentsJson['securitySchemes'] as Map) - .then((schemes) => results['securitySchemes'] = schemes)); - } - - await Future.wait(futures); - - final mergedComponents = Map.from(componentsJson); - mergedComponents.addAll(results); - - return ApiComponents.fromJson(mergedComponents); - } - - /// 并行解析服务器 - Future> _parseServersParallel( - List serversJson) async { - if (serversJson.length <= _config.maxConcurrency) { - return serversJson - .map((json) => ApiServer.fromJson(json as Map)) - .toList(); - } - - final chunks = _chunkList(serversJson, _config.maxConcurrency); - final futures = chunks.map((chunk) => _parseServerChunk(chunk)); - final results = await Future.wait(futures); - - // 合并结果 - final mergedServers = []; - for (final serverList in results) { - mergedServers.addAll(serverList); - } - - return mergedServers; - } - - /// 解析路径块 - Future> _parsePathChunk( - Map pathChunk) async { - return _parsePathsSequential(pathChunk); - } - - /// 解析服务器块 - Future> _parseServerChunk(List serverChunk) async { - return serverChunk - .map((json) => ApiServer.fromJson(json as Map)) - .toList(); - } - - /// 顺序解析路径 - Map _parsePathsSequential(Map pathsJson) { - final paths = {}; - - pathsJson.forEach((pathPattern, pathData) { - if (pathData is Map) { - pathData.forEach((method, operationData) { - if (operationData is Map) { - try { - final apiPath = - ApiPath.fromJson(pathPattern, method, operationData); - paths[pathPattern] = apiPath; - } catch (e) { - // 忽略解析错误的路径 - } - } - }); - } - }); - - return paths; - } - - /// 并行解析 Schemas - Future> _parseSchemasParallel( - Map schemasJson) async { - if (schemasJson.length <= _config.maxConcurrency) { - return _parseSchemasSequential(schemasJson); - } - - final chunks = _chunkMap(schemasJson, _config.maxConcurrency); - final futures = chunks.map((chunk) => _parseSchemaChunk(chunk)); - final results = await Future.wait(futures); - - // 合并结果 - final mergedSchemas = {}; - for (final schemaMap in results) { - mergedSchemas.addAll(schemaMap); - } - - return mergedSchemas; - } - - /// 并行解析安全方案 - Future> _parseSecuritySchemesParallel( - Map schemesJson) async { - final schemes = {}; - - schemesJson.forEach((name, schemeData) { - if (schemeData is Map) { - try { - final scheme = ApiSecurityScheme.fromJson(schemeData); - schemes[name] = scheme; - } catch (e) { - // 忽略解析错误的安全方案 - } - } - }); - - return schemes; - } - - /// 解析 Schema 块 - Future> _parseSchemaChunk( - Map schemaChunk) async { - return _parseSchemasSequential(schemaChunk); - } - - /// 顺序解析 Schemas - Map _parseSchemasSequential( - Map schemasJson) { - final schemas = {}; - - schemasJson.forEach((name, schemaData) { - if (schemaData is Map) { - try { - final model = ApiModel.fromJson(name, schemaData); - schemas[name] = model; - } catch (e) { - // 忽略解析错误的 schema - } - } - }); - - return schemas; - } - - /// 验证基础结构 - void _validateBasicStructure(Map json) { - if (!json.containsKey('openapi') && !json.containsKey('swagger')) { - throw const FormatException( - 'Invalid OpenAPI document: missing version field'); - } - - if (!json.containsKey('info')) { - throw const FormatException( - 'Invalid OpenAPI document: missing info object'); - } - - final info = json['info'] as Map?; - if (info == null || - !info.containsKey('title') || - !info.containsKey('version')) { - throw const FormatException( - 'Invalid OpenAPI document: info object must contain title and version'); - } - } - - /// 将 Map 分块 - List> _chunkMap( - Map map, int chunkSize) { - final chunks = >[]; - final entries = map.entries.toList(); - - for (int i = 0; i < entries.length; i += chunkSize) { - final end = (i + chunkSize).clamp(0, entries.length); - final chunk = {}; - - for (int j = i; j < end; j++) { - final entry = entries[j]; - chunk[entry.key] = entry.value; - } - - chunks.add(chunk); - } - - return chunks; - } - - /// 将 List 分块 - List> _chunkList(List list, int chunkSize) { - final chunks = >[]; - - for (int i = 0; i < list.length; i += chunkSize) { - final end = (i + chunkSize).clamp(0, list.length); - chunks.add(list.sublist(i, end)); - } - - return chunks; - } - - /// 获取内存使用量(简化实现) - int _getMemoryUsage() { - // 在实际实现中,这里会使用 dart:developer 或其他方式获取真实的内存使用量 - return 0; - } - - /// 清除缓存 - void clearCache() { - _cache.clear(); - } - - /// 获取缓存统计 - Map getCacheStats() { - return { - 'size': _cache.length, - 'keys': _cache.keys.toList(), - }; - } -} diff --git a/lib/core/smart_cache.dart b/lib/core/smart_cache.dart deleted file mode 100644 index 1d31d68..0000000 --- a/lib/core/smart_cache.dart +++ /dev/null @@ -1,444 +0,0 @@ -/// 智能缓存系统 -/// 支持智能失效、增量解析和内存管理 -library; - -import 'dart:async'; - -/// 缓存条目 -class CacheEntry { - final String key; - final T value; - final DateTime createdAt; - final DateTime lastAccessedAt; - final Duration ttl; - final String? etag; - final int? version; - final Map metadata; - - CacheEntry({ - required this.key, - required this.value, - required this.createdAt, - DateTime? lastAccessedAt, - this.ttl = const Duration(hours: 1), - this.etag, - this.version, - this.metadata = const {}, - }) : lastAccessedAt = lastAccessedAt ?? createdAt; - - /// 是否已过期 - bool get isExpired => DateTime.now().difference(createdAt) > ttl; - - /// 是否需要刷新 - bool get needsRefresh => - DateTime.now().difference(lastAccessedAt) > - Duration(minutes: ttl.inMinutes ~/ 2); - - /// 创建更新的条目 - CacheEntry withAccess() { - return CacheEntry( - key: key, - value: value, - createdAt: createdAt, - lastAccessedAt: DateTime.now(), - ttl: ttl, - etag: etag, - version: version, - metadata: metadata, - ); - } - - /// 创建新版本的条目 - CacheEntry withValue(T newValue, {String? newEtag, int? newVersion}) { - return CacheEntry( - key: key, - value: newValue, - createdAt: DateTime.now(), - lastAccessedAt: DateTime.now(), - ttl: ttl, - etag: newEtag ?? etag, - version: newVersion ?? ((version ?? 0) + 1), - metadata: metadata, - ); - } -} - -/// 缓存策略 -enum CacheStrategy { - /// 最近最少使用 - lru, - - /// 最近最常使用 - lfu, - - /// 先进先出 - fifo, - - /// 基于时间的过期 - ttl, - - /// 智能策略(结合多种因素) - smart, -} - -/// 缓存统计 -class CacheStats { - final int totalRequests; - final int hits; - final int misses; - final int evictions; - final int size; - final int maxSize; - final Duration averageAccessTime; - final Map keyAccessCounts; - - const CacheStats({ - required this.totalRequests, - required this.hits, - required this.misses, - required this.evictions, - required this.size, - required this.maxSize, - required this.averageAccessTime, - required this.keyAccessCounts, - }); - - double get hitRate => totalRequests > 0 ? hits / totalRequests : 0.0; - double get missRate => totalRequests > 0 ? misses / totalRequests : 0.0; - double get fillRate => maxSize > 0 ? size / maxSize : 0.0; - - @override - String toString() { - return ''' -Cache Statistics: - Total Requests: $totalRequests - Hits: $hits (${(hitRate * 100).toStringAsFixed(1)}%) - Misses: $misses (${(missRate * 100).toStringAsFixed(1)}%) - Evictions: $evictions - Size: $size / $maxSize (${(fillRate * 100).toStringAsFixed(1)}%) - Average Access Time: ${averageAccessTime.inMicroseconds}μs - Most Accessed Keys: ${_getTopKeys()} -'''; - } - - String _getTopKeys() { - final sorted = keyAccessCounts.entries.toList() - ..sort((a, b) => b.value.compareTo(a.value)); - return sorted.take(5).map((e) => '${e.key}(${e.value})').join(', '); - } -} - -/// 智能缓存管理器 -class SmartCache { - final int _maxSize; - final CacheStrategy _strategy; - final Duration _defaultTtl; - final bool _enablePersistence; - - final Map> _cache = {}; - final Map _accessCounts = {}; - final Map _lastAccess = {}; - final List _accessOrder = []; - - int _totalRequests = 0; - int _hits = 0; - int _misses = 0; - int _evictions = 0; - final List _accessTimes = []; - - SmartCache({ - int maxSize = 1000, - CacheStrategy strategy = CacheStrategy.smart, - Duration defaultTtl = const Duration(hours: 1), - bool enablePersistence = false, - }) : _maxSize = maxSize, - _strategy = strategy, - _defaultTtl = defaultTtl, - _enablePersistence = enablePersistence; - - /// 获取缓存值 - T? get(String key) { - final stopwatch = Stopwatch()..start(); - _totalRequests++; - - final entry = _cache[key]; - if (entry == null) { - _misses++; - stopwatch.stop(); - _accessTimes.add(stopwatch.elapsed); - return null; - } - - // 检查是否过期 - if (entry.isExpired) { - _cache.remove(key); - _accessCounts.remove(key); - _lastAccess.remove(key); - _accessOrder.remove(key); - _misses++; - stopwatch.stop(); - _accessTimes.add(stopwatch.elapsed); - return null; - } - - // 更新访问统计 - _hits++; - _updateAccessStats(key); - _cache[key] = entry.withAccess(); - - stopwatch.stop(); - _accessTimes.add(stopwatch.elapsed); - return entry.value; - } - - /// 设置缓存值 - void put(String key, T value, - {Duration? ttl, String? etag, Map? metadata}) { - final entry = CacheEntry( - key: key, - value: value, - createdAt: DateTime.now(), - ttl: ttl ?? _defaultTtl, - etag: etag, - metadata: metadata ?? {}, - ); - - // 如果缓存已满,执行驱逐策略 - if (_cache.length >= _maxSize && !_cache.containsKey(key)) { - _evict(); - } - - _cache[key] = entry; - _updateAccessStats(key); - } - - /// 检查是否存在且未过期 - bool containsKey(String key) { - final entry = _cache[key]; - if (entry == null) return false; - - if (entry.isExpired) { - _cache.remove(key); - _accessCounts.remove(key); - _lastAccess.remove(key); - _accessOrder.remove(key); - return false; - } - - return true; - } - - /// 移除缓存项 - T? remove(String key) { - final entry = _cache.remove(key); - _accessCounts.remove(key); - _lastAccess.remove(key); - _accessOrder.remove(key); - return entry?.value; - } - - /// 清空缓存 - void clear() { - _cache.clear(); - _accessCounts.clear(); - _lastAccess.clear(); - _accessOrder.clear(); - } - - /// 获取缓存统计 - CacheStats getStats() { - final avgAccessTime = _accessTimes.isNotEmpty - ? Duration( - microseconds: _accessTimes - .map((d) => d.inMicroseconds) - .reduce((a, b) => a + b) ~/ - _accessTimes.length) - : Duration.zero; - - return CacheStats( - totalRequests: _totalRequests, - hits: _hits, - misses: _misses, - evictions: _evictions, - size: _cache.length, - maxSize: _maxSize, - averageAccessTime: avgAccessTime, - keyAccessCounts: Map.from(_accessCounts), - ); - } - - /// 获取需要刷新的键 - List getKeysNeedingRefresh() { - return _cache.entries - .where((entry) => entry.value.needsRefresh) - .map((entry) => entry.key) - .toList(); - } - - /// 批量刷新 - Future refreshKeys( - List keys, Future Function(String key) refreshFunction) async { - final futures = keys.map((key) async { - try { - final newValue = await refreshFunction(key); - final oldEntry = _cache[key]; - if (oldEntry != null) { - _cache[key] = oldEntry.withValue(newValue); - } - } catch (e) { - // 刷新失败,保留旧值 - } - }); - - await Future.wait(futures); - } - - /// 预热缓存 - Future warmUp(Map Function()> warmUpFunctions) async { - final futures = warmUpFunctions.entries.map((entry) async { - try { - final value = await entry.value(); - put(entry.key, value); - } catch (e) { - // 预热失败,忽略 - } - }); - - await Future.wait(futures); - } - - /// 更新访问统计 - void _updateAccessStats(String key) { - _accessCounts[key] = (_accessCounts[key] ?? 0) + 1; - _lastAccess[key] = DateTime.now(); - - // 更新访问顺序 - _accessOrder.remove(key); - _accessOrder.add(key); - } - - /// 执行驱逐策略 - void _evict() { - if (_cache.isEmpty) return; - - String? keyToEvict; - - switch (_strategy) { - case CacheStrategy.lru: - keyToEvict = _evictLRU(); - break; - case CacheStrategy.lfu: - keyToEvict = _evictLFU(); - break; - case CacheStrategy.fifo: - keyToEvict = _evictFIFO(); - break; - case CacheStrategy.ttl: - keyToEvict = _evictTTL(); - break; - case CacheStrategy.smart: - keyToEvict = _evictSmart(); - break; - } - - if (keyToEvict != null) { - remove(keyToEvict); - _evictions++; - } - } - - /// LRU 驱逐 - String? _evictLRU() { - if (_accessOrder.isEmpty) return null; - return _accessOrder.first; - } - - /// LFU 驱逐 - String? _evictLFU() { - if (_accessCounts.isEmpty) return null; - - final sorted = _accessCounts.entries.toList() - ..sort((a, b) => a.value.compareTo(b.value)); - - return sorted.first.key; - } - - /// FIFO 驱逐 - String? _evictFIFO() { - if (_cache.isEmpty) return null; - - final sorted = _cache.entries.toList() - ..sort((a, b) => a.value.createdAt.compareTo(b.value.createdAt)); - - return sorted.first.key; - } - - /// TTL 驱逐 - String? _evictTTL() { - // 首先尝试驱逐已过期的项 - for (final entry in _cache.entries) { - if (entry.value.isExpired) { - return entry.key; - } - } - - // 如果没有过期项,驱逐最早创建的 - return _evictFIFO(); - } - - /// 智能驱逐 - String? _evictSmart() { - if (_cache.isEmpty) return null; - - // 计算每个项的驱逐分数(越高越应该被驱逐) - final scores = {}; - final now = DateTime.now(); - - for (final entry in _cache.entries) { - final key = entry.key; - final cacheEntry = entry.value; - - // 时间因子(越老分数越高) - final ageFactor = now.difference(cacheEntry.createdAt).inMinutes / 60.0; - - // 访问频率因子(访问越少分数越高) - final accessCount = _accessCounts[key] ?? 1; - final frequencyFactor = 1.0 / accessCount; - - // 最近访问因子(越久未访问分数越高) - final lastAccess = _lastAccess[key] ?? cacheEntry.createdAt; - final recencyFactor = now.difference(lastAccess).inMinutes / 60.0; - - // 过期因子 - final expireFactor = cacheEntry.isExpired ? 10.0 : 0.0; - - // 综合分数 - scores[key] = ageFactor * 0.3 + - frequencyFactor * 0.3 + - recencyFactor * 0.3 + - expireFactor; - } - - // 返回分数最高的键 - final sorted = scores.entries.toList() - ..sort((a, b) => b.value.compareTo(a.value)); - - return sorted.first.key; - } - - /// 持久化缓存(简化实现) - Future persist() async { - if (!_enablePersistence) return; - - // 这里应该将缓存数据写入文件或数据库 - // 实际实现会更复杂 - } - - /// 从持久化存储加载缓存(简化实现) - Future load() async { - if (!_enablePersistence) return; - - // 这里应该从文件或数据库读取缓存数据 - // 实际实现会更复杂 - } -} diff --git a/lib/generators/documentation_generator.dart b/lib/generators/documentation_generator.dart index 6acc7f8..e171573 100644 --- a/lib/generators/documentation_generator.dart +++ b/lib/generators/documentation_generator.dart @@ -141,27 +141,19 @@ class DocumentationGenerator extends BaseGenerator { buffer.writeln(''); // 支持的格式 - buffer.writeln('### 🌐 服务器配置'); + buffer.writeln('### 📝 支持的格式'); buffer.writeln(''); - if (document.servers.isNotEmpty) { - for (final server in document.servers) { - buffer.writeln('**服务器**: `${server.url}`'); - if (server.description.isNotEmpty) { - buffer.writeln('- ${server.description}'); - } - if (server.variables.isNotEmpty) { - buffer.writeln('- 变量:'); - server.variables.forEach((name, variable) { - buffer.writeln( - ' - `$name`: ${variable.description} (默认: ${variable.defaultValue})'); - }); - } - buffer.writeln(''); - } - } else { - buffer.writeln('**服务器**: 相对路径 `/`'); - buffer.writeln(''); + buffer.writeln('**请求格式**:'); + for (final format in document.consumes) { + buffer.writeln('- `$format`'); } + buffer.writeln(''); + + buffer.writeln('**响应格式**:'); + for (final format in document.produces) { + buffer.writeln('- `$format`'); + } + buffer.writeln(''); } /// 生成认证信息 @@ -598,12 +590,11 @@ class DocumentationGenerator extends BaseGenerator { // 已移动到 StringUtils.extractControllerName - /// 获取基础URL (从 OpenAPI 3.0 servers 配置) + /// 获取基础URL String _getBaseUrl() { - if (document.servers.isNotEmpty) { - return document.servers.first.url; - } - return '/'; // 默认相对路径 + return document.schemes.isNotEmpty + ? '${document.schemes.first}://${document.host}${document.basePath}' + : 'https://${document.host}${document.basePath}'; } /// 获取参数位置名称 diff --git a/lib/generators/endpoint_code_generator.dart b/lib/generators/endpoint_code_generator.dart index 326cdaf..9b41b63 100644 --- a/lib/generators/endpoint_code_generator.dart +++ b/lib/generators/endpoint_code_generator.dart @@ -33,10 +33,12 @@ class EndpointCodeGenerator extends BaseGenerator { buffer.writeln(' ApiPaths._(); // 私有构造函数,防止实例化'); buffer.writeln(''); - // 生成基础URL常量 (从 OpenAPI 3.0 servers 配置) + // 生成基础URL常量 if (includeBaseUrl) { final baseUrl = customBaseUrl ?? - (document.servers.isNotEmpty ? document.servers.first.url : '/'); + (document.schemes.isNotEmpty + ? '${document.schemes.first}://${document.host}${document.basePath}' + : 'https://${document.host}${document.basePath}'); buffer.writeln(' /// 基础URL'); buffer.writeln(' static const String baseUrl = \'$baseUrl\';'); diff --git a/lib/generators/model_code_generator.dart b/lib/generators/model_code_generator.dart index ebd4061..47c545f 100644 --- a/lib/generators/model_code_generator.dart +++ b/lib/generators/model_code_generator.dart @@ -48,8 +48,155 @@ class ModelCodeGenerator extends ModelGenerator { return generateEnumCode(model); } - // 只使用 JsonSerializable 注解版本 - return generateAnnotatedModelCode(model); + return useSimpleModels + ? generateSimpleModelCode(model) + : generateAnnotatedModelCode(model); + } + + /// 生成简洁版模型代码 + String generateSimpleModelCode(ApiModel model) { + final className = StringUtils.generateClassName(model.name); + final buffer = StringBuffer(); + + // 生成导入依赖 + final importedTypes = getImportedTypes(model); + for (final importType in importedTypes) { + final importFileName = StringUtils.generateFileName(importType); + buffer.writeln('import \'$importFileName\';'); + } + + if (importedTypes.isNotEmpty) { + buffer.writeln(''); + } + + // 生成类注释 + if (model.description.isNotEmpty) { + buffer.writeln(StringUtils.generateComment(model.description)); + } + + buffer.writeln('class $className {'); + + // 生成属性 + model.properties.forEach((propName, property) { + final dartType = getDartPropertyType(property); + final nullable = property.nullable ? '?' : ''; + final dartPropName = StringUtils.toDartPropertyName(propName); + + if (property.description.isNotEmpty) { + buffer.writeln( + ' ${StringUtils.generateComment(property.description)}', + ); + } + + buffer.writeln(' final $dartType$nullable $dartPropName;'); + buffer.writeln(''); + }); + + // 生成构造函数 + if (model.properties.isEmpty) { + buffer.writeln(' const $className();'); + } else { + buffer.writeln(' const $className({'); + model.properties.forEach((propName, property) { + final dartPropName = StringUtils.toDartPropertyName(propName); + final required = property.required ? 'required ' : ''; + buffer.writeln(' ${required}this.$dartPropName,'); + }); + buffer.writeln(' });'); + } + buffer.writeln(''); + + // 生成 fromJson 方法 + buffer.writeln( + ' factory $className.fromJson(Map json) {', + ); + if (model.properties.isEmpty) { + buffer.writeln(' return const $className();'); + } else { + buffer.writeln(' return $className('); + model.properties.forEach((propName, property) { + final dartPropName = StringUtils.toDartPropertyName(propName); + final dartType = getDartPropertyType(property); + + buffer.write(' $dartPropName: '); + + // 生成类型转换逻辑 + if (property.type == PropertyType.reference && + property.reference != null) { + final refType = StringUtils.generateClassName(property.reference!); + if (property.nullable) { + buffer.write( + 'json[\'$propName\'] != null ? $refType.fromJson(json[\'$propName\']) : null', + ); + } else { + buffer.write('$refType.fromJson(json[\'$propName\'])'); + } + } else if (property.type == PropertyType.array) { + // 简化的数组处理 + buffer.write( + 'json[\'$propName\'] != null ? List.from(json[\'$propName\']) : null', + ); + } else { + // 基本类型 + if (property.nullable) { + buffer.write('json[\'$propName\'] as $dartType?'); + } else { + buffer.write('json[\'$propName\'] as $dartType'); + } + } + + buffer.writeln(','); + }); + buffer.writeln(' );'); + } + buffer.writeln(' }'); + buffer.writeln(''); + + // 生成 toJson 方法 + buffer.writeln(' Map toJson() {'); + buffer.writeln(' return {'); + model.properties.forEach((propName, property) { + final dartPropName = StringUtils.toDartPropertyName(propName); + + if (property.type == PropertyType.reference && + property.reference != null) { + buffer.write(' \'$propName\': $dartPropName?.toJson()'); + } else if (property.type == PropertyType.array) { + buffer.write(' \'$propName\': $dartPropName'); + } else { + buffer.write(' \'$propName\': $dartPropName'); + } + + buffer.writeln(','); + }); + buffer.writeln(' };'); + buffer.writeln(' }'); + buffer.writeln(''); + + // 生成 copyWith 方法 + if (model.properties.isNotEmpty) { + buffer.writeln(' $className copyWith({'); + model.properties.forEach((propName, property) { + final dartType = getDartPropertyType(property); + final dartPropName = StringUtils.toDartPropertyName(propName); + buffer.writeln(' $dartType? $dartPropName,'); + }); + buffer.writeln(' }) {'); + buffer.writeln(' return $className('); + model.properties.forEach((propName, property) { + final dartPropName = StringUtils.toDartPropertyName(propName); + buffer.writeln( + ' $dartPropName: $dartPropName ?? this.$dartPropName,', + ); + }); + buffer.writeln(' );'); + buffer.writeln(' }'); + buffer.writeln(''); + } + + buffer.writeln('}'); + + return buffer.toString(); } /// 生成带注解的模型代码 @@ -85,7 +232,6 @@ class ModelCodeGenerator extends ModelGenerator { // 生成属性 model.properties.forEach((propName, property) { final dartType = getDartPropertyType(property); - // 根据文档判断是否可空:只有显式标记为 nullable: true 的才可空 final nullable = property.nullable ? '?' : ''; final dartPropName = StringUtils.toDartPropertyName(propName); @@ -113,9 +259,7 @@ class ModelCodeGenerator extends ModelGenerator { buffer.writeln(' const $className({'); model.properties.forEach((propName, property) { final dartPropName = StringUtils.toDartPropertyName(propName); - // 对于非可空属性,必须添加 required 修饰符 - final shouldBeRequired = !property.nullable; - final required = shouldBeRequired ? 'required ' : ''; + final required = property.required ? 'required ' : ''; buffer.writeln(' ${required}this.$dartPropName,'); }); buffer.writeln(' });'); @@ -124,14 +268,14 @@ class ModelCodeGenerator extends ModelGenerator { // 生成 fromJson 工厂方法 buffer.writeln( - ' factory $className.fromJson(Map json) =>', + ' factory $className.fromJson(Map json) => _\$${className}FromJson(json);', ); - buffer.writeln(' _\$${className}FromJson(json);'); buffer.writeln(''); // 生成 toJson 方法 buffer.writeln( - ' Map toJson() => _\$${className}ToJson(this);'); + ' Map toJson() => _\$${className}ToJson(this);', + ); buffer.writeln(''); buffer.writeln('}'); @@ -208,8 +352,9 @@ class ModelCodeGenerator extends ModelGenerator { return _generateEnumCodeWithoutImports(model); } - // 只使用 JsonSerializable 注解版本 - return _generateAnnotatedModelCodeWithoutImports(model); + return useSimpleModels + ? _generateSimpleModelCodeWithoutImports(model) + : _generateAnnotatedModelCodeWithoutImports(model); } /// 生成枚举代码(不包含导入语句) @@ -281,6 +426,141 @@ class ModelCodeGenerator extends ModelGenerator { // 已移动到 StringUtils.generateEnumValueName + /// 生成简洁版模型代码(不包含导入语句) + String _generateSimpleModelCodeWithoutImports(ApiModel model) { + final className = StringUtils.generateClassName(model.name); + final buffer = StringBuffer(); + + // 生成类注释 + if (model.description.isNotEmpty) { + buffer.writeln(StringUtils.generateComment(model.description)); + } + + buffer.writeln('class $className {'); + + // 生成属性 + model.properties.forEach((propName, property) { + final dartType = getDartPropertyType(property); + final nullable = property.nullable ? '?' : ''; + final dartPropName = StringUtils.toDartPropertyName(propName); + + if (property.description.isNotEmpty) { + buffer.writeln( + ' ${StringUtils.generateComment(property.description)}', + ); + } + + buffer.writeln(' final $dartType$nullable $dartPropName;'); + buffer.writeln(''); + }); + + // 生成构造函数 + if (model.properties.isEmpty) { + buffer.writeln(' const $className();'); + } else { + buffer.writeln(' const $className({'); + model.properties.forEach((propName, property) { + final dartPropName = StringUtils.toDartPropertyName(propName); + final required = property.required ? 'required ' : ''; + buffer.writeln(' ${required}this.$dartPropName,'); + }); + buffer.writeln(' });'); + } + buffer.writeln(''); + + // 生成 fromJson 方法 + buffer.writeln( + ' factory $className.fromJson(Map json) {', + ); + if (model.properties.isEmpty) { + buffer.writeln(' return const $className();'); + } else { + buffer.writeln(' return $className('); + model.properties.forEach((propName, property) { + final dartPropName = StringUtils.toDartPropertyName(propName); + final dartType = getDartPropertyType(property); + + buffer.write(' $dartPropName: '); + + // 生成类型转换逻辑 + if (property.type == PropertyType.reference && + property.reference != null) { + final refType = StringUtils.generateClassName(property.reference!); + if (property.nullable) { + buffer.write( + 'json[\'$propName\'] != null ? $refType.fromJson(json[\'$propName\']) : null', + ); + } else { + buffer.write('$refType.fromJson(json[\'$propName\'])'); + } + } else if (property.type == PropertyType.array) { + // 简化的数组处理 + buffer.write( + 'json[\'$propName\'] != null ? List.from(json[\'$propName\']) : null', + ); + } else { + // 基本类型 + if (property.nullable) { + buffer.write('json[\'$propName\'] as $dartType?'); + } else { + buffer.write('json[\'$propName\'] as $dartType'); + } + } + + buffer.writeln(','); + }); + buffer.writeln(' );'); + } + buffer.writeln(' }'); + buffer.writeln(''); + + // 生成 toJson 方法 + buffer.writeln(' Map toJson() {'); + buffer.writeln(' return {'); + model.properties.forEach((propName, property) { + final dartPropName = StringUtils.toDartPropertyName(propName); + + if (property.type == PropertyType.reference && + property.reference != null) { + buffer.write(' \'$propName\': $dartPropName?.toJson()'); + } else if (property.type == PropertyType.array) { + buffer.write(' \'$propName\': $dartPropName'); + } else { + buffer.write(' \'$propName\': $dartPropName'); + } + + buffer.writeln(','); + }); + buffer.writeln(' };'); + buffer.writeln(' }'); + buffer.writeln(''); + + // 生成 copyWith 方法 + if (model.properties.isNotEmpty) { + buffer.writeln(' $className copyWith({'); + model.properties.forEach((propName, property) { + final dartType = getDartPropertyType(property); + final dartPropName = StringUtils.toDartPropertyName(propName); + buffer.writeln(' $dartType? $dartPropName,'); + }); + buffer.writeln(' }) {'); + buffer.writeln(' return $className('); + model.properties.forEach((propName, property) { + final dartPropName = StringUtils.toDartPropertyName(propName); + buffer.writeln( + ' $dartPropName: $dartPropName ?? this.$dartPropName,', + ); + }); + buffer.writeln(' );'); + buffer.writeln(' }'); + buffer.writeln(''); + } + + buffer.writeln('}'); + + return buffer.toString(); + } + /// 生成带注解的模型代码(不包含导入语句) String _generateAnnotatedModelCodeWithoutImports(ApiModel model) { final className = StringUtils.generateClassName(model.name); @@ -303,7 +583,6 @@ class ModelCodeGenerator extends ModelGenerator { // 生成属性 model.properties.forEach((propName, property) { final dartType = getDartPropertyType(property); - // 根据文档判断是否可空:只有显式标记为 nullable: true 的才可空 final nullable = property.nullable ? '?' : ''; final dartPropName = StringUtils.toDartPropertyName(propName); @@ -331,9 +610,7 @@ class ModelCodeGenerator extends ModelGenerator { buffer.writeln(' const $className({'); model.properties.forEach((propName, property) { final dartPropName = StringUtils.toDartPropertyName(propName); - // 对于非可空属性,必须添加 required 修饰符 - final shouldBeRequired = !property.nullable; - final required = shouldBeRequired ? 'required ' : ''; + final required = property.required ? 'required ' : ''; buffer.writeln(' ${required}this.$dartPropName,'); }); buffer.writeln(' });'); @@ -342,14 +619,14 @@ class ModelCodeGenerator extends ModelGenerator { // 生成 fromJson 工厂方法 buffer.writeln( - ' factory $className.fromJson(Map json) =>', + ' factory $className.fromJson(Map json) => _\$${className}FromJson(json);', ); - buffer.writeln(' _\$${className}FromJson(json);'); buffer.writeln(''); // 生成 toJson 方法 buffer.writeln( - ' Map toJson() => _\$${className}ToJson(this);'); + ' Map toJson() => _\$${className}ToJson(this);', + ); buffer.writeln(''); buffer.writeln('}'); diff --git a/lib/generators/optimized_retrofit_generator.dart b/lib/generators/optimized_retrofit_generator.dart deleted file mode 100644 index 7158720..0000000 --- a/lib/generators/optimized_retrofit_generator.dart +++ /dev/null @@ -1,547 +0,0 @@ -/// 优化的 Retrofit API 代码生成器 -/// 专门针对 Dio + Retrofit 项目架构优化 -library; - -import '../core/models.dart'; -import 'base_generator.dart'; - -/// 优化的 Retrofit API 生成器 -/// 基于实际项目的 Dio + Retrofit 架构进行优化 -class OptimizedRetrofitGenerator extends BaseGenerator { - final String className; - final bool generateModularApis; - final bool generateBaseResult; - final bool generatePagination; - final bool generateFileUpload; - final String baseResultType; - final String pageResultType; - - OptimizedRetrofitGenerator({ - this.className = 'ApiService', - this.generateModularApis = true, - this.generateBaseResult = true, - this.generatePagination = true, - this.generateFileUpload = true, - this.baseResultType = 'BaseResult', - this.pageResultType = 'BasePageResult', - }); - - @override - String get generatorType => 'OptimizedRetrofitGenerator'; - - @override - String generate() { - throw UnimplementedError('Use generateFromDocument instead'); - } - - /// 生成优化的 API 代码 - String generateFromDocument(SwaggerDocument document) { - final buffer = StringBuffer(); - - // 生成文件头 - _generateFileHeader(buffer); - - // 生成导入语句 - _generateImports(buffer); - - // 生成基础响应类型(如果需要) - if (generateBaseResult) { - _generateBaseResultTypes(buffer); - } - - // 生成分页类型(如果需要) - if (generatePagination) { - _generatePaginationTypes(buffer); - } - - // 生成文件上传类型(如果需要) - if (generateFileUpload) { - _generateFileUploadTypes(buffer); - } - - // 生成模块化 API 或单一 API - if (generateModularApis) { - _generateModularApis(buffer, document); - } else { - _generateSingleApi(buffer, document); - } - - // 生成工具类 - _generateUtilityClasses(buffer); - - return buffer.toString(); - } - - /// 生成文件头注释 - void _generateFileHeader(StringBuffer buffer) { - buffer.writeln('/// 自动生成的 API 接口文件'); - buffer.writeln('/// 基于 Dio + Retrofit 架构优化'); - buffer.writeln('/// 支持模块化、分页、文件上传等功能'); - buffer.writeln('/// 请勿手动修改此文件'); - buffer.writeln('/// 生成时间: ${DateTime.now().toIso8601String()}'); - buffer.writeln(); - } - - /// 生成导入语句 - void _generateImports(StringBuffer buffer) { - buffer.writeln('// Dart 核心库'); - buffer.writeln('import \'dart:convert\';'); - buffer.writeln('import \'dart:io\';'); - buffer.writeln('import \'dart:typed_data\';'); - buffer.writeln(); - - buffer.writeln('// 网络请求相关'); - buffer.writeln('import \'package:dio/dio.dart\';'); - buffer.writeln('import \'package:retrofit/retrofit.dart\';'); - buffer.writeln('import \'package:json_annotation/json_annotation.dart\';'); - buffer.writeln(); - - buffer.writeln('// 文件处理'); - buffer.writeln('import \'package:path/path.dart\' as path;'); - buffer.writeln('import \'package:http_parser/http_parser.dart\';'); - buffer.writeln(); - - buffer.writeln('// 生成的代码'); - buffer.writeln('part \'${_getGeneratedFileName()}.g.dart\';'); - buffer.writeln(); - } - - /// 生成基础响应类型 - void _generateBaseResultTypes(StringBuffer buffer) { - buffer.writeln('/// 基础响应结果'); - buffer.writeln('@JsonSerializable(genericArgumentFactories: true)'); - buffer.writeln('class $baseResultType {'); - buffer.writeln(' /// 响应码'); - buffer.writeln(' final int code;'); - buffer.writeln(); - buffer.writeln(' /// 响应消息'); - buffer.writeln(' final String message;'); - buffer.writeln(); - buffer.writeln(' /// 响应数据'); - buffer.writeln(' final T? data;'); - buffer.writeln(); - buffer.writeln(' /// 是否成功'); - buffer.writeln(' bool get isSuccess => code == 200;'); - buffer.writeln(); - buffer.writeln(' const $baseResultType({'); - buffer.writeln(' required this.code,'); - buffer.writeln(' required this.message,'); - buffer.writeln(' this.data,'); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln(' factory $baseResultType.fromJson('); - buffer.writeln(' Map json,'); - buffer.writeln(' T Function(Object? json) fromJsonT,'); - buffer.writeln(' ) => _\$${baseResultType}FromJson(json, fromJsonT);'); - buffer.writeln(); - buffer.writeln( - ' Map toJson(Object Function(T value) toJsonT) =>'); - buffer.writeln(' _\$${baseResultType}ToJson(this, toJsonT);'); - buffer.writeln('}'); - buffer.writeln(); - } - - /// 生成分页类型 - void _generatePaginationTypes(StringBuffer buffer) { - buffer.writeln('/// 分页参数'); - buffer.writeln('@JsonSerializable()'); - buffer.writeln('class BasePageParameter {'); - buffer.writeln(' /// 页码(从1开始)'); - buffer.writeln(' final int page;'); - buffer.writeln(); - buffer.writeln(' /// 每页大小'); - buffer.writeln(' final int size;'); - buffer.writeln(); - buffer.writeln(' const BasePageParameter({'); - buffer.writeln(' this.page = 1,'); - buffer.writeln(' this.size = 20,'); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln( - ' factory BasePageParameter.fromJson(Map json) =>'); - buffer.writeln(' _\$BasePageParameterFromJson(json);'); - buffer.writeln(); - buffer.writeln( - ' Map toJson() => _\$BasePageParameterToJson(this);'); - buffer.writeln('}'); - buffer.writeln(); - - buffer.writeln('/// 分页响应结果'); - buffer.writeln('@JsonSerializable(genericArgumentFactories: true)'); - buffer.writeln('class $pageResultType {'); - buffer.writeln(' /// 数据列表'); - buffer.writeln(' final List list;'); - buffer.writeln(); - buffer.writeln(' /// 总数量'); - buffer.writeln(' final int total;'); - buffer.writeln(); - buffer.writeln(' /// 当前页码'); - buffer.writeln(' final int page;'); - buffer.writeln(); - buffer.writeln(' /// 每页大小'); - buffer.writeln(' final int size;'); - buffer.writeln(); - buffer.writeln(' /// 总页数'); - buffer.writeln(' int get totalPages => (total / size).ceil();'); - buffer.writeln(); - buffer.writeln(' /// 是否有下一页'); - buffer.writeln(' bool get hasNext => page < totalPages;'); - buffer.writeln(); - buffer.writeln(' /// 是否有上一页'); - buffer.writeln(' bool get hasPrevious => page > 1;'); - buffer.writeln(); - buffer.writeln(' const $pageResultType({'); - buffer.writeln(' required this.list,'); - buffer.writeln(' required this.total,'); - buffer.writeln(' required this.page,'); - buffer.writeln(' required this.size,'); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln(' factory $pageResultType.fromJson('); - buffer.writeln(' Map json,'); - buffer.writeln(' T Function(Object? json) fromJsonT,'); - buffer.writeln(' ) => _\$${pageResultType}FromJson(json, fromJsonT);'); - buffer.writeln(); - buffer.writeln( - ' Map toJson(Object Function(T value) toJsonT) =>'); - buffer.writeln(' _\$${pageResultType}ToJson(this, toJsonT);'); - buffer.writeln('}'); - buffer.writeln(); - } - - /// 生成文件上传类型 - void _generateFileUploadTypes(StringBuffer buffer) { - buffer.writeln('/// 文件上传请求'); - buffer.writeln('@JsonSerializable()'); - buffer.writeln('class FileUploadRequest {'); - buffer.writeln(' /// 文件'); - buffer.writeln(' @JsonKey(includeFromJson: false, includeToJson: false)'); - buffer.writeln(' final MultipartFile file;'); - buffer.writeln(); - buffer.writeln(' /// 文件名'); - buffer.writeln(' final String? filename;'); - buffer.writeln(); - buffer.writeln(' /// 文件类型'); - buffer.writeln(' final String? contentType;'); - buffer.writeln(); - buffer.writeln(' const FileUploadRequest({'); - buffer.writeln(' required this.file,'); - buffer.writeln(' this.filename,'); - buffer.writeln(' this.contentType,'); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln( - ' factory FileUploadRequest.fromJson(Map json) =>'); - buffer.writeln(' _\$FileUploadRequestFromJson(json);'); - buffer.writeln(); - buffer.writeln( - ' Map toJson() => _\$FileUploadRequestToJson(this);'); - buffer.writeln('}'); - buffer.writeln(); - - buffer.writeln('/// 文件上传响应'); - buffer.writeln('@JsonSerializable()'); - buffer.writeln('class FileUploadResult {'); - buffer.writeln(' /// 文件 URL'); - buffer.writeln(' final String url;'); - buffer.writeln(); - buffer.writeln(' /// 文件名'); - buffer.writeln(' final String filename;'); - buffer.writeln(); - buffer.writeln(' /// 文件大小'); - buffer.writeln(' final int size;'); - buffer.writeln(); - buffer.writeln(' /// 文件类型'); - buffer.writeln(' final String? contentType;'); - buffer.writeln(); - buffer.writeln(' const FileUploadResult({'); - buffer.writeln(' required this.url,'); - buffer.writeln(' required this.filename,'); - buffer.writeln(' required this.size,'); - buffer.writeln(' this.contentType,'); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln( - ' factory FileUploadResult.fromJson(Map json) =>'); - buffer.writeln(' _\$FileUploadResultFromJson(json);'); - buffer.writeln(); - buffer.writeln( - ' Map toJson() => _\$FileUploadResultToJson(this);'); - buffer.writeln('}'); - buffer.writeln(); - } - - /// 生成模块化 API - void _generateModularApis(StringBuffer buffer, SwaggerDocument document) { - // 按路径前缀分组 API - final modules = _groupApisByModule(document); - - for (final entry in modules.entries) { - final moduleName = entry.key; - final paths = entry.value; - - _generateModuleApi(buffer, moduleName, paths); - } - - // 生成主 API 类 - _generateMainApiClass(buffer, modules.keys.toList()); - } - - /// 生成单一 API - void _generateSingleApi(StringBuffer buffer, SwaggerDocument document) { - buffer.writeln('/// $className API 接口'); - buffer.writeln('@RestApi()'); - buffer.writeln('abstract class $className {'); - buffer.writeln( - ' factory $className(Dio dio, {String? baseUrl}) = _$className;'); - buffer.writeln(); - - // 生成所有 API 方法 - document.paths.forEach((path, apiPath) { - _generateApiMethod(buffer, path, apiPath); - }); - - buffer.writeln('}'); - buffer.writeln(); - } - - /// 按模块分组 API - Map> _groupApisByModule( - SwaggerDocument document) { - final modules = >{}; - - document.paths.forEach((path, apiPath) { - final moduleName = _extractModuleName(path); - modules.putIfAbsent(moduleName, () => {}); - modules[moduleName]![path] = apiPath; - }); - - return modules; - } - - /// 提取模块名称 - String _extractModuleName(String path) { - final parts = path.split('/').where((part) => part.isNotEmpty).toList(); - if (parts.length >= 3) { - // /api/v1/ModuleName/... -> ModuleName - return _toPascalCase(parts[2]); - } - return 'Common'; - } - - /// 生成模块 API - void _generateModuleApi( - StringBuffer buffer, String moduleName, Map paths) { - final className = '${moduleName}Api'; - - buffer.writeln('/// $moduleName 模块 API'); - buffer.writeln('@RestApi()'); - buffer.writeln('abstract class $className {'); - buffer.writeln( - ' factory $className(Dio dio, {String? baseUrl}) = _$className;'); - buffer.writeln(); - - paths.forEach((path, apiPath) { - _generateApiMethod(buffer, path, apiPath); - }); - - buffer.writeln('}'); - buffer.writeln(); - } - - /// 生成主 API 类 - void _generateMainApiClass(StringBuffer buffer, List modules) { - buffer.writeln('/// 主 API 服务类'); - buffer.writeln('/// 包含所有模块的 API 接口'); - buffer.writeln('class $className {'); - buffer.writeln(' final Dio _dio;'); - buffer.writeln(); - - // 生成模块 API 属性 - for (final module in modules) { - final propertyName = _toCamelCase(module); - buffer.writeln(' late final ${module}Api $propertyName;'); - } - - buffer.writeln(); - buffer.writeln(' $className(this._dio, {String? baseUrl}) {'); - - // 初始化模块 API - for (final module in modules) { - final propertyName = _toCamelCase(module); - buffer - .writeln(' $propertyName = ${module}Api(_dio, baseUrl: baseUrl);'); - } - - buffer.writeln(' }'); - buffer.writeln('}'); - buffer.writeln(); - } - - /// 生成 API 方法 - void _generateApiMethod(StringBuffer buffer, String path, ApiPath apiPath) { - final methodName = _generateMethodName(path, apiPath.method); - final returnType = _generateReturnType(apiPath); - final parameters = _generateParameters(apiPath); - - buffer.writeln( - ' /// ${apiPath.summary.isNotEmpty ? apiPath.summary : apiPath.description}'); - if (apiPath.description.isNotEmpty && - apiPath.description != apiPath.summary) { - buffer.writeln(' /// ${apiPath.description}'); - } - buffer.writeln(' @${apiPath.method.value.toUpperCase()}(\'$path\')'); - - // 添加特殊注解 - if (_isMultipartRequest(apiPath)) { - buffer.writeln(' @MultiPart()'); - } - - buffer.writeln(' Future<$returnType> $methodName($parameters);'); - buffer.writeln(); - } - - /// 生成方法名 - String _generateMethodName(String path, HttpMethod method) { - final pathParts = path - .split('/') - .where((part) => part.isNotEmpty && !part.startsWith('{')) - .toList(); - final methodPrefix = method.value.toLowerCase(); - - if (pathParts.length >= 3) { - // 移除 api/v1 前缀 - pathParts.removeRange(0, 2); - } - - final nameParts = pathParts.map((part) => _toPascalCase(part)).join(''); - return '$methodPrefix$nameParts'; - } - - /// 生成返回类型 - String _generateReturnType(ApiPath apiPath) { - // 检查是否有成功响应 - final successResponse = - apiPath.responses['200'] ?? apiPath.responses['201']; - if (successResponse != null && successResponse.content.isNotEmpty) { - final jsonContent = successResponse.content['application/json']; - if (jsonContent?.schema != null) { - // 根据 schema 生成类型 - return '$baseResultType'; - } - } - return '$baseResultType'; - } - - /// 生成参数 - String _generateParameters(ApiPath apiPath) { - final params = []; - - // 路径参数 - for (final param in apiPath.parameters - .where((p) => p.location == ParameterLocation.path)) { - params.add( - '@Path(\'${param.name}\') ${_getDartType(param.type)} ${param.name}'); - } - - // 查询参数 - for (final param in apiPath.parameters - .where((p) => p.location == ParameterLocation.query)) { - final required = param.required ? 'required ' : ''; - params.add( - '@Query(\'${param.name}\') ${required}${_getDartType(param.type)}${param.required ? '' : '?'} ${param.name}'); - } - - // 请求体 - if (apiPath.requestBody != null) { - if (_isMultipartRequest(apiPath)) { - // 文件上传 - params.add('@Part() MultipartFile file'); - } else { - // JSON 请求体 - params.add('@Body() Map body'); - } - } - - return params.join(', '); - } - - /// 检查是否是 multipart 请求 - bool _isMultipartRequest(ApiPath apiPath) { - if (apiPath.requestBody == null) return false; - return apiPath.requestBody!.content.keys - .any((type) => type.contains('multipart')); - } - - /// 获取 Dart 类型 - String _getDartType(PropertyType type) { - switch (type) { - case PropertyType.string: - return 'String'; - case PropertyType.integer: - return 'int'; - case PropertyType.number: - return 'double'; - case PropertyType.boolean: - return 'bool'; - case PropertyType.array: - return 'List'; - case PropertyType.object: - return 'Map'; - default: - return 'dynamic'; - } - } - - /// 生成工具类 - void _generateUtilityClasses(StringBuffer buffer) { - buffer.writeln('/// API 工具类'); - buffer.writeln('class ApiUtils {'); - buffer.writeln(' /// 创建文件上传对象'); - buffer.writeln( - ' static Future createFileUpload(String filePath) async {'); - buffer.writeln(' return MultipartFile.fromFile('); - buffer.writeln(' filePath,'); - buffer.writeln(' filename: path.basename(filePath),'); - buffer.writeln(' );'); - buffer.writeln(' }'); - buffer.writeln(); - buffer.writeln(' /// 创建分页参数'); - buffer.writeln( - ' static BasePageParameter createPageParam({int page = 1, int size = 20}) {'); - buffer.writeln(' return BasePageParameter(page: page, size: size);'); - buffer.writeln(' }'); - buffer.writeln('}'); - } - - /// 获取生成文件名 - String _getGeneratedFileName() { - return '${_toSnakeCase(className)}_api'; - } - - /// 转换为 PascalCase - String _toPascalCase(String input) { - return input - .split('_') - .map((word) => word.isEmpty - ? '' - : word[0].toUpperCase() + word.substring(1).toLowerCase()) - .join(''); - } - - /// 转换为 camelCase - String _toCamelCase(String input) { - final pascalCase = _toPascalCase(input); - return pascalCase.isEmpty - ? '' - : pascalCase[0].toLowerCase() + pascalCase.substring(1); - } - - /// 转换为 snake_case - String _toSnakeCase(String input) { - return input - .replaceAllMapped( - RegExp(r'[A-Z]'), (match) => '_${match.group(0)!.toLowerCase()}') - .replaceAll(RegExp(r'^_'), ''); - } -} diff --git a/lib/generators/performance_generator.dart b/lib/generators/performance_generator.dart deleted file mode 100644 index a631e9d..0000000 --- a/lib/generators/performance_generator.dart +++ /dev/null @@ -1,591 +0,0 @@ -/// 高性能代码生成器 -/// 支持并行生成、增量生成和智能缓存 -library; - -import 'dart:async'; -import '../core/models.dart'; -import '../core/smart_cache.dart'; -import 'base_generator.dart'; - -/// 生成任务 -class GenerationTask { - final String id; - final String type; - final Map data; - final DateTime createdAt; - - GenerationTask({ - required this.id, - required this.type, - required this.data, - DateTime? createdAt, - }) : createdAt = createdAt ?? DateTime.now(); -} - -/// 生成结果 -class GenerationResult { - final String taskId; - final String content; - final Duration generationTime; - final Map metadata; - - const GenerationResult({ - required this.taskId, - required this.content, - required this.generationTime, - this.metadata = const {}, - }); -} - -/// 生成性能统计 -class GenerationStats { - final int totalTasks; - final int completedTasks; - final int failedTasks; - final Duration totalTime; - final Duration averageTaskTime; - final int linesGenerated; - final int bytesGenerated; - final double parallelEfficiency; - - const GenerationStats({ - required this.totalTasks, - required this.completedTasks, - required this.failedTasks, - required this.totalTime, - required this.averageTaskTime, - required this.linesGenerated, - required this.bytesGenerated, - required this.parallelEfficiency, - }); - - double get successRate => totalTasks > 0 ? completedTasks / totalTasks : 0.0; - double get linesPerSecond => totalTime.inMilliseconds > 0 - ? linesGenerated / (totalTime.inMilliseconds / 1000) - : 0.0; - double get bytesPerSecond => totalTime.inMilliseconds > 0 - ? bytesGenerated / (totalTime.inMilliseconds / 1000) - : 0.0; - - @override - String toString() { - return ''' -Generation Performance Statistics: - Total Tasks: $totalTasks - Completed: $completedTasks (${(successRate * 100).toStringAsFixed(1)}%) - Failed: $failedTasks - Total Time: ${totalTime.inMilliseconds}ms - Average Task Time: ${averageTaskTime.inMilliseconds}ms - Lines Generated: $linesGenerated (${linesPerSecond.toStringAsFixed(1)}/s) - Bytes Generated: ${(bytesGenerated / 1024).toStringAsFixed(2)}KB (${(bytesPerSecond / 1024).toStringAsFixed(2)}KB/s) - Parallel Efficiency: ${(parallelEfficiency * 100).toStringAsFixed(1)}% -'''; - } -} - -/// 高性能代码生成器 -class PerformanceGenerator extends BaseGenerator { - final int _maxConcurrency; - final bool _enableCaching; - final bool _enableIncremental; - final bool _enableParallel; - - final SmartCache _cache; - final Map _previousGeneration = {}; - final List _results = []; - - int _totalTasks = 0; - int _completedTasks = 0; - int _failedTasks = 0; - final List _taskTimes = []; - - PerformanceGenerator({ - int maxConcurrency = 4, - bool enableCaching = true, - bool enableIncremental = true, - bool enableParallel = true, - }) : _maxConcurrency = maxConcurrency, - _enableCaching = enableCaching, - _enableIncremental = enableIncremental, - _enableParallel = enableParallel, - _cache = SmartCache( - maxSize: 1000, - strategy: CacheStrategy.smart, - defaultTtl: Duration(hours: 1), - ); - - @override - String get generatorType => 'PerformanceGenerator'; - - @override - String generate() { - throw UnimplementedError('Use generateFromDocument instead'); - } - - /// 高性能生成文档 - Future generateFromDocument(SwaggerDocument document) async { - final stopwatch = Stopwatch()..start(); - - try { - // 分析变更 - final changes = _enableIncremental ? _analyzeChanges(document) : null; - - // 创建生成任务 - final tasks = _createGenerationTasks(document, changes); - _totalTasks = tasks.length; - - // 执行生成 - final results = _enableParallel && tasks.length > 1 - ? await _generateParallel(tasks) - : await _generateSequential(tasks); - - // 合并结果 - final finalResult = _mergeResults(results); - - // 更新缓存和历史 - if (_enableIncremental) { - _updateGenerationHistory(document, finalResult); - } - - stopwatch.stop(); - return finalResult; - } catch (e) { - stopwatch.stop(); - rethrow; - } - } - - /// 分析文档变更 - Map? _analyzeChanges(SwaggerDocument document) { - final currentHash = _calculateDocumentHash(document); - final previousHash = _previousGeneration['hash']; - - if (previousHash == null || currentHash != previousHash) { - return { - 'hasChanges': true, - 'currentHash': currentHash, - 'previousHash': previousHash, - 'changedSections': _detectChangedSections(document), - }; - } - - return { - 'hasChanges': false, - 'currentHash': currentHash, - }; - } - - /// 创建生成任务 - List _createGenerationTasks( - SwaggerDocument document, Map? changes) { - final tasks = []; - - // 如果启用增量生成且没有变更,返回空任务列表 - if (_enableIncremental && changes != null && !changes['hasChanges']) { - return tasks; - } - - // 文件头任务 - tasks.add(GenerationTask( - id: 'header', - type: 'header', - data: { - 'title': document.title, - 'version': document.version, - 'description': document.description, - }, - )); - - // 导入任务 - tasks.add(GenerationTask( - id: 'imports', - type: 'imports', - data: {}, - )); - - // 模型生成任务 - document.models.forEach((name, model) { - tasks.add(GenerationTask( - id: 'model_$name', - type: 'model', - data: { - 'name': name, - 'model': model, - }, - )); - }); - - // API 生成任务 - final pathGroups = _groupPathsByModule(document.paths); - pathGroups.forEach((module, paths) { - tasks.add(GenerationTask( - id: 'api_$module', - type: 'api', - data: { - 'module': module, - 'paths': paths, - }, - )); - }); - - return tasks; - } - - /// 并行生成 - Future> _generateParallel( - List tasks) async { - final chunks = _chunkTasks(tasks, _maxConcurrency); - final results = []; - - for (final chunk in chunks) { - final chunkResults = await Future.wait( - chunk.map((task) => _executeTask(task)), - ); - results.addAll(chunkResults); - } - - return results; - } - - /// 顺序生成 - Future> _generateSequential( - List tasks) async { - final results = []; - - for (final task in tasks) { - final result = await _executeTask(task); - results.add(result); - } - - return results; - } - - /// 执行单个任务 - Future _executeTask(GenerationTask task) async { - final stopwatch = Stopwatch()..start(); - - try { - // 检查缓存 - if (_enableCaching) { - final cacheKey = _generateCacheKey(task); - final cached = _cache.get(cacheKey); - if (cached != null) { - stopwatch.stop(); - _completedTasks++; - _taskTimes.add(stopwatch.elapsed); - - return GenerationResult( - taskId: task.id, - content: cached, - generationTime: stopwatch.elapsed, - metadata: {'fromCache': true}, - ); - } - } - - // 生成内容 - final content = await _generateTaskContent(task); - - // 更新缓存 - if (_enableCaching) { - final cacheKey = _generateCacheKey(task); - _cache.put(cacheKey, content); - } - - stopwatch.stop(); - _completedTasks++; - _taskTimes.add(stopwatch.elapsed); - - return GenerationResult( - taskId: task.id, - content: content, - generationTime: stopwatch.elapsed, - metadata: {'fromCache': false}, - ); - } catch (e) { - stopwatch.stop(); - _failedTasks++; - _taskTimes.add(stopwatch.elapsed); - - return GenerationResult( - taskId: task.id, - content: '// Error generating ${task.type}: $e', - generationTime: stopwatch.elapsed, - metadata: {'error': e.toString()}, - ); - } - } - - /// 生成任务内容 - Future _generateTaskContent(GenerationTask task) async { - switch (task.type) { - case 'header': - return _generateHeader(task.data); - case 'imports': - return _generateImports(task.data); - case 'model': - return _generateModel(task.data); - case 'api': - return _generateApi(task.data); - default: - throw UnsupportedError('Unknown task type: ${task.type}'); - } - } - - /// 生成文件头 - String _generateHeader(Map data) { - final buffer = StringBuffer(); - buffer.writeln('/// Generated API for ${data['title']}'); - buffer.writeln('/// Version: ${data['version']}'); - buffer.writeln('/// ${data['description']}'); - buffer.writeln('/// Generated at: ${DateTime.now().toIso8601String()}'); - buffer.writeln(); - return buffer.toString(); - } - - /// 生成导入语句 - String _generateImports(Map data) { - final buffer = StringBuffer(); - buffer.writeln('import \'dart:convert\';'); - buffer.writeln('import \'package:dio/dio.dart\';'); - buffer.writeln('import \'package:retrofit/retrofit.dart\';'); - buffer.writeln('import \'package:json_annotation/json_annotation.dart\';'); - buffer.writeln(); - buffer.writeln('part \'generated_api.g.dart\';'); - buffer.writeln(); - return buffer.toString(); - } - - /// 生成模型 - String _generateModel(Map data) { - final name = data['name'] as String; - final model = data['model'] as ApiModel; - - final buffer = StringBuffer(); - buffer.writeln('@JsonSerializable()'); - buffer.writeln('class $name {'); - - // 生成属性 - model.properties.forEach((propName, property) { - buffer.writeln(' final ${_getDartType(property.type)} $propName;'); - }); - - buffer.writeln(); - buffer.writeln(' const $name({'); - model.properties.forEach((propName, property) { - final required = property.required ? 'required ' : ''; - buffer.writeln(' ${required}this.$propName,'); - }); - buffer.writeln(' });'); - - buffer.writeln(); - buffer.writeln(' factory $name.fromJson(Map json) =>'); - buffer.writeln(' _\$${name}FromJson(json);'); - buffer.writeln(); - buffer - .writeln(' Map toJson() => _\$${name}ToJson(this);'); - buffer.writeln('}'); - buffer.writeln(); - - return buffer.toString(); - } - - /// 生成 API - String _generateApi(Map data) { - final module = data['module'] as String; - final paths = data['paths'] as Map; - - final buffer = StringBuffer(); - buffer.writeln('@RestApi()'); - buffer.writeln('abstract class ${module}Api {'); - buffer.writeln( - ' factory ${module}Api(Dio dio, {String? baseUrl}) = _${module}Api;'); - buffer.writeln(); - - paths.forEach((path, apiPath) { - buffer.writeln(' @${apiPath.method.value.toUpperCase()}(\'$path\')'); - buffer.writeln( - ' Future ${_generateMethodName(path, apiPath.method)}();'); - buffer.writeln(); - }); - - buffer.writeln('}'); - buffer.writeln(); - - return buffer.toString(); - } - - /// 合并生成结果 - String _mergeResults(List results) { - final buffer = StringBuffer(); - - // 按任务类型排序 - final sortedResults = List.from(results); - sortedResults.sort((a, b) { - final order = ['header', 'imports', 'model', 'api']; - final aType = a.taskId.split('_')[0]; - final bType = b.taskId.split('_')[0]; - final aIndex = order.indexOf(aType); - final bIndex = order.indexOf(bType); - return aIndex.compareTo(bIndex); - }); - - for (final result in sortedResults) { - buffer.write(result.content); - } - - return buffer.toString(); - } - - /// 将任务分块 - List> _chunkTasks( - List tasks, int chunkSize) { - final chunks = >[]; - - for (int i = 0; i < tasks.length; i += chunkSize) { - final end = (i + chunkSize).clamp(0, tasks.length); - chunks.add(tasks.sublist(i, end)); - } - - return chunks; - } - - /// 按模块分组路径 - Map> _groupPathsByModule( - Map paths) { - final groups = >{}; - - paths.forEach((path, apiPath) { - final module = _extractModuleName(path); - groups.putIfAbsent(module, () => {}); - groups[module]![path] = apiPath; - }); - - return groups; - } - - /// 提取模块名 - String _extractModuleName(String path) { - final parts = path.split('/').where((part) => part.isNotEmpty).toList(); - if (parts.length >= 3) { - return _toPascalCase(parts[2]); - } - return 'Common'; - } - - /// 生成缓存键 - String _generateCacheKey(GenerationTask task) { - final dataHash = task.data.toString().hashCode; - return '${task.type}_${dataHash}'; - } - - /// 计算文档哈希 - String _calculateDocumentHash(SwaggerDocument document) { - final content = - '${document.title}_${document.version}_${document.paths.length}_${document.models.length}'; - return content.hashCode.toString(); - } - - /// 检测变更的部分 - List _detectChangedSections(SwaggerDocument document) { - // 简化实现,实际应该更详细地比较各个部分 - return ['paths', 'models', 'components']; - } - - /// 更新生成历史 - void _updateGenerationHistory(SwaggerDocument document, String result) { - _previousGeneration['hash'] = _calculateDocumentHash(document); - _previousGeneration['result'] = result; - _previousGeneration['timestamp'] = DateTime.now().toIso8601String(); - } - - /// 获取性能统计 - GenerationStats getStats() { - final totalTime = _taskTimes.isNotEmpty - ? _taskTimes.reduce((a, b) => a + b) - : Duration.zero; - - final averageTime = _taskTimes.isNotEmpty - ? Duration( - microseconds: _taskTimes - .map((d) => d.inMicroseconds) - .reduce((a, b) => a + b) ~/ - _taskTimes.length) - : Duration.zero; - - // 计算生成的行数和字节数 - int linesGenerated = 0; - int bytesGenerated = 0; - - for (final result in _results) { - linesGenerated += result.content.split('\n').length; - bytesGenerated += result.content.length; - } - - // 计算并行效率(简化) - final parallelEfficiency = _enableParallel && _totalTasks > 1 ? 0.8 : 1.0; - - return GenerationStats( - totalTasks: _totalTasks, - completedTasks: _completedTasks, - failedTasks: _failedTasks, - totalTime: totalTime, - averageTaskTime: averageTime, - linesGenerated: linesGenerated, - bytesGenerated: bytesGenerated, - parallelEfficiency: parallelEfficiency, - ); - } - - /// 获取缓存统计 - CacheStats getCacheStats() => _cache.getStats(); - - /// 清除缓存 - void clearCache() => _cache.clear(); - - /// 获取 Dart 类型 - String _getDartType(PropertyType type) { - switch (type) { - case PropertyType.string: - return 'String'; - case PropertyType.integer: - return 'int'; - case PropertyType.number: - return 'double'; - case PropertyType.boolean: - return 'bool'; - case PropertyType.array: - return 'List'; - case PropertyType.object: - return 'Map'; - default: - return 'dynamic'; - } - } - - /// 生成方法名 - String _generateMethodName(String path, HttpMethod method) { - final pathParts = path - .split('/') - .where((part) => part.isNotEmpty && !part.startsWith('{')) - .toList(); - final methodPrefix = method.value.toLowerCase(); - - if (pathParts.length >= 3) { - pathParts.removeRange(0, 2); - } - - final nameParts = pathParts.map((part) => _toPascalCase(part)).join(''); - return '$methodPrefix$nameParts'; - } - - /// 转换为 PascalCase - String _toPascalCase(String input) { - return input - .split('_') - .map((word) => word.isEmpty - ? '' - : word[0].toUpperCase() + word.substring(1).toLowerCase()) - .join(''); - } -} diff --git a/lib/generators/retrofit_api_generator.dart b/lib/generators/retrofit_api_generator.dart index 544a3f9..179ce1d 100644 --- a/lib/generators/retrofit_api_generator.dart +++ b/lib/generators/retrofit_api_generator.dart @@ -5,20 +5,18 @@ import 'base_generator.dart'; /// Retrofit 风格的 API 生成器 /// 负责生成带有注解的 API 接口类 class RetrofitApiGenerator extends BaseGenerator { + final SwaggerDocument document; final String className; final bool useRetrofit; final bool useDio; final bool splitByTags; - final bool generateModels; - late SwaggerDocument document; - - RetrofitApiGenerator({ + RetrofitApiGenerator( + this.document, { this.className = 'ApiClient', this.useRetrofit = true, this.useDio = true, - this.splitByTags = true, // 默认启用拆分模式 - this.generateModels = true, + this.splitByTags = false, }); @override @@ -26,12 +24,6 @@ class RetrofitApiGenerator extends BaseGenerator { @override String generate() { - throw UnimplementedError('Use generateFromDocument instead'); - } - - /// 生成 API 代码 - String generateFromDocument(SwaggerDocument document) { - this.document = document; // 设置文档引用 if (splitByTags) { // 按 tags 分组生成多个文件时,返回主文件内容 return generateMainApiFile(); @@ -52,18 +44,6 @@ class RetrofitApiGenerator extends BaseGenerator { // 生成导入语句 _generateImports(buffer); - // 生成安全方案相关代码 - buffer.write(_generateSecurityCode(document)); - - // 生成媒体类型处理代码 - buffer.write(_generateMediaTypeHandlers()); - - // 生成文件上传处理代码 - buffer.write(_generateFileUploadHandlers()); - - // 生成编码处理代码 - buffer.write(_generateEncodingHandlers()); - // 生成 API 接口类 _generateApiInterface(buffer); @@ -117,26 +97,14 @@ class RetrofitApiGenerator extends BaseGenerator { /// 生成导入语句 void _generateImports(StringBuffer buffer) { - // 添加核心依赖的导入 - buffer.writeln('import \'dart:convert\';'); - buffer.writeln('import \'dart:io\';'); - buffer.writeln('import \'dart:typed_data\';'); - - // Dio 和 Retrofit 相关导入 if (useDio) { buffer.writeln('import \'package:dio/dio.dart\';'); } + if (useRetrofit) { buffer.writeln('import \'package:retrofit/retrofit.dart\';'); - buffer - .writeln('import \'package:json_annotation/json_annotation.dart\';'); } - // 其他工具包导入 - buffer.writeln('import \'package:crypto/crypto.dart\';'); - buffer.writeln('import \'package:path/path.dart\' as path;'); - buffer.writeln('import \'package:http_parser/http_parser.dart\';'); - buffer.writeln(''); // 导入基础响应类型(从用户项目中导入) @@ -146,10 +114,9 @@ class RetrofitApiGenerator extends BaseGenerator { 'import \'package:learning_officer_oa/common/models/common/base_page_result.dart\';'); buffer.writeln(''); - // 导入生成的模型类(按字母顺序排序) + // 导入生成的模型类 final modelImports = _getRequiredModelImports(); - final sortedModelImports = modelImports.toList()..sort(); - for (final modelImport in sortedModelImports) { + for (final modelImport in modelImports) { buffer.writeln( 'import \'../../api_models/${StringUtils.generateFileName(modelImport)}\';'); } @@ -166,32 +133,17 @@ class RetrofitApiGenerator extends BaseGenerator { /// 生成 API 接口类 void _generateApiInterface(StringBuffer buffer) { buffer.writeln('/// $className API 接口'); - buffer.writeln('/// 使用 Retrofit 和 Dio 进行网络请求'); - buffer.writeln('/// 支持多种媒体类型、文件上传、认证等功能'); + buffer.writeln('/// 使用 Retrofit 风格的注解定义'); if (useRetrofit) { - // 添加 baseUrl(如果有的话) - final baseUrl = - document.servers.isNotEmpty ? document.servers.first.url : ''; - if (baseUrl.isNotEmpty) { - buffer.writeln( - '@RestApi(baseUrl: \'$baseUrl\', parser: Parser.JsonSerializable)'); - } else { - buffer.writeln('@RestApi(parser: Parser.JsonSerializable)'); - } + buffer.writeln('@RestApi(parser: Parser.JsonSerializable)'); } buffer.writeln('abstract class $className {'); if (useRetrofit) { - buffer.writeln(' /// 创建 API 服务实例'); - buffer.writeln(' /// [dio] Dio 实例,可以预配置拦截器、超时等'); - buffer.writeln(' /// [baseUrl] 可选的基础 URL,会覆盖注解中的 baseUrl'); buffer.writeln( ' factory $className(Dio dio, {String? baseUrl}) = _$className;'); - } else { - buffer.writeln(' final Dio _dio;'); - buffer.writeln(' $className(this._dio);'); } buffer.writeln(''); @@ -228,35 +180,8 @@ class RetrofitApiGenerator extends BaseGenerator { final cleanPath = StringUtils.cleanPath(path.path); // 生成方法注释 - final parameters = _generateParameters(path); - if (path.summary.isNotEmpty) { buffer.writeln(' ${StringUtils.generateComment(path.summary)}'); - - // 如果有参数描述,添加参数文档 - final paramsWithDescription = parameters - .where((p) => p.description.isNotEmpty || p.defaultValue != null) - .toList(); - - if (paramsWithDescription.isNotEmpty) { - buffer.writeln(' ///'); - buffer.writeln(' /// 参数:'); - - for (final param in paramsWithDescription) { - final commentParts = []; - - if (param.description.isNotEmpty) { - commentParts.add(param.description); - } - - if (param.defaultValue != null) { - commentParts.add('默认值: ${param.defaultValue}'); - } - - final comment = commentParts.join(' - '); - buffer.writeln(' /// - ${param.name}: $comment'); - } - } } if (path.description.isNotEmpty && path.description != path.summary) { buffer.writeln(' ${StringUtils.generateComment(path.description)}'); @@ -269,6 +194,7 @@ class RetrofitApiGenerator extends BaseGenerator { // 生成方法签名 final returnType = _generateReturnType(path); + final parameters = _generateParameters(path); buffer.writeln(' Future<$returnType> $methodName('); @@ -276,7 +202,6 @@ class RetrofitApiGenerator extends BaseGenerator { for (int i = 0; i < parameters.length; i++) { final param = parameters[i]; final isLast = i == parameters.length - 1; - if (param.annotation.isNotEmpty) { buffer.writeln( ' ${param.annotation} ${param.type} ${param.name}${isLast ? '' : ','}'); @@ -344,14 +269,13 @@ class RetrofitApiGenerator extends BaseGenerator { return _wrapWithBaseResult(schemaType, path); } - // 特殊处理健康检查接口 - final pathLower = path.path.toLowerCase(); - if (pathLower.contains('healthcheck') || pathLower.contains('health')) { - return 'BaseResult'; + // 如果无法从 schema 解析,使用智能推断 + final inferredType = _inferReturnTypeFromPath(path); + if (inferredType != null) { + return _wrapWithBaseResult(inferredType, path); } - // 如果没有明确的 schema 定义,使用通用类型 - // 这通常表示后端文档不完整,应该要求后端完善 swagger 文档 + // 默认返回类型 return 'BaseResult>'; } @@ -396,16 +320,19 @@ class RetrofitApiGenerator extends BaseGenerator { for (final statusCode in successResponses) { final response = path.responses[statusCode]; if (response != null) { - // 检查 content.application/json.schema (OpenAPI 3.0) - final applicationJsonMediaType = response.content['application/json']; - if (applicationJsonMediaType != null) { - final schema = applicationJsonMediaType.schema; - if (schema != null && _hasPaginationSchema(schema)) { - return true; + // 检查 content.application/json.schema (Swagger 3.0) + if (response.content != null) { + final applicationJson = + response.content!['application/json'] as Map?; + if (applicationJson != null) { + final schema = applicationJson['schema'] as Map?; + if (schema != null && _hasPaginationSchema(schema)) { + return true; + } } } - // 检查 schema 字段 (Swagger 2.0 兼容) + // 检查 schema 字段 (Swagger 2.0) if (response.schema != null && _hasPaginationSchema(response.schema!)) { return true; } @@ -643,16 +570,19 @@ class RetrofitApiGenerator extends BaseGenerator { for (final statusCode in successResponses) { final response = path.responses[statusCode]; if (response != null) { - // 检查 content.application/json.schema (OpenAPI 3.0) - final applicationJsonMediaType = response.content['application/json']; - if (applicationJsonMediaType != null) { - final schema = applicationJsonMediaType.schema; - if (schema != null && _isArraySchema(schema)) { - return true; + // 检查 content.application/json.schema (Swagger 3.0) + if (response.content != null) { + final applicationJson = + response.content!['application/json'] as Map?; + if (applicationJson != null) { + final schema = applicationJson['schema'] as Map?; + if (schema != null && _isArraySchema(schema)) { + return true; + } } } - // 检查 schema 字段 (Swagger 2.0 兼容) + // 检查 schema 字段 (Swagger 2.0) if (response.schema != null && _isArraySchema(response.schema!)) { return true; } @@ -669,17 +599,20 @@ class RetrofitApiGenerator extends BaseGenerator { /// 从响应中提取返回类型 String? _extractResponseType(ApiResponse response) { - // 优先检查 content.application/json.schema (OpenAPI 3.0) - final applicationJsonMediaType = response.content['application/json']; - if (applicationJsonMediaType != null) { - final schema = applicationJsonMediaType.schema; - final type = _extractTypeFromSchema(schema); - if (type != null) { - return type; + // 优先检查 content.application/json.schema (Swagger 3.0) + if (response.content != null) { + final applicationJson = + response.content!['application/json'] as Map?; + if (applicationJson != null) { + final schema = applicationJson['schema'] as Map?; + final type = _extractTypeFromSchema(schema); + if (type != null) { + return type; + } } } - // 检查 schema 字段 (Swagger 2.0 兼容) + // 检查 schema 字段 (Swagger 2.0) final type = _extractTypeFromSchema(response.schema); if (type != null) { return type; @@ -692,19 +625,6 @@ class RetrofitApiGenerator extends BaseGenerator { String? _extractTypeFromSchema(Map? schema) { if (schema == null) return null; - // 处理高级 Schema 特性 - final advancedType = _handleAdvancedSchemaFeatures(schema); - if (advancedType != null) { - return advancedType; - } - - // 处理组合模式 (allOf/oneOf/anyOf) - if (schema['allOf'] != null || - schema['oneOf'] != null || - schema['anyOf'] != null) { - return _extractTypeFromCompositionSchema(schema); - } - // 处理 $ref 引用 if (schema['\$ref'] != null) { final ref = schema['\$ref'] as String; @@ -817,14 +737,6 @@ class RetrofitApiGenerator extends BaseGenerator { return 'double'; case 'boolean': return 'bool'; - case 'array': - // 处理数组类型 - final items = schema['items'] as Map?; - if (items != null) { - final itemType = _extractTypeFromSchema(items); - return 'List<${itemType ?? 'dynamic'}>'; - } - return 'List'; case 'null': return 'dynamic'; default: @@ -866,6 +778,31 @@ class RetrofitApiGenerator extends BaseGenerator { return null; } + /// 根据路径推断返回类型 + String? _inferReturnTypeFromPath(ApiPath path) { + final pathLower = path.path.toLowerCase(); + final summaryLower = path.summary.toLowerCase(); + final operationId = path.operationId.toLowerCase(); + final tags = path.tags.map((tag) => tag.toLowerCase()).toList(); + + // 基于 operationId 推断类型 + if (operationId.isNotEmpty) { + final inferredType = _inferTypeFromOperationId(operationId); + if (inferredType != null) { + return inferredType; + } + } + + // 基于路径关键词推断类型 + final inferredType = + _inferTypeFromPathKeywords(pathLower, summaryLower, tags); + if (inferredType != null) { + return inferredType; + } + + return null; + } + /// 生成参数列表 List _generateParameters(ApiPath path) { final parameters = []; @@ -880,8 +817,6 @@ class RetrofitApiGenerator extends BaseGenerator { type: _getDartType(param.type), annotation: useRetrofit ? '@Path(\'${param.name}\')' : '', required: param.required, - description: param.description, - defaultValue: param.defaultValue, )); } @@ -913,8 +848,6 @@ class RetrofitApiGenerator extends BaseGenerator { type: '${_getDartType(param.type)}$nullable', annotation: useRetrofit ? '@Query(\'${param.name}\')' : '', required: param.required, - description: param.description, - defaultValue: param.defaultValue, )); } } @@ -931,27 +864,20 @@ class RetrofitApiGenerator extends BaseGenerator { type: bodyType, annotation: useRetrofit ? '@Body()' : '', required: false, - description: param.description, - defaultValue: param.defaultValue, )); } - // 如果是 POST/PUT/PATCH 但没有明确的 body 参数,检查是否真的需要请求体 + // 如果是 POST/PUT/PATCH 但没有明确的 body 参数,添加一个通用的 body 参数 if ((path.method == HttpMethod.post || path.method == HttpMethod.put || path.method == HttpMethod.patch) && - bodyParams.isEmpty && - _needsRequestBody(path)) { + bodyParams.isEmpty) { final bodyType = _inferRequestBodyType(path); - final isRequired = path.requestBody?.required ?? false; - final nullable = isRequired ? '' : '?'; - parameters.add(ApiMethodParameter( name: 'request', - type: '$bodyType$nullable', + type: bodyType, annotation: useRetrofit ? '@Body()' : '', - required: isRequired, - description: path.requestBody?.description ?? '', + required: false, )); } @@ -968,20 +894,60 @@ class RetrofitApiGenerator extends BaseGenerator { } } - // 如果没有明确的 requestBody schema 定义,使用通用类型 - // 这通常表示后端文档不完整,应该要求后端完善 swagger 文档 + // 如果无法从 schema 解析,使用路径推断 + final pathLower = path.path.toLowerCase(); + + // 登录请求 + if (pathLower.contains('/login/userlogin') && !pathLower.contains('code')) { + return 'UserLoginRequest'; + } + + if (pathLower.contains('/login/usercodelogin') || + pathLower.contains('/getuserlogincode')) { + return 'LoginCodeRequest'; + } + + // 注册请求 + if (pathLower.contains('/register')) { + return 'RegisterRequest'; + } + + // 刷新token + if (pathLower.contains('/refreshtoken')) { + return 'RefreshTokenRequest'; + } + + // 修改密码 + if (pathLower.contains('/updatemypasswod')) { + return 'MyInfoResetPwdRequest'; + } + + // 换绑手机 + if (pathLower.contains('/updatemyphone')) { + return 'MyPhoneBindRequest'; + } + + // 班级相关请求 + if (pathLower.contains('/addclasses')) { + return 'ClassTeacherRequest'; + } + + // 默认使用通用类型 return 'Map'; } /// 从请求体中提取请求类型 String? _extractRequestBodyType(ApiRequestBody requestBody) { // 检查 content.application/json.schema - final applicationJsonMediaType = requestBody.content['application/json']; - if (applicationJsonMediaType != null) { - final schema = applicationJsonMediaType.schema; - final type = _extractTypeFromSchema(schema); - if (type != null) { - return type; + if (requestBody.content != null) { + final applicationJson = + requestBody.content!['application/json'] as Map?; + if (applicationJson != null) { + final schema = applicationJson['schema'] as Map?; + final type = _extractTypeFromSchema(schema); + if (type != null) { + return type; + } } } @@ -1162,6 +1128,14 @@ class RetrofitApiGenerator extends BaseGenerator { // 已移动到 StringUtils.cleanPath + /// 获取基础URL + String _getBaseUrl() { + if (document.schemes.isNotEmpty) { + return '${document.schemes.first}://${document.host}${document.basePath}'; + } + return 'https://${document.host}${document.basePath}'; + } + /// 按 tags 分组路径 Map> _groupPathsByTags() { final groups = >{}; @@ -1196,13 +1170,8 @@ class RetrofitApiGenerator extends BaseGenerator { // 导入基础响应类型(从用户项目中导入) buffer.writeln( 'import \'package:learning_officer_oa/common/models/common/base_result.dart\';'); - - // 只有在需要分页时才导入 base_page_result.dart - if (_needsPaginationImportForDocument()) { - buffer.writeln( - 'import \'package:learning_officer_oa/common/models/common/base_page_result.dart\';'); - } - + buffer.writeln( + 'import \'package:learning_officer_oa/common/models/common/base_page_result.dart\';'); buffer.writeln(''); // 导入错误处理相关类 @@ -1337,19 +1306,13 @@ class RetrofitApiGenerator extends BaseGenerator { // 导入基础响应类型(从用户项目中导入) buffer.writeln( 'import \'package:learning_officer_oa/common/models/common/base_result.dart\';'); - - // 只有在需要分页时才导入 base_page_result.dart - if (_needsPaginationImport(paths)) { - buffer.writeln( - 'import \'package:learning_officer_oa/common/models/common/base_page_result.dart\';'); - } - + buffer.writeln( + 'import \'package:learning_officer_oa/common/models/common/base_page_result.dart\';'); buffer.writeln(''); - // 导入生成的模型类(按字母顺序排序) + // 导入生成的模型类 final modelImports = _getRequiredModelImportsForPaths(paths); - final sortedModelImports = modelImports.toList()..sort(); - for (final modelImport in sortedModelImports) { + for (final modelImport in modelImports) { buffer.writeln( 'import \'../../api_models/${StringUtils.generateFileName(modelImport)}\';'); } @@ -1407,51 +1370,6 @@ class RetrofitApiGenerator extends BaseGenerator { return '${StringUtils.toPascalCase(tagName)}Api'; } - /// 检查整个文档是否需要导入分页相关类型 - bool _needsPaginationImportForDocument() { - for (final path in document.paths.values) { - final returnType = _generateReturnType(path); - // 检查返回类型是否包含 BasePageResult - if (returnType.contains('BasePageResult')) { - return true; - } - } - return false; - } - - /// 检查是否需要请求体 - bool _needsRequestBody(ApiPath path) { - // 如果有明确定义的 requestBody,则需要 - if (path.requestBody != null) { - return true; - } - - // 如果有 body 类型的参数,则需要 - final bodyParams = path.parameters - .where((p) => p.location == ParameterLocation.body) - .toList(); - if (bodyParams.isNotEmpty) { - return true; - } - - // 如果没有明确的 requestBody 或 body 参数定义,则不添加请求体 - // 这是最保守的做法,避免添加不必要的参数 - // 如果后端需要请求体但没有在 swagger 中定义,应该要求后端完善文档 - return false; - } - - /// 检查指定路径列表是否需要导入分页相关类型 - bool _needsPaginationImport(List paths) { - for (final path in paths) { - final returnType = _generateReturnType(path); - // 检查返回类型是否包含 BasePageResult - if (returnType.contains('BasePageResult')) { - return true; - } - } - return false; - } - /// 获取指定路径列表所需的模型导入 Set _getRequiredModelImportsForPaths(List paths) { final imports = {}; @@ -1704,6 +1622,102 @@ class RetrofitApiGenerator extends BaseGenerator { } } } + + /// 基于 operationId 推断类型 + String? _inferTypeFromOperationId(String operationId) { + // 基于 operationId 的模式匹配推断类型 + if (operationId.contains('login')) { + return 'UserLoginResult'; + } + if (operationId.contains('register')) { + return 'UserLoginResult'; + } + if (operationId.contains('get') && operationId.contains('list')) { + // 根据 operationId 推断列表类型 + if (operationId.contains('class')) { + return 'List'; + } + if (operationId.contains('task')) { + return 'List'; + } + if (operationId.contains('school')) { + return 'List'; + } + if (operationId.contains('user')) { + return 'List'; + } + } + if (operationId.contains('upload')) { + return 'SysFileViewDto'; + } + if (operationId.contains('config')) { + return 'OsConfigResult'; + } + if (operationId.contains('sign')) { + return 'OssSignResult'; + } + if (operationId.contains('version')) { + return 'UpdateappResult'; + } + + return null; + } + + /// 基于路径关键词推断类型 + String? _inferTypeFromPathKeywords( + String pathLower, String summaryLower, List tags) { + // 基于路径关键词的智能推断 + if (pathLower.contains('healthcheck') || pathLower.contains('health')) { + return 'void'; + } + + if (pathLower.contains('/login/')) { + return 'UserLoginResult'; + } + + if (pathLower.contains('/get') && pathLower.contains('list')) { + // 列表类型的推断 + if (pathLower.contains('class') && !pathLower.contains('task')) { + return 'List'; + } + if (pathLower.contains('task')) { + return 'List'; + } + if (pathLower.contains('school')) { + return 'List'; + } + if (pathLower.contains('user')) { + return 'List'; + } + } + + if (pathLower.contains('/upload') || pathLower.contains('/file')) { + return 'SysFileViewDto'; + } + + if (pathLower.contains('/config')) { + return 'OsConfigResult'; + } + + if (pathLower.contains('/sign')) { + return 'OssSignResult'; + } + + if (pathLower.contains('/version')) { + return 'UpdateappResult'; + } + + // 基于 summary 和 tags 的推断 + if (summaryLower.contains('列表') || summaryLower.contains('分页')) { + return 'List'; + } + + if (tags.any((tag) => tag.contains('task'))) { + return 'TaskInfoResult'; + } + + return null; + } } /// API 方法参数 @@ -1712,961 +1726,11 @@ class ApiMethodParameter { final String type; final String annotation; final bool required; - final String description; - final dynamic defaultValue; ApiMethodParameter({ required this.name, required this.type, required this.annotation, required this.required, - this.description = '', - this.defaultValue, }); } - -/// 组合模式处理扩展 -extension CompositionSchemaExtension on RetrofitApiGenerator { - /// 从组合模式 schema 中提取类型 - String? _extractTypeFromCompositionSchema(Map schema) { - // 优先处理带有 discriminator 的组合模式 - if (schema['discriminator'] != null) { - final discriminatorType = _handleDiscriminatorSchema(schema); - if (discriminatorType != null) { - return discriminatorType; - } - } - - // 处理 allOf - 合并所有 schema - if (schema['allOf'] != null) { - final allOfSchemas = schema['allOf'] as List; - return _handleAllOfSchema(allOfSchemas); - } - - // 处理 oneOf - 选择其中一个 schema (通常生成联合类型或基类) - if (schema['oneOf'] != null) { - final oneOfSchemas = schema['oneOf'] as List; - return _handleOneOfSchema(oneOfSchemas); - } - - // 处理 anyOf - 可以匹配一个或多个 schema - if (schema['anyOf'] != null) { - final anyOfSchemas = schema['anyOf'] as List; - return _handleAnyOfSchema(anyOfSchemas); - } - - return null; - } - - /// 处理 allOf 组合模式 - String? _handleAllOfSchema(List schemas) { - // allOf 表示必须满足所有 schema,通常用于继承或组合 - // 我们尝试找到第一个有具体类型的 schema - for (final schemaData in schemas) { - if (schemaData is Map) { - // 如果是引用,直接返回引用的类型 - if (schemaData['\$ref'] != null) { - final ref = schemaData['\$ref'] as String; - final refName = ref.split('/').last; - return StringUtils.generateClassName(refName); - } - - // 如果有具体类型,返回该类型 - if (schemaData['type'] != null) { - final type = schemaData['type'] as String; - if (type == 'object') { - // 对于对象类型,我们可能需要生成一个组合类型 - // 暂时返回 Map - return 'Map'; - } else if (type == 'array') { - // 处理数组类型 - final items = schemaData['items']; - if (items != null) { - final itemType = - _extractTypeFromSchema(items as Map?); - return 'List<${itemType ?? 'dynamic'}>'; - } - return 'List'; - } else { - return _mapJsonTypeToFlutterType(type); - } - } - } - } - - // 如果没有找到具体类型,返回通用类型 - return 'Map'; - } - - /// 处理 oneOf 组合模式 - String? _handleOneOfSchema(List schemas) { - // oneOf 表示必须匹配其中一个 schema,通常用于联合类型 - // 在 Dart 中,我们可以使用基类或 Object 类型 - - // 检查是否所有 schema 都是引用类型 - final refTypes = []; - for (final schemaData in schemas) { - if (schemaData is Map && schemaData['\$ref'] != null) { - final ref = schemaData['\$ref'] as String; - final refName = ref.split('/').last; - refTypes.add(StringUtils.generateClassName(refName)); - } - } - - if (refTypes.isNotEmpty) { - // 如果有多个引用类型,返回 Object 或第一个类型 - if (refTypes.length == 1) { - return refTypes.first; - } else { - // 对于多个类型,我们可以返回 Object 或创建联合类型 - return 'Object'; // 或者可以生成联合类型接口 - } - } - - // 如果不是引用类型,尝试提取第一个有效类型 - for (final schemaData in schemas) { - if (schemaData is Map) { - final extractedType = _extractTypeFromSchema(schemaData); - if (extractedType != null) { - return extractedType; - } - } - } - - return 'Object'; - } - - /// 处理带有 discriminator 的组合模式 - String? _handleDiscriminatorSchema(Map schema) { - final discriminatorData = schema['discriminator'] as Map?; - if (discriminatorData == null) return null; - - final mapping = discriminatorData['mapping'] as Map? ?? {}; - - // 如果有 oneOf 或 anyOf,并且有 discriminator,我们可以生成更智能的类型 - if (schema['oneOf'] != null || schema['anyOf'] != null) { - final schemas = (schema['oneOf'] ?? schema['anyOf']) as List; - - // 如果有映射表,我们可以根据映射生成联合类型 - if (mapping.isNotEmpty) { - final mappedTypes = []; - mapping.values.forEach((value) { - if (value is String) { - // 提取引用的类型名 - final refName = value.split('/').last; - mappedTypes.add(StringUtils.generateClassName(refName)); - } - }); - - if (mappedTypes.isNotEmpty) { - // 返回第一个类型作为基类,或者 Object - return mappedTypes.first; - } - } - - // 如果没有映射表,使用默认的 oneOf 处理 - return _handleOneOfSchema(schemas); - } - - return null; - } - - /// 处理 anyOf 组合模式 - String? _handleAnyOfSchema(List schemas) { - // anyOf 表示可以匹配一个或多个 schema - // 处理方式类似 oneOf,但更宽松 - return _handleOneOfSchema(schemas); - } - - /// 将 JSON Schema 类型映射到 Flutter 类型 - String _mapJsonTypeToFlutterType(String jsonType) { - switch (jsonType) { - case 'string': - return 'String'; - case 'integer': - return 'int'; - case 'number': - return 'double'; - case 'boolean': - return 'bool'; - case 'array': - return 'List'; - case 'object': - return 'Map'; - default: - return 'dynamic'; - } - } - - /// 处理高级 Schema 特性 - String? _handleAdvancedSchemaFeatures(Map schema) { - // 处理 const 值 - if (schema['const'] != null) { - final constValue = schema['const']; - if (constValue is String) { - return 'String'; // 常量字符串 - } else if (constValue is num) { - return constValue is int ? 'int' : 'double'; - } else if (constValue is bool) { - return 'bool'; - } - return 'dynamic'; - } - - // 处理 additionalProperties - if (schema['additionalProperties'] != null) { - final additionalProps = schema['additionalProperties']; - if (additionalProps is bool) { - return additionalProps ? 'Map' : 'Map'; - } else if (additionalProps is Map) { - // additionalProperties 是一个 schema - final valueType = _extractTypeFromSchema(additionalProps); - return 'Map'; - } - } - - // 处理 patternProperties - if (schema['patternProperties'] != null) { - final patternProps = schema['patternProperties'] as Map?; - if (patternProps != null && patternProps.isNotEmpty) { - // 对于模式属性,我们通常返回 Map - // 因为 Dart 不支持基于正则表达式的类型约束 - return 'Map'; - } - } - - // 处理条件 Schema (if/then/else) - if (schema['if'] != null || - schema['then'] != null || - schema['else'] != null) { - // 对于条件 Schema,我们尝试从 then 或 else 中提取类型 - if (schema['then'] != null) { - final thenType = - _extractTypeFromSchema(schema['then'] as Map?); - if (thenType != null) return thenType; - } - if (schema['else'] != null) { - final elseType = - _extractTypeFromSchema(schema['else'] as Map?); - if (elseType != null) return elseType; - } - return 'dynamic'; // 无法确定具体类型 - } - - return null; - } - - /// 生成安全方案相关的代码 - String _generateSecurityCode(SwaggerDocument document) { - final buffer = StringBuffer(); - - // 生成安全方案常量 - if (document.components.securitySchemes.isNotEmpty) { - buffer.writeln('// Security Schemes'); - buffer.writeln('class SecuritySchemes {'); - - document.components.securitySchemes.forEach((name, scheme) { - buffer.writeln(' /// ${scheme.description}'); - if (scheme.isApiKey) { - buffer.writeln( - ' static const String ${StringUtils.generateConstantName(name)} = \'$name\';'); - buffer.writeln( - ' static const String ${StringUtils.generateConstantName(name)}_PARAM = \'${scheme.name}\';'); - buffer.writeln( - ' static const String ${StringUtils.generateConstantName(name)}_LOCATION = \'${scheme.location?.value}\';'); - } else if (scheme.isHttp) { - buffer.writeln( - ' static const String ${StringUtils.generateConstantName(name)} = \'$name\';'); - buffer.writeln( - ' static const String ${StringUtils.generateConstantName(name)}_SCHEME = \'${scheme.scheme}\';'); - if (scheme.bearerFormat != null) { - buffer.writeln( - ' static const String ${StringUtils.generateConstantName(name)}_FORMAT = \'${scheme.bearerFormat}\';'); - } - } else if (scheme.isOAuth2) { - buffer.writeln( - ' static const String ${StringUtils.generateConstantName(name)} = \'$name\';'); - if (scheme.flows?.hasAnyFlow == true) { - final flows = scheme.flows!; - flows.availableFlows.forEach((flowType) { - final flow = flows.getFlow(flowType); - if (flow != null) { - final flowName = StringUtils.generateConstantName( - '${name}_${flowType.value}'); - if (flow.hasAuthorizationUrl) { - buffer.writeln( - ' static const String ${flowName}_AUTH_URL = \'${flow.authorizationUrl}\';'); - } - if (flow.hasTokenUrl) { - buffer.writeln( - ' static const String ${flowName}_TOKEN_URL = \'${flow.tokenUrl}\';'); - } - if (flow.hasScopes) { - buffer.writeln( - ' static const Map ${flowName}_SCOPES = {'); - flow.scopes.forEach((scope, description) { - buffer.writeln(' \'$scope\': \'$description\','); - }); - buffer.writeln(' };'); - } - } - }); - } - } - buffer.writeln(); - }); - - buffer.writeln('}'); - buffer.writeln(); - } - - // 生成安全拦截器 - buffer.writeln('// Security Interceptors'); - buffer.writeln('class ApiKeyInterceptor extends Interceptor {'); - buffer.writeln(' final String apiKey;'); - buffer.writeln(' final String paramName;'); - buffer.writeln(' final String location;'); - buffer.writeln(); - buffer.writeln(' ApiKeyInterceptor({'); - buffer.writeln(' required this.apiKey,'); - buffer.writeln(' required this.paramName,'); - buffer.writeln(' required this.location,'); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln(' @override'); - buffer.writeln( - ' void onRequest(RequestOptions options, RequestInterceptorHandler handler) {'); - buffer.writeln(' switch (location) {'); - buffer.writeln(' case \'header\':'); - buffer.writeln(' options.headers[paramName] = apiKey;'); - buffer.writeln(' break;'); - buffer.writeln(' case \'query\':'); - buffer.writeln(' options.queryParameters[paramName] = apiKey;'); - buffer.writeln(' break;'); - buffer.writeln(' case \'cookie\':'); - buffer.writeln( - ' options.headers[\'Cookie\'] = \'\$paramName=\$apiKey\';'); - buffer.writeln(' break;'); - buffer.writeln(' }'); - buffer.writeln(' handler.next(options);'); - buffer.writeln(' }'); - buffer.writeln('}'); - buffer.writeln(); - - buffer.writeln('class BearerTokenInterceptor extends Interceptor {'); - buffer.writeln(' final String token;'); - buffer.writeln(' final String? tokenPrefix;'); - buffer.writeln(); - buffer.writeln(' BearerTokenInterceptor({'); - buffer.writeln(' required this.token,'); - buffer.writeln(' this.tokenPrefix = \'Bearer\','); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln(' @override'); - buffer.writeln( - ' void onRequest(RequestOptions options, RequestInterceptorHandler handler) {'); - buffer.writeln(' if (tokenPrefix != null && tokenPrefix!.isNotEmpty) {'); - buffer.writeln( - ' options.headers[\'Authorization\'] = \'\$tokenPrefix \$token\';'); - buffer.writeln(' } else {'); - buffer.writeln(' options.headers[\'Authorization\'] = token;'); - buffer.writeln(' }'); - buffer.writeln(' handler.next(options);'); - buffer.writeln(' }'); - buffer.writeln('}'); - buffer.writeln(); - - buffer.writeln('class BasicAuthInterceptor extends Interceptor {'); - buffer.writeln(' final String username;'); - buffer.writeln(' final String password;'); - buffer.writeln(); - buffer.writeln(' BasicAuthInterceptor({'); - buffer.writeln(' required this.username,'); - buffer.writeln(' required this.password,'); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln(' @override'); - buffer.writeln( - ' void onRequest(RequestOptions options, RequestInterceptorHandler handler) {'); - buffer.writeln( - ' final credentials = base64Encode(utf8.encode(\'\$username:\$password\'));'); - buffer.writeln( - ' options.headers[\'Authorization\'] = \'Basic \$credentials\';'); - buffer.writeln(' handler.next(options);'); - buffer.writeln(' }'); - buffer.writeln('}'); - buffer.writeln(); - - buffer.writeln('class DigestAuthInterceptor extends Interceptor {'); - buffer.writeln(' final String username;'); - buffer.writeln(' final String password;'); - buffer.writeln(' String? _realm;'); - buffer.writeln(' String? _nonce;'); - buffer.writeln(' String? _qop;'); - buffer.writeln(' String? _opaque;'); - buffer.writeln(); - buffer.writeln(' DigestAuthInterceptor({'); - buffer.writeln(' required this.username,'); - buffer.writeln(' required this.password,'); - buffer.writeln(' });'); - buffer.writeln(); - buffer.writeln(' @override'); - buffer.writeln( - ' void onRequest(RequestOptions options, RequestInterceptorHandler handler) {'); - buffer.writeln(' if (_nonce != null) {'); - buffer.writeln(' final uri = options.uri.toString();'); - buffer.writeln(' final method = options.method;'); - buffer.writeln( - ' final ha1 = md5.convert(utf8.encode(\'\$username:\$_realm:\$password\')).toString();'); - buffer.writeln( - ' final ha2 = md5.convert(utf8.encode(\'\$method:\$uri\')).toString();'); - buffer.writeln( - ' final response = md5.convert(utf8.encode(\'\$ha1:\$_nonce:\$ha2\')).toString();'); - buffer.writeln(); - buffer.writeln( - ' final authHeader = \'Digest username="\$username", realm="\$_realm", \' +'); - buffer.writeln( - ' \'nonce="\$_nonce", uri="\$uri", response="\$response"\';'); - buffer.writeln(); - buffer.writeln(' if (_qop != null) {'); - buffer.writeln(' // TODO: Implement qop support'); - buffer.writeln(' }'); - buffer.writeln(); - buffer.writeln(' if (_opaque != null) {'); - buffer.writeln(' // authHeader += \', opaque="\$_opaque"\';'); - buffer.writeln(' }'); - buffer.writeln(); - buffer.writeln(' options.headers[\'Authorization\'] = authHeader;'); - buffer.writeln(' }'); - buffer.writeln(' handler.next(options);'); - buffer.writeln(' }'); - buffer.writeln(); - buffer.writeln(' @override'); - buffer.writeln( - ' void onError(DioException err, ErrorInterceptorHandler handler) {'); - buffer.writeln(' if (err.response?.statusCode == 401) {'); - buffer.writeln( - ' final wwwAuth = err.response?.headers[\'www-authenticate\']?.first;'); - buffer.writeln( - ' if (wwwAuth != null && wwwAuth.startsWith(\'Digest\')) {'); - buffer.writeln(' _parseDigestChallenge(wwwAuth);'); - buffer.writeln(' // Retry the request with digest auth'); - buffer.writeln(' final options = err.requestOptions;'); - buffer.writeln(' onRequest(options, RequestInterceptorHandler());'); - buffer.writeln( - ' // Note: In real implementation, you would retry the request here'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln(' handler.next(err);'); - buffer.writeln(' }'); - buffer.writeln(); - buffer.writeln(' void _parseDigestChallenge(String challenge) {'); - buffer.writeln(' final regex = RegExp(r\'(\\w+)="([^"]+)"\');'); - buffer.writeln(' final matches = regex.allMatches(challenge);'); - buffer.writeln(' for (final match in matches) {'); - buffer.writeln(' final key = match.group(1);'); - buffer.writeln(' final value = match.group(2);'); - buffer.writeln(' switch (key) {'); - buffer.writeln(' case \'realm\':'); - buffer.writeln(' _realm = value;'); - buffer.writeln(' break;'); - buffer.writeln(' case \'nonce\':'); - buffer.writeln(' _nonce = value;'); - buffer.writeln(' break;'); - buffer.writeln(' case \'qop\':'); - buffer.writeln(' _qop = value;'); - buffer.writeln(' break;'); - buffer.writeln(' case \'opaque\':'); - buffer.writeln(' _opaque = value;'); - buffer.writeln(' break;'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln('}'); - buffer.writeln(); - - return buffer.toString(); - } - - /// 生成媒体类型处理代码 - String _generateMediaTypeHandlers() { - final buffer = StringBuffer(); - - buffer.writeln('// Media Type Handlers'); - buffer.writeln('class MediaTypeHandler {'); - buffer.writeln(' /// 处理 JSON 数据'); - buffer.writeln(' static Map handleJson(dynamic data) {'); - buffer.writeln(' if (data is String) {'); - buffer.writeln(' return jsonDecode(data) as Map;'); - buffer.writeln(' } else if (data is Map) {'); - buffer.writeln(' return data;'); - buffer.writeln(' }'); - buffer.writeln(' throw ArgumentError(\'Invalid JSON data type\');'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 处理 XML 数据'); - buffer.writeln(' static String handleXml(dynamic data) {'); - buffer.writeln(' if (data is String) {'); - buffer.writeln(' return data;'); - buffer.writeln(' }'); - buffer.writeln(' return data.toString();'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 处理表单数据'); - buffer.writeln( - ' static FormData handleFormData(Map data) {'); - buffer.writeln(' final formData = FormData();'); - buffer.writeln(' data.forEach((key, value) {'); - buffer.writeln(' if (value is MultipartFile) {'); - buffer.writeln(' formData.files.add(MapEntry(key, value));'); - buffer.writeln(' } else if (value is List) {'); - buffer.writeln(' for (final file in value) {'); - buffer.writeln(' formData.files.add(MapEntry(key, file));'); - buffer.writeln(' }'); - buffer.writeln(' } else {'); - buffer.writeln( - ' formData.fields.add(MapEntry(key, value.toString()));'); - buffer.writeln(' }'); - buffer.writeln(' });'); - buffer.writeln(' return formData;'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 处理 URL 编码表单数据'); - buffer.writeln( - ' static String handleUrlEncodedForm(Map data) {'); - buffer.writeln(' final params = [];'); - buffer.writeln(' data.forEach((key, value) {'); - buffer.writeln(' final encodedKey = Uri.encodeComponent(key);'); - buffer.writeln( - ' final encodedValue = Uri.encodeComponent(value.toString());'); - buffer.writeln(' params.add(\'\$encodedKey=\$encodedValue\');'); - buffer.writeln(' });'); - buffer.writeln(' return params.join(\'&\');'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 处理二进制数据'); - buffer.writeln(' static List handleBinary(dynamic data) {'); - buffer.writeln(' if (data is List) {'); - buffer.writeln(' return data;'); - buffer.writeln(' } else if (data is String) {'); - buffer.writeln(' return utf8.encode(data);'); - buffer.writeln(' }'); - buffer.writeln(' throw ArgumentError(\'Invalid binary data type\');'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 处理文本数据'); - buffer.writeln(' static String handleText(dynamic data) {'); - buffer.writeln(' return data.toString();'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 根据媒体类型处理数据'); - buffer.writeln( - ' static dynamic handleByMediaType(String mediaType, dynamic data) {'); - buffer.writeln(' switch (mediaType.toLowerCase()) {'); - buffer.writeln(' case \'application/json\':'); - buffer.writeln(' return handleJson(data);'); - buffer.writeln(' case \'application/xml\':'); - buffer.writeln(' case \'text/xml\':'); - buffer.writeln(' return handleXml(data);'); - buffer.writeln(' case \'multipart/form-data\':'); - buffer.writeln( - ' return handleFormData(data as Map);'); - buffer.writeln(' case \'application/x-www-form-urlencoded\':'); - buffer.writeln( - ' return handleUrlEncodedForm(data as Map);'); - buffer.writeln(' case \'application/octet-stream\':'); - buffer.writeln(' case \'application/pdf\':'); - buffer.writeln(' case \'image/png\':'); - buffer.writeln(' case \'image/jpeg\':'); - buffer.writeln(' case \'image/gif\':'); - buffer.writeln(' case \'audio/mpeg\':'); - buffer.writeln(' case \'video/mp4\':'); - buffer.writeln(' return handleBinary(data);'); - buffer.writeln(' case \'text/plain\':'); - buffer.writeln(' case \'text/html\':'); - buffer.writeln(' case \'text/csv\':'); - buffer.writeln(' case \'image/svg+xml\':'); - buffer.writeln(' return handleText(data);'); - buffer.writeln(' default:'); - buffer.writeln(' return data;'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln('}'); - buffer.writeln(); - - return buffer.toString(); - } - - /// 生成文件上传处理代码 - String _generateFileUploadHandlers() { - final buffer = StringBuffer(); - - buffer.writeln('// File Upload Handlers'); - buffer.writeln('class FileUploadHandler {'); - buffer.writeln(' /// 创建单个文件的 MultipartFile'); - buffer.writeln(' static Future createMultipartFile({'); - buffer.writeln(' required String filePath,'); - buffer.writeln(' String? filename,'); - buffer.writeln(' String? contentType,'); - buffer.writeln(' }) async {'); - buffer.writeln(' return MultipartFile.fromFile('); - buffer.writeln(' filePath,'); - buffer.writeln(' filename: filename ?? path.basename(filePath),'); - buffer.writeln( - ' contentType: contentType != null ? MediaType.parse(contentType) : null,'); - buffer.writeln(' );'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 从字节数组创建 MultipartFile'); - buffer.writeln(' static MultipartFile createMultipartFileFromBytes({'); - buffer.writeln(' required List bytes,'); - buffer.writeln(' required String filename,'); - buffer.writeln(' String? contentType,'); - buffer.writeln(' }) {'); - buffer.writeln(' return MultipartFile.fromBytes('); - buffer.writeln(' bytes,'); - buffer.writeln(' filename: filename,'); - buffer.writeln( - ' contentType: contentType != null ? MediaType.parse(contentType) : null,'); - buffer.writeln(' );'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 从流创建 MultipartFile'); - buffer.writeln(' static MultipartFile createMultipartFileFromStream({'); - buffer.writeln(' required Stream> stream,'); - buffer.writeln(' required int length,'); - buffer.writeln(' required String filename,'); - buffer.writeln(' String? contentType,'); - buffer.writeln(' }) {'); - buffer.writeln(' return MultipartFile('); - buffer.writeln(' stream,'); - buffer.writeln(' length,'); - buffer.writeln(' filename: filename,'); - buffer.writeln( - ' contentType: contentType != null ? MediaType.parse(contentType) : null,'); - buffer.writeln(' );'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 创建图片文件的 MultipartFile'); - buffer.writeln(' static Future createImageFile({'); - buffer.writeln(' required String filePath,'); - buffer.writeln(' String? filename,'); - buffer.writeln(' }) async {'); - buffer.writeln( - ' final extension = path.extension(filePath).toLowerCase();'); - buffer.writeln(' String? contentType;'); - buffer.writeln(' switch (extension) {'); - buffer.writeln(' case \'.jpg\':'); - buffer.writeln(' case \'.jpeg\':'); - buffer.writeln(' contentType = \'image/jpeg\';'); - buffer.writeln(' break;'); - buffer.writeln(' case \'.png\':'); - buffer.writeln(' contentType = \'image/png\';'); - buffer.writeln(' break;'); - buffer.writeln(' case \'.gif\':'); - buffer.writeln(' contentType = \'image/gif\';'); - buffer.writeln(' break;'); - buffer.writeln(' case \'.svg\':'); - buffer.writeln(' contentType = \'image/svg+xml\';'); - buffer.writeln(' break;'); - buffer.writeln(' default:'); - buffer.writeln(' contentType = \'application/octet-stream\';'); - buffer.writeln(' }'); - buffer.writeln(' return createMultipartFile('); - buffer.writeln(' filePath: filePath,'); - buffer.writeln(' filename: filename,'); - buffer.writeln(' contentType: contentType,'); - buffer.writeln(' );'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 创建音频文件的 MultipartFile'); - buffer.writeln(' static Future createAudioFile({'); - buffer.writeln(' required String filePath,'); - buffer.writeln(' String? filename,'); - buffer.writeln(' }) async {'); - buffer.writeln( - ' final extension = path.extension(filePath).toLowerCase();'); - buffer.writeln(' String? contentType;'); - buffer.writeln(' switch (extension) {'); - buffer.writeln(' case \'.mp3\':'); - buffer.writeln(' contentType = \'audio/mpeg\';'); - buffer.writeln(' break;'); - buffer.writeln(' case \'.wav\':'); - buffer.writeln(' contentType = \'audio/wav\';'); - buffer.writeln(' break;'); - buffer.writeln(' case \'.ogg\':'); - buffer.writeln(' contentType = \'audio/ogg\';'); - buffer.writeln(' break;'); - buffer.writeln(' default:'); - buffer.writeln(' contentType = \'audio/mpeg\';'); - buffer.writeln(' }'); - buffer.writeln(' return createMultipartFile('); - buffer.writeln(' filePath: filePath,'); - buffer.writeln(' filename: filename,'); - buffer.writeln(' contentType: contentType,'); - buffer.writeln(' );'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 创建视频文件的 MultipartFile'); - buffer.writeln(' static Future createVideoFile({'); - buffer.writeln(' required String filePath,'); - buffer.writeln(' String? filename,'); - buffer.writeln(' }) async {'); - buffer.writeln( - ' final extension = path.extension(filePath).toLowerCase();'); - buffer.writeln(' String? contentType;'); - buffer.writeln(' switch (extension) {'); - buffer.writeln(' case \'.mp4\':'); - buffer.writeln(' contentType = \'video/mp4\';'); - buffer.writeln(' break;'); - buffer.writeln(' case \'.avi\':'); - buffer.writeln(' contentType = \'video/x-msvideo\';'); - buffer.writeln(' break;'); - buffer.writeln(' case \'.mov\':'); - buffer.writeln(' contentType = \'video/quicktime\';'); - buffer.writeln(' break;'); - buffer.writeln(' default:'); - buffer.writeln(' contentType = \'video/mp4\';'); - buffer.writeln(' }'); - buffer.writeln(' return createMultipartFile('); - buffer.writeln(' filePath: filePath,'); - buffer.writeln(' filename: filename,'); - buffer.writeln(' contentType: contentType,'); - buffer.writeln(' );'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 验证文件大小'); - buffer.writeln( - ' static bool validateFileSize(String filePath, int maxSizeInBytes) {'); - buffer.writeln(' final file = File(filePath);'); - buffer.writeln(' if (!file.existsSync()) return false;'); - buffer.writeln(' return file.lengthSync() <= maxSizeInBytes;'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 验证文件类型'); - buffer.writeln( - ' static bool validateFileType(String filePath, List allowedExtensions) {'); - buffer.writeln( - ' final extension = path.extension(filePath).toLowerCase();'); - buffer.writeln(' return allowedExtensions.contains(extension);'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 批量创建文件'); - buffer - .writeln(' static Future> createMultipleFiles({'); - buffer.writeln(' required List filePaths,'); - buffer.writeln(' String? contentType,'); - buffer.writeln(' }) async {'); - buffer.writeln(' final files = [];'); - buffer.writeln(' for (final filePath in filePaths) {'); - buffer.writeln(' final file = await createMultipartFile('); - buffer.writeln(' filePath: filePath,'); - buffer.writeln(' contentType: contentType,'); - buffer.writeln(' );'); - buffer.writeln(' files.add(file);'); - buffer.writeln(' }'); - buffer.writeln(' return files;'); - buffer.writeln(' }'); - buffer.writeln('}'); - buffer.writeln(); - - return buffer.toString(); - } - - /// 生成编码处理代码 - String _generateEncodingHandlers() { - final buffer = StringBuffer(); - - buffer.writeln('// Encoding Handlers'); - buffer.writeln('class EncodingHandler {'); - buffer.writeln(' /// 支持的字符编码'); - buffer - .writeln(' static const Map supportedEncodings = {'); - buffer.writeln(' \'utf-8\': utf8,'); - buffer.writeln(' \'utf8\': utf8,'); - buffer.writeln(' \'ascii\': ascii,'); - buffer.writeln(' \'latin1\': latin1,'); - buffer.writeln(' \'iso-8859-1\': latin1,'); - buffer.writeln(' };'); - buffer.writeln(); - - buffer.writeln(' /// 根据编码名称获取编码器'); - buffer.writeln(' static Encoding getEncoding(String? encodingName) {'); - buffer.writeln(' if (encodingName == null) return utf8;'); - buffer.writeln( - ' final normalizedName = encodingName.toLowerCase().replaceAll(\'_\', \'-\');'); - buffer.writeln(' return supportedEncodings[normalizedName] ?? utf8;'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 编码字符串'); - buffer.writeln( - ' static List encodeString(String data, [String? encodingName]) {'); - buffer.writeln(' final encoding = getEncoding(encodingName);'); - buffer.writeln(' return encoding.encode(data);'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 解码字节数组'); - buffer.writeln( - ' static String decodeBytes(List bytes, [String? encodingName]) {'); - buffer.writeln(' final encoding = getEncoding(encodingName);'); - buffer.writeln(' return encoding.decode(bytes);'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// Base64 编码'); - buffer.writeln(' static String encodeBase64(List bytes) {'); - buffer.writeln(' return base64Encode(bytes);'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// Base64 解码'); - buffer.writeln(' static List decodeBase64(String data) {'); - buffer.writeln(' return base64Decode(data);'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// URL 编码'); - buffer.writeln(' static String encodeUrl(String data) {'); - buffer.writeln(' return Uri.encodeComponent(data);'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// URL 解码'); - buffer.writeln(' static String decodeUrl(String data) {'); - buffer.writeln(' return Uri.decodeComponent(data);'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 处理 Content-Encoding'); - buffer.writeln( - ' static List handleContentEncoding(List data, String? encoding) {'); - buffer.writeln(' if (encoding == null) return data;'); - buffer.writeln(' switch (encoding.toLowerCase()) {'); - buffer.writeln(' case \'gzip\':'); - buffer.writeln(' return gzip.decode(data);'); - buffer.writeln(' case \'deflate\':'); - buffer.writeln(' return zlib.decode(data);'); - buffer.writeln(' case \'br\':'); - buffer.writeln(' // Brotli 解码需要额外的包支持'); - buffer.writeln( - ' throw UnsupportedError(\'Brotli encoding not supported\');'); - buffer.writeln(' case \'identity\':'); - buffer.writeln(' default:'); - buffer.writeln(' return data;'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 处理 Transfer-Encoding'); - buffer.writeln( - ' static List handleTransferEncoding(List data, String? encoding) {'); - buffer.writeln(' if (encoding == null) return data;'); - buffer.writeln(' switch (encoding.toLowerCase()) {'); - buffer.writeln(' case \'chunked\':'); - buffer.writeln(' return _decodeChunked(data);'); - buffer.writeln(' case \'compress\':'); - buffer.writeln( - ' throw UnsupportedError(\'Compress transfer encoding not supported\');'); - buffer.writeln(' case \'deflate\':'); - buffer.writeln(' return zlib.decode(data);'); - buffer.writeln(' case \'gzip\':'); - buffer.writeln(' return gzip.decode(data);'); - buffer.writeln(' case \'identity\':'); - buffer.writeln(' default:'); - buffer.writeln(' return data;'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 解码分块传输编码'); - buffer.writeln(' static List _decodeChunked(List data) {'); - buffer.writeln(' final result = [];'); - buffer.writeln(' var offset = 0;'); - buffer.writeln(' while (offset < data.length) {'); - buffer.writeln(' // 查找块大小行的结束'); - buffer.writeln(' var lineEnd = offset;'); - buffer.writeln(' while (lineEnd < data.length - 1) {'); - buffer.writeln( - ' if (data[lineEnd] == 13 && data[lineEnd + 1] == 10) break; // \\r\\n'); - buffer.writeln(' lineEnd++;'); - buffer.writeln(' }'); - buffer.writeln(' if (lineEnd >= data.length - 1) break;'); - buffer.writeln(); - buffer.writeln(' // 解析块大小'); - buffer.writeln( - ' final sizeHex = String.fromCharCodes(data.sublist(offset, lineEnd));'); - buffer.writeln( - ' final chunkSize = int.tryParse(sizeHex, radix: 16) ?? 0;'); - buffer.writeln(' if (chunkSize == 0) break; // 最后一个块'); - buffer.writeln(); - buffer.writeln(' // 跳过 \\r\\n'); - buffer.writeln(' offset = lineEnd + 2;'); - buffer.writeln(); - buffer.writeln(' // 读取块数据'); - buffer.writeln(' if (offset + chunkSize <= data.length) {'); - buffer.writeln( - ' result.addAll(data.sublist(offset, offset + chunkSize));'); - buffer.writeln(' offset += chunkSize + 2; // 跳过块数据后的 \\r\\n'); - buffer.writeln(' } else {'); - buffer.writeln(' break;'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln(' return result;'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 检测字符编码'); - buffer.writeln(' static String? detectEncoding(List bytes) {'); - buffer.writeln(' // 检测 BOM'); - buffer.writeln(' if (bytes.length >= 3) {'); - buffer.writeln( - ' if (bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) {'); - buffer.writeln(' return \'utf-8\';'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln(' if (bytes.length >= 2) {'); - buffer.writeln(' if (bytes[0] == 0xFF && bytes[1] == 0xFE) {'); - buffer.writeln(' return \'utf-16le\';'); - buffer.writeln(' }'); - buffer.writeln(' if (bytes[0] == 0xFE && bytes[1] == 0xFF) {'); - buffer.writeln(' return \'utf-16be\';'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln(' // 默认假设为 UTF-8'); - buffer.writeln(' return \'utf-8\';'); - buffer.writeln(' }'); - buffer.writeln(); - - buffer.writeln(' /// 验证编码是否有效'); - buffer.writeln( - ' static bool isValidEncoding(List bytes, String encodingName) {'); - buffer.writeln(' try {'); - buffer.writeln(' final encoding = getEncoding(encodingName);'); - buffer.writeln(' encoding.decode(bytes);'); - buffer.writeln(' return true;'); - buffer.writeln(' } catch (e) {'); - buffer.writeln(' return false;'); - buffer.writeln(' }'); - buffer.writeln(' }'); - buffer.writeln('}'); - buffer.writeln(); - - return buffer.toString(); - } -} diff --git a/lib/parsers/swagger_data_parser.dart b/lib/parsers/swagger_data_parser.dart index 4412a31..d6fe40b 100644 --- a/lib/parsers/swagger_data_parser.dart +++ b/lib/parsers/swagger_data_parser.dart @@ -8,21 +8,23 @@ import '../core/exceptions.dart'; import '../core/models.dart'; import '../utils/cache_manager.dart'; import '../utils/performance_monitor.dart'; -import '../utils/reference_resolver.dart'; import '../utils/string_utils.dart'; +import '../utils/type_validator.dart'; /// Swagger数据解析器 /// 负责解析Swagger JSON文档并提取相关信息 class SwaggerDataParser { final CacheManager _cacheManager; final PerformanceMonitor _performanceMonitor; + final TypeValidator _typeValidator; // 缓存解析结果 SwaggerDocument? _cachedDocument; SwaggerDataParser() : _cacheManager = CacheManager(), - _performanceMonitor = PerformanceMonitor(); + _performanceMonitor = PerformanceMonitor(), + _typeValidator = TypeValidator(); /// 获取并解析Swagger JSON文档 Future fetchAndParseSwaggerDocument() async { @@ -109,11 +111,12 @@ class SwaggerDataParser { final version = info['version'] as String? ?? '1.0.0'; final description = info['description'] as String? ?? ''; - // 解析 servers (OpenAPI 3.0) - final servers = _parseServers(jsonData); - - // 解析 components (OpenAPI 3.0) - final components = _parseComponents(jsonData); + // 解析其他基本信息 + final host = jsonData['host'] as String? ?? ''; + final basePath = jsonData['basePath'] as String? ?? '/'; + final schemes = List.from(jsonData['schemes'] ?? ['https']); + final consumes = List.from(jsonData['consumes'] ?? []); + final produces = List.from(jsonData['produces'] ?? []); // 解析tags信息 (用于获取控制器描述) final tagsInfo = _parseTagsInfo(jsonData); @@ -121,8 +124,8 @@ class SwaggerDataParser { // 解析API路径 final paths = _parseApiPaths(jsonData); - // 解析API模型 (从 components 中提取) - final models = components.schemas; + // 解析API模型 + final models = _parseApiModels(jsonData); // 解析API控制器 (传入tags信息) final controllers = _parseApiControllers(paths, tagsInfo); @@ -131,8 +134,11 @@ class SwaggerDataParser { title: title, version: version, description: description, - servers: servers, - components: components, + host: host, + basePath: basePath, + schemes: schemes, + consumes: consumes, + produces: produces, paths: paths, models: models, controllers: controllers, @@ -146,64 +152,6 @@ class SwaggerDataParser { }); } - /// 解析 servers 配置 (OpenAPI 3.0) - List _parseServers(Map jsonData) { - final servers = []; - - try { - final serversJson = jsonData['servers'] as List?; - if (serversJson != null) { - for (final serverJson in serversJson) { - if (serverJson is Map) { - final server = ApiServer.fromJson(serverJson); - servers.add(server); - } - } - } - - // 如果没有 servers 配置,提供默认值 - if (servers.isEmpty) { - servers.add(const ApiServer(url: '/')); - } - } catch (e) { - print('⚠️ 解析servers配置时发生错误: $e'); - // 提供默认服务器配置 - servers.add(const ApiServer(url: '/')); - } - - return servers; - } - - /// 解析 components 配置 (OpenAPI 3.0) - ApiComponents _parseComponents(Map jsonData) { - try { - final componentsJson = jsonData['components'] as Map?; - if (componentsJson != null) { - // 使用引用解析器处理复杂嵌套和循环引用 - final resolver = ReferenceResolver(); - final resolvedSchemas = resolver.resolveModels(componentsJson); - - // 创建 ApiComponents,但使用解析后的 schemas - final components = ApiComponents.fromJson(componentsJson); - return ApiComponents( - schemas: resolvedSchemas, - responses: components.responses, - parameters: components.parameters, - examples: components.examples, - requestBodies: components.requestBodies, - headers: components.headers, - securitySchemes: components.securitySchemes, - links: components.links, - callbacks: components.callbacks, - ); - } - } catch (e) { - print('⚠️ 解析components配置时发生错误: $e'); - } - - return const ApiComponents(); - } - /// 解析tags信息 Map _parseTagsInfo(Map jsonData) { final tagsInfo = {}; @@ -262,6 +210,41 @@ class SwaggerDataParser { return paths; } + /// 解析API模型 + Map _parseApiModels(Map jsonData) { + final models = {}; + + // 优先解析 components/schemas (Swagger 3.0) + final schemas = jsonData['components']?['schemas'] as Map?; + // 如果没有 components/schemas,尝试解析 definitions (Swagger 2.0) + final definitions = jsonData['definitions'] as Map?; + + final modelDefinitions = schemas ?? definitions; + + if (modelDefinitions == null) { + print('ℹ️ 未发现模型定义 (components/schemas 或 definitions)'); + return models; + } + + print( + '🔍 发现模型定义位置: ${schemas != null ? 'components/schemas' : 'definitions'}', + ); + + try { + modelDefinitions.forEach((name, definition) { + final model = ApiModel.fromJson( + name, + definition as Map, + ); + models[name] = model; + }); + } catch (e) { + throw SwaggerParseException('解析API模型失败', details: e.toString()); + } + + return models; + } + /// 解析API控制器 Map _parseApiControllers( Map paths, diff --git a/lib/swagger_cli_new.dart b/lib/swagger_cli_new.dart index 14aff84..a0f1dc9 100644 --- a/lib/swagger_cli_new.dart +++ b/lib/swagger_cli_new.dart @@ -3,13 +3,14 @@ import 'dart:io'; import 'commands/base_command.dart'; import 'commands/generate_command.dart'; import 'core/config.dart'; - +import 'utils/performance_monitor.dart'; import 'utils/string_utils.dart'; /// Swagger CLI 应用程序 /// 使用命令模式架构的新版本CLI工具 class SwaggerCLI { final Map _commands = {}; + final PerformanceMonitor _monitor = PerformanceMonitor(); SwaggerCLI() { _registerCommands(); diff --git a/lib/swagger_generator_flutter.dart b/lib/swagger_generator_flutter.dart deleted file mode 100644 index 7153249..0000000 --- a/lib/swagger_generator_flutter.dart +++ /dev/null @@ -1,19 +0,0 @@ -/// Swagger Generator Flutter -/// -/// 一个强大的 Flutter OpenAPI 3.0 代码生成器,专门为 Dio + Retrofit 架构优化。 -library swagger_generator_flutter; - -export 'core/error_reporter.dart'; -// 核心模型 -export 'core/models.dart'; -export 'core/performance_parser.dart'; -export 'core/smart_cache.dart'; -export 'generators/optimized_retrofit_generator.dart'; -export 'generators/performance_generator.dart'; -// 生成器 -export 'generators/retrofit_api_generator.dart'; -// 工具类 -export 'utils/string_utils.dart'; -// 验证器 -export 'validators/enhanced_validator.dart'; -export 'validators/schema_validator.dart'; diff --git a/lib/utils/file_utils.dart b/lib/utils/file_utils.dart index 1073fca..1ebe935 100644 --- a/lib/utils/file_utils.dart +++ b/lib/utils/file_utils.dart @@ -289,6 +289,7 @@ class FileUtils { /// 生成唯一文件名 static Future generateUniqueFileName( String basePath, String fileName) async { + final directory = Directory(basePath); final extension = getFileExtension(fileName); final nameWithoutExt = getFileNameWithoutExtension(fileName); diff --git a/lib/utils/reference_resolver.dart b/lib/utils/reference_resolver.dart deleted file mode 100644 index d035c2b..0000000 --- a/lib/utils/reference_resolver.dart +++ /dev/null @@ -1,301 +0,0 @@ -/// 引用解析器 -/// 处理复杂嵌套类型和循环引用检测 -library reference_resolver; - -import '../core/models.dart'; - -/// 引用解析器 -/// 负责处理 OpenAPI 文档中的复杂引用关系 -class ReferenceResolver { - /// 已解析的模型缓存 - final Map _resolvedModels = {}; - - /// 当前解析路径(用于循环引用检测) - final Set _resolutionPath = {}; - - /// 原始 JSON 数据缓存 - final Map> _rawSchemas = {}; - - /// 最大解析深度(防止过深的嵌套) - final int maxDepth; - - /// 当前解析深度 - int _currentDepth = 0; - - ReferenceResolver({this.maxDepth = 50}); - - /// 解析所有模型,处理复杂引用关系 - Map resolveModels(Map componentsJson) { - final schemasJson = - componentsJson['schemas'] as Map? ?? {}; - - // 第一步:缓存所有原始 schema 数据 - _cacheRawSchemas(schemasJson); - - // 第二步:解析所有模型 - final resolvedModels = {}; - for (final schemaName in schemasJson.keys) { - try { - final model = resolveModel(schemaName); - if (model != null) { - resolvedModels[schemaName] = model; - } - } catch (e) { - print('⚠️ 解析模型 $schemaName 时发生错误: $e'); - // 创建一个基本的模型作为后备 - resolvedModels[schemaName] = ApiModel( - name: schemaName, - description: '解析失败的模型', - properties: {}, - required: [], - ); - } - } - - return resolvedModels; - } - - /// 缓存原始 schema 数据 - void _cacheRawSchemas(Map schemasJson) { - schemasJson.forEach((name, schemaData) { - if (schemaData is Map) { - _rawSchemas[name] = schemaData; - } - }); - } - - /// 解析单个模型 - ApiModel? resolveModel(String modelName) { - // 检查是否已经解析过 - if (_resolvedModels.containsKey(modelName)) { - return _resolvedModels[modelName]; - } - - // 检查循环引用 - if (_resolutionPath.contains(modelName)) { - print('🔄 检测到循环引用: ${_resolutionPath.join(' -> ')} -> $modelName'); - return _createCircularReferenceModel(modelName); - } - - // 检查解析深度 - if (_currentDepth >= maxDepth) { - print('⚠️ 达到最大解析深度 $maxDepth,停止解析 $modelName'); - return _createDepthLimitModel(modelName); - } - - // 获取原始数据 - final schemaData = _rawSchemas[modelName]; - if (schemaData == null) { - print('⚠️ 未找到模型定义: $modelName'); - return null; - } - - // 开始解析 - _resolutionPath.add(modelName); - _currentDepth++; - - try { - final model = _parseModelWithContext(modelName, schemaData); - _resolvedModels[modelName] = model; - return model; - } finally { - _resolutionPath.remove(modelName); - _currentDepth--; - } - } - - /// 在上下文中解析模型 - ApiModel _parseModelWithContext(String name, Map json) { - // 检查是否是枚举类型 - final isEnum = json['enum'] != null; - if (isEnum) { - return _parseEnumModel(name, json); - } - - // 检查组合模式 - if (json['allOf'] != null || - json['oneOf'] != null || - json['anyOf'] != null) { - return _parseCompositionModel(name, json); - } - - // 解析普通对象模型 - return _parseObjectModel(name, json); - } - - /// 解析枚举模型 - ApiModel _parseEnumModel(String name, Map json) { - final enumValues = List.from(json['enum'] ?? []); - final enumType = - PropertyType.fromString(json['type'] as String? ?? 'string'); - - return ApiModel( - name: name, - description: json['description'] as String? ?? '', - properties: {}, - required: [], - isEnum: true, - enumValues: enumValues, - enumType: enumType, - ); - } - - /// 解析组合模式模型 - ApiModel _parseCompositionModel(String name, Map json) { - // 解析组合模式 - final allOf = _parseSchemaList(json['allOf'] as List? ?? []); - final oneOf = _parseSchemaList(json['oneOf'] as List? ?? []); - final anyOf = _parseSchemaList(json['anyOf'] as List? ?? []); - - final notJson = json['not'] as Map?; - final not = notJson != null ? ApiSchema.fromJson(notJson) : null; - - // 解析 discriminator - final discriminatorJson = json['discriminator'] as Map?; - final discriminator = discriminatorJson != null - ? ApiDiscriminator.fromJson(discriminatorJson) - : null; - - // 对于组合模式,我们需要合并属性 - final mergedProperties = {}; - final mergedRequired = []; - - // 从 allOf 中合并属性 - for (final schema in allOf) { - _mergeSchemaProperties(schema, mergedProperties, mergedRequired); - } - - // 如果有直接的 properties,也要合并 - if (json['properties'] != null) { - final directProperties = _parseProperties( - json['properties'] as Map, - List.from(json['required'] ?? []), - ); - mergedProperties.addAll(directProperties); - mergedRequired.addAll(List.from(json['required'] ?? [])); - } - - return ApiModel( - name: name, - description: json['description'] as String? ?? '', - properties: mergedProperties, - required: mergedRequired.toSet().toList(), - allOf: allOf, - oneOf: oneOf, - anyOf: anyOf, - not: not, - discriminator: discriminator, - ); - } - - /// 解析对象模型 - ApiModel _parseObjectModel(String name, Map json) { - final properties = _parseProperties( - json['properties'] as Map? ?? {}, - List.from(json['required'] ?? []), - ); - - final required = List.from(json['required'] ?? []); - - return ApiModel( - name: name, - description: json['description'] as String? ?? '', - properties: properties, - required: required, - ); - } - - /// 解析 schema 列表 - List _parseSchemaList(List schemaList) { - return schemaList - .map((schema) => ApiSchema.fromJson(schema as Map)) - .toList(); - } - - /// 合并 schema 的属性 - void _mergeSchemaProperties( - ApiSchema schema, - Map targetProperties, - List targetRequired, - ) { - // 如果是引用,解析引用的模型 - if (schema.isReference && schema.reference != null) { - final referencedModel = resolveModel(schema.reference!); - if (referencedModel != null) { - targetProperties.addAll(referencedModel.properties); - targetRequired.addAll(referencedModel.required); - } - } else { - // 直接合并属性 - targetProperties.addAll(schema.properties); - targetRequired.addAll(schema.required); - } - } - - /// 解析属性 - Map _parseProperties( - Map propertiesJson, - List requiredFields, - ) { - final properties = {}; - - propertiesJson.forEach((propName, propData) { - if (propData is Map) { - try { - final property = - _parsePropertyWithContext(propName, propData, requiredFields); - properties[propName] = property; - } catch (e) { - print('⚠️ 解析属性 $propName 时发生错误: $e'); - // 创建一个基本属性作为后备 - properties[propName] = ApiProperty( - name: propName, - type: PropertyType.string, - description: '解析失败的属性', - required: requiredFields.contains(propName), - ); - } - } - }); - - return properties; - } - - /// 在上下文中解析属性 - ApiProperty _parsePropertyWithContext( - String name, - Map json, - List requiredFields, - ) { - // 使用现有的 ApiProperty.fromJson,但在循环引用检测的上下文中 - return ApiProperty.fromJson(name, json, requiredFields); - } - - /// 创建循环引用模型 - ApiModel _createCircularReferenceModel(String modelName) { - return ApiModel( - name: modelName, - description: '循环引用模型 - 为避免无限递归而创建的占位符', - properties: {}, - required: [], - ); - } - - /// 创建深度限制模型 - ApiModel _createDepthLimitModel(String modelName) { - return ApiModel( - name: modelName, - description: '深度限制模型 - 达到最大解析深度而创建的占位符', - properties: {}, - required: [], - ); - } - - /// 清理缓存 - void clearCache() { - _resolvedModels.clear(); - _resolutionPath.clear(); - _rawSchemas.clear(); - _currentDepth = 0; - } -} diff --git a/lib/utils/string_utils.dart b/lib/utils/string_utils.dart index 5e27c26..f461494 100644 --- a/lib/utils/string_utils.dart +++ b/lib/utils/string_utils.dart @@ -210,14 +210,6 @@ class StringUtils { return toPascalCase(cleanName); } - /// 生成常量名称 (UPPER_SNAKE_CASE) - static String generateConstantName(String name) { - // 清理特殊字符 - final cleanName = name.replaceAll(RegExp(r'[^a-zA-Z0-9_]'), '_'); - // 转换为 snake_case 然后转为大写 - return toSnakeCase(cleanName).toUpperCase(); - } - /// 生成文件名 static String generateFileName(String name) { // 转换为snake_case并添加.dart扩展名 diff --git a/lib/validators/enhanced_validator.dart b/lib/validators/enhanced_validator.dart deleted file mode 100644 index 7f554d8..0000000 --- a/lib/validators/enhanced_validator.dart +++ /dev/null @@ -1,597 +0,0 @@ -/// 增强的 OpenAPI 验证器 -/// 集成详细的错误报告和修复建议 -library; - -import '../core/error_reporter.dart'; -import '../core/models.dart'; - -/// 增强的 OpenAPI 验证器 -class EnhancedValidator { - final ErrorReporter _errorReporter; - final bool _includeWarnings; - - EnhancedValidator({ - bool includeWarnings = true, - }) : _errorReporter = ErrorReporter(), - _includeWarnings = includeWarnings; - - /// 获取错误报告器 - ErrorReporter get errorReporter => _errorReporter; - - /// 验证 OpenAPI 文档 - bool validateDocument(SwaggerDocument document) { - _errorReporter.clear(); - - // 基础结构验证 - _validateBasicStructure(document); - - // 路径验证 - _validatePaths(document); - - // 组件验证 - _validateComponents(document); - - // 安全方案验证 - _validateSecurity(document); - - // 最佳实践检查 - if (_includeWarnings) { - _checkBestPractices(document); - } - - return !_errorReporter.hasErrorsOrCritical; - } - - /// 验证基础结构 - void _validateBasicStructure(SwaggerDocument document) { - // 验证标题 - if (document.title.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_INFO_TITLE', - title: 'Missing API Title', - description: 'API title is required in the info object.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - jsonPath: 'info.title', - suggestions: [ - FixSuggestion( - description: 'Add a descriptive title for your API', - codeExample: '"title": "My API"', - ), - ], - ); - } - - // 验证版本 - if (document.version.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_INFO_VERSION', - title: 'Missing API Version', - description: 'API version is required in the info object.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - jsonPath: 'info.version', - suggestions: [ - FixSuggestion( - description: 'Add a version number using semantic versioning', - codeExample: '"version": "1.0.0"', - documentationUrl: 'https://semver.org/', - ), - ], - ); - } - - // 验证描述 - if (document.description.isEmpty && _includeWarnings) { - _errorReporter.reportError( - id: 'MISSING_INFO_DESCRIPTION', - title: 'Missing API Description', - description: - 'API description helps users understand the purpose of your API.', - severity: ErrorSeverity.warning, - category: ErrorCategory.bestPractice, - jsonPath: 'info.description', - suggestions: [ - FixSuggestion( - description: 'Add a description explaining what your API does', - codeExample: - '"description": "This API provides user management functionality"', - ), - ], - ); - } - - // 验证服务器配置 - if (document.servers.isEmpty && _includeWarnings) { - _errorReporter.reportError( - id: 'MISSING_SERVERS', - title: 'Missing Server Configuration', - description: - 'Server configuration helps clients know where to send requests.', - severity: ErrorSeverity.warning, - category: ErrorCategory.bestPractice, - jsonPath: 'servers', - suggestions: [ - FixSuggestion( - description: 'Add at least one server configuration', - codeExample: - '"servers": [{"url": "https://api.example.com", "description": "Production server"}]', - ), - ], - ); - } - } - - /// 验证路径 - void _validatePaths(SwaggerDocument document) { - if (document.paths.isEmpty) { - _errorReporter.reportError( - id: 'EMPTY_PATHS', - title: 'Empty Paths Object', - description: 'OpenAPI document must contain at least one path.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - jsonPath: 'paths', - suggestions: [ - FixSuggestion( - description: 'Add at least one API endpoint', - codeExample: - '"/users": { "get": { "responses": { "200": { "description": "Success" } } } }', - ), - ], - ); - return; - } - - document.paths.forEach((pathPattern, apiPath) { - _validatePath(pathPattern, apiPath); - }); - } - - /// 验证单个路径 - void _validatePath(String pathPattern, ApiPath apiPath) { - final pathKey = 'paths["$pathPattern"][${apiPath.method.value}]'; - - // 验证路径格式 - if (!pathPattern.startsWith('/')) { - _errorReporter.reportError( - id: 'INVALID_PATH_FORMAT', - title: 'Invalid Path Format', - description: 'Path must start with a forward slash.', - severity: ErrorSeverity.error, - category: ErrorCategory.syntax, - jsonPath: pathKey, - snippet: pathPattern, - suggestions: [ - FixSuggestion( - description: 'Ensure path starts with /', - codeExample: '"/$pathPattern" instead of "$pathPattern"', - ), - ], - ); - } - - // 验证响应 - if (apiPath.responses.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_OPERATION_RESPONSES', - title: 'Missing Operation Responses', - description: 'Every operation must define at least one response.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - jsonPath: '$pathKey.responses', - suggestions: [ - FixSuggestion( - description: 'Add at least a default response', - codeExample: '"responses": { "200": { "description": "Success" } }', - ), - ], - ); - } - - // 验证操作 ID - if (apiPath.operationId.isEmpty && _includeWarnings) { - _errorReporter.reportError( - id: 'MISSING_OPERATION_ID', - title: 'Missing Operation ID', - description: - 'Operation should have an operationId for better code generation.', - severity: ErrorSeverity.warning, - category: ErrorCategory.bestPractice, - jsonPath: '$pathKey.operationId', - suggestions: [ - FixSuggestion( - description: 'Add a unique operationId', - codeExample: - '"operationId": "${_generateOperationId(pathPattern, apiPath.method)}"', - ), - ], - ); - } - - // 验证摘要 - if (apiPath.summary.isEmpty && _includeWarnings) { - _errorReporter.reportError( - id: 'MISSING_OPERATION_SUMMARY', - title: 'Missing Operation Summary', - description: - 'Operation should have a summary for better documentation.', - severity: ErrorSeverity.info, - category: ErrorCategory.bestPractice, - jsonPath: '$pathKey.summary', - suggestions: [ - FixSuggestion( - description: 'Add a brief summary', - codeExample: '"summary": "Get all users"', - ), - ], - ); - } - - // 验证参数 - _validateParameters(apiPath.parameters, pathKey, pathPattern); - - // 验证响应 - _validateResponses(apiPath.responses, pathKey); - } - - /// 验证参数 - void _validateParameters( - List parameters, String pathKey, String pathPattern) { - // 提取路径参数 - final pathParams = _extractPathParameters(pathPattern); - final declaredPathParams = parameters - .where((p) => p.location == ParameterLocation.path) - .map((p) => p.name) - .toSet(); - - // 检查路径参数是否都有声明 - for (final param in pathParams) { - if (!declaredPathParams.contains(param)) { - _errorReporter.reportError( - id: 'UNDECLARED_PATH_PARAMETER', - title: 'Undeclared Path Parameter', - description: - 'Path parameter "$param" is used in the path but not declared in parameters.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - jsonPath: '$pathKey.parameters', - suggestions: [ - FixSuggestion( - description: 'Add parameter declaration', - codeExample: - '{"name": "$param", "in": "path", "required": true, "schema": {"type": "string"}}', - ), - ], - ); - } - } - - // 验证每个参数 - for (int i = 0; i < parameters.length; i++) { - final param = parameters[i]; - final paramPath = '$pathKey.parameters[$i]'; - - // 验证参数名 - if (param.name.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_PARAMETER_NAME', - title: 'Missing Parameter Name', - description: 'Parameter must have a name.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - jsonPath: '$paramPath.name', - suggestions: [ - FixSuggestion( - description: 'Add a name for the parameter', - codeExample: '"name": "userId"', - ), - ], - ); - } - - // 验证路径参数必须是必需的 - if (param.location == ParameterLocation.path && !param.required) { - _errorReporter.reportError( - id: 'PATH_PARAMETER_NOT_REQUIRED', - title: 'Path Parameter Not Required', - description: 'Path parameters must be marked as required.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - jsonPath: '$paramPath.required', - suggestions: [ - FixSuggestion( - description: 'Set required: true for path parameters', - codeExample: '"required": true', - ), - ], - ); - } - } - } - - /// 验证响应 - void _validateResponses(Map responses, String pathKey) { - bool hasSuccessResponse = false; - bool hasErrorResponse = false; - - responses.forEach((code, response) { - final responsePath = '$pathKey.responses["$code"]'; - final statusCode = int.tryParse(code) ?? 0; - - // 检查成功响应 - if (statusCode >= 200 && statusCode < 300) { - hasSuccessResponse = true; - } - - // 检查错误响应 - if (statusCode >= 400) { - hasErrorResponse = true; - } - - // 验证响应描述 - if (response.description.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_RESPONSE_DESCRIPTION', - title: 'Missing Response Description', - description: 'Response should have a description.', - severity: ErrorSeverity.warning, - category: ErrorCategory.bestPractice, - jsonPath: '$responsePath.description', - suggestions: [ - FixSuggestion( - description: 'Add a description for the response', - codeExample: '"description": "Successful operation"', - ), - ], - ); - } - }); - - // 检查是否有成功响应 - if (!hasSuccessResponse && _includeWarnings) { - _errorReporter.reportError( - id: 'NO_SUCCESS_RESPONSE', - title: 'No Success Response', - description: - 'Operation should define at least one success response (2xx).', - severity: ErrorSeverity.warning, - category: ErrorCategory.bestPractice, - jsonPath: '$pathKey.responses', - suggestions: [ - FixSuggestion( - description: 'Add a success response', - codeExample: '"200": { "description": "Success" }', - ), - ], - ); - } - - // 检查是否有错误响应 - if (!hasErrorResponse && _includeWarnings) { - _errorReporter.reportError( - id: 'NO_ERROR_RESPONSE', - title: 'No Error Response', - description: - 'Consider adding error responses (4xx/5xx) for better API documentation.', - severity: ErrorSeverity.info, - category: ErrorCategory.bestPractice, - jsonPath: '$pathKey.responses', - suggestions: [ - FixSuggestion( - description: 'Add common error responses', - codeExample: - '"400": { "description": "Bad Request" }, "404": { "description": "Not Found" }', - ), - ], - ); - } - } - - /// 验证组件 - void _validateComponents(SwaggerDocument document) { - // 验证 schemas - document.components.schemas.forEach((name, model) { - _validateSchema(name, model); - }); - - // 验证安全方案 - document.components.securitySchemes.forEach((name, scheme) { - _validateSecurityScheme(name, scheme); - }); - } - - /// 验证 Schema - void _validateSchema(String name, ApiModel model) { - final schemaPath = 'components.schemas["$name"]'; - - // 验证模型名称 - if (model.name.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_SCHEMA_NAME', - title: 'Missing Schema Name', - description: 'Schema should have a name.', - severity: ErrorSeverity.error, - category: ErrorCategory.validation, - jsonPath: schemaPath, - suggestions: [ - FixSuggestion( - description: 'Ensure schema has a valid name', - codeExample: - 'Schema name should match the key in components.schemas', - ), - ], - ); - } - - // 检查属性数量 - if (model.properties.length > 20 && _includeWarnings) { - _errorReporter.reportError( - id: 'LARGE_SCHEMA_OBJECT', - title: 'Large Schema Object', - description: - 'Schema has many properties (${model.properties.length}), consider breaking it down.', - severity: ErrorSeverity.info, - category: ErrorCategory.performance, - jsonPath: schemaPath, - suggestions: [ - FixSuggestion( - description: 'Consider using composition with allOf', - codeExample: - '"allOf": [{ "\$ref": "#/components/schemas/BaseModel" }, { "type": "object", "properties": {...} }]', - ), - ], - ); - } - } - - /// 验证安全方案 - void _validateSecurityScheme(String name, ApiSecurityScheme scheme) { - final schemePath = 'components.securitySchemes["$name"]'; - - switch (scheme.type) { - case SecuritySchemeType.apiKey: - if (scheme.name == null || scheme.name!.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_API_KEY_NAME', - title: 'Missing API Key Name', - description: - 'API Key security scheme must specify a parameter name.', - severity: ErrorSeverity.error, - category: ErrorCategory.security, - jsonPath: '$schemePath.name', - suggestions: [ - FixSuggestion( - description: 'Add name field for API key parameter', - codeExample: '"name": "X-API-Key"', - ), - ], - ); - } - break; - - case SecuritySchemeType.http: - if (scheme.scheme == null || scheme.scheme!.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_HTTP_SCHEME', - title: 'Missing HTTP Scheme', - description: - 'HTTP security scheme must specify a scheme (basic, bearer, etc.).', - severity: ErrorSeverity.error, - category: ErrorCategory.security, - jsonPath: '$schemePath.scheme', - suggestions: [ - FixSuggestion( - description: 'Add scheme field', - codeExample: '"scheme": "bearer"', - ), - ], - ); - } - break; - - case SecuritySchemeType.oauth2: - if (scheme.flows == null) { - _errorReporter.reportError( - id: 'MISSING_OAUTH2_FLOWS', - title: 'Missing OAuth2 Flows', - description: 'OAuth2 security scheme must define flows.', - severity: ErrorSeverity.error, - category: ErrorCategory.security, - jsonPath: '$schemePath.flows', - suggestions: [ - FixSuggestion( - description: 'Add flows configuration', - codeExample: - '"flows": { "authorizationCode": { "authorizationUrl": "...", "tokenUrl": "..." } }', - ), - ], - ); - } - break; - - case SecuritySchemeType.openIdConnect: - if (scheme.openIdConnectUrl == null || - scheme.openIdConnectUrl!.isEmpty) { - _errorReporter.reportError( - id: 'MISSING_OPENID_URL', - title: 'Missing OpenID Connect URL', - description: 'OpenID Connect security scheme must specify a URL.', - severity: ErrorSeverity.error, - category: ErrorCategory.security, - jsonPath: '$schemePath.openIdConnectUrl', - suggestions: [ - FixSuggestion( - description: 'Add OpenID Connect URL', - codeExample: - '"openIdConnectUrl": "https://example.com/.well-known/openid_configuration"', - ), - ], - ); - } - break; - } - } - - /// 验证安全配置 - void _validateSecurity(SwaggerDocument document) { - // 这里可以添加安全配置的验证逻辑 - } - - /// 检查最佳实践 - void _checkBestPractices(SwaggerDocument document) { - // 检查是否使用了标签 - final hasTaggedOperations = - document.paths.values.any((path) => path.tags.isNotEmpty); - if (!hasTaggedOperations) { - _errorReporter.reportError( - id: 'NO_OPERATION_TAGS', - title: 'No Operation Tags', - description: 'Consider using tags to organize your API operations.', - severity: ErrorSeverity.info, - category: ErrorCategory.bestPractice, - jsonPath: 'paths', - suggestions: [ - FixSuggestion( - description: 'Add tags to operations', - codeExample: '"tags": ["users"]', - ), - ], - ); - } - } - - /// 提取路径参数 - Set _extractPathParameters(String path) { - final regex = RegExp(r'\{([^}]+)\}'); - final matches = regex.allMatches(path); - return matches.map((match) => match.group(1)!).toSet(); - } - - /// 生成操作 ID - String _generateOperationId(String path, HttpMethod method) { - final pathParts = path - .split('/') - .where((part) => part.isNotEmpty && !part.startsWith('{')) - .toList(); - final methodPrefix = method.value.toLowerCase(); - - if (pathParts.length >= 3) { - // 移除 api/v1 前缀 - pathParts.removeRange(0, 2); - } - - final nameParts = pathParts.map((part) => _toPascalCase(part)).join(''); - return '$methodPrefix$nameParts'; - } - - /// 转换为 PascalCase - String _toPascalCase(String input) { - return input - .split('_') - .map((word) => word.isEmpty - ? '' - : word[0].toUpperCase() + word.substring(1).toLowerCase()) - .join(''); - } -} diff --git a/lib/validators/schema_validator.dart b/lib/validators/schema_validator.dart deleted file mode 100644 index a4e74e3..0000000 --- a/lib/validators/schema_validator.dart +++ /dev/null @@ -1,845 +0,0 @@ -/// Schema 验证器 -/// 验证 OpenAPI 3.0 文档的完整性和正确性 -library; - -import '../core/models.dart'; - -/// Schema 验证结果 -class ValidationResult { - final bool isValid; - final List errors; - final List warnings; - - const ValidationResult({ - required this.isValid, - this.errors = const [], - this.warnings = const [], - }); - - /// 创建成功的验证结果 - factory ValidationResult.success( - {List warnings = const []}) { - return ValidationResult( - isValid: true, - warnings: warnings, - ); - } - - /// 创建失败的验证结果 - factory ValidationResult.failure(List errors, - {List warnings = const []}) { - return ValidationResult( - isValid: false, - errors: errors, - warnings: warnings, - ); - } - - /// 是否有警告 - bool get hasWarnings => warnings.isNotEmpty; - - /// 是否有错误 - bool get hasErrors => errors.isNotEmpty; -} - -/// 验证错误 -class ValidationError { - final String path; - final String message; - final ValidationErrorType type; - final String? suggestion; - - const ValidationError({ - required this.path, - required this.message, - required this.type, - this.suggestion, - }); - - @override - String toString() { - final buffer = StringBuffer(); - buffer.write('[$type] $path: $message'); - if (suggestion != null) { - buffer.write(' (建议: $suggestion)'); - } - return buffer.toString(); - } -} - -/// 验证警告 -class ValidationWarning { - final String path; - final String message; - final String? suggestion; - - const ValidationWarning({ - required this.path, - required this.message, - this.suggestion, - }); - - @override - String toString() { - final buffer = StringBuffer(); - buffer.write('[WARNING] $path: $message'); - if (suggestion != null) { - buffer.write(' (建议: $suggestion)'); - } - return buffer.toString(); - } -} - -/// 验证错误类型 -enum ValidationErrorType { - required, - format, - type, - reference, - constraint, - compatibility, - security, -} - -/// Schema 验证器 -class SchemaValidator { - final List _errors = []; - final List _warnings = []; - - /// 验证 OpenAPI 文档 - ValidationResult validateDocument(SwaggerDocument document) { - _errors.clear(); - _warnings.clear(); - - // 验证基本信息 - _validateInfo(document); - - // 验证服务器配置 - _validateServers(document.servers); - - // 验证路径 - _validatePaths(document.paths); - - // 验证组件 - _validateComponents(document.components); - - // 验证安全方案 - _validateSecurity(document.security, document.components.securitySchemes); - - return ValidationResult( - isValid: _errors.isEmpty, - errors: List.from(_errors), - warnings: List.from(_warnings), - ); - } - - /// 验证基本信息 - void _validateInfo(SwaggerDocument document) { - if (document.title.isEmpty) { - _errors.add(const ValidationError( - path: 'info.title', - message: 'API 标题不能为空', - type: ValidationErrorType.required, - suggestion: '请提供有意义的 API 标题', - )); - } - - if (document.version.isEmpty) { - _errors.add(const ValidationError( - path: 'info.version', - message: 'API 版本不能为空', - type: ValidationErrorType.required, - suggestion: '请使用语义化版本号,如 "1.0.0"', - )); - } - - if (document.description.isEmpty) { - _warnings.add(const ValidationWarning( - path: 'info.description', - message: 'API 描述为空', - suggestion: '建议添加 API 的详细描述', - )); - } - } - - /// 验证服务器配置 - void _validateServers(List servers) { - if (servers.isEmpty) { - _warnings.add(const ValidationWarning( - path: 'servers', - message: '未定义服务器配置', - suggestion: '建议添加至少一个服务器配置', - )); - return; - } - - for (int i = 0; i < servers.length; i++) { - final server = servers[i]; - final path = 'servers[$i]'; - - if (server.url.isEmpty) { - _errors.add(ValidationError( - path: '$path.url', - message: '服务器 URL 不能为空', - type: ValidationErrorType.required, - )); - } else if (!_isValidUrl(server.url)) { - _errors.add(ValidationError( - path: '$path.url', - message: '服务器 URL 格式无效: ${server.url}', - type: ValidationErrorType.format, - suggestion: '请使用有效的 URL 格式,如 "https://api.example.com"', - )); - } - - // 验证服务器变量 - server.variables.forEach((name, variable) { - if (variable.defaultValue.isEmpty) { - _errors.add(ValidationError( - path: '$path.variables.$name.default', - message: '服务器变量必须有默认值', - type: ValidationErrorType.required, - )); - } - }); - } - } - - /// 验证路径 - void _validatePaths(Map paths) { - if (paths.isEmpty) { - _errors.add(const ValidationError( - path: 'paths', - message: 'API 文档必须包含至少一个路径', - type: ValidationErrorType.required, - )); - return; - } - - paths.forEach((pathPattern, path) { - final pathKey = 'paths["$pathPattern"][${path.method.value}]'; - _validatePath(path, pathKey); - }); - } - - /// 验证单个路径 - void _validatePath(ApiPath path, String pathKey) { - // 验证操作 ID - if (path.operationId.isEmpty) { - _warnings.add(ValidationWarning( - path: '$pathKey.operationId', - message: '缺少操作 ID', - suggestion: '建议为每个操作添加唯一的 operationId', - )); - } - - // 验证摘要和描述 - if (path.summary.isEmpty) { - _warnings.add(ValidationWarning( - path: '$pathKey.summary', - message: '缺少操作摘要', - suggestion: '建议添加简短的操作描述', - )); - } - - // 验证参数 - for (int i = 0; i < path.parameters.length; i++) { - _validateParameter(path.parameters[i], '$pathKey.parameters[$i]'); - } - - // 验证请求体 - if (path.requestBody != null) { - _validateRequestBody(path.requestBody!, '$pathKey.requestBody'); - } - - // 验证响应 - if (path.responses.isEmpty) { - _errors.add(ValidationError( - path: '$pathKey.responses', - message: '操作必须定义至少一个响应', - type: ValidationErrorType.required, - )); - } else { - path.responses.forEach((code, response) { - _validateResponse(response, '$pathKey.responses["$code"]'); - }); - } - - // 验证安全要求 - for (int i = 0; i < path.security.length; i++) { - _validateSecurityRequirement(path.security[i], '$pathKey.security[$i]'); - } - } - - /// 验证参数 - void _validateParameter(ApiParameter parameter, String path) { - if (parameter.name.isEmpty) { - _errors.add(ValidationError( - path: '$path.name', - message: '参数名称不能为空', - type: ValidationErrorType.required, - )); - } - - // 验证路径参数必须是必需的 - if (parameter.location == ParameterLocation.path && !parameter.required) { - _errors.add(ValidationError( - path: '$path.required', - message: '路径参数必须是必需的', - type: ValidationErrorType.constraint, - )); - } - - // 验证参数类型 - if (parameter.type == PropertyType.unknown) { - _warnings.add(ValidationWarning( - path: '$path.type', - message: '参数类型未知', - suggestion: '建议明确指定参数类型', - )); - } - } - - /// 验证请求体 - void _validateRequestBody(ApiRequestBody requestBody, String path) { - if (requestBody.content.isEmpty) { - _errors.add(ValidationError( - path: '$path.content', - message: '请求体必须定义至少一种内容类型', - type: ValidationErrorType.required, - )); - } - - requestBody.content.forEach((mediaType, content) { - _validateMediaType(content, '$path.content["$mediaType"]', mediaType); - }); - } - - /// 验证响应 - void _validateResponse(ApiResponse response, String path) { - if (response.description.isEmpty) { - _warnings.add(ValidationWarning( - path: '$path.description', - message: '响应缺少描述', - suggestion: '建议为响应添加描述', - )); - } - - response.content.forEach((mediaType, content) { - _validateMediaType(content, '$path.content["$mediaType"]', mediaType); - }); - } - - /// 验证媒体类型 - void _validateMediaType( - ApiMediaType mediaType, String path, String contentType) { - // 验证 schema - if (mediaType.schema == null) { - _warnings.add(ValidationWarning( - path: '$path.schema', - message: '媒体类型缺少 schema 定义', - suggestion: '建议为媒体类型添加 schema', - )); - } - - // 验证编码(仅适用于 multipart 和 form data) - if (contentType.startsWith('multipart/') || contentType.contains('form')) { - if (mediaType.encoding.isEmpty) { - _warnings.add(ValidationWarning( - path: '$path.encoding', - message: '表单数据建议定义编码信息', - suggestion: '为文件上传字段添加 contentType 等编码信息', - )); - } - } - } - - /// 验证组件 - void _validateComponents(ApiComponents? components) { - if (components == null) return; - - // 验证 schemas - components.schemas.forEach((name, model) { - _validateModel(model, 'components.schemas["$name"]'); - }); - - // 验证安全方案 - components.securitySchemes.forEach((name, scheme) { - _validateSecurityScheme(scheme, 'components.securitySchemes["$name"]'); - }); - } - - /// 验证模型 - void _validateModel(ApiModel model, String path) { - if (model.name.isEmpty) { - _errors.add(ValidationError( - path: '$path.name', - message: '模型名称不能为空', - type: ValidationErrorType.required, - )); - } - - // 验证属性 - model.properties.forEach((name, property) { - _validateProperty(property, '$path.properties["$name"]'); - }); - - // 验证必需字段 - for (final requiredField in model.required) { - if (!model.properties.containsKey(requiredField)) { - _errors.add(ValidationError( - path: '$path.required', - message: '必需字段 "$requiredField" 在属性中未定义', - type: ValidationErrorType.reference, - )); - } - } - } - - /// 验证属性 - void _validateProperty(ApiProperty property, String path) { - if (property.name.isEmpty) { - _errors.add(ValidationError( - path: '$path.name', - message: '属性名称不能为空', - type: ValidationErrorType.required, - )); - } - - if (property.type == PropertyType.unknown) { - _warnings.add(ValidationWarning( - path: '$path.type', - message: '属性类型未知', - suggestion: '建议明确指定属性类型', - )); - } - } - - /// 验证安全方案 - void _validateSecurity(List security, - Map schemes) { - for (int i = 0; i < security.length; i++) { - _validateSecurityRequirement(security[i], 'security[$i]'); - } - } - - /// 验证安全要求 - void _validateSecurityRequirement( - ApiSecurityRequirement requirement, String path) { - for (final schemeName in requirement.schemeNames) { - // 这里应该验证安全方案是否在 components.securitySchemes 中定义 - // 但由于当前模型结构限制,我们只能添加警告 - if (schemeName.isEmpty) { - _warnings.add(ValidationWarning( - path: path, - message: '安全方案名称为空', - suggestion: '请确保安全方案名称有效', - )); - } - } - } - - /// 验证安全方案 - void _validateSecurityScheme(ApiSecurityScheme scheme, String path) { - switch (scheme.type) { - case SecuritySchemeType.apiKey: - if (scheme.name == null || scheme.name!.isEmpty) { - _errors.add(ValidationError( - path: '$path.name', - message: 'API Key 安全方案必须指定参数名称', - type: ValidationErrorType.required, - )); - } - break; - case SecuritySchemeType.http: - if (scheme.scheme == null || scheme.scheme!.isEmpty) { - _errors.add(ValidationError( - path: '$path.scheme', - message: 'HTTP 安全方案必须指定认证方案', - type: ValidationErrorType.required, - )); - } - break; - case SecuritySchemeType.oauth2: - if (scheme.flows == null) { - _errors.add(ValidationError( - path: '$path.flows', - message: 'OAuth2 安全方案必须定义流程', - type: ValidationErrorType.required, - )); - } - break; - case SecuritySchemeType.openIdConnect: - if (scheme.openIdConnectUrl == null || - scheme.openIdConnectUrl!.isEmpty) { - _errors.add(ValidationError( - path: '$path.openIdConnectUrl', - message: 'OpenID Connect 安全方案必须指定 URL', - type: ValidationErrorType.required, - )); - } - break; - } - } - - /// 验证 URL 格式 - bool _isValidUrl(String url) { - try { - final uri = Uri.parse(url); - return uri.hasScheme && (uri.scheme == 'http' || uri.scheme == 'https'); - } catch (e) { - return false; - } - } - - /// 验证文档结构完整性 - void validateDocumentStructure(SwaggerDocument document) { - _validateOpenApiVersion(document); - _validatePathStructure(document); - _validateComponentReferences(document); - _validateSecurityReferences(document); - _validateExampleConsistency(document); - _validateResponseStructure(document); - _validateParameterConsistency(document); - } - - /// 验证 OpenAPI 版本 - void _validateOpenApiVersion(SwaggerDocument document) { - // SwaggerDocument 没有直接的 openApiVersion 属性 - // 这里我们假设它是 OpenAPI 3.0 兼容的 - _warnings.add(const ValidationWarning( - path: 'openapi', - message: '无法验证 OpenAPI 版本', - suggestion: '确保使用 OpenAPI 3.0.x 或 3.1.x 版本', - )); - } - - /// 验证路径结构 - void _validatePathStructure(SwaggerDocument document) { - final pathPatterns = document.paths.keys.toList(); - - // 检查路径冲突 - for (int i = 0; i < pathPatterns.length; i++) { - for (int j = i + 1; j < pathPatterns.length; j++) { - if (_pathsConflict(pathPatterns[i], pathPatterns[j])) { - _errors.add(ValidationError( - path: 'paths', - message: '路径冲突: "${pathPatterns[i]}" 与 "${pathPatterns[j]}"', - type: ValidationErrorType.constraint, - suggestion: '确保路径模式不会产生歧义', - )); - } - } - } - - // 检查路径参数一致性 - document.paths.forEach((pathPattern, path) { - final pathParams = _extractPathParameters(pathPattern); - - final declaredParams = path.parameters - .where((p) => p.location == ParameterLocation.path) - .map((p) => p.name) - .toSet(); - - // 检查路径中的参数是否都有声明 - for (final param in pathParams) { - if (!declaredParams.contains(param)) { - _errors.add(ValidationError( - path: 'paths["$pathPattern"][${path.method.value}].parameters', - message: '路径参数 "$param" 未在参数列表中声明', - type: ValidationErrorType.reference, - suggestion: '添加路径参数的声明', - )); - } - } - - // 检查声明的路径参数是否都在路径中使用 - for (final param in declaredParams) { - if (!pathParams.contains(param)) { - _warnings.add(ValidationWarning( - path: 'paths["$pathPattern"][${path.method.value}].parameters', - message: '声明的路径参数 "$param" 未在路径中使用', - suggestion: '移除未使用的参数声明或修正路径', - )); - } - } - }); - } - - /// 验证组件引用 - void _validateComponentReferences(SwaggerDocument document) { - final schemas = document.components.schemas.keys.toSet(); - final securitySchemes = document.components.securitySchemes.keys.toSet(); - - // 收集所有引用 - final schemaRefs = {}; - final securityRefs = {}; - - _collectReferences(document, schemaRefs, securityRefs); - - // 检查未定义的引用 - for (final ref in schemaRefs) { - if (!schemas.contains(ref)) { - _errors.add(ValidationError( - path: 'components.schemas', - message: '引用的 schema "$ref" 未定义', - type: ValidationErrorType.reference, - suggestion: '定义缺失的 schema 或修正引用', - )); - } - } - - for (final ref in securityRefs) { - if (!securitySchemes.contains(ref)) { - _errors.add(ValidationError( - path: 'components.securitySchemes', - message: '引用的安全方案 "$ref" 未定义', - type: ValidationErrorType.reference, - suggestion: '定义缺失的安全方案或修正引用', - )); - } - } - - // 检查未使用的组件 - for (final schema in schemas) { - if (!schemaRefs.contains(schema)) { - _warnings.add(ValidationWarning( - path: 'components.schemas["$schema"]', - message: 'Schema "$schema" 已定义但未被使用', - suggestion: '移除未使用的 schema 或添加引用', - )); - } - } - } - - /// 验证安全方案引用 - void _validateSecurityReferences(SwaggerDocument document) { - final definedSchemes = document.components.securitySchemes.keys.toSet(); - - // 检查全局安全要求 - for (int i = 0; i < document.security.length; i++) { - final requirement = document.security[i]; - for (final schemeName in requirement.schemeNames) { - if (!definedSchemes.contains(schemeName)) { - _errors.add(ValidationError( - path: 'security[$i]', - message: '引用的安全方案 "$schemeName" 未定义', - type: ValidationErrorType.reference, - suggestion: '在 components.securitySchemes 中定义该安全方案', - )); - } - } - } - - // 检查操作级别的安全要求 - document.paths.forEach((pathPattern, path) { - for (int i = 0; i < path.security.length; i++) { - final requirement = path.security[i]; - for (final schemeName in requirement.schemeNames) { - if (!definedSchemes.contains(schemeName)) { - _errors.add(ValidationError( - path: 'paths["$pathPattern"][${path.method.value}].security[$i]', - message: '引用的安全方案 "$schemeName" 未定义', - type: ValidationErrorType.reference, - suggestion: '在 components.securitySchemes 中定义该安全方案', - )); - } - } - } - }); - } - - /// 验证示例一致性 - void _validateExampleConsistency(SwaggerDocument document) { - document.paths.forEach((pathPattern, path) { - // 验证请求体示例 - if (path.requestBody != null) { - path.requestBody!.content.forEach((mediaType, content) { - _validateMediaTypeExamples(content, - '$pathPattern[${path.method.value}].requestBody.content["$mediaType"]'); - }); - } - - // 验证响应示例 - path.responses.forEach((code, response) { - response.content.forEach((mediaType, content) { - _validateMediaTypeExamples(content, - '$pathPattern[${path.method.value}].responses["$code"].content["$mediaType"]'); - }); - }); - }); - } - - /// 验证媒体类型示例 - void _validateMediaTypeExamples(ApiMediaType mediaType, String path) { - // 检查 example 和 examples 不能同时存在 - if (mediaType.example != null && mediaType.examples.isNotEmpty) { - _warnings.add(ValidationWarning( - path: path, - message: 'example 和 examples 不应同时存在', - suggestion: '使用 examples 对象来提供多个示例', - )); - } - - // 验证示例格式 - if (mediaType.example != null && mediaType.schema != null) { - // TODO: 根据 schema 验证 example 的格式 - } - } - - /// 验证响应结构 - void _validateResponseStructure(SwaggerDocument document) { - document.paths.forEach((pathPattern, path) { - // 检查是否有成功响应 - final hasSuccessResponse = path.responses.keys.any((code) { - final statusCode = int.tryParse(code) ?? 0; - return statusCode >= 200 && statusCode < 300; - }); - - if (!hasSuccessResponse) { - _warnings.add(ValidationWarning( - path: 'paths["$pathPattern"][${path.method.value}].responses', - message: '缺少成功响应 (2xx)', - suggestion: '添加至少一个成功响应', - )); - } - - // 检查错误响应 - final hasErrorResponse = path.responses.keys.any((code) { - final statusCode = int.tryParse(code) ?? 0; - return statusCode >= 400; - }); - - if (!hasErrorResponse) { - _warnings.add(ValidationWarning( - path: 'paths["$pathPattern"][${path.method.value}].responses', - message: '建议添加错误响应 (4xx/5xx)', - suggestion: '添加常见的错误响应,如 400、401、404、500', - )); - } - }); - } - - /// 验证参数一致性 - void _validateParameterConsistency(SwaggerDocument document) { - final parameterNames = >{}; - - document.paths.forEach((pathPattern, path) { - for (final param in path.parameters) { - final key = '${param.location.name}:${param.name}'; - parameterNames.putIfAbsent(pathPattern, () => {}); - - if (parameterNames[pathPattern]!.contains(key)) { - _errors.add(ValidationError( - path: 'paths["$pathPattern"][${path.method.value}].parameters', - message: '重复的参数: ${param.name} (${param.location.name})', - type: ValidationErrorType.constraint, - suggestion: '确保参数名称在同一位置类型中唯一', - )); - } else { - parameterNames[pathPattern]!.add(key); - } - } - }); - } - - /// 检查路径是否冲突 - bool _pathsConflict(String path1, String path2) { - if (path1 == path2) return true; - - // 将路径参数替换为通配符进行比较 - final normalized1 = path1.replaceAll(RegExp(r'\{[^}]+\}'), '*'); - final normalized2 = path2.replaceAll(RegExp(r'\{[^}]+\}'), '*'); - - return normalized1 == normalized2; - } - - /// 提取路径参数 - Set _extractPathParameters(String path) { - final regex = RegExp(r'\{([^}]+)\}'); - final matches = regex.allMatches(path); - return matches.map((match) => match.group(1)!).toSet(); - } - - /// 收集所有引用 - void _collectReferences(SwaggerDocument document, Set schemaRefs, - Set securityRefs) { - // 从路径中收集引用 - document.paths.forEach((pathPattern, path) { - // 从参数中收集引用 - for (final _ in path.parameters) { - // TODO: 收集参数 schema 引用 - } - - // 从请求体中收集引用 - if (path.requestBody != null) { - path.requestBody!.content.forEach((mediaType, content) { - _collectSchemaReferences(content.schema, schemaRefs); - }); - } - - // 从响应中收集引用 - path.responses.forEach((code, response) { - response.content.forEach((mediaType, content) { - _collectSchemaReferences(content.schema, schemaRefs); - }); - }); - - // 从安全要求中收集引用 - for (final requirement in path.security) { - securityRefs.addAll(requirement.schemeNames); - } - }); - - // 从全局安全要求中收集引用 - for (final requirement in document.security) { - securityRefs.addAll(requirement.schemeNames); - } - - // 从组件中收集引用 - document.components.schemas.forEach((name, model) { - for (final _ in model.properties.values) { - // TODO: 收集属性 schema 引用 - } - }); - } - - /// 收集 Schema 引用 - void _collectSchemaReferences( - Map? schema, Set refs) { - if (schema == null) return; - - // 检查 $ref - final ref = schema['\$ref'] as String?; - if (ref != null && ref.startsWith('#/components/schemas/')) { - final refName = ref.substring('#/components/schemas/'.length); - refs.add(refName); - } - - // 递归检查嵌套 schema - if (schema['items'] is Map) { - _collectSchemaReferences(schema['items'] as Map, refs); - } - - if (schema['properties'] is Map) { - final properties = schema['properties'] as Map; - properties.forEach((key, value) { - if (value is Map) { - _collectSchemaReferences(value, refs); - } - }); - } - - // 检查组合 schema - for (final key in ['allOf', 'oneOf', 'anyOf']) { - if (schema[key] is List) { - final list = schema[key] as List; - for (final item in list) { - if (item is Map) { - _collectSchemaReferences(item, refs); - } - } - } - } - } -} diff --git a/pubspec.lock b/pubspec.lock index b05ac26..3709437 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -185,22 +185,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.1.0" - dio: - dependency: "direct dev" - description: - name: dio - sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" - url: "https://pub.flutter-io.cn" - source: hosted - version: "5.8.0+1" - dio_web_adapter: - dependency: transitive - description: - name: dio_web_adapter - sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.1.1" fake_async: dependency: transitive description: @@ -340,7 +324,7 @@ packages: source: hosted version: "3.0.1" logging: - dependency: "direct main" + dependency: transitive description: name: logging sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 @@ -396,7 +380,7 @@ packages: source: hosted version: "2.2.0" path: - dependency: "direct main" + dependency: transitive description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" @@ -427,14 +411,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.5.0" - retrofit: - dependency: "direct dev" - description: - name: retrofit - sha256: "84d70114a5b6bae5f4c1302335f9cb610ebeb1b02023d5e7e87697aaff52926a" - url: "https://pub.flutter-io.cn" - source: hosted - version: "4.6.0" shelf: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 0e8ae97..f0be349 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,12 +19,12 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - + # 代码生成必需的依赖 build_runner: ^2.4.7 json_serializable: ^6.7.1 test: ^1.24.0 - + dio: any retrofit: any learning_officer_oa: any diff --git a/run_swagger.sh b/run_swagger.sh index 6ecde0c..115aa40 100755 --- a/run_swagger.sh +++ b/run_swagger.sh @@ -20,53 +20,16 @@ show_help() { echo -e "${YELLOW}用法: $0 [命令] [选项]${NC}" echo "" echo -e "${GREEN}快速命令:${NC}" - echo -e " $0 all # 生成所有文件(推荐)" + echo -e " $0 all # 生成所有文件" echo -e " $0 models # 生成数据模型" echo -e " $0 docs # 生成API文档" echo -e " $0 api # 生成Retrofit API" echo "" - echo -e "${GREEN}工具命令:${NC}" - echo -e " $0 clean # 清理生成的文件" - echo -e " $0 validate # 验证生成的代码" - echo -e " $0 format # 格式化代码" - echo "" echo -e "${GREEN}直接使用:${NC}" echo -e " dart run bin/main.dart generate --help" echo "" } -# 检查必要的工具 -check_prerequisites() { - if ! command -v dart &> /dev/null; then - echo -e "${YELLOW}❌ Dart SDK 未安装或不在 PATH 中${NC}" - exit 1 - fi - - if [ ! -f "$CLI_DART_FILE" ]; then - echo -e "${YELLOW}❌ CLI 文件不存在: $CLI_DART_FILE${NC}" - exit 1 - fi -} - -# 执行生成并格式化 -generate_and_format() { - local cmd="$1" - echo -e "${CYAN}🚀 执行: $cmd${NC}" - - if eval "$cmd"; then - echo -e "${CYAN}🔧 修复和排序 imports...${NC}" - dart fix --apply - - echo -e "${CYAN}🎨 格式化代码...${NC}" - dart format . - - echo -e "${GREEN}✅ 生成完成!${NC}" - else - echo -e "${YELLOW}❌ 生成失败${NC}" - exit 1 - fi -} - # 主函数 main() { if [ $# -eq 0 ] || [ "$1" = "help" ] || [ "$1" = "--help" ]; then @@ -74,50 +37,26 @@ main() { exit 0 fi - # 检查必要工具(除了 clean 命令) - if [ "$1" != "clean" ]; then - check_prerequisites - fi - case "$1" in all) - dart run "$CLI_DART_FILE" generate --models --api - dart fix --apply # 先修复和排序 imports - dart format . # 再格式化代码 + dart run "$CLI_DART_FILE" generate --models --api --split-by-tags + dart format . + dart fix --apply ;; models) dart run "$CLI_DART_FILE" generate --models - dart fix --apply # 先修复和排序 imports - dart format . # 再格式化代码 + dart format . + dart fix --apply ;; docs) dart run "$CLI_DART_FILE" generate --docs - dart fix --apply # 先修复和排序 imports - dart format . # 再格式化代码 + dart format . + dart fix --apply ;; api) dart run "$CLI_DART_FILE" generate --api - dart fix --apply # 先修复和排序 imports - dart format . # 再格式化代码 - ;; - clean) - echo -e "${CYAN}🧹 清理生成的文件...${NC}" - rm -rf generator/ - echo -e "${GREEN}✅ 清理完成${NC}" - ;; - validate) - echo -e "${CYAN}🔍 验证生成的代码...${NC}" - if [ -f "validate.sh" ]; then - ./validate.sh - else - echo -e "${YELLOW}⚠️ 验证脚本不存在,请先运行: chmod +x validate.sh${NC}" - fi - ;; - format) - echo -e "${CYAN}🎨 格式化代码...${NC}" - dart fix --apply # 先修复和排序 imports - dart format . # 再格式化代码 - echo -e "${GREEN}✅ 格式化完成${NC}" + dart format . + dart fix --apply ;; *) echo -e "${YELLOW}未知命令: $1${NC}" diff --git a/swagger.json b/swagger.json deleted file mode 100644 index e805c3d..0000000 --- a/swagger.json +++ /dev/null @@ -1,12902 +0,0 @@ -{ - "openapi": "3.0.1", - "info": { - "title": "OA移动端Api", - "version": "v1" - }, - "paths": { - "/api/v1/FollowManager/GetSubjectinfos": { - "get": { - "tags": [ - "FollowManager" - ], - "summary": "获取所有科目列表", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Subjectinfo" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Subjectinfo" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Subjectinfo" - } - } - } - } - } - } - } - }, - "/api/v1/FollowManager/GetClassSubs": { - "get": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-根据班级id获取班级科目绑定表列表", - "parameters": [ - { - "name": "classId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassSubResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassSubResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassSubResult" - } - } - } - } - } - } - } - }, - "/api/v1/FollowManager/GetClassTeachersByClassId": { - "get": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-根据班级id获取班级教师绑定表列表", - "parameters": [ - { - "name": "classId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassTeacherResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassTeacherResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassTeacherResult" - } - } - } - } - } - } - } - }, - "/api/v1/FollowManager/AddUpdateClassTeachers": { - "put": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-添加班级教师绑定表(会删除之前的)", - "parameters": [ - { - "name": "ClassesId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassTeacherRequest" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassTeacherRequest" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassTeacherRequest" - } - } - }, - "application/*+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassTeacherRequest" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/FollowManager/DeleteClassTeachers": { - "delete": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-删除班级教师绑定表", - "parameters": [ - { - "name": "id", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/FollowManager/GetFinancial_Indicators": { - "get": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-获取当前时间的经费指标", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/Financial_indicators" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/Financial_indicators" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/Financial_indicators" - } - } - } - } - } - } - }, - "/api/v1/FollowManager/GetFinancial_Classes": { - "get": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-获取当前时间的班级经费使用列表", - "parameters": [ - { - "name": "class_id", - "in": "query", - "description": "班级id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/FinancialClassSumResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/FinancialClassSumResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/FinancialClassSumResult" - } - } - } - } - } - } - }, - "/api/v1/FollowManager/AddFinancial_Classes": { - "put": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-添加班级经费使用", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/FinancialClassRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/FinancialClassRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/FinancialClassRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/FinancialClassRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/FollowManager/GetStudents": { - "get": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-获取班级学生列表", - "parameters": [ - { - "name": "classId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StudentResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StudentResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/StudentResult" - } - } - } - } - } - } - } - }, - "/api/v1/FollowManager/AddClassesStudent": { - "put": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-添加班级学生绑定表", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/StudentRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/StudentRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/StudentRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/StudentRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/FollowManager/DeleteClassesStudent": { - "delete": { - "tags": [ - "FollowManager" - ], - "summary": "工作台-删除班级学生绑定表", - "parameters": [ - { - "name": "classId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "userId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/HealthCheck": { - "get": { - "tags": [ - "HealthCheck" - ], - "summary": "健康检查接口", - "parameters": [ - { - "name": "api-version", - "in": "query", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v1/Index/GetBanner": { - "get": { - "tags": [ - "Index" - ], - "summary": "获取首页的轮播图", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BannerResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BannerResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BannerResult" - } - } - } - } - } - } - } - }, - "/api/v1/Index/GetDatetimeNow": { - "get": { - "tags": [ - "Index" - ], - "summary": "获取服务器当前时间", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - }, - "application/json": { - "schema": { - "type": "string" - } - }, - "text/json": { - "schema": { - "type": "string" - } - } - } - } - } - } - }, - "/api/v1/Index/GetClasses": { - "get": { - "tags": [ - "Index" - ], - "summary": "获取本人所管班级列表", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Classes" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Classes" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Classes" - } - } - } - } - } - } - } - }, - "/api/v1/Index/GetClassesTaskChecklistUsers": { - "get": { - "tags": [ - "Index" - ], - "summary": "获取本人通用工作指标列表", - "parameters": [ - { - "name": "PageIndex", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "PageSize", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 10 - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/Index_ClassesTaskCheckList_UserPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/Index_ClassesTaskCheckList_UserPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/Index_ClassesTaskCheckList_UserPageResponse" - } - } - } - } - } - } - }, - "/api/v1/Index/GetClassesTaskList": { - "get": { - "tags": [ - "Index" - ], - "summary": "获取首页的待办任务列表", - "parameters": [ - { - "name": "class_id", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "PageIndex", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "PageSize", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 10 - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - } - } - } - } - } - }, - "/api/v1/Index/GetTaskList": { - "get": { - "tags": [ - "Index" - ], - "summary": "获取任务列表", - "parameters": [ - { - "name": "PageIndex", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "PageSize", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 10 - } - }, - { - "name": "Task_index_type", - "in": "query", - "description": "任务指标类型-1班级;2通用", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "class_id", - "in": "query", - "description": "Task_index_type为1时,班级id必传", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "TaskTypeEnum", - "in": "query", - "description": "任务类型枚举", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "BeginDate", - "in": "query", - "description": "开始日期", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndDate", - "in": "query", - "description": "结束日期", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "Status", - "in": "query", - "description": "0:未开始 1:进行中 2:已结束 3:问题待处理(仅用于双师跟课)。多个用英文逗号分开", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - } - } - } - } - } - }, - "/api/v1/Index/GetHistoryTaskList": { - "get": { - "tags": [ - "Index" - ], - "summary": "获取历史任务列表", - "parameters": [ - { - "name": "PageIndex", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "PageSize", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 10 - } - }, - { - "name": "Task_index_type", - "in": "query", - "description": "任务指标类型-1班级;2通用", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "class_id", - "in": "query", - "description": "Task_index_type为1时,班级id必传", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "TaskTypeEnum", - "in": "query", - "description": "任务类型枚举", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "BeginDate", - "in": "query", - "description": "开始日期", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndDate", - "in": "query", - "description": "结束日期", - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassesTaskListResultPageResponse" - } - } - } - } - } - } - }, - "/api/v1/Login/GetOpenTest": { - "get": { - "tags": [ - "Login" - ], - "summary": "获取是否开启测试", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/Login/userLogin": { - "post": { - "tags": [ - "Login" - ], - "summary": "普通用户登录", - "requestBody": { - "description": "登录信息", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/LoginRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/userLoginResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/userLoginResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/userLoginResult" - } - } - } - } - } - } - }, - "/api/v1/Login/GetMyUserSig": { - "get": { - "tags": [ - "Login" - ], - "summary": "获取 UserSig 鉴权票据", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - }, - "application/json": { - "schema": { - "type": "string" - } - }, - "text/json": { - "schema": { - "type": "string" - } - } - } - } - } - } - }, - "/api/v1/Login/userCodeLogin": { - "post": { - "tags": [ - "Login" - ], - "summary": "普通用户验证码登录", - "requestBody": { - "description": "登录信息", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/LoginCodeRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/LoginCodeRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/LoginCodeRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/LoginCodeRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/userLoginResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/userLoginResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/userLoginResult" - } - } - } - } - } - } - }, - "/api/v1/Login/GetUserLoginCode": { - "post": { - "tags": [ - "Login" - ], - "summary": "普通用户验证码登录-获取验证码", - "requestBody": { - "description": "获取信息", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/userLoginRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/userLoginRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/userLoginRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/userLoginRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v1/Login/RefreshToken": { - "post": { - "tags": [ - "Login" - ], - "summary": "换取token", - "requestBody": { - "description": "登录信息", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/RefreshTokenRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/RefreshTokenRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/RefreshTokenRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/RefreshTokenRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "string" - } - }, - "application/json": { - "schema": { - "type": "string" - } - }, - "text/json": { - "schema": { - "type": "string" - } - } - } - } - } - } - }, - "/api/v1/Login/Register": { - "put": { - "tags": [ - "Login" - ], - "summary": "注册", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/RegisterRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/RegisterRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/RegisterRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/RegisterRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v1/Login/LogOff": { - "post": { - "tags": [ - "Login" - ], - "summary": "注销", - "parameters": [ - { - "name": "account", - "in": "query", - "description": "账号", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v1/MobileManager/GetMinisterAdminUsers": { - "post": { - "tags": [ - "MobileManager" - ], - "summary": "获取本人是部长管理的组长用户列表", - "parameters": [ - { - "name": "TeamLeaderUserName", - "in": "query", - "description": "用户姓名", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetMinisterAdminUsersAll": { - "post": { - "tags": [ - "MobileManager" - ], - "summary": "获取本人是部长管理的组长和学习官用户列表", - "parameters": [ - { - "name": "TeamLeaderUserName", - "in": "query", - "description": "用户姓名", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetTeamLeaderUsers": { - "post": { - "tags": [ - "MobileManager" - ], - "summary": "获取本人是组长管理的学习官用户列表", - "requestBody": { - "description": "组长id集合,不传则本人id", - "content": { - "application/json-patch+json": { - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - "application/*+json": { - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserFoundationResult" - } - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetSchoolResults": { - "get": { - "tags": [ - "MobileManager" - ], - "summary": "获取管理的学校列表", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchoolResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchoolResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchoolResult" - } - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetClassesBySchoolId": { - "get": { - "tags": [ - "MobileManager" - ], - "summary": "根据学校获取所有班级列表", - "parameters": [ - { - "name": "schoolId", - "in": "query", - "description": "学校id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesResult" - } - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetBindClassesBySchoolId": { - "get": { - "tags": [ - "MobileManager" - ], - "summary": "根据学校获取这个学校【本人管理班级】列表", - "parameters": [ - { - "name": "schoolId", - "in": "query", - "description": "学校id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesResult" - } - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetClassesAndFollowBySchoolId": { - "get": { - "tags": [ - "MobileManager" - ], - "summary": "根据学校获取管理的班级列表(包含学习官信息)", - "parameters": [ - { - "name": "schoolId", - "in": "query", - "description": "学校id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesAndFollowResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesAndFollowResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesAndFollowResult" - } - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetClassesTaskChecklists": { - "get": { - "tags": [ - "MobileManager" - ], - "summary": "组长根据班级id获取工作任务指标列表", - "parameters": [ - { - "name": "classesId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ClassManageTaskListResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassManageTaskListResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassManageTaskListResult" - } - } - } - } - } - } - }, - "/api/v1/MobileManager/ClassManagerAddUpdateTaskCheckList": { - "put": { - "tags": [ - "MobileManager" - ], - "summary": "组长新增工作任务指标", - "parameters": [ - { - "name": "followId", - "in": "query", - "description": "学习官id集合", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassManager_Task_checklistRequest" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassManager_Task_checklistRequest" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassManager_Task_checklistRequest" - } - } - }, - "application/*+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassManager_Task_checklistRequest" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetTaskCheckListByType": { - "get": { - "tags": [ - "MobileManager" - ], - "summary": "部长获取工作任务指标列表", - "parameters": [ - { - "name": "TaskType", - "in": "query", - "description": "班级/通用任务类型 1班级;2通用", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Task_checklistResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Task_checklistResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Task_checklistResult" - } - } - } - } - } - } - } - }, - "/api/v1/MobileManager/AddTaskCheckList": { - "put": { - "tags": [ - "MobileManager" - ], - "summary": "部长新增工作任务指标\r\n(会删除所有管理的班级任务指标-删除所有管理的学习官的通用任务指标)", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Task_checklistRequest" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Task_checklistRequest" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Task_checklistRequest" - } - } - }, - "application/*+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Task_checklistRequest" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/MobileManager/GetDataSummariz": { - "get": { - "tags": [ - "MobileManager" - ], - "summary": "部长获取数据统计", - "parameters": [ - { - "name": "BeginTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "FollowId", - "in": "query", - "description": "学习官id【可能存在组长id,组长也是学习官】", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "TeamLeaderUserId", - "in": "query", - "description": "组长id,查询该组所有人", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskFinishList" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskFinishList" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskFinishList" - } - } - } - } - } - } - } - }, - "/api/v1/MyInfo/GetTencentIMAppID": { - "get": { - "tags": [ - "MyInfo" - ], - "summary": "获取腾讯IM的AppID", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "integer", - "format": "int32" - } - }, - "application/json": { - "schema": { - "type": "integer", - "format": "int32" - } - }, - "text/json": { - "schema": { - "type": "integer", - "format": "int32" - } - } - } - } - } - } - }, - "/api/v1/MyInfo/GetOssConfig": { - "get": { - "tags": [ - "MyInfo" - ], - "summary": "获取oss配置", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/OSSConfigResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/OSSConfigResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/OSSConfigResult" - } - } - } - } - } - } - }, - "/api/v1/MyInfo/GetOssSign": { - "get": { - "tags": [ - "MyInfo" - ], - "summary": "获取oss预签名", - "parameters": [ - { - "name": "objectName", - "in": "query", - "description": "只传后缀。例【https://meeting-yhzh.oss-cn-hangzhou.aliyuncs.com/sss/11.txt】中的【txt】", - "schema": { - "type": "string" - } - }, - { - "name": "type", - "in": "query", - "description": "文件模块类型:1、普通文件上传; 2:资料收集", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/OssSignResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/OssSignResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/OssSignResult" - } - } - } - } - } - } - }, - "/api/v1/MyInfo/DeleteOSSFile": { - "delete": { - "tags": [ - "MyInfo" - ], - "summary": "删除oss存储中的服务", - "parameters": [ - { - "name": "filePath", - "in": "query", - "description": "完整网络路径", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/MyInfo/GetUpdateVersion": { - "get": { - "tags": [ - "MyInfo" - ], - "summary": "获取APP/客户端版本更新信息", - "parameters": [ - { - "name": "upType", - "in": "query", - "description": "1:APP,2:客户端", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/UpdateappResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpdateappResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/UpdateappResult" - } - } - } - } - } - } - }, - "/api/v1/MyInfo/UpdateMyPhoneInfo": { - "put": { - "tags": [ - "MyInfo" - ], - "summary": "换绑本人手机信息", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/MyPhoneBindRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/MyPhoneBindRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/MyPhoneBindRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/MyPhoneBindRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/MyInfo/UpdateMyPasswodInfo": { - "put": { - "tags": [ - "MyInfo" - ], - "summary": "修改本人密码", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/MyInfoResetPwdRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/MyInfoResetPwdRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/MyInfoResetPwdRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/MyInfoResetPwdRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/MyInfo/GetPhoneCode": { - "get": { - "tags": [ - "MyInfo" - ], - "summary": "获取验证码-5分钟有效期(登录系统后)", - "parameters": [ - { - "name": "type", - "in": "query", - "description": "1:换绑手机", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "phone", - "in": "query", - "description": "phone", - "schema": { - "type": "string" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/MyInfo/FileUpload": { - "put": { - "tags": [ - "MyInfo" - ], - "summary": "文件上传(返回文件id)", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/System_filesRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/System_filesRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/System_filesRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/System_filesRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "integer", - "format": "int64" - } - }, - "application/json": { - "schema": { - "type": "integer", - "format": "int64" - } - }, - "text/json": { - "schema": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - }, - "/api/v1/TaskClassCadreMeeting/AddUpdateClassCadreMeeting": { - "put": { - "tags": [ - "TaskClassCadreMeeting" - ], - "summary": "创建/修改班干部会议任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskClassCadreMeeting/DeleteClassCadreMeetingFile": { - "delete": { - "tags": [ - "TaskClassCadreMeeting" - ], - "summary": "删除班干部会议文件信息", - "parameters": [ - { - "name": "ClassmeetingId", - "in": "query", - "description": "班干部会id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "fileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskClassCadreMeeting/ClassCadreMeetingFinish": { - "put": { - "tags": [ - "TaskClassCadreMeeting" - ], - "summary": "完成班干部会议任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskClassCadreMeeting/GetClassCadreMeetingResult": { - "get": { - "tags": [ - "TaskClassCadreMeeting" - ], - "summary": "根据任务id获取班干部会议信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassCadreMeetingResult" - } - } - } - } - } - } - }, - "/api/v1/TaskClassesActivity/AddUpdateTaskClassesActivity": { - "put": { - "tags": [ - "TaskClassesActivity" - ], - "summary": "添加或更新班级活动", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskClassesActivity/DeleteTaskClassesActivityFile": { - "delete": { - "tags": [ - "TaskClassesActivity" - ], - "summary": "删除班级活动文件信息", - "parameters": [ - { - "name": "ActivityId", - "in": "query", - "description": "活动Id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "fileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskClassesActivity/TaskClassesActivityFinish": { - "put": { - "tags": [ - "TaskClassesActivity" - ], - "summary": "完成班级活动", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskClassesActivity/GetTaskClassesActivityResult": { - "get": { - "tags": [ - "TaskClassesActivity" - ], - "summary": "根据任务id获取班干部班级活动信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassesActivityResult" - } - } - } - } - } - } - }, - "/api/v1/TaskClassMeeting/AddUpdateClassMeeting": { - "put": { - "tags": [ - "TaskClassMeeting" - ], - "summary": "创建/修改召开会议任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskClassMeeting/DeleteClassMeetingFile": { - "delete": { - "tags": [ - "TaskClassMeeting" - ], - "summary": "删除召开会议文件信息", - "parameters": [ - { - "name": "ClassmeetingId", - "in": "query", - "description": "召开id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "fileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskClassMeeting/ClassMeetingFinish": { - "put": { - "tags": [ - "TaskClassMeeting" - ], - "summary": "完成召开会议任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskClassMeeting/GetClassMeetingResult": { - "get": { - "tags": [ - "TaskClassMeeting" - ], - "summary": "根据任务id获取召开班级会议信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ClassMeetingResult" - } - } - } - } - } - } - }, - "/api/v1/TaskCoachSub/AddUpdateTaskCoachSub": { - "put": { - "tags": [ - "TaskCoachSub" - ], - "summary": "添加或更新学科辅助", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskCoachSub/DeleteTaskCoachSubFile": { - "delete": { - "tags": [ - "TaskCoachSub" - ], - "summary": "删除学科辅助文件信息", - "parameters": [ - { - "name": "CoachId", - "in": "query", - "description": "辅导表任务id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "fileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskCoachSub/TaskCoachSubFinish": { - "put": { - "tags": [ - "TaskCoachSub" - ], - "summary": "完成学科辅助", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskCoachSub/GetTaskCoachSubResult": { - "get": { - "tags": [ - "TaskCoachSub" - ], - "summary": "根据任务id获取班干部学科辅助信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CoachSubInfoResult" - } - } - } - } - } - } - }, - "/api/v1/TaskCultural/AddUpdateCulturalTask": { - "put": { - "tags": [ - "TaskCultural" - ], - "summary": "创建/修改文创内容任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CulturalRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CulturalRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CulturalRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CulturalRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskCultural/DeleteCulturalFile": { - "delete": { - "tags": [ - "TaskCultural" - ], - "summary": "删除文创内容文件", - "parameters": [ - { - "name": "CulturalId", - "in": "query", - "description": "文创id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "FileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskCultural/CulturalFinish": { - "post": { - "tags": [ - "TaskCultural" - ], - "summary": "完成文创内容任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/CulturalFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CulturalFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CulturalFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/CulturalFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskCultural/GetCulturalDetailResult": { - "get": { - "tags": [ - "TaskCultural" - ], - "summary": "获取文创内容详情结果", - "parameters": [ - { - "name": "taskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CulturalDetailResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CulturalDetailResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CulturalDetailResult" - } - } - } - } - } - } - }, - "/api/v1/TaskDataCollect/AddUpdateDataCollect": { - "put": { - "tags": [ - "TaskDataCollect" - ], - "summary": "创建/修改数据收集任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/DataCollectRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DataCollectRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DataCollectRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DataCollectRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskDataCollect/GetDataCollectUserResults": { - "get": { - "tags": [ - "TaskDataCollect" - ], - "summary": "获取数据收集用户列表", - "parameters": [ - { - "name": "ClassId", - "in": "query", - "description": "班级id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "CollectId", - "in": "query", - "description": "采集任务id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DataCollectUserResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DataCollectUserResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DataCollectUserResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskDataCollect/GetSunTaskFileResultsByUserId": { - "get": { - "tags": [ - "TaskDataCollect" - ], - "summary": "获取用户的数据收集", - "parameters": [ - { - "name": "UserId", - "in": "query", - "description": "用户id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "CollectId", - "in": "query", - "description": "采集任务id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskDataCollect/SaveDataCollectFile": { - "put": { - "tags": [ - "TaskDataCollect" - ], - "summary": "保存数据收集文件信息", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DataCollectFileRequest" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DataCollectFileRequest" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DataCollectFileRequest" - } - } - }, - "application/*+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DataCollectFileRequest" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskDataCollect/DeleteDataCollectFile": { - "delete": { - "tags": [ - "TaskDataCollect" - ], - "summary": "删除数据收集文件信息", - "parameters": [ - { - "name": "SunTaskId", - "in": "query", - "description": "数据收集id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "UserId", - "in": "query", - "description": "用户id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "FileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskDataCollect/DataCollectFinish": { - "put": { - "tags": [ - "TaskDataCollect" - ], - "summary": "完成数据收集任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/DataCollectFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DataCollectFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DataCollectFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/DataCollectFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskDataCollect/GetDataCollectResult": { - "get": { - "tags": [ - "TaskDataCollect" - ], - "summary": "根据任务id获取数据收集信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/DataCollectResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/DataCollectResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/DataCollectResult" - } - } - } - } - } - } - }, - "/api/v1/TaskFollow/GetWeekCourseTable": { - "get": { - "tags": [ - "TaskFollow" - ], - "summary": "根据时间获取当周课程表(时间不传默认一周)", - "parameters": [ - { - "name": "ClassId", - "in": "query", - "description": "班级id必传", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "StartTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/WeekModel" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/WeekModel" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/WeekModel" - } - } - } - } - } - } - } - }, - "/api/v1/TaskFollow/GetCourseWeekDetail": { - "get": { - "tags": [ - "TaskFollow" - ], - "summary": "根据课程ID获取课程详情", - "parameters": [ - { - "name": "ClassCourseId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/CourseWeekDetailOutput" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/CourseWeekDetailOutput" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/CourseWeekDetailOutput" - } - } - } - } - } - } - }, - "/api/v1/TaskFollow/GetFollowTaskByDate": { - "get": { - "tags": [ - "TaskFollow" - ], - "summary": "获取时间段内双师课堂课程id集合", - "parameters": [ - { - "name": "ClassesId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "BeginDateTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndDateTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - } - } - } - } - } - }, - "/api/v1/TaskFollow/AddUpdateTaskCoachSub": { - "put": { - "tags": [ - "TaskFollow" - ], - "summary": "添加双师课堂(无修改)", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowInfoRequest" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowInfoRequest" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowInfoRequest" - } - } - }, - "application/*+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowInfoRequest" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK" - } - } - } - }, - "/api/v1/TaskFollow/AddFollowAbsenceUser": { - "put": { - "tags": [ - "TaskFollow" - ], - "summary": "添加缺勤人员(每次覆盖上一次的)", - "parameters": [ - { - "name": "FollowId", - "in": "query", - "description": "跟课记录id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowAbsenceUserRequest" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowAbsenceUserRequest" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowAbsenceUserRequest" - } - } - }, - "application/*+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowAbsenceUserRequest" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskFollow/AddFollowKeyNoteUser": { - "put": { - "tags": [ - "TaskFollow" - ], - "summary": "添加重点人员(每次覆盖上一次的)", - "parameters": [ - { - "name": "FollowId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowKeyNoteUserRequest" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowKeyNoteUserRequest" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowKeyNoteUserRequest" - } - } - }, - "application/*+json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowKeyNoteUserRequest" - } - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskFollow/AddFollowTeachersituation": { - "put": { - "tags": [ - "TaskFollow" - ], - "summary": "添加老师、学生问题(每次覆盖上一次的)", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/FollowQuestionRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/FollowQuestionRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/FollowQuestionRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/FollowQuestionRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskFollow/TaskCoachSubFinish": { - "put": { - "tags": [ - "TaskFollow" - ], - "summary": "完成双师课堂(完成后判断是否有待处理任务。状态改为已完成或待处理)", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/FollowInfoFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/FollowInfoFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/FollowInfoFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/FollowInfoFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskFollow/GetTaskCoachSubResult": { - "get": { - "tags": [ - "TaskFollow" - ], - "summary": "根据任务id获取班干部双师课堂信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/FollowInfoResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/FollowInfoResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/FollowInfoResult" - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/GetTaskTypeInfo": { - "get": { - "tags": [ - "TaskInfo" - ], - "summary": "获取任务类型列表", - "parameters": [ - { - "name": "PageIndex", - "in": "query", - "description": "当前页", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "description": "一页条数", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SysParameterPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SysParameterPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SysParameterPageResponse" - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/GetTaskTypeInfoByPid": { - "get": { - "tags": [ - "TaskInfo" - ], - "summary": "根据父级ID获取该级任务类型列表", - "parameters": [ - { - "name": "pid", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SysParameter" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SysParameter" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SysParameter" - } - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/GetTaskTypeInfoAllByPid": { - "get": { - "tags": [ - "TaskInfo" - ], - "summary": "获取该pid下的所有参数", - "parameters": [ - { - "name": "pid", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SysParameter" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SysParameter" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SysParameter" - } - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/GetTaskTypeInfoAllByPValue": { - "get": { - "tags": [ - "TaskInfo" - ], - "summary": "获取该PValue本级和下级的所有参数", - "parameters": [ - { - "name": "PValue", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SysParameter" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SysParameter" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SysParameter" - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/GetAssistUsers": { - "get": { - "tags": [ - "TaskInfo" - ], - "summary": "获取协助人员(同校同级的学习官、当前账户绑定的组长、组长上级的部长)", - "parameters": [ - { - "name": "ClassesId", - "in": "query", - "description": "班级id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/AssistUserResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/AssistUserResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/AssistUserResult" - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/GetCloudSchoolList": { - "get": { - "tags": [ - "TaskInfo" - ], - "summary": "获取通讯录云校树", - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchoolTree" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchoolTree" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchoolTree" - } - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/GetUserBooksResultBySchoolId": { - "get": { - "tags": [ - "TaskInfo" - ], - "summary": "根据学校id查询通讯录人员信息", - "parameters": [ - { - "name": "schoolId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserBooksResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserBooksResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserBooksResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/GetUserBooksResultByUserId": { - "get": { - "tags": [ - "TaskInfo" - ], - "summary": "根据id获取该用户的资料信息", - "parameters": [ - { - "name": "UserId", - "in": "query", - "description": "用户id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SchoolUserBooksResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SchoolUserBooksResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SchoolUserBooksResult" - } - } - } - } - } - } - }, - "/api/v1/TaskInfo/DeleteTask": { - "delete": { - "tags": [ - "TaskInfo" - ], - "summary": "删除任务(适用于所有类型任务)", - "parameters": [ - { - "name": "taskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskMeeting/AddUpdateTaskMeeting": { - "put": { - "tags": [ - "TaskMeeting" - ], - "summary": "添加或更新会议任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskMeeting/DeleteTaskMeetingFile": { - "delete": { - "tags": [ - "TaskMeeting" - ], - "summary": "删除会议文件信息", - "parameters": [ - { - "name": "MeetingId", - "in": "query", - "description": "会id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "fileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskMeeting/TaskMeetingFinish": { - "put": { - "tags": [ - "TaskMeeting" - ], - "summary": "完成会议任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskMeeting/GetTaskMeetingResult": { - "get": { - "tags": [ - "TaskMeeting" - ], - "summary": "根据任务id获取班干部会议信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/MeetingInfoResult" - } - } - } - } - } - } - }, - "/api/v1/TaskOther/AddUpdateOtherInfo": { - "put": { - "tags": [ - "TaskOther" - ], - "summary": "创建/修改其他任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskOther/DeleteOtherInfoFile": { - "delete": { - "tags": [ - "TaskOther" - ], - "summary": "删除其他文件信息", - "parameters": [ - { - "name": "OtherId", - "in": "query", - "description": "其他id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "fileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskOther/OtherInfoFinish": { - "put": { - "tags": [ - "TaskOther" - ], - "summary": "完成其他任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskOther/GetOtherInfoResult": { - "get": { - "tags": [ - "TaskOther" - ], - "summary": "根据任务id获取其他信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/OtherInfoResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/OtherInfoResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSolution/GetList": { - "get": { - "tags": [ - "TaskSolution" - ], - "summary": "获取解决方案列表", - "parameters": [ - { - "name": "ProblemTitle", - "in": "query", - "description": "备 注:问题描述\r\n默认值:", - "schema": { - "type": "string" - } - }, - { - "name": "ProblemObj", - "in": "query", - "description": "备 注:适用对象 1:学校;2:教师;3:学生\r\n默认值:", - "schema": { - "$ref": "#/components/schemas/ToolObjectType" - } - }, - { - "name": "ProblemPhenomenon", - "in": "query", - "description": "备 注:问题显著现象\r\n默认值:", - "schema": { - "type": "string" - } - }, - { - "name": "ClassesId", - "in": "query", - "description": "班级id(必传)", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "ProblemTaskType", - "in": "query", - "description": "任务类型枚举列表", - "schema": { - "$ref": "#/components/schemas/SysTaskTypeEnums" - } - }, - { - "name": "PageIndex", - "in": "query", - "description": "当前页", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "PageSize", - "in": "query", - "description": "一页条数", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SolutionListViewMobileDtoPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SolutionListViewMobileDtoPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SolutionListViewMobileDtoPageResponse" - } - } - } - } - } - } - }, - "/api/v1/TaskSolution/GetSingle": { - "get": { - "tags": [ - "TaskSolution" - ], - "summary": "获取解决方案详情", - "parameters": [ - { - "name": "id", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SolutionDetailViewDto" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SolutionDetailViewDto" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SolutionDetailViewDto" - } - } - } - } - } - } - }, - "/api/v1/TaskSolution/GetQuestionListByQuestionType": { - "get": { - "tags": [ - "TaskSolution" - ], - "summary": "根据问题类别获取问题类型列表及数量", - "parameters": [ - { - "name": "questionType", - "in": "query", - "description": "1:学生;2:老师;", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QuestionInfoByTypeResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QuestionInfoByTypeResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QuestionInfoByTypeResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSolution/GetQuestionListByTaskType": { - "get": { - "tags": [ - "TaskSolution" - ], - "summary": "根据任务问题枚举获取问题列表", - "parameters": [ - { - "name": "taskEnum", - "in": "query", - "description": "任务问题枚举", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "userId", - "in": "query", - "description": "搜索 用户id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "year", - "in": "query", - "description": "搜索 年", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "month", - "in": "query", - "description": "搜索 月", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "isChain", - "in": "query", - "description": "是否查询环比,0查询有环比的,1查询历史总记录", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/QuestionInfoByTaskEnumResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/QuestionInfoByTaskEnumResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/QuestionInfoByTaskEnumResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSolution/GetQuestionByUserId": { - "get": { - "tags": [ - "TaskSolution" - ], - "summary": "根据用户id获取问题列表", - "parameters": [ - { - "name": "userId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QuestionInfoByTypeResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QuestionInfoByTypeResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QuestionInfoByTypeResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSpot/AddSpotCheckTask": { - "put": { - "tags": [ - "TaskSpot" - ], - "summary": "学习行为习惯全面抽查-添加/修改工作任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSpot/AddSpotCheckUser": { - "put": { - "tags": [ - "TaskSpot" - ], - "summary": "学习行为习惯全面抽查-添加工作任务-添加抽查用户(只要有添加,就不能修改任务)", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskUserRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskUserRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskUserRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskUserRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskSpot/SpotTaskFinish": { - "put": { - "tags": [ - "TaskSpot" - ], - "summary": "学习行为习惯全面抽查-结束工作任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskSpot/GetSpotCheckType": { - "get": { - "tags": [ - "TaskSpot" - ], - "summary": "学习行为习惯全面抽查-根据抽查项目 获取任务计划分值标准", - "parameters": [ - { - "name": "Check_id", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotCheckTypeValue" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotCheckTypeValue" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotCheckTypeValue" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSpot/GetSpotTaskInfoById": { - "get": { - "tags": [ - "TaskSpot" - ], - "summary": "学习行为习惯全面抽查-获取抽查任务信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SpotTaskResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SpotTaskResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSpot/GetSpotTaskUser": { - "get": { - "tags": [ - "TaskSpot" - ], - "summary": "学习行为习惯全面抽查-根据抽查id获取抽查任务用户信息(抽查记录)", - "parameters": [ - { - "name": "SpotId", - "in": "query", - "description": "必传", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "Date", - "in": "query", - "description": "日期", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "UserId", - "in": "query", - "description": "学生id", - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotTaskUserResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotTaskUserResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotTaskUserResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSpot/GetSpotTaskUserDateBySpotId": { - "get": { - "tags": [ - "TaskSpot" - ], - "summary": "学习行为习惯全面抽查-根据抽查id获取已抽查用户的 日期记录信息", - "parameters": [ - { - "name": "SpotId", - "in": "query", - "description": "必传", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "type": "string", - "format": "date-time" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string", - "format": "date-time" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "type": "string", - "format": "date-time" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetTaskLogResult": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取用户该任务操作记录(工作进度)(日报周报月报通用)", - "parameters": [ - { - "name": "taskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "UserId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskLoginfoResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskLoginfoResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskLoginfoResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizPlanById": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "根据总结id获取总结计划信息(日报周报月报通用)", - "parameters": [ - { - "name": "SummarizId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizPlan" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizPlan" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizPlan" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizNoReadByType": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取用户未读的总结任务数量", - "parameters": [ - { - "name": "type", - "in": "query", - "description": "1:日报 2:周报 3:月报", - "schema": { - "type": "integer", - "format": "int32" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SummarizNoReadResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizNoReadResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizNoReadResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizDayListResult": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "管理端获取本人所管理的人员的日报", - "parameters": [ - { - "name": "UserIds", - "in": "query", - "description": "", - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - { - "name": "UserName", - "in": "query", - "description": "", - "schema": { - "type": "string" - } - }, - { - "name": "BeginTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "PageIndex", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "PageSize", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 10 - } - }, - { - "name": "isOnlyNoRead", - "in": "query", - "description": "", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SummarizDayListResultPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizDayListResultPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizDayListResultPageResponse" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizeTaskByDate": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取日报中的任务列表-根据日期获取任务列表(日报)", - "parameters": [ - { - "name": "Date", - "in": "query", - "description": "日期", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "UserId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,只获取他作为学习官绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizTaskResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizTaskResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizTaskResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/AddDaySummarize": { - "put": { - "tags": [ - "TaskSummarize" - ], - "summary": "添加日报", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SummarizeDayRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizeDayRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizeDayRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SummarizeDayRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizDayDateSlot": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取日报信息(时间段)", - "parameters": [ - { - "name": "BeginDate", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndDate", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "userId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "type": "string" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizDay": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取日报信息", - "parameters": [ - { - "name": "workDate", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "userId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SummarizDayResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizDayResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizDayResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/EvaluationSumDay": { - "put": { - "tags": [ - "TaskSummarize" - ], - "summary": "评价日报", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizWeekListResult": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "管理端获取本人所管理的人员的周报", - "parameters": [ - { - "name": "UserIds", - "in": "query", - "description": "", - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - { - "name": "UserName", - "in": "query", - "description": "", - "schema": { - "type": "string" - } - }, - { - "name": "BeginTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "PageIndex", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "PageSize", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 10 - } - }, - { - "name": "isOnlyNoRead", - "in": "query", - "description": "", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekTaskResultPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekTaskResultPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekTaskResultPageResponse" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizWeekTaskByDate": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取周报中的任务列表-根据开始日期和结束日期获取任务列表(周报)", - "parameters": [ - { - "name": "BeginDate", - "in": "query", - "description": "开始日期", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndDate", - "in": "query", - "description": "结束日期", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "UserId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizTaskResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizTaskResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizTaskResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/AddWeekSummarize": { - "put": { - "tags": [ - "TaskSummarize" - ], - "summary": "添加周报", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizWeekByDate": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取周报信息(时间段)", - "parameters": [ - { - "name": "BeginDate", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndDate", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "userId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizWeekTaskResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizWeekTaskResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizWeekTaskResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizWeek": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取周报信息", - "parameters": [ - { - "name": "BeginDate", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndDate", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "userId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekListResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekListResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizWeekListResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/EvaluationSumWeek": { - "put": { - "tags": [ - "TaskSummarize" - ], - "summary": "评价周报", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizMonthTaskResult": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "管理端获取本人所管理的人员的月报", - "parameters": [ - { - "name": "UserIds", - "in": "query", - "description": "", - "schema": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - } - } - }, - { - "name": "UserName", - "in": "query", - "description": "", - "schema": { - "type": "string" - } - }, - { - "name": "BeginTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "EndTime", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - }, - { - "name": "PageIndex", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 1 - } - }, - { - "name": "PageSize", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32", - "default": 10 - } - }, - { - "name": "isOnlyNoRead", - "in": "query", - "description": "", - "schema": { - "type": "boolean", - "default": false - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthTaskResultPageResponse" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthTaskResultPageResponse" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthTaskResultPageResponse" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizMonthTaskByDate": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取月报中的任务完成情况列表(月报)", - "parameters": [ - { - "name": "Year", - "in": "query", - "description": "年份", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "Month", - "in": "query", - "description": "月份", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "UserId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthStandardResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthStandardResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthStandardResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/AddMonthSummarize": { - "put": { - "tags": [ - "TaskSummarize" - ], - "summary": "添加月报", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizMonthByYear": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取月报信息-一年的", - "parameters": [ - { - "name": "Year", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "userId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizMonthTaskResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizMonthTaskResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizMonthTaskResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/GetSummarizMonth": { - "get": { - "tags": [ - "TaskSummarize" - ], - "summary": "获取月报信息", - "parameters": [ - { - "name": "Year", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "Month", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int32" - } - }, - { - "name": "userId", - "in": "query", - "description": "用户id,不传则获取自己(组长时,获取他作为学习官时绑定的班级或通用任务)", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthListResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthListResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/SummarizMonthListResult" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/EvaluationSumMonth": { - "put": { - "tags": [ - "TaskSummarize" - ], - "summary": "评价月报", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/EvaluationSumRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskSummarize/AddReadSummariz": { - "put": { - "tags": [ - "TaskSummarize" - ], - "summary": "添加日报 周报 月报的已读信息", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/ReadSummarizRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/ReadSummarizRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/ReadSummarizRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/ReadSummarizRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskTalk/AddUpdateTaskTalk": { - "put": { - "tags": [ - "TaskTalk" - ], - "summary": "添加或更新谈话任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/TalkInfoRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TalkInfoRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TalkInfoRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/TalkInfoRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskTalk/DeleteTaskTalk": { - "delete": { - "tags": [ - "TaskTalk" - ], - "summary": "删除谈话任务文件", - "parameters": [ - { - "name": "Talk_id", - "in": "query", - "description": "谈话记录表id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "fileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskTalk/TaskTalkFinish": { - "put": { - "tags": [ - "TaskTalk" - ], - "summary": "结束谈话任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/TaskTalkFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TaskTalkFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TaskTalkFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/TaskTalkFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskTalk/GetTaskTalkResult": { - "get": { - "tags": [ - "TaskTalk" - ], - "summary": "获取任务谈话结果", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TaskTalkResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TaskTalkResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TaskTalkResult" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherBehavior/AddUpdateTaskTeacherBehavior": { - "put": { - "tags": [ - "TaskTeacherBehavior" - ], - "summary": "添加或更新教师行为规范任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherBehavior/AddTeacherBehaviorQuestion": { - "put": { - "tags": [ - "TaskTeacherBehavior" - ], - "summary": "添加观察问题记录", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/Teacher_behavior_questionRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/Teacher_behavior_questionRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/Teacher_behavior_questionRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/Teacher_behavior_questionRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherBehavior/GetTeacherBehaviorQuestionNumList": { - "get": { - "tags": [ - "TaskTeacherBehavior" - ], - "summary": "获取教师行为规范问题列表(观察记录)", - "parameters": [ - { - "name": "tbId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "Date", - "in": "query", - "description": "", - "schema": { - "type": "string", - "format": "date-time" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeacherBehaviorQuestionNumResult" - } - } - }, - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeacherBehaviorQuestionNumResult" - } - } - }, - "text/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeacherBehaviorQuestionNumResult" - } - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherBehavior/GetTeacherBehaviorQuestionResult": { - "get": { - "tags": [ - "TaskTeacherBehavior" - ], - "summary": "根据问题观察记录id获取问题详细", - "parameters": [ - { - "name": "QuestionId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorQuestionResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorQuestionResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorQuestionResult" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherBehavior/TeacherBehaviorFinish": { - "put": { - "tags": [ - "TaskTeacherBehavior" - ], - "summary": "结束教师行为规范任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherBehavior/GetTeacherBehaviorResults": { - "get": { - "tags": [ - "TaskTeacherBehavior" - ], - "summary": "获取教师行为规范结果列表", - "parameters": [ - { - "name": "taskId", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TeacherBehaviorResult" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherTalk/AddUpdateTeacherTalkInfo": { - "put": { - "tags": [ - "TaskTeacherTalk" - ], - "summary": "创建/修改教师谈话任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/BaseTaskAddResult" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherTalk/DeleteTeacherTalkInfoFile": { - "delete": { - "tags": [ - "TaskTeacherTalk" - ], - "summary": "删除教师谈话文件信息", - "parameters": [ - { - "name": "TalkId", - "in": "query", - "description": "谈话id", - "schema": { - "type": "integer", - "format": "int64" - } - }, - { - "name": "fileId", - "in": "query", - "description": "文件id", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherTalk/TeacherTalkInfoFinish": { - "put": { - "tags": [ - "TaskTeacherTalk" - ], - "summary": "完成教师谈话任务", - "requestBody": { - "description": "", - "content": { - "application/json-patch+json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoFinishRequest" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoFinishRequest" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoFinishRequest" - } - }, - "application/*+json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoFinishRequest" - } - } - } - }, - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "type": "boolean" - } - }, - "application/json": { - "schema": { - "type": "boolean" - } - }, - "text/json": { - "schema": { - "type": "boolean" - } - } - } - } - } - } - }, - "/api/v1/TaskTeacherTalk/GetTeacherTalkInfoResult": { - "get": { - "tags": [ - "TaskTeacherTalk" - ], - "summary": "根据任务id获取教师谈话信息", - "parameters": [ - { - "name": "TaskId", - "in": "query", - "description": "", - "schema": { - "type": "integer", - "format": "int64" - } - } - ], - "responses": { - "200": { - "description": "OK", - "content": { - "text/plain": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoResult" - } - }, - "application/json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoResult" - } - }, - "text/json": { - "schema": { - "$ref": "#/components/schemas/TeacherTalkInfoResult" - } - } - } - } - } - } - } - }, - "components": { - "schemas": { - "AssistUserResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "Id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - } - }, - "additionalProperties": false, - "description": "人员基本信息" - }, - "BannerResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "id", - "format": "int64" - }, - "bannerFileId": { - "type": "integer", - "description": "备 注:文件id\r\n默认值:", - "format": "int64" - }, - "bannerName": { - "type": "string", - "description": "备 注:banne名称\r\n默认值:", - "nullable": true - }, - "bannerFileUrl": { - "type": "string", - "description": "备 注:文件地址", - "nullable": true - }, - "bannerFileName": { - "type": "string", - "description": "文件名称", - "nullable": true - }, - "bannerFileSize": { - "type": "integer", - "description": "文件大小", - "format": "int64", - "nullable": true - } - }, - "additionalProperties": false - }, - "BaseTaskAddResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "新增后返回的任务id", - "format": "int64" - }, - "sunClassTaskId": { - "type": "integer", - "description": "任务子表的id(例:新增学习习惯全面抽查,此id则为抽查工作记录id,也就是SpotId)\r\n也可能是0,为0时,说明没有子表数据,以任务id为主", - "format": "int64" - } - }, - "additionalProperties": false - }, - "BaseTaskClassResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "status": { - "type": "integer", - "description": "任务状态 0:未开始 1:进行中 2:已结束 3:问题待处理(仅用于双师跟课)", - "format": "int32" - }, - "classesId": { - "type": "integer", - "description": "备 注:班级id(班级任务)\r\n默认值:", - "format": "int64", - "nullable": true - }, - "classesName": { - "type": "string", - "description": "备 注:班级名称(用于展示)", - "nullable": true - }, - "gradeLevel": { - "type": "string", - "description": "备 注:年级\r\n默认值:", - "nullable": true - }, - "graduationYear": { - "type": "integer", - "description": "备 注:所属届\r\n默认值:", - "format": "int32" - }, - "taskTypeEnum": { - "type": "integer", - "description": "备 注:参数表 枚举值,任务类型\r\n默认值:", - "format": "int32" - }, - "taskTypeName": { - "type": "string", - "description": "备 注:任务类型名称(用于展示)", - "nullable": true - }, - "taskTitleSuffix": { - "type": "string", - "description": "备 注:任务标题后缀,用于展示(有值时,将任务类型名称 和该字段用 “-”连接)\r\n默认值:", - "nullable": true - }, - "startDate": { - "type": "string", - "description": "备 注:开始日期\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endDate": { - "type": "string", - "description": "备 注:结束日期\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "isLongwork": { - "type": "integer", - "description": "备 注:是否长期性工作(0否,1是)\r\n默认值:", - "format": "int64" - }, - "finishDate": { - "type": "string", - "description": "备 注:任务完成日期\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "finishDatetime": { - "type": "string", - "description": "备 注:任务完成时间\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "taskUserId": { - "type": "integer", - "description": "备 注:执行人id(通用任务才有)\r\n默认值:", - "format": "int64", - "nullable": true - }, - "taskIndexType": { - "type": "integer", - "description": "备 注:任务指标类型-1班级;2通用; 班级时,classes_id不为空;通用时,执行人id不为空\r\n默认值:", - "format": "int32" - } - }, - "additionalProperties": false - }, - "BaseTaskFileRequest": { - "type": "object", - "properties": { - "classesTaskId": { - "type": "integer", - "description": "关联表id(非任务主表id)", - "format": "int64" - }, - "fileId": { - "type": "integer", - "description": "文件id", - "format": "int64" - } - }, - "additionalProperties": false - }, - "ClassCadreMeetingFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "classCadreId": { - "type": "integer", - "description": "班干部会议ID", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "会议纪要", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "description": "文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassCadreMeetingRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "classCadreId": { - "type": "integer", - "description": "id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "meetingTitle": { - "type": "string", - "description": "会议主题", - "nullable": true - }, - "userIds": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, - "description": "参会人员id", - "nullable": true - } - }, - "additionalProperties": false, - "description": "开展班干部会议请求参数" - }, - "ClassCadreMeetingResult": { - "type": "object", - "properties": { - "classCadreId": { - "type": "integer", - "description": "班干部会议记录ID", - "format": "int64" - }, - "meetingTitle": { - "type": "string", - "description": "会议标题", - "nullable": true - }, - "remark": { - "type": "string", - "description": "会议纪要", - "nullable": true - }, - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "sunTaskUserResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskUserResult" - }, - "description": "关联用户", - "nullable": true - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "关联文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassManageTaskListResult": { - "type": "object", - "properties": { - "taskChecklistUser": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesTaskChecklistUserResult" - }, - "description": "通用工作指标清单列表", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassManager_Task_checklistRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "新增为null", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "备 注:任务类型id\r\n默认值:", - "format": "int64" - }, - "targetNumber": { - "type": "integer", - "description": "备 注:任务指标数\r\n默认值:", - "format": "int32" - }, - "taskType": { - "type": "integer", - "description": "备 注:班级/通用任务类型 1班级;2通用\r\n默认值:", - "format": "int32" - } - }, - "additionalProperties": false - }, - "ClassMeetingFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "classMeetingId": { - "type": "integer", - "description": "班级会议ID", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "会议纪要", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "description": "文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassMeetingRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "classMeetingId": { - "type": "integer", - "description": "id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "meetingTitle": { - "type": "string", - "description": "会议主题", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassMeetingResult": { - "type": "object", - "properties": { - "classMeetingId": { - "type": "integer", - "description": "班级会议记录ID", - "format": "int64" - }, - "meetingTitle": { - "type": "string", - "description": "会议标题", - "nullable": true - }, - "meetingContent": { - "type": "string", - "description": "会议纪要", - "nullable": true - }, - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "关联文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassSubResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64", - "nullable": true - }, - "className": { - "type": "string", - "description": "班级名称", - "nullable": true - }, - "subName": { - "type": "string", - "description": "科目名称", - "nullable": true - }, - "classId": { - "type": "integer", - "description": "班级Id", - "format": "int64" - }, - "subId": { - "type": "integer", - "description": "科目Id", - "format": "int64" - } - }, - "additionalProperties": false, - "description": "工作台-班级科目绑定表" - }, - "ClassTeacherRequest": { - "type": "object", - "properties": { - "classId": { - "type": "integer", - "description": "班级Id", - "format": "int64" - }, - "teacherName": { - "type": "string", - "description": "教师名称", - "nullable": true - }, - "subId": { - "type": "integer", - "description": "科目Id,0时为班主任(此id从班级里面的科目读取)", - "format": "int64" - } - }, - "additionalProperties": false - }, - "ClassTeacherResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "classId": { - "type": "integer", - "description": "班级Id", - "format": "int64" - }, - "className": { - "type": "string", - "description": "班级名称", - "nullable": true - }, - "teacherName": { - "type": "string", - "description": "教师名称", - "nullable": true - }, - "subId": { - "type": "integer", - "description": "科目Id,0时为班主任", - "format": "int64" - }, - "subName": { - "type": "string", - "description": "科目名称", - "nullable": true - } - }, - "additionalProperties": false, - "description": "工作台-班级教师" - }, - "ClassTypeEnum": { - "enum": [ - 0, - 1, - 2, - 3, - 4, - 5, - 6, - 10, - 20 - ], - "type": "integer", - "format": "int32" - }, - "Classes": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "className": { - "type": "string", - "description": "备 注:名称\r\n默认值:", - "nullable": true - }, - "schoolId": { - "type": "integer", - "description": "备 注:学校编号\r\n默认值:", - "format": "int64" - }, - "gradeLevel": { - "type": "string", - "description": "备 注:年级\r\n默认值:", - "nullable": true - }, - "graduationYear": { - "type": "integer", - "description": "备 注:所属届\r\n默认值:", - "format": "int32" - }, - "createTime": { - "type": "string", - "description": "备 注:添加时间\r\n默认值:", - "format": "date-time" - }, - "createPositionId": { - "type": "integer", - "description": "备 注:创建者部门Id\r\n默认值:", - "format": "int64", - "nullable": true - }, - "deleteState": { - "type": "boolean", - "description": "备 注:删除状态\r\n默认值:" - }, - "type": { - "$ref": "#/components/schemas/ClassTypeEnum" - }, - "teachingLevel": { - "$ref": "#/components/schemas/TeachingLevelEnum" - } - }, - "additionalProperties": false, - "description": "班级表" - }, - "ClassesActivityFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "activityId": { - "type": "integer", - "description": "班级活动ID", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "活动记录", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "description": "文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassesActivityRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "activityId": { - "type": "integer", - "description": "活动id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "activityTitle": { - "type": "string", - "description": "备 注:活动主题\r\n默认值:", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassesActivityResult": { - "type": "object", - "properties": { - "activityId": { - "type": "integer", - "description": "活动id", - "format": "int64" - }, - "activityTitle": { - "type": "string", - "description": "备 注:活动主题\r\n默认值:", - "nullable": true - }, - "remark": { - "type": "string", - "description": "备 注:活动记录\r\n默认值:", - "nullable": true - }, - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "关联文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "ClassesAndFollowResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "description": "班级id", - "nullable": true - }, - "gradeLevel": { - "type": "string", - "description": "备 注:年级\r\n默认值:", - "nullable": true - }, - "graduationYear": { - "type": "integer", - "description": "备 注:所属届\r\n默认值:", - "format": "int32" - }, - "followName": { - "type": "string", - "description": "学习官名称", - "nullable": true - }, - "followId": { - "type": "integer", - "description": "学习官id", - "format": "int64" - } - }, - "additionalProperties": false - }, - "ClassesResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "description": "班级名称", - "nullable": true - }, - "gradeLevel": { - "type": "string", - "description": "备 注:年级\r\n默认值:", - "nullable": true - }, - "graduationYear": { - "type": "integer", - "description": "备 注:所属届\r\n默认值:", - "format": "int32" - } - }, - "additionalProperties": false - }, - "ClassesTaskChecklistUserResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "taskTypeEnum": { - "type": "integer", - "description": "备 注:任务类型枚举值\r\n默认值:", - "format": "int64" - }, - "taskTypeEnumName": { - "type": "string", - "description": "备 注:任务类型名称", - "nullable": true - }, - "taskUserId": { - "type": "integer", - "description": "备 注:任务接受人id\r\n默认值:", - "format": "int64" - }, - "targetNumber": { - "type": "integer", - "description": "备 注:任务达标数\r\n默认值:", - "format": "int32" - }, - "taskType": { - "type": "integer", - "description": "备 注:班级/通用任务类型 1班级;2通用\r\n默认值:", - "format": "int32" - } - }, - "additionalProperties": false, - "description": "通用工作任务指标清单" - }, - "ClassesTaskListResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "status": { - "type": "integer", - "description": "备 注:任务状态 0:未开始 1:进行中 2:已结束 3:问题待处理(仅用于双师跟课)\r\n默认值:", - "format": "int32" - }, - "classesId": { - "type": "integer", - "description": "备 注:班级id(班级任务)\r\n默认值:", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "备 注:参数表 枚举值,任务类型\r\n默认值:", - "format": "int32" - }, - "taskTitleSuffix": { - "type": "string", - "description": "备 注:任务标题后缀,用于展示\r\n默认值:", - "nullable": true - }, - "startDate": { - "type": "string", - "description": "备 注:开始日期\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endDate": { - "type": "string", - "description": "备 注:结束日期\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskIndexType": { - "type": "integer", - "description": "备 注:任务指标类型-1班级;2通用; 班级时,classes_id不为空;通用时,执行人id不为空\r\n默认值:", - "format": "int32" - } - }, - "additionalProperties": false, - "description": "任务列表" - }, - "ClassesTaskListResultPageResponse": { - "type": "object", - "properties": { - "total": { - "type": "integer", - "description": "总记录条数", - "format": "int32" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ClassesTaskListResult" - }, - "description": "响应数据", - "nullable": true - } - }, - "additionalProperties": false, - "description": "分页响应实体类" - }, - "CoachSubInfoFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "新增为null,编辑时传Id", - "format": "int64" - }, - "coachId": { - "type": "integer", - "description": "备 注:学科辅助任务Id\r\n默认值:", - "format": "int64" - }, - "coachContent": { - "type": "string", - "description": "备 注:辅导内容\r\n默认值:", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "CoachSubInfoRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "coachId": { - "type": "integer", - "description": "辅导表id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "coachSubId": { - "type": "integer", - "description": "科目id", - "format": "int64" - }, - "coachSubName": { - "type": "string", - "description": "科目名称", - "nullable": true - }, - "userId": { - "type": "array", - "items": { - "type": "integer", - "format": "int64" - }, - "description": "参会人员", - "nullable": true - } - }, - "additionalProperties": false - }, - "CoachSubInfoResult": { - "type": "object", - "properties": { - "coachId": { - "type": "integer", - "description": "学科辅助ID", - "format": "int64" - }, - "coachSubId": { - "type": "integer", - "description": "学科辅助科目id", - "format": "int64" - }, - "coachSubName": { - "type": "string", - "description": "学科辅助科目名称", - "nullable": true - }, - "coachContent": { - "type": "string", - "description": "学科辅助内容", - "nullable": true - }, - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "sunTaskUserResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskUserResult" - }, - "description": "关联用户", - "nullable": true - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "关联文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "CourseWeekDetailOutput": { - "type": "object", - "properties": { - "classCourseId": { - "type": "integer", - "description": "课程id", - "format": "int64" - }, - "subject": { - "type": "integer", - "description": "科目id", - "format": "int32" - }, - "subjectName": { - "type": "string", - "description": "科目名称", - "nullable": true - }, - "teacherName": { - "type": "string", - "description": "云校老师", - "nullable": true - }, - "teacherId": { - "type": "integer", - "description": "云校老师", - "format": "int64" - }, - "landingTeacherId": { - "type": "integer", - "description": "落地老师", - "format": "int64" - }, - "landingTeacherName": { - "type": "string", - "description": "落地老师", - "nullable": true - }, - "planStartTime": { - "type": "string", - "description": "上课时间", - "format": "date-time" - }, - "planEndTime": { - "type": "string", - "description": "下课时间", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "CulturalDetailResult": { - "type": "object", - "properties": { - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "culturalId": { - "type": "integer", - "description": "文创id", - "format": "int64" - }, - "culturalTitle": { - "type": "string", - "description": "文创标题", - "nullable": true - }, - "remark": { - "type": "string", - "description": "备 注:更新说明\r\n默认值:", - "nullable": true - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "文创文件信息", - "nullable": true - } - }, - "additionalProperties": false - }, - "CulturalFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "culturalId": { - "type": "integer", - "description": "文创ID", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "工作内容", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "description": "文创文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "CulturalRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "culturalId": { - "type": "integer", - "description": "文创id 新增不传,修改必传", - "format": "int64", - "nullable": true - }, - "culturalTitle": { - "type": "string", - "description": "文创标题", - "nullable": true - } - }, - "additionalProperties": false - }, - "DataCollectFileRequest": { - "type": "object", - "properties": { - "classesTaskId": { - "type": "integer", - "description": "关联表id(非任务主表id)", - "format": "int64" - }, - "fileId": { - "type": "integer", - "description": "文件id", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "用户ID", - "format": "int64" - } - }, - "additionalProperties": false - }, - "DataCollectFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "collectId": { - "type": "integer", - "description": "采集ID", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "分析总结", - "nullable": true - } - }, - "additionalProperties": false - }, - "DataCollectRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "dataCollectId": { - "type": "integer", - "description": "数据采集任务ID(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "collectTitle": { - "type": "string", - "description": "数据采集标题", - "nullable": true - } - }, - "additionalProperties": false - }, - "DataCollectResult": { - "type": "object", - "properties": { - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "collectId": { - "type": "integer", - "description": "采集ID", - "format": "int64" - }, - "collectTitle": { - "type": "string", - "description": "采集主题", - "nullable": true - }, - "remark": { - "type": "string", - "description": "分析总结", - "nullable": true - }, - "collectUsers": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DataCollectUserResult" - }, - "description": "已采集用户列表", - "nullable": true - } - }, - "additionalProperties": false - }, - "DataCollectUserResult": { - "type": "object", - "properties": { - "userId": { - "type": "integer", - "description": "用户ID", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户名", - "nullable": true - }, - "fileCount": { - "type": "integer", - "description": "采集文件数量", - "format": "int32" - } - }, - "additionalProperties": false - }, - "EvaluationSumRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "总结报告id", - "format": "int64" - }, - "content": { - "type": "string", - "description": "评论内容", - "nullable": true - } - }, - "additionalProperties": false - }, - "FinancialClassRequest": { - "type": "object", - "properties": { - "classId": { - "type": "integer", - "description": "班级id", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "用途", - "nullable": true - }, - "money": { - "type": "number", - "description": "元", - "format": "double" - }, - "financialTime": { - "type": "string", - "description": "使用时间", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "添加班级使用经费记录" - }, - "FinancialClassResult": { - "type": "object", - "properties": { - "financialTime": { - "type": "string", - "description": "备 注:使用时间\r\n默认值:", - "format": "date-time" - }, - "remark": { - "type": "string", - "description": "用途", - "nullable": true - }, - "money": { - "type": "number", - "description": "消费费用(元)", - "format": "double" - } - }, - "additionalProperties": false - }, - "FinancialClassSumResult": { - "type": "object", - "properties": { - "sumMoney": { - "type": "number", - "description": "累计金额", - "format": "double" - }, - "financialClassResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FinancialClassResult" - }, - "description": "使用经费", - "nullable": true - } - }, - "additionalProperties": false - }, - "Financial_indicators": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "money": { - "type": "number", - "description": "备 注:本时段经费金额\r\n默认值:", - "format": "double" - } - }, - "additionalProperties": false, - "description": "经费管理" - }, - "FollowAbsenceUserRequest": { - "type": "object", - "properties": { - "followId": { - "type": "integer", - "description": "双师课堂记录表id", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "用户id", - "format": "int64" - }, - "handleState": { - "type": "integer", - "description": "处理状态 默认0 0未处理 1忽略 2发起谈话", - "format": "int64" - } - }, - "additionalProperties": false - }, - "FollowAbsenceUserResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "followId": { - "type": "integer", - "description": "跟课id", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "用户id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - } - }, - "additionalProperties": false - }, - "FollowInfoFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "followId": { - "type": "integer", - "description": "备 注:跟课id", - "format": "int64" - } - }, - "additionalProperties": false - }, - "FollowInfoRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "classCourseId": { - "type": "integer", - "description": "备 注:课程id\r\n默认值:", - "format": "int64" - } - }, - "additionalProperties": false - }, - "FollowInfoResult": { - "type": "object", - "properties": { - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "followTeachersituations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowTeachersituationResult" - }, - "description": "落地老师问题", - "nullable": true - }, - "followAbsenceUserResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowAbsenceUserResult" - }, - "description": "跟课缺席用户列表", - "nullable": true - }, - "followKeynoteUserResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowKeynoteUserResult" - }, - "description": "重点学生列表", - "nullable": true - }, - "followId": { - "type": "integer", - "description": "跟课ID", - "format": "int64" - }, - "classCourseId": { - "type": "integer", - "description": "备 注:课程id\r\n默认值:", - "format": "int64" - }, - "classesFollowMethod": { - "type": "integer", - "description": "备 注:跟课方式1:直播;2:录播;\r\n默认值:", - "format": "int32", - "nullable": true - }, - "classesSignalStability": { - "type": "integer", - "description": "备 注:信号是否稳定;0否;1:是;\r\n默认值:", - "format": "int32", - "nullable": true - }, - "concentrationActivityEnum": { - "type": "integer", - "description": "备 注:整体活跃度,参数id\r\n默认值:", - "format": "int32", - "nullable": true - }, - "concentrationLevelEnum": { - "type": "integer", - "description": "备 注:整体专注度,参数id\r\n默认值:", - "format": "int32", - "nullable": true - }, - "masteryLevelEnum": { - "type": "integer", - "description": "备 注:整体问题回答正确率/知识掌握程度,参数id\r\n默认值:", - "format": "int32", - "nullable": true - }, - "remark": { - "type": "string", - "description": "其他", - "nullable": true - } - }, - "additionalProperties": false - }, - "FollowKeyNoteUserRequest": { - "type": "object", - "properties": { - "followId": { - "type": "integer", - "description": "备 注:跟课id\r\n默认值:", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "备 注:重点学生用户id\r\n默认值:", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "备 注:描述\r\n默认值:", - "nullable": true - } - }, - "additionalProperties": false - }, - "FollowKeynoteUserResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "followId": { - "type": "integer", - "description": "跟课id", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "重点学生id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "重点学生姓名", - "nullable": true - }, - "remark": { - "type": "string", - "description": "描述", - "nullable": true - } - }, - "additionalProperties": false - }, - "FollowQuestionRequest": { - "type": "object", - "properties": { - "followId": { - "type": "integer", - "description": "备 注:跟课id", - "format": "int64" - }, - "followTeachersituations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FollowTeachersituationRequest" - }, - "description": "落地老师的问题列表", - "nullable": true - }, - "classesFollowMethod": { - "type": "integer", - "description": "备 注:跟课方式1:直播;2:录播;\r\n默认值:", - "format": "int32", - "nullable": true - }, - "classesSignalStability": { - "type": "integer", - "description": "备 注:信号是否稳定;0否;1:是;\r\n默认值:", - "format": "int32", - "nullable": true - }, - "concentrationActivityEnum": { - "type": "integer", - "description": "备 注:整体活跃度,参数id\r\n默认值:", - "format": "int32", - "nullable": true - }, - "concentrationLevelEnum": { - "type": "integer", - "description": "备 注:整体专注度,参数id\r\n默认值:", - "format": "int32", - "nullable": true - }, - "masteryLevelEnum": { - "type": "integer", - "description": "备 注:整体问题回答正确率/知识掌握程度,参数id\r\n默认值:", - "format": "int32", - "nullable": true - }, - "remark": { - "type": "string", - "description": "其他", - "nullable": true - } - }, - "additionalProperties": false - }, - "FollowTeachersituationRequest": { - "type": "object", - "properties": { - "followId": { - "type": "integer", - "description": "备 注:跟课id\r\n默认值:", - "format": "int64" - }, - "paramId": { - "type": "integer", - "description": "备 注:落地老师-问题类型,字典表\r\n默认值:", - "format": "int64" - } - }, - "additionalProperties": false - }, - "FollowTeachersituationResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "followId": { - "type": "integer", - "description": "跟课id", - "format": "int64" - }, - "paramId": { - "type": "integer", - "description": "落地老师-问题类型,字典表", - "format": "int64" - }, - "paramName": { - "type": "string", - "description": "问题描述", - "nullable": true - } - }, - "additionalProperties": false - }, - "Index_ClassesTaskCheckList_User": { - "type": "object", - "properties": { - "taskTypeEnum": { - "type": "integer", - "description": "任务类型枚举", - "format": "int64" - }, - "taskTypeName": { - "type": "string", - "description": "任务类型枚举-名称", - "nullable": true - }, - "createTaskCount": { - "type": "integer", - "description": "已创建任务数量", - "format": "int32" - }, - "okTaskCount": { - "type": "integer", - "description": "已完成任务数量", - "format": "int32" - }, - "shouldTaskCount": { - "type": "integer", - "description": "应完成任务数量", - "format": "int32" - } - }, - "additionalProperties": false, - "description": "通用首页任务清单用户信息" - }, - "Index_ClassesTaskCheckList_UserPageResponse": { - "type": "object", - "properties": { - "total": { - "type": "integer", - "description": "总记录条数", - "format": "int32" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Index_ClassesTaskCheckList_User" - }, - "description": "响应数据", - "nullable": true - } - }, - "additionalProperties": false, - "description": "分页响应实体类" - }, - "LoginCodeRequest": { - "type": "object", - "properties": { - "phone": { - "type": "string", - "description": "电话", - "nullable": true - }, - "code": { - "type": "string", - "description": "验证码", - "nullable": true - }, - "loginType": { - "type": "integer", - "description": "登录类型 1:Android;2Ios", - "format": "int32" - } - }, - "additionalProperties": false - }, - "LoginRequest": { - "type": "object", - "properties": { - "username": { - "type": "string", - "description": "用户名", - "nullable": true - }, - "pwd": { - "type": "string", - "description": "密码", - "nullable": true - }, - "loginType": { - "type": "integer", - "description": "登录类型 1:Android;2Ios", - "format": "int32" - } - }, - "additionalProperties": false - }, - "MeetingInfoFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "meetingId": { - "type": "integer", - "description": "会议ID", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "会议纪要", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "MeetingInfoRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "meetingId": { - "type": "integer", - "description": "会议任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "meetingTitle": { - "type": "string", - "description": "会议主题", - "nullable": true - }, - "meetingUsername": { - "type": "string", - "description": "参会人员", - "nullable": true - } - }, - "additionalProperties": false - }, - "MeetingInfoResult": { - "type": "object", - "properties": { - "meetingId": { - "type": "integer", - "description": "会议ID", - "format": "int64" - }, - "meetingTitle": { - "type": "string", - "description": "会议主题", - "nullable": true - }, - "remark": { - "type": "string", - "description": "会议纪要", - "nullable": true - }, - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "meetingUsername": { - "type": "string", - "description": "参会人员", - "nullable": true - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "关联文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "MyInfoResetPwdRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "用户id", - "format": "int64" - }, - "password": { - "type": "string", - "description": "原密码", - "nullable": true - }, - "newPassword": { - "type": "string", - "description": "新密码", - "nullable": true - } - }, - "additionalProperties": false, - "description": "修改密码" - }, - "MyPhoneBindRequest": { - "type": "object", - "properties": { - "phone": { - "type": "string", - "description": "电话", - "nullable": true - }, - "phoneCode": { - "type": "string", - "description": "验证码", - "nullable": true - } - }, - "additionalProperties": false, - "description": "换绑电话" - }, - "OSSConfigResult": { - "type": "object", - "properties": { - "accessKeyId": { - "type": "string", - "nullable": true - }, - "accessKeySecret": { - "type": "string", - "nullable": true - }, - "endpoint": { - "type": "string", - "nullable": true - }, - "bucketName": { - "type": "string", - "nullable": true - }, - "size": { - "type": "integer", - "format": "int64" - } - }, - "additionalProperties": false - }, - "OssSignResult": { - "type": "object", - "properties": { - "filePath": { - "type": "string", - "description": "上传路径", - "nullable": true - }, - "fileSize": { - "type": "integer", - "description": "文件限制大小", - "format": "int64" - }, - "uploadUrl": { - "type": "string", - "description": "上传URL", - "nullable": true - } - }, - "additionalProperties": false - }, - "OtherInfoFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "otherId": { - "type": "integer", - "description": "其他ID", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "工作内容", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "OtherInfoRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "otherId": { - "type": "integer", - "description": "id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "otherTitle": { - "type": "string", - "description": "任务描述", - "nullable": true - } - }, - "additionalProperties": false - }, - "OtherInfoResult": { - "type": "object", - "properties": { - "otherId": { - "type": "integer", - "description": "班干部会议记录ID", - "format": "int64" - }, - "otherTitle": { - "type": "string", - "description": "工作描述", - "nullable": true - }, - "remark": { - "type": "string", - "description": "工作内容", - "nullable": true - }, - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "关联文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "ProblemSemesterViewDto": { - "type": "object", - "properties": { - "solutionSemesterEnum": { - "$ref": "#/components/schemas/SolutionSemesterEnum" - }, - "solutionSemesterName": { - "type": "string", - "description": "解决方案枚举名称", - "nullable": true, - "readOnly": true - } - }, - "additionalProperties": false - }, - "ProblemTaskTypeViewDto": { - "type": "object", - "properties": { - "taskTypeEnum": { - "$ref": "#/components/schemas/SysTaskTypeEnums" - }, - "taskTypeEnumName": { - "type": "string", - "description": "任务类型枚举名称", - "nullable": true, - "readOnly": true - } - }, - "additionalProperties": false - }, - "QuestionInfoByTaskEnumResult": { - "type": "object", - "properties": { - "questionName": { - "type": "string", - "description": "问题类型", - "nullable": true - }, - "questionCount": { - "type": "integer", - "description": "条数", - "format": "int32" - }, - "questionChain": { - "type": "string", - "description": "环比", - "nullable": true - }, - "questionInfoResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/QuestionInfoResult" - }, - "description": "问题列表", - "nullable": true - } - }, - "additionalProperties": false - }, - "QuestionInfoByTypeResult": { - "type": "object", - "properties": { - "questionName": { - "type": "string", - "description": "问题类型", - "nullable": true - }, - "questionCount": { - "type": "integer", - "description": "首页本月条数/类型总条数", - "format": "int32" - } - }, - "additionalProperties": false - }, - "QuestionInfoResult": { - "type": "object", - "properties": { - "questionUserId": { - "type": "integer", - "description": "问题人id", - "format": "int64" - }, - "questionUserName": { - "type": "string", - "description": "问题人", - "nullable": true - }, - "addTime": { - "type": "string", - "description": "问题时间", - "format": "date-time" - } - }, - "additionalProperties": false, - "description": "问题列表" - }, - "ReadSummarizRequest": { - "type": "object", - "properties": { - "sumId": { - "type": "integer", - "description": "总结id", - "format": "int64" - }, - "sumType": { - "type": "integer", - "description": "总结类型 1日报 2周报 3月报", - "format": "int32" - } - }, - "additionalProperties": false - }, - "RefreshTokenRequest": { - "type": "object", - "properties": { - "token": { - "type": "string", - "description": "过期的token", - "nullable": true - } - }, - "additionalProperties": false - }, - "RegisterRequest": { - "type": "object", - "properties": { - "account": { - "type": "string", - "description": "账号", - "nullable": true - }, - "password": { - "type": "string", - "description": "密码", - "nullable": true - }, - "userName": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "SchoolResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "schoolName": { - "type": "string", - "nullable": true - } - }, - "additionalProperties": false - }, - "SchoolTree": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "schoolName": { - "type": "string", - "nullable": true - }, - "count": { - "type": "integer", - "format": "int32" - }, - "users": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserBooksResult" - }, - "nullable": true - }, - "children": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchoolTree" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "SchoolUserBooksResult": { - "type": "object", - "properties": { - "cloudSchoolName": { - "type": "string", - "description": "云校名称", - "nullable": true - }, - "schoolName": { - "type": "string", - "description": "学校名称", - "nullable": true - }, - "id": { - "type": "integer", - "description": "Id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - }, - "headImage": { - "type": "string", - "description": "头像", - "nullable": true - }, - "roleEnum": { - "$ref": "#/components/schemas/SysRoleEnum" - }, - "phone": { - "type": "string", - "description": "电话", - "nullable": true - } - }, - "additionalProperties": false - }, - "SolutionDetailViewDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "problemTitle": { - "type": "string", - "description": "备 注:问题描述\r\n默认值:", - "nullable": true - }, - "upTime": { - "type": "string", - "description": "最后修改时间", - "format": "date-time" - }, - "problemObj": { - "$ref": "#/components/schemas/ToolObjectType" - }, - "toolClassType": { - "$ref": "#/components/schemas/ToolClassType" - }, - "problemSemesters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProblemSemesterViewDto" - }, - "description": "关联学段枚举列表", - "nullable": true - }, - "problemPhenomenon": { - "type": "string", - "description": "备 注:问题显著现象\r\n默认值:", - "nullable": true - }, - "solutionContent": { - "type": "string", - "description": "备 注:解决方案文本描述\r\n默认值:", - "nullable": true - }, - "problemTaskTypes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProblemTaskTypeViewDto" - }, - "description": "关联任务类型枚举列表", - "nullable": true - }, - "toolKits": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ToolKitViewDto" - }, - "description": "解决方案工具列表", - "nullable": true - } - }, - "additionalProperties": false - }, - "SolutionListViewDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "problemTitle": { - "type": "string", - "description": "备 注:问题描述\r\n默认值:", - "nullable": true - }, - "upTime": { - "type": "string", - "description": "最后修改时间", - "format": "date-time" - }, - "problemObj": { - "$ref": "#/components/schemas/ToolObjectType" - }, - "toolClassType": { - "$ref": "#/components/schemas/ToolClassType" - }, - "problemSemesters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProblemSemesterViewDto" - }, - "description": "关联学段枚举列表", - "nullable": true - } - }, - "additionalProperties": false - }, - "SolutionListViewMobileDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "problemTitle": { - "type": "string", - "description": "备 注:问题描述\r\n默认值:", - "nullable": true - }, - "upTime": { - "type": "string", - "description": "最后修改时间", - "format": "date-time" - }, - "problemObj": { - "$ref": "#/components/schemas/ToolObjectType" - }, - "toolClassType": { - "$ref": "#/components/schemas/ToolClassType" - }, - "problemPhenomenon": { - "type": "string", - "description": "备 注:问题显著现象\r\n默认值:", - "nullable": true - }, - "problemSemesters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ProblemSemesterViewDto" - }, - "description": "关联学段枚举列表", - "nullable": true - } - }, - "additionalProperties": false - }, - "SolutionListViewMobileDtoPageResponse": { - "type": "object", - "properties": { - "total": { - "type": "integer", - "description": "总记录条数", - "format": "int32" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SolutionListViewMobileDto" - }, - "description": "响应数据", - "nullable": true - } - }, - "additionalProperties": false, - "description": "分页响应实体类" - }, - "SolutionSemesterEnum": { - "enum": [ - 0, - 71, - 72, - 73, - 74, - 81, - 82, - 83, - 84, - 91, - 92, - 93, - 94, - 101, - 102, - 103, - 104, - 111, - 112, - 113, - 114, - 121, - 122, - 123, - 124 - ], - "type": "integer", - "description": "解决方案及工具包使用年级枚举", - "format": "int32" - }, - "SpotCheckTypeValue": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "value": { - "type": "integer", - "description": "备 注:分值\r\n默认值:", - "format": "int32" - }, - "valueName": { - "type": "string", - "description": "备 注:标准内容\r\n默认值:", - "nullable": true - }, - "checkId": { - "type": "integer", - "description": "备 注:所属抽查标准\r\n默认值:", - "format": "int64" - } - }, - "additionalProperties": false, - "description": "学习行为习惯全面抽查流程标准-类型表-各项具体分值表" - }, - "SpotTaskFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "spotId": { - "type": "integer", - "description": "抽查记录表id", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "反馈/反思", - "nullable": true - } - }, - "additionalProperties": false, - "description": "学习行为习惯全面抽查任务完成请求类" - }, - "SpotTaskRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "spotId": { - "type": "integer", - "description": "抽查任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "checkProjectid": { - "type": "integer", - "description": "备 注:抽查项目id\r\n默认值:", - "format": "int64" - } - }, - "additionalProperties": false, - "description": "学习行为习惯全面抽查任务请求类" - }, - "SpotTaskResult": { - "type": "object", - "properties": { - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "spotId": { - "type": "integer", - "description": "抽查任务id", - "format": "int64" - }, - "classesTaskId": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "checkProjectid": { - "type": "integer", - "description": "抽查项目id", - "format": "int64" - }, - "checkProjectName": { - "type": "string", - "description": "抽查项目名称", - "nullable": true - }, - "remark": { - "type": "string", - "description": "反馈/反思", - "nullable": true - }, - "spotTaskUserResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SpotTaskUserResult" - }, - "description": "抽查人员列表", - "nullable": true - } - }, - "additionalProperties": false, - "description": "学习行为习惯全面抽查任务结果类" - }, - "SpotTaskUserRequest": { - "type": "object", - "properties": { - "spotId": { - "type": "integer", - "description": "抽查记录表id", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "抽查人员id", - "format": "int64" - }, - "valueTotal": { - "type": "integer", - "description": "分值", - "format": "int32" - } - }, - "additionalProperties": false, - "description": "学习行为习惯全面抽查任务-抽查人员请求类" - }, - "SpotTaskUserResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "id", - "format": "int64" - }, - "spotId": { - "type": "integer", - "description": "抽查记录表id", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "抽查人员id", - "format": "int64" - }, - "valueTotal": { - "type": "number", - "description": "得分", - "format": "double" - }, - "userName": { - "type": "string", - "description": "抽查人员名称", - "nullable": true - }, - "addTime": { - "type": "string", - "description": "添加时间", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "StudentRequest": { - "type": "object", - "properties": { - "classesId": { - "type": "integer", - "description": "班级id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户名称", - "nullable": true - } - }, - "additionalProperties": false - }, - "StudentResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "学生Id", - "format": "int64" - }, - "name": { - "type": "string", - "description": "学生姓名", - "nullable": true - } - }, - "additionalProperties": false - }, - "Subjectinfo": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "name": { - "type": "string", - "description": "备 注:学科名称\r\n默认值:", - "nullable": true - }, - "thisid": { - "type": "integer", - "description": "备 注:自己数据库Id\r\n默认值:", - "format": "int64" - }, - "createtime": { - "type": "string", - "description": "备 注:创建时间\r\n默认值:", - "format": "date-time" - }, - "updatetime": { - "type": "string", - "description": "备 注:更新时间\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "deletestate": { - "type": "boolean", - "description": "备 注:是否删除 true=删除\r\n默认值:" - }, - "ordinal": { - "type": "integer", - "description": "备 注:排序\r\n默认值:", - "format": "int32" - } - }, - "additionalProperties": false, - "description": "学科/科目表" - }, - "SummarizDayListResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "日报Id", - "format": "int64" - }, - "workDate": { - "type": "string", - "description": "备 注:工作总结日期\r\n默认值:", - "format": "date-time" - }, - "questContent": { - "type": "string", - "description": "备 注:问题反馈\r\n默认值:", - "nullable": true - }, - "userId": { - "type": "integer", - "description": "用户id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - }, - "userEnum": { - "type": "integer", - "description": "备 注:用户角色枚举(如果是组长,只有部长评价,如果是学习官,有部长和组长评价)\r\n默认值:", - "format": "int32" - }, - "addTime": { - "type": "string", - "description": "备 注:添加时间\r\n默认值:", - "format": "date-time" - }, - "superiorEvaluation": { - "type": "string", - "description": "备 注:组长评价\r\n默认值:", - "nullable": true - }, - "superiorUserId": { - "type": "integer", - "description": "备 注:组长评价人id\r\n默认值:", - "format": "int64", - "nullable": true - }, - "superiorUserName": { - "type": "string", - "description": "备 注:组长评价人\r\n默认值:", - "nullable": true - }, - "ministerEvaluation": { - "type": "string", - "description": "备 注:部长评价\r\n默认值:", - "nullable": true - }, - "ministerUserId": { - "type": "integer", - "description": "备 注:部长评价人id\r\n默认值:", - "format": "int64", - "nullable": true - }, - "ministerUserName": { - "type": "string", - "description": "备 注:部长评价人\r\n默认值:", - "nullable": true - }, - "nextTimeContent": { - "type": "string", - "description": "备 注:下次工作内容\r\n默认值:", - "nullable": true - }, - "readId": { - "type": "integer", - "description": "已读id(如果null则未读)", - "format": "int64", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizDayListResultPageResponse": { - "type": "object", - "properties": { - "total": { - "type": "integer", - "description": "总记录条数", - "format": "int32" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizDayListResult" - }, - "description": "响应数据", - "nullable": true - } - }, - "additionalProperties": false, - "description": "分页响应实体类" - }, - "SummarizDayResult": { - "type": "object", - "properties": { - "taskList": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizTaskResult" - }, - "description": "任务列表", - "nullable": true - }, - "summarizDay": { - "$ref": "#/components/schemas/SummarizDayTaskResult" - } - }, - "additionalProperties": false - }, - "SummarizDayTaskResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "userEnum": { - "type": "integer", - "description": "用户角色枚举", - "format": "int32" - }, - "userId": { - "type": "integer", - "description": "用户Id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - }, - "workDate": { - "type": "string", - "description": "工作总结日期", - "format": "date-time" - }, - "questContent": { - "type": "string", - "description": "问题反馈", - "nullable": true - }, - "addTime": { - "type": "string", - "description": "创建时间", - "format": "date-time" - }, - "superiorEvaluation": { - "type": "string", - "description": "组长评价", - "nullable": true - }, - "superiorUserId": { - "type": "integer", - "description": "组长用户Id", - "format": "int64", - "nullable": true - }, - "superiorUserName": { - "type": "string", - "description": "组长用户名", - "nullable": true - }, - "ministerEvaluation": { - "type": "string", - "description": "部长评价", - "nullable": true - }, - "ministerUserId": { - "type": "integer", - "description": "部长用户Id", - "format": "int64", - "nullable": true - }, - "ministerUserName": { - "type": "string", - "description": "部长用户名", - "nullable": true - }, - "nextTimeContent": { - "type": "string", - "description": "备 注:下次工作内容\r\n默认值:", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizMonthCheckList": { - "type": "object", - "properties": { - "taskTypeEnum": { - "type": "integer", - "description": "任务类型枚举", - "format": "int64" - }, - "taskTypeName": { - "type": "string", - "description": "任务类型枚举-名称", - "nullable": true - }, - "okTaskCount": { - "type": "integer", - "description": "已完成任务数量", - "format": "int32" - }, - "shouldTaskCount": { - "type": "integer", - "description": "应完成任务数量(为0时,代表是指标之外的)", - "format": "int64" - } - }, - "additionalProperties": false - }, - "SummarizMonthListResult": { - "type": "object", - "properties": { - "taskInfo": { - "$ref": "#/components/schemas/SummarizMonthStandardResult" - }, - "summarizMonthTaskResult": { - "$ref": "#/components/schemas/SummarizMonthTaskResult" - } - }, - "additionalProperties": false - }, - "SummarizMonthRequest": { - "type": "object", - "properties": { - "workYear": { - "type": "integer", - "description": "备 注:工作年份\r\n默认值:", - "format": "int32", - "nullable": true - }, - "workMonth": { - "type": "integer", - "description": "备 注:工作月份\r\n默认值:", - "format": "int32" - }, - "questContent": { - "type": "string", - "description": "备 注:问题反馈\r\n默认值:", - "nullable": true - }, - "monthContent": { - "type": "string", - "description": "备 注:本月总结\r\n默认值:", - "nullable": true - }, - "nextTimeContent": { - "type": "string", - "description": "备 注:下次工作内容\r\n默认值:", - "nullable": true - }, - "plans": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizPlanRequest" - }, - "description": "计划任务", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizMonthStandardResult": { - "type": "object", - "properties": { - "generalTasks": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizMonthCheckList" - }, - "description": "通用任务列表", - "nullable": true - }, - "taskFinishLists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TaskFinishList" - }, - "description": "其他工作完成情况", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizMonthTaskResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "备 注:用户id\r\n默认值:", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - }, - "userEnum": { - "type": "integer", - "description": "备 注:用户角色枚举(如果是组长,只有部长评价,如果是学习官,有部长和组长评价)\r\n默认值:", - "format": "int32" - }, - "workYear": { - "type": "integer", - "description": "备 注:工作年份\r\n默认值:", - "format": "int32", - "nullable": true - }, - "workMonth": { - "type": "integer", - "description": "备 注:工作月份\r\n默认值:", - "format": "int32" - }, - "questContent": { - "type": "string", - "description": "备 注:问题反馈\r\n默认值:", - "nullable": true - }, - "monthContent": { - "type": "string", - "description": "备 注:本月总结\r\n默认值:", - "nullable": true - }, - "addTime": { - "type": "string", - "description": "备 注:添加时间\r\n默认值:", - "format": "date-time" - }, - "superiorEvaluation": { - "type": "string", - "description": "备 注:组长评价\r\n默认值:", - "nullable": true - }, - "superiorUserId": { - "type": "integer", - "description": "备 注:组长评价人id\r\n默认值:", - "format": "int64", - "nullable": true - }, - "superiorAddtime": { - "type": "string", - "description": "备 注:组长评价时间\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "superiorUserName": { - "type": "string", - "description": "组长用户名", - "nullable": true - }, - "ministerEvaluation": { - "type": "string", - "description": "备 注:部长评价\r\n默认值:", - "nullable": true - }, - "ministerUserId": { - "type": "integer", - "description": "备 注:部长评价人id\r\n默认值:", - "format": "int64", - "nullable": true - }, - "ministerAddtime": { - "type": "string", - "description": "备 注:部长评价时间\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "ministerUserName": { - "type": "string", - "description": "部长用户名", - "nullable": true - }, - "nextTimeContent": { - "type": "string", - "description": "备 注:下次工作内容\r\n默认值:", - "nullable": true - }, - "readId": { - "type": "integer", - "description": "已读id(如果null则未读)", - "format": "int64", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizMonthTaskResultPageResponse": { - "type": "object", - "properties": { - "total": { - "type": "integer", - "description": "总记录条数", - "format": "int32" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizMonthTaskResult" - }, - "description": "响应数据", - "nullable": true - } - }, - "additionalProperties": false, - "description": "分页响应实体类" - }, - "SummarizNoReadResult": { - "type": "object", - "properties": { - "noReadCount": { - "type": "integer", - "description": "未读消息数量", - "format": "int32" - } - }, - "additionalProperties": false - }, - "SummarizPlan": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "备 注:用户id\r\n默认值:", - "format": "int64" - }, - "summarizType": { - "type": "integer", - "description": "备 注:总结类型,1:日报;2:周报;3:月报;\r\n默认值:", - "format": "int32" - }, - "summarizId": { - "type": "integer", - "description": "备 注:总结id\r\n默认值:", - "format": "int64" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "startDate": { - "type": "string", - "description": "备 注:开始日期\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "endDate": { - "type": "string", - "description": "备 注:结束日期\r\n默认值:", - "format": "date-time" - }, - "taskTypeEnum": { - "type": "integer", - "description": "备 注:任务类型枚举\r\n默认值:", - "format": "int32" - }, - "taskTypeName": { - "type": "string", - "description": "备 注:任务类型名称\r\n默认值:", - "nullable": true - }, - "taskTitleSuffix": { - "type": "string", - "description": "备 注:任务标题后缀,用于展示\r\n默认值:", - "nullable": true - } - }, - "additionalProperties": false, - "description": "工作总结-下次工作计划" - }, - "SummarizPlanRequest": { - "type": "object", - "properties": { - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTypeEnum": { - "type": "integer", - "description": "备 注:任务类型枚举\r\n默认值:", - "format": "int32" - }, - "taskTypeName": { - "type": "string", - "description": "备 注:任务类型名称\r\n默认值:", - "nullable": true - }, - "taskTitleSuffix": { - "type": "string", - "description": "备 注:任务标题后缀,用于展示\r\n默认值:", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizTaskResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "status": { - "type": "integer", - "description": "备 注:任务状态 0:未开始 1:进行中 2:已结束 3:问题待处理(仅用于双师跟课)\r\n默认值:", - "format": "int32" - }, - "classesId": { - "type": "integer", - "description": "备 注:班级id(班级任务)\r\n默认值:", - "format": "int64", - "nullable": true - }, - "classesName": { - "type": "string", - "description": "备 注:班级名称", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "备 注:参数表 枚举值,任务类型\r\n默认值:", - "format": "int32" - }, - "taskTypeName": { - "type": "string", - "description": "备 注:任务类型名称", - "nullable": true - }, - "taskTitleSuffix": { - "type": "string", - "description": "备 注:任务标题后缀,用于展示\r\n默认值:", - "nullable": true - }, - "startDate": { - "type": "string", - "description": "备 注:开始日期\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endDate": { - "type": "string", - "description": "备 注:结束日期\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskIndexType": { - "type": "integer", - "description": "备 注:任务指标类型-1班级;2通用; 班级时,classes_id不为空;通用时,执行人id不为空\r\n默认值:", - "format": "int32" - }, - "finishDate": { - "type": "string", - "description": "备 注:任务完成日期\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "finishDatetime": { - "type": "string", - "description": "备 注:任务完成时间\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "taskWorkTime": { - "type": "string", - "description": "备 注:任务首次操作时间\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "taskWorkDate": { - "type": "string", - "description": "备 注:任务首次操作日期\r\n默认值:", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizWeekListResult": { - "type": "object", - "properties": { - "taskList": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizTaskResult" - }, - "description": "任务列表", - "nullable": true - }, - "summarizWeekTaskResult": { - "$ref": "#/components/schemas/SummarizWeekTaskResult" - } - }, - "additionalProperties": false - }, - "SummarizWeekRequest": { - "type": "object", - "properties": { - "workYear": { - "type": "integer", - "description": "备 注:工作年份\r\n默认值:", - "format": "int32" - }, - "workMonth": { - "type": "integer", - "description": "备 注:工作月份\r\n默认值:", - "format": "int32" - }, - "workWeek": { - "type": "integer", - "description": "备 注:工作周报\r\n默认值:", - "format": "int32" - }, - "beginDate": { - "type": "string", - "description": "备 注:工作总结日期-开始\r\n默认值:", - "format": "date-time" - }, - "endDate": { - "type": "string", - "description": "备 注:工作总结日期-结束\r\n默认值:", - "format": "date-time" - }, - "questContent": { - "type": "string", - "description": "备 注:问题反馈\r\n默认值:", - "nullable": true - }, - "nextTimeContent": { - "type": "string", - "description": "备 注:下次工作内容\r\n默认值:", - "nullable": true - }, - "plans": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizPlanRequest" - }, - "description": "计划任务", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizWeekTaskResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "userEnum": { - "type": "integer", - "description": "用户角色枚举", - "format": "int32" - }, - "userId": { - "type": "integer", - "description": "用户Id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - }, - "workYear": { - "type": "integer", - "description": "总结年份", - "format": "int32" - }, - "workMonth": { - "type": "integer", - "description": "总结月份", - "format": "int32" - }, - "workWeek": { - "type": "integer", - "description": "总结周", - "format": "int32" - }, - "beginDate": { - "type": "string", - "description": "开始日期", - "format": "date-time", - "nullable": true - }, - "endDate": { - "type": "string", - "description": "结束日期", - "format": "date-time", - "nullable": true - }, - "questContent": { - "type": "string", - "description": "问题反馈", - "nullable": true - }, - "addTime": { - "type": "string", - "description": "创建时间", - "format": "date-time" - }, - "superiorEvaluation": { - "type": "string", - "description": "组长评价", - "nullable": true - }, - "superiorUserId": { - "type": "integer", - "description": "组长用户Id", - "format": "int64", - "nullable": true - }, - "superiorAddtime": { - "type": "string", - "description": "备 注:组长评价时间\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "superiorUserName": { - "type": "string", - "description": "组长用户名", - "nullable": true - }, - "ministerEvaluation": { - "type": "string", - "description": "部长评价", - "nullable": true - }, - "ministerUserId": { - "type": "integer", - "description": "部长用户Id", - "format": "int64", - "nullable": true - }, - "ministerAddtime": { - "type": "string", - "description": "备 注:部长评价时间\r\n默认值:", - "format": "date-time", - "nullable": true - }, - "ministerUserName": { - "type": "string", - "description": "部长用户名", - "nullable": true - }, - "nextTimeContent": { - "type": "string", - "description": "备 注:下次工作内容\r\n默认值:", - "nullable": true - }, - "readId": { - "type": "integer", - "description": "已读id(如果null则未读)", - "format": "int64", - "nullable": true - } - }, - "additionalProperties": false - }, - "SummarizWeekTaskResultPageResponse": { - "type": "object", - "properties": { - "total": { - "type": "integer", - "description": "总记录条数", - "format": "int32" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizWeekTaskResult" - }, - "description": "响应数据", - "nullable": true - } - }, - "additionalProperties": false, - "description": "分页响应实体类" - }, - "SummarizeDayRequest": { - "type": "object", - "properties": { - "workDate": { - "type": "string", - "description": "备 注:工作总结日期\r\n默认值:", - "format": "date-time" - }, - "questContent": { - "type": "string", - "description": "备 注:问题反馈\r\n默认值:", - "nullable": true - }, - "nextTimeContent": { - "type": "string", - "description": "备 注:下次工作内容\r\n默认值:", - "nullable": true - }, - "plans": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SummarizPlanRequest" - }, - "description": "计划任务", - "nullable": true - } - }, - "additionalProperties": false - }, - "SunTaskFileResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "文件关联表的id", - "format": "int64" - }, - "sunTaskId": { - "type": "integer", - "description": "子任务关联表id", - "format": "int64" - }, - "fileId": { - "type": "integer", - "description": "文件id", - "format": "int64" - }, - "filePath": { - "type": "string", - "description": "备 注:文件路径", - "nullable": true - }, - "fileSize": { - "type": "integer", - "description": "备 注:文件大小(文件大小-kb,不足1kb为1kb)\r\n默认值:", - "format": "int64", - "nullable": true - } - }, - "additionalProperties": false, - "description": "任务关联文件" - }, - "SunTaskUserResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "用户关联表的id", - "format": "int64" - }, - "sunTaskId": { - "type": "integer", - "description": "子任务关联表id", - "format": "int64" - }, - "userId": { - "type": "integer", - "description": "", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "备 注:文件路径", - "nullable": true - } - }, - "additionalProperties": false, - "description": "任务关联用户" - }, - "SysFileViewDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "fileName": { - "type": "string", - "description": "备 注:原文件名\r\n默认值:", - "nullable": true - }, - "filePath": { - "type": "string", - "description": "备 注:文件所在路径\r\n默认值:", - "nullable": true - }, - "fileType": { - "type": "string", - "description": "备 注:文件类型\r\n默认值:", - "nullable": true - }, - "addtime": { - "type": "string", - "description": "备 注:上传时间\r\n默认值:", - "format": "date-time", - "nullable": true - } - }, - "additionalProperties": false - }, - "SysParameter": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "pid": { - "type": "integer", - "description": "备 注:父级id,默认0,0时无父级\r\n默认值:", - "format": "int64" - }, - "pName": { - "type": "string", - "description": "备 注:参数名称\r\n默认值:", - "nullable": true - }, - "pValue": { - "type": "integer", - "description": "备 注:枚举值,不可重复,自定义 或 直接生成,后续业务关联也是关联此字段\r\n默认值:", - "format": "int64" - }, - "sort": { - "type": "integer", - "description": "备 注:排序,默认0\r\n默认值:", - "format": "int32" - }, - "isDelete": { - "type": "integer", - "description": "备 注:0正常,1已删除\r\n默认值:", - "format": "int32" - }, - "isQuestion": { - "type": "integer", - "description": "备 注:是否是问题。0否,1是\r\n默认值:", - "format": "int32" - }, - "questionType": { - "type": "integer", - "description": "备 注:问题类别。0无(不是问题时默认0),1学生、2教师\r\n默认值:", - "format": "int32" - }, - "child": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SysParameter" - }, - "nullable": true - } - }, - "additionalProperties": false, - "description": "字典表" - }, - "SysParameterPageResponse": { - "type": "object", - "properties": { - "total": { - "type": "integer", - "description": "总记录条数", - "format": "int32" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SysParameter" - }, - "description": "响应数据", - "nullable": true - } - }, - "additionalProperties": false, - "description": "分页响应实体类" - }, - "SysRoleEnum": { - "enum": [ - 1, - 2, - 1001, - 1002, - 1003 - ], - "type": "integer", - "description": "系统角色枚举", - "format": "int32" - }, - "SysTaskTypeEnums": { - "enum": [ - 1, - 2, - 3, - 4, - 5, - 6, - 7, - 8, - 9, - 10, - 11, - 12 - ], - "type": "integer", - "description": "任务类型枚举", - "format": "int32" - }, - "System_filesRequest": { - "type": "object", - "properties": { - "fileName": { - "type": "string", - "description": "备 注:原文件名包括后缀例如【111.txt】\r\n默认值:", - "nullable": true - }, - "filePath": { - "type": "string", - "description": "备 注:文件Url路径\r\n默认值:", - "nullable": true - }, - "fileType": { - "type": "string", - "description": "备 注:文件类型(文件后缀名,不带.)\r\n默认值:", - "nullable": true - }, - "fileSize": { - "type": "integer", - "description": "备 注:文件大小(文件大小-kb,不足1kb为1kb)\r\n默认值:", - "format": "int64", - "nullable": true - } - }, - "additionalProperties": false - }, - "TalkInfoRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "talkId": { - "type": "integer", - "description": "谈话记录表id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "quiltUserid": { - "type": "integer", - "description": "被谈话人id", - "format": "int64" - } - }, - "additionalProperties": false - }, - "TaskFinishList": { - "type": "object", - "properties": { - "taskTypeEnum": { - "type": "integer", - "description": "任务类型枚举", - "format": "int64" - }, - "taskTypeName": { - "type": "string", - "description": "任务类型枚举-名称", - "nullable": true - }, - "taskCount": { - "type": "integer", - "description": "任务数量", - "format": "int32" - } - }, - "additionalProperties": false - }, - "TaskLoginfoResult": { - "type": "object", - "properties": { - "taskId": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "sunTaskId": { - "type": "integer", - "description": "备 注:子任务id\r\n默认值:", - "format": "int64" - }, - "addDate": { - "type": "string", - "description": "备 注:操作日期\r\n默认值:", - "format": "date-time" - }, - "logType": { - "type": "integer", - "description": "备 注:操作类型。1新增,2推进,3完成任务\r\n默认值:", - "format": "int32" - }, - "logCount": { - "type": "integer", - "description": "当天操作记录数量", - "format": "int32" - } - }, - "additionalProperties": false - }, - "TaskTalkFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "talkId": { - "type": "integer", - "description": "谈话表id", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "谈话纪要", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "TaskTalkResult": { - "type": "object", - "properties": { - "talkId": { - "type": "integer", - "description": "谈话表id", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "谈话纪要", - "nullable": true - }, - "userId": { - "type": "integer", - "description": "用户id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户名称", - "nullable": true - }, - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "关联文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "Task_checklistRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "新增为null,编辑时传Id", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "备 注:任务类型id\r\n默认值:", - "format": "int64" - }, - "targetNumber": { - "type": "integer", - "description": "备 注:任务指标数\r\n默认值:", - "format": "int32" - }, - "taskType": { - "type": "integer", - "description": "备 注:班级/通用任务类型 1班级;2通用\r\n默认值:", - "format": "int32" - } - }, - "additionalProperties": false - }, - "Task_checklistResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int64" - }, - "taskTypeEnumName": { - "type": "string", - "description": "备 注:任务类型名称", - "nullable": true - }, - "taskUserId": { - "type": "integer", - "description": "备 注:用户id\r\n默认值:", - "format": "int64" - }, - "targetNumber": { - "type": "integer", - "description": "备 注:任务指标数\r\n默认值:", - "format": "int64" - }, - "taskType": { - "type": "integer", - "description": "备 注:班级/通用任务类型 1班级;2通用\r\n默认值:", - "format": "int32" - } - }, - "additionalProperties": false - }, - "TeacherBehaviorFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "tBId": { - "type": "integer", - "description": "观察表id", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "分析/总结", - "nullable": true - } - }, - "additionalProperties": false - }, - "TeacherBehaviorQuestionNumResult": { - "type": "object", - "properties": { - "questionId": { - "type": "integer", - "description": "问题id", - "format": "int64" - }, - "num": { - "type": "integer", - "description": "问题个数", - "format": "int32" - }, - "addTime": { - "type": "string", - "description": "记录时间", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "TeacherBehaviorQuestionResult": { - "type": "object", - "properties": { - "previewString": { - "type": "string", - "description": "预习安排", - "nullable": true - }, - "cooperationString": { - "type": "string", - "description": "课堂配合", - "nullable": true - }, - "afterString": { - "type": "string", - "description": "课后观察", - "nullable": true - } - }, - "additionalProperties": false - }, - "TeacherBehaviorRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "tBId": { - "type": "integer", - "description": "教师行为规范id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "behaviorUserName": { - "type": "string", - "description": "观察对象姓名", - "nullable": true - }, - "behaviorUserId": { - "type": "integer", - "description": "观察对象Id", - "format": "int64" - } - }, - "additionalProperties": false - }, - "TeacherBehaviorResult": { - "type": "object", - "properties": { - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "tBId": { - "type": "integer", - "description": "观察表id", - "format": "int64" - }, - "behaviorUserName": { - "type": "string", - "description": "观察对象名称", - "nullable": true - }, - "remark": { - "type": "string", - "description": "反馈反思", - "nullable": true - }, - "teacherBehaviorQuestionNumResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TeacherBehaviorQuestionNumResult" - }, - "description": "观察记录列表", - "nullable": true - } - }, - "additionalProperties": false - }, - "TeacherTalkInfoFinishRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id", - "format": "int64" - }, - "teacherTalkId": { - "type": "integer", - "description": "谈话ID", - "format": "int64" - }, - "remark": { - "type": "string", - "description": "谈话纪要", - "nullable": true - }, - "files": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BaseTaskFileRequest" - }, - "nullable": true - } - }, - "additionalProperties": false - }, - "TeacherTalkInfoRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "任务id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "classesId": { - "type": "integer", - "description": "班级id(班级任务时,classes_id不为空;通用任务时,班级id为空 null)", - "format": "int64", - "nullable": true - }, - "taskTypeEnum": { - "type": "integer", - "description": "任务类型id", - "format": "int32" - }, - "startTime": { - "type": "string", - "description": "备 注:开始时间\r\n默认值:", - "format": "date-time" - }, - "endTime": { - "type": "string", - "description": "备 注:结束时间\r\n默认值:", - "format": "date-time" - }, - "taskTitleSuffix": { - "type": "string", - "description": "任务后缀", - "nullable": true - }, - "teacherTalkId": { - "type": "integer", - "description": "id(新增时为null,修改时必传)", - "format": "int64", - "nullable": true - }, - "quiltUserName": { - "type": "string", - "description": "被谈话老师用户姓名", - "nullable": true - } - }, - "additionalProperties": false - }, - "TeacherTalkInfoResult": { - "type": "object", - "properties": { - "talkId": { - "type": "integer", - "description": "谈话记录ID", - "format": "int64" - }, - "quiltUserName": { - "type": "string", - "description": "被谈话老师用户姓名", - "nullable": true - }, - "remark": { - "type": "string", - "description": "谈话纪要", - "nullable": true - }, - "taskInfo": { - "$ref": "#/components/schemas/BaseTaskClassResult" - }, - "sunTaskFileResults": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SunTaskFileResult" - }, - "description": "关联文件", - "nullable": true - } - }, - "additionalProperties": false - }, - "Teacher_behavior_questionRequest": { - "type": "object", - "properties": { - "tBId": { - "type": "integer", - "description": "观察记录id", - "format": "int64" - }, - "previewId": { - "type": "string", - "description": "预习安排问题,参数id,多个用英文逗号分割", - "nullable": true - }, - "previewTypeId": { - "type": "string", - "description": "预习安排-预习方式问题,参数id,多个用英文逗号分割", - "nullable": true - }, - "inspectTypeEnum": { - "type": "integer", - "description": "预习安排-检查方式: 1课前检查;2课间检查;3全面检查;4未检查", - "format": "int32", - "nullable": true - }, - "previewResultEnum": { - "type": "integer", - "description": "预习安排-预习效果;参数id", - "format": "int32", - "nullable": true - }, - "cooperationId": { - "type": "string", - "description": "备 注:课堂配合,参数id,多个用英文逗号分割\r\n默认值:", - "nullable": true - }, - "cooperationInspectionEnum": { - "type": "integer", - "description": "备 注:课堂配合-巡视频率,1好;2中;3低\r\n默认值:", - "format": "int32", - "nullable": true - }, - "afterClassId": { - "type": "string", - "description": "备 注:课后观察,参数id,多个用英文逗号分割\r\n默认值:", - "nullable": true - } - }, - "additionalProperties": false - }, - "TeachingLevelEnum": { - "enum": [ - 1, - 2 - ], - "type": "integer", - "description": "班级教学层次枚举", - "format": "int32" - }, - "ToolClassType": { - "enum": [ - 1, - 2, - 3 - ], - "type": "integer", - "format": "int32" - }, - "ToolKitSemesterViewDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "toolKitId": { - "type": "integer", - "description": "备 注:工具包Id\r\n默认值:", - "format": "int64" - }, - "solutionSemesterEnum": { - "$ref": "#/components/schemas/SolutionSemesterEnum" - }, - "solutionSemesterName": { - "type": "string", - "nullable": true, - "readOnly": true - } - }, - "additionalProperties": false, - "description": "工具包学期视图数据传输对象" - }, - "ToolKitViewDto": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "format": "int64" - }, - "toolName": { - "type": "string", - "description": "备 注:工具名称\r\n默认值:", - "nullable": true - }, - "toolType": { - "type": "string", - "description": "备 注:工具格式 文件后缀名\r\n默认值:", - "nullable": true - }, - "toolSize": { - "type": "integer", - "description": "备 注:大小 kb\r\n默认值:", - "format": "int32" - }, - "problemObj": { - "$ref": "#/components/schemas/ToolObjectType" - }, - "upTime": { - "type": "string", - "description": "备 注:最后更新时间\r\n默认值:", - "format": "date-time" - }, - "fileinfo": { - "$ref": "#/components/schemas/SysFileViewDto" - }, - "addTime": { - "type": "string", - "description": "备 注:添加时间\r\n默认值:", - "format": "date-time" - }, - "toolClassType": { - "$ref": "#/components/schemas/ToolClassType" - }, - "toolKitSemesters": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ToolKitSemesterViewDto" - }, - "nullable": true - }, - "solutionLists": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SolutionListViewDto" - }, - "description": "关联解决方案列表", - "nullable": true - } - }, - "additionalProperties": false - }, - "ToolObjectType": { - "enum": [ - 1, - 2, - 3 - ], - "type": "integer", - "description": "工具对象类型枚举", - "format": "int32" - }, - "UpdateappResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "备 注:\r\n默认值:", - "format": "int64" - }, - "version": { - "type": "integer", - "description": "备 注:版本\r\n默认值:", - "format": "int32" - }, - "versionName": { - "type": "string", - "description": "版本号", - "nullable": true - }, - "remark": { - "type": "string", - "description": "版本说明", - "nullable": true - }, - "imageBase": { - "type": "string", - "description": "二维码图片:base64", - "nullable": true - }, - "updatetype": { - "type": "integer", - "description": "1:安卓APP,2:客户端,3:IOS APP", - "format": "int32", - "nullable": true - }, - "isActive": { - "type": "integer", - "description": "1启用 0停用", - "format": "int32", - "nullable": true - }, - "fileid": { - "type": "integer", - "description": "备 注:文件id\r\n默认值:", - "format": "int64", - "nullable": true - }, - "fileName": { - "type": "string", - "description": "原文件名", - "nullable": true - }, - "filePath": { - "type": "string", - "description": "文件路径", - "nullable": true - }, - "fileSize": { - "type": "integer", - "description": "备 注:文件大小(文件大小-kb,不足1kb为1kb)\r\n默认值:", - "format": "int64", - "nullable": true - } - }, - "additionalProperties": false - }, - "UserBooksResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "Id", - "format": "int64" - }, - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - }, - "headImage": { - "type": "string", - "description": "头像", - "nullable": true - }, - "roleEnum": { - "$ref": "#/components/schemas/SysRoleEnum" - }, - "phone": { - "type": "string", - "description": "电话", - "nullable": true - } - }, - "additionalProperties": false - }, - "UserFoundationResult": { - "type": "object", - "properties": { - "userName": { - "type": "string", - "description": "用户姓名", - "nullable": true - }, - "userId": { - "type": "integer", - "description": "用户id", - "format": "int64" - }, - "roleEnum": { - "$ref": "#/components/schemas/SysRoleEnum" - } - }, - "additionalProperties": false, - "description": "用户基本表" - }, - "UserResult": { - "type": "object", - "properties": { - "id": { - "type": "integer", - "description": "备 注:用户中心id\r\n默认值:", - "format": "int64" - }, - "realName": { - "type": "string", - "description": "备 注:姓名\r\n默认值:", - "nullable": true - }, - "account": { - "type": "string", - "description": "备 注:账号\r\n默认值:", - "nullable": true - }, - "roleEnum": { - "$ref": "#/components/schemas/SysRoleEnum" - }, - "cloudId": { - "type": "integer", - "description": "云校id", - "format": "int64", - "nullable": true - }, - "roleName": { - "type": "string", - "description": "角色名称", - "nullable": true - }, - "cloudName": { - "type": "string", - "description": "备 注:云校名称\r\n默认值:", - "nullable": true - }, - "phone": { - "type": "string", - "description": "备 注:手机号\r\n默认值:", - "nullable": true - }, - "headImage": { - "type": "string", - "description": "头像URL", - "nullable": true - } - }, - "additionalProperties": false - }, - "WeekModel": { - "type": "object", - "properties": { - "week": { - "type": "integer", - "description": "周", - "format": "int32" - }, - "weekDay": { - "type": "string", - "description": "", - "format": "date-time" - }, - "weekDayDetails": { - "type": "array", - "items": { - "$ref": "#/components/schemas/weekDayDetail" - }, - "description": "", - "nullable": true - } - }, - "additionalProperties": false - }, - "userLoginRequest": { - "type": "object", - "properties": { - "phone": { - "type": "string", - "description": "电话", - "nullable": true - } - }, - "additionalProperties": false - }, - "userLoginResult": { - "type": "object", - "properties": { - "token": { - "type": "string", - "description": "Token", - "nullable": true - }, - "userInfo": { - "$ref": "#/components/schemas/UserResult" - }, - "userSig": { - "type": "string", - "description": "UserSig", - "nullable": true - } - }, - "additionalProperties": false - }, - "weekDayDetail": { - "type": "object", - "properties": { - "classCourseId": { - "type": "integer", - "description": "课程id", - "format": "int64" - }, - "subject": { - "type": "integer", - "description": "科目id", - "format": "int32" - }, - "subjectName": { - "type": "string", - "description": "科目名称", - "nullable": true - }, - "teacherName": { - "type": "string", - "description": "云校老师", - "nullable": true - }, - "teacherId": { - "type": "integer", - "description": "云校老师id", - "format": "int64" - }, - "landingTeacherId": { - "type": "integer", - "description": "落地老师", - "format": "int64" - }, - "landingTeacherName": { - "type": "string", - "description": "落地老师", - "nullable": true - }, - "planStartTime": { - "type": "string", - "description": "上课时间", - "format": "date-time" - }, - "planEndTime": { - "type": "string", - "description": "下课时间", - "format": "date-time" - } - }, - "additionalProperties": false - } - }, - "securitySchemes": { - "Bearer": { - "type": "apiKey", - "description": "在下框中输入请求头中需要添加Jwt授权Token:Bearer {Token},注意中间有空格", - "name": "Authorization", - "in": "header" - } - } - }, - "security": [ - { - "Bearer": [ ] - } - ], - "tags": [ - { - "name": "HealthCheck", - "description": "健康检查控制器" - }, - { - "name": "FollowManager", - "description": "工作台" - }, - { - "name": "Index", - "description": "首页控制器" - }, - { - "name": "Login", - "description": "登录" - }, - { - "name": "MobileManager", - "description": "移动端部长/组长管理" - }, - { - "name": "MyInfo", - "description": "我的" - }, - { - "name": "TaskInfo", - "description": "工作任务api" - }, - { - "name": "TaskSummarize", - "description": "总结任务报告api" - }, - { - "name": "TaskClassCadreMeeting", - "description": "开展班干部会议api" - }, - { - "name": "TaskClassesActivity", - "description": "班级活动" - }, - { - "name": "TaskClassMeeting", - "description": "召开班会任务" - }, - { - "name": "TaskCoachSub", - "description": "学科辅助" - }, - { - "name": "TaskCultural", - "description": "更新文创内容" - }, - { - "name": "TaskDataCollect", - "description": "任务数据采集控制器" - }, - { - "name": "TaskFollow", - "description": "双师课堂任务api" - }, - { - "name": "TaskMeeting", - "description": "参加会议任务api" - }, - { - "name": "TaskOther", - "description": "其他任务相关接口" - }, - { - "name": "TaskSolution", - "description": "任务-解决方案api" - }, - { - "name": "TaskSpot", - "description": "学习行为习惯全面抽查" - }, - { - "name": "TaskTalk", - "description": "一对一学生谈话任务api" - }, - { - "name": "TaskTeacherBehavior", - "description": "教师行为规范" - }, - { - "name": "TaskTeacherTalk", - "description": "教师谈话任务控制器" - } - ] -} \ No newline at end of file diff --git a/test_function_name.dart b/test_function_name.dart new file mode 100644 index 0000000..c537341 --- /dev/null +++ b/test_function_name.dart @@ -0,0 +1,21 @@ +import 'lib/utils/string_utils.dart'; + +void main() { + print('Testing function name generation:'); + print( + 'GetClassesTaskChecklistUsers -> ${StringUtils.toCamelCase('GetClassesTaskChecklistUsers')}'); + print('GetUserInfo -> ${StringUtils.toCamelCase('GetUserInfo')}'); + print('CreateTask -> ${StringUtils.toCamelCase('CreateTask')}'); + print('UpdateUserProfile -> ${StringUtils.toCamelCase('UpdateUserProfile')}'); + print('DeleteTaskById -> ${StringUtils.toCamelCase('DeleteTaskById')}'); + + print('\nTesting existing camelCase:'); + print( + 'getClassesTaskChecklistUsers -> ${StringUtils.toCamelCase('getClassesTaskChecklistUsers')}'); + print('getUserInfo -> ${StringUtils.toCamelCase('getUserInfo')}'); + + print('\nTesting snake_case:'); + print( + 'get_classes_task_checklist_users -> ${StringUtils.toCamelCase('get_classes_task_checklist_users')}'); + print('get_user_info -> ${StringUtils.toCamelCase('get_user_info')}'); +} diff --git a/test_property_name.dart b/test_property_name.dart new file mode 100644 index 0000000..8b6cfbb --- /dev/null +++ b/test_property_name.dart @@ -0,0 +1,76 @@ +import 'lib/utils/string_utils.dart'; + +void main() { + print('Testing property name conversion:'); + print('classCadreId -> ${StringUtils.toDartPropertyName('classCadreId')}'); + print('meetingTitle -> ${StringUtils.toDartPropertyName('meetingTitle')}'); + print('taskInfo -> ${StringUtils.toDartPropertyName('taskInfo')}'); + print( + 'sunTaskUserResults -> ${StringUtils.toDartPropertyName('sunTaskUserResults')}'); + print( + 'sunTaskFileResults -> ${StringUtils.toDartPropertyName('sunTaskFileResults')}'); + + print('\nTesting snake_case conversion:'); + print( + 'class_cadre_id -> ${StringUtils.toDartPropertyName('class_cadre_id')}'); + print('meeting_title -> ${StringUtils.toDartPropertyName('meeting_title')}'); + print('task_info -> ${StringUtils.toDartPropertyName('task_info')}'); + + print('\nTesting problematic field names:'); + print('PageIndex -> ${StringUtils.toDartPropertyName('PageIndex')}'); + print('ProblemTitle -> ${StringUtils.toDartPropertyName('ProblemTitle')}'); + print('ProblemObj -> ${StringUtils.toDartPropertyName('ProblemObj')}'); + print( + 'ProblemPhenomenon -> ${StringUtils.toDartPropertyName('ProblemPhenomenon')}'); + print('ClassesId -> ${StringUtils.toDartPropertyName('ClassesId')}'); + print( + 'ProblemTaskType -> ${StringUtils.toDartPropertyName('ProblemTaskType')}'); + print('PageSize -> ${StringUtils.toDartPropertyName('PageSize')}'); + + print('\nTesting parameter name conversion:'); + print('api-version -> ${StringUtils.toDartPropertyName('api-version')}'); + print('user-id -> ${StringUtils.toDartPropertyName('user-id')}'); + print('file_name -> ${StringUtils.toDartPropertyName('file_name')}'); + print('with space -> ${StringUtils.toDartPropertyName('with space')}'); + + print('\nTesting kebab-case conversion:'); + print('api-version -> ${StringUtils.toDartPropertyName('api-version')}'); + print('user-id -> ${StringUtils.toDartPropertyName('user-id')}'); + print('page-size -> ${StringUtils.toDartPropertyName('page-size')}'); + print('to-camel-case -> ${StringUtils.toDartPropertyName('to-camel-case')}'); + + print('\nTesting tag names:'); + print( + 'Follow Manager -> ${StringUtils.toDartPropertyName('Follow Manager')}'); + print('Health Check -> ${StringUtils.toDartPropertyName('Health Check')}'); + print( + 'Mobile Manager -> ${StringUtils.toDartPropertyName('Mobile Manager')}'); + print('My Info -> ${StringUtils.toDartPropertyName('My Info')}'); + print( + 'Task Class Cadre Meeting -> ${StringUtils.toDartPropertyName('Task Class Cadre Meeting')}'); + print( + 'Task Class Meeting -> ${StringUtils.toDartPropertyName('Task Class Meeting')}'); + print( + 'Task Coach Sub -> ${StringUtils.toDartPropertyName('Task Coach Sub')}'); + print('Task Cultural -> ${StringUtils.toDartPropertyName('Task Cultural')}'); + print( + 'Task Data Collect -> ${StringUtils.toDartPropertyName('Task Data Collect')}'); + print('Task Follow -> ${StringUtils.toDartPropertyName('Task Follow')}'); + print('Task Info -> ${StringUtils.toDartPropertyName('Task Info')}'); + print('Task Meeting -> ${StringUtils.toDartPropertyName('Task Meeting')}'); + print('Task Other -> ${StringUtils.toDartPropertyName('Task Other')}'); + print('Task Solution -> ${StringUtils.toDartPropertyName('Task Solution')}'); + print('Task Spot -> ${StringUtils.toDartPropertyName('Task Spot')}'); + print( + 'Task Summarize -> ${StringUtils.toDartPropertyName('Task Summarize')}'); + print('Task Talk -> ${StringUtils.toDartPropertyName('Task Talk')}'); + print( + 'Task Teacher Behavior -> ${StringUtils.toDartPropertyName('Task Teacher Behavior')}'); + print( + 'Task Teacher Talk -> ${StringUtils.toDartPropertyName('Task Teacher Talk')}'); + + print('\nTesting comment cleaning:'); + print('部长新增工作任务指标(会删除所有管理的班级任务指标)-删除所有管理的学习官的通用任务指标'); + print( + 'Cleaned: ${StringUtils.cleanDescription('部长新增工作任务指标(会删除所有管理的班级任务指标)-删除所有管理的学习官的通用任务指标')}'); +} diff --git a/tests/comprehensive_generator_test.dart b/tests/comprehensive_generator_test.dart deleted file mode 100644 index 789d6ee..0000000 --- a/tests/comprehensive_generator_test.dart +++ /dev/null @@ -1,613 +0,0 @@ -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:swagger_generator_flutter/generators/optimized_retrofit_generator.dart'; -import 'package:swagger_generator_flutter/generators/performance_generator.dart'; -import 'package:swagger_generator_flutter/generators/retrofit_api_generator.dart'; -import 'package:test/test.dart'; - -void main() { - group('Comprehensive Generator Tests', () { - late SwaggerDocument testDocument; - - setUp(() { - testDocument = const SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'A comprehensive test API', - servers: [ - ApiServer( - url: 'https://api.example.com', - description: 'Production server', - ), - ], - components: ApiComponents( - schemas: {}, - securitySchemes: { - 'bearerAuth': const ApiSecurityScheme( - type: SecuritySchemeType.http, - description: 'Bearer token', - scheme: 'bearer', - bearerFormat: 'JWT', - ), - 'apiKey': const ApiSecurityScheme( - type: SecuritySchemeType.apiKey, - description: 'API Key', - name: 'X-API-Key', - location: ApiKeyLocation.header, - ), - }, - ), - paths: { - '/users': const ApiPath( - path: '/users', - method: HttpMethod.get, - summary: 'Get all users', - description: 'Retrieve a list of all users', - operationId: 'getUsers', - tags: ['users'], - parameters: [ - ApiParameter( - name: 'page', - location: ParameterLocation.query, - required: false, - type: PropertyType.integer, - description: 'Page number', - ), - ApiParameter( - name: 'limit', - location: ParameterLocation.query, - required: false, - type: PropertyType.integer, - description: 'Items per page', - ), - ], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Successful response', - content: { - 'application/json': const ApiMediaType( - schema: { - 'type': 'array', - 'items': { - '\$ref': '#/components/schemas/User', - }, - }, - ), - }, - ), - '400': const ApiResponse( - code: '400', - description: 'Bad request', - ), - '401': const ApiResponse( - code: '401', - description: 'Unauthorized', - ), - }, - security: [ - ApiSecurityRequirement( - requirements: {'bearerAuth': []}, - ), - ], - ), - '/users/{id}': const ApiPath( - path: '/users/{id}', - method: HttpMethod.get, - summary: 'Get user by ID', - description: 'Retrieve a specific user by their ID', - operationId: 'getUserById', - tags: ['users'], - parameters: [ - ApiParameter( - name: 'id', - location: ParameterLocation.path, - required: true, - type: PropertyType.integer, - description: 'User ID', - ), - ], - responses: { - '200': const ApiResponse( - code: '200', - description: 'User found', - content: { - 'application/json': const ApiMediaType( - schema: { - '\$ref': '#/components/schemas/User', - }, - ), - }, - ), - '404': const ApiResponse( - code: '404', - description: 'User not found', - ), - }, - ), - '/users/create': const ApiPath( - path: '/users/create', - method: HttpMethod.post, - summary: 'Create user', - description: 'Create a new user', - operationId: 'createUser', - tags: ['users'], - parameters: [], - requestBody: ApiRequestBody( - description: 'User data', - required: true, - content: { - 'application/json': const ApiMediaType( - schema: { - '\$ref': '#/components/schemas/CreateUserRequest', - }, - ), - }, - ), - responses: { - '201': const ApiResponse( - code: '201', - description: 'User created', - content: { - 'application/json': const ApiMediaType( - schema: { - '\$ref': '#/components/schemas/User', - }, - ), - }, - ), - '400': const ApiResponse( - code: '400', - description: 'Invalid input', - ), - }, - ), - '/files/upload': const ApiPath( - path: '/files/upload', - method: HttpMethod.post, - summary: 'Upload file', - description: 'Upload a file to the server', - operationId: 'uploadFile', - tags: ['files'], - parameters: [], - requestBody: ApiRequestBody( - description: 'File to upload', - required: true, - content: { - 'multipart/form-data': const ApiMediaType( - schema: { - 'type': 'object', - 'properties': { - 'file': { - 'type': 'string', - 'format': 'binary', - }, - 'description': { - 'type': 'string', - }, - }, - }, - ), - }, - ), - responses: { - '200': const ApiResponse( - code: '200', - description: 'File uploaded successfully', - content: { - 'application/json': const ApiMediaType( - schema: { - '\$ref': '#/components/schemas/FileUploadResult', - }, - ), - }, - ), - }, - ), - }, - models: { - 'User': const ApiModel( - name: 'User', - description: 'User model', - properties: { - 'id': const ApiProperty( - name: 'id', - type: PropertyType.integer, - description: 'User ID', - required: true, - ), - 'name': const ApiProperty( - name: 'name', - type: PropertyType.string, - description: 'User name', - required: true, - ), - 'email': const ApiProperty( - name: 'email', - type: PropertyType.string, - description: 'User email', - required: true, - ), - 'createdAt': const ApiProperty( - name: 'createdAt', - type: PropertyType.string, - description: 'Creation timestamp', - required: false, - ), - }, - required: ['id', 'name', 'email'], - ), - 'CreateUserRequest': const ApiModel( - name: 'CreateUserRequest', - description: 'Request model for creating a user', - properties: { - 'name': const ApiProperty( - name: 'name', - type: PropertyType.string, - description: 'User name', - required: true, - ), - 'email': const ApiProperty( - name: 'email', - type: PropertyType.string, - description: 'User email', - required: true, - ), - }, - required: ['name', 'email'], - ), - 'FileUploadResult': const ApiModel( - name: 'FileUploadResult', - description: 'Result of file upload', - properties: { - 'url': const ApiProperty( - name: 'url', - type: PropertyType.string, - description: 'File URL', - required: true, - ), - 'filename': const ApiProperty( - name: 'filename', - type: PropertyType.string, - description: 'Original filename', - required: true, - ), - 'size': const ApiProperty( - name: 'size', - type: PropertyType.integer, - description: 'File size in bytes', - required: true, - ), - }, - required: ['url', 'filename', 'size'], - ), - }, - controllers: {}, - security: [ - ApiSecurityRequirement( - requirements: {'bearerAuth': []}, - ), - ], - ); - }); - - group('RetrofitApiGenerator', () { - test('generates basic Retrofit API', () { - final generator = RetrofitApiGenerator( - className: 'TestApiService', - splitByTags: false, - ); - - final result = generator.generateFromDocument(testDocument); - - expect(result, isNotEmpty); - expect(result, contains('abstract class TestApiService')); - expect(result, contains('@RestApi()')); - expect(result, contains('factory TestApiService(Dio dio')); - expect(result, contains('@GET(\'/users\')')); - expect(result, contains('@POST(\'/users\')')); - expect(result, contains('@Path(\'id\')')); - expect(result, contains('@Query(\'page\')')); - expect(result, contains('@Body()')); - }); - - test('generates split APIs by tags', () { - final generator = RetrofitApiGenerator( - className: 'ApiService', - splitByTags: true, - ); - - final result = generator.generateFromDocument(testDocument); - - expect(result, isNotEmpty); - expect(result, contains('UsersApi')); - expect(result, contains('FilesApi')); - expect(result, contains('class ApiService')); - expect(result, contains('late final UsersApi users')); - expect(result, contains('late final FilesApi files')); - }); - - test('handles file upload endpoints', () { - final generator = RetrofitApiGenerator(); - - final result = generator.generateFromDocument(testDocument); - - expect(result, contains('@POST(\'/files/upload\')')); - expect(result, contains('@MultiPart()')); - expect(result, contains('MultipartFile')); - }); - - test('generates proper parameter annotations', () { - final generator = RetrofitApiGenerator(); - - final result = generator.generateFromDocument(testDocument); - - // Path parameters - expect(result, contains('@Path(\'id\') int id')); - - // Query parameters - expect(result, contains('@Query(\'page\') int? page')); - expect(result, contains('@Query(\'limit\') int? limit')); - - // Body parameters - expect(result, contains('@Body() CreateUserRequest body')); - }); - - test('generates security annotations', () { - final generator = RetrofitApiGenerator(); - - final result = generator.generateFromDocument(testDocument); - - // Should include headers for authentication - expect( - result, anyOf([contains('Authorization'), contains('X-API-Key')])); - }); - }); - - group('OptimizedRetrofitGenerator', () { - test('generates optimized code with base types', () { - final generator = OptimizedRetrofitGenerator( - className: 'OptimizedApiService', - generateModularApis: true, - generateBaseResult: true, - generatePagination: true, - generateFileUpload: true, - ); - - final result = generator.generateFromDocument(testDocument); - - expect(result, isNotEmpty); - expect(result, contains('class BaseResult')); - expect(result, contains('class BasePageResult')); - expect(result, contains('class FileUploadRequest')); - expect(result, contains('class FileUploadResult')); - expect(result, contains('class ApiUtils')); - }); - - test('generates modular APIs', () { - final generator = OptimizedRetrofitGenerator( - generateModularApis: true, - ); - - final result = generator.generateFromDocument(testDocument); - - expect(result, contains('class UsersApi')); - expect(result, contains('class FilesApi')); - expect(result, contains('class ApiService')); - }); - - test('generates single API when modular is disabled', () { - final generator = OptimizedRetrofitGenerator( - generateModularApis: false, - className: 'SingleApiService', - ); - - final result = generator.generateFromDocument(testDocument); - - expect(result, contains('abstract class SingleApiService')); - expect(result, isNot(contains('class UsersApi'))); - expect(result, isNot(contains('class FilesApi'))); - }); - - test('includes utility methods', () { - final generator = OptimizedRetrofitGenerator( - generateFileUpload: true, - generatePagination: true, - ); - - final result = generator.generateFromDocument(testDocument); - - expect(result, contains('class ApiUtils')); - expect(result, contains('createFileUpload')); - expect(result, contains('createPageParam')); - }); - }); - - group('PerformanceGenerator', () { - test('generates code with performance tracking', () async { - final generator = PerformanceGenerator( - maxConcurrency: 2, - enableCaching: true, - enableParallel: true, - ); - - final result = await generator.generateFromDocument(testDocument); - - expect(result, isNotEmpty); - expect(result, contains('Generated API for Test API')); - expect(result, contains('class User')); - expect(result, contains('CommonApi')); - - final stats = generator.getStats(); - expect(stats.totalTasks, greaterThan(0)); - expect(stats.completedTasks, greaterThan(0)); - }); - - test('caching improves performance', () async { - final generator = PerformanceGenerator( - enableCaching: true, - ); - - // First generation - final stopwatch1 = Stopwatch()..start(); - await generator.generateFromDocument(testDocument); - stopwatch1.stop(); - - // Second generation (should use cache) - final stopwatch2 = Stopwatch()..start(); - await generator.generateFromDocument(testDocument); - stopwatch2.stop(); - - // Second should be faster due to caching - expect(stopwatch2.elapsedMicroseconds, - lessThan(stopwatch1.elapsedMicroseconds)); - - final cacheStats = generator.getCacheStats(); - expect(cacheStats.hits, greaterThan(0)); - }); - }); - - group('Code Quality', () { - test('generated code is valid Dart syntax', () { - final generator = RetrofitApiGenerator(); - final result = generator.generateFromDocument(testDocument); - - // Basic syntax checks - expect(result, isNot(contains(';;'))); // No double semicolons - expect(result, isNot(contains(',,'))); // No double commas - expect(result, - isNot(contains(' '))); // No double spaces (basic formatting) - - // Check for proper imports - expect(result, contains('import \'package:dio/dio.dart\';')); - expect(result, contains('import \'package:retrofit/retrofit.dart\';')); - - // Check for proper class structure - final classMatches = RegExp(r'class \w+').allMatches(result); - final abstractClassMatches = - RegExp(r'abstract class \w+').allMatches(result); - expect( - classMatches.length + abstractClassMatches.length, greaterThan(0)); - }); - - test('handles special characters in names', () { - const specialDocument = SwaggerDocument( - title: 'API with Special-Characters_and.dots', - version: '1.0.0', - description: 'Test API', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/special-endpoint_with.dots': const ApiPath( - path: '/special-endpoint_with.dots', - method: HttpMethod.get, - summary: 'Special endpoint', - description: 'Endpoint with special characters', - operationId: 'getSpecialEndpoint', - tags: ['special-tag_with.dots'], - parameters: [], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final generator = RetrofitApiGenerator(); - final result = generator.generateFromDocument(specialDocument); - - expect(result, isNotEmpty); - // Should handle special characters in class names - expect(result, contains('class')); - }); - - test('generates proper JSON annotations', () { - final generator = OptimizedRetrofitGenerator( - generateBaseResult: true, - ); - - final result = generator.generateFromDocument(testDocument); - - expect(result, contains('@JsonSerializable()')); - expect(result, contains('fromJson')); - expect(result, contains('toJson')); - expect(result, contains('_\$')); - }); - - test('handles nullable and required fields correctly', () { - final generator = RetrofitApiGenerator(); - final result = generator.generateFromDocument(testDocument); - - // Required path parameters should not be nullable - expect(result, contains('@Path(\'id\') int id')); - - // Optional query parameters should be nullable - expect(result, contains('@Query(\'page\') int? page')); - expect(result, contains('@Query(\'limit\') int? limit')); - }); - }); - - group('Error Handling', () { - test('handles empty document gracefully', () { - const emptyDocument = SwaggerDocument( - title: 'Empty API', - version: '1.0.0', - description: 'Empty test API', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: {}, - models: {}, - controllers: {}, - security: [], - ); - - final generator = RetrofitApiGenerator(); - final result = generator.generateFromDocument(emptyDocument); - - expect(result, isNotEmpty); - expect(result, contains('Empty API')); - // Should still generate basic structure even with no paths - }); - - test('handles missing operation IDs', () { - const documentWithoutOperationIds = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/test': const ApiPath( - path: '/test', - method: HttpMethod.get, - summary: 'Test endpoint', - description: 'Test', - operationId: '', // Empty operation ID - tags: [], - parameters: [], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final generator = RetrofitApiGenerator(); - expect( - () => generator.generateFromDocument(documentWithoutOperationIds), - returnsNormally); - }); - }); - }); -} diff --git a/tests/comprehensive_parser_test.dart b/tests/comprehensive_parser_test.dart deleted file mode 100644 index d1fe4d5..0000000 --- a/tests/comprehensive_parser_test.dart +++ /dev/null @@ -1,623 +0,0 @@ -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:test/test.dart'; - -void main() { - group('Comprehensive Parser Tests', () { - group('OpenAPI 3.0 Core Features', () { - test('parses basic OpenAPI 3.0 document', () { - final json = { - 'openapi': '3.0.3', - 'info': { - 'title': 'Test API', - 'version': '1.0.0', - 'description': 'A test API', - }, - 'servers': [ - { - 'url': 'https://api.example.com', - 'description': 'Production server', - }, - ], - 'paths': { - '/users': { - 'get': { - 'summary': 'Get users', - 'operationId': 'getUsers', - 'responses': { - '200': { - 'description': 'Success', - 'content': { - 'application/json': { - 'schema': { - 'type': 'array', - 'items': { - '\$ref': '#/components/schemas/User', - }, - }, - }, - }, - }, - }, - }, - }, - }, - 'components': { - 'schemas': { - 'User': { - 'type': 'object', - 'properties': { - 'id': { - 'type': 'integer', - 'format': 'int64', - }, - 'name': { - 'type': 'string', - }, - }, - 'required': ['id', 'name'], - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - - expect(document.title, equals('Test API')); - expect(document.version, equals('1.0.0')); - expect(document.description, equals('A test API')); - expect(document.servers, hasLength(1)); - expect(document.servers.first.url, equals('https://api.example.com')); - expect(document.paths, hasLength(1)); - expect(document.models, hasLength(1)); - expect(document.models.containsKey('User'), isTrue); - }); - - test('parses servers with variables', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'servers': [ - { - 'url': 'https://{environment}.example.com/{basePath}', - 'description': 'Configurable server', - 'variables': { - 'environment': { - 'default': 'api', - 'enum': ['api', 'staging', 'dev'], - 'description': 'Environment name', - }, - 'basePath': { - 'default': 'v1', - 'description': 'API version', - }, - }, - }, - ], - 'paths': {}, - }; - - final document = SwaggerDocument.fromJson(json); - final server = document.servers.first; - - expect( - server.url, equals('https://{environment}.example.com/{basePath}')); - expect(server.variables, hasLength(2)); - expect(server.variables.containsKey('environment'), isTrue); - expect(server.variables['environment']!.defaultValue, equals('api')); - expect(server.variables['environment']!.enumValues, hasLength(3)); - }); - - test('parses complex request body', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'paths': { - '/users': { - 'post': { - 'summary': 'Create user', - 'requestBody': { - 'description': 'User to create', - 'required': true, - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/User', - }, - 'examples': { - 'user1': { - 'summary': 'Example user', - 'value': { - 'name': 'John Doe', - 'email': 'john@example.com', - }, - }, - }, - }, - 'application/xml': { - 'schema': { - '\$ref': '#/components/schemas/User', - }, - }, - }, - }, - 'responses': { - '201': {'description': 'Created'}, - }, - }, - }, - }, - 'components': { - 'schemas': { - 'User': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'email': {'type': 'string'}, - }, - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - final path = document.paths['/users']!; - - expect(path.requestBody, isNotNull); - expect(path.requestBody!.required, isTrue); - expect(path.requestBody!.content, hasLength(2)); - expect( - path.requestBody!.content.containsKey('application/json'), isTrue); - expect( - path.requestBody!.content.containsKey('application/xml'), isTrue); - - final jsonContent = path.requestBody!.content['application/json']!; - expect(jsonContent.examples, hasLength(1)); - expect(jsonContent.examples.containsKey('user1'), isTrue); - }); - - test('parses complex responses with headers and links', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'paths': { - '/users/{id}': { - 'get': { - 'summary': 'Get user', - 'parameters': [ - { - 'name': 'id', - 'in': 'path', - 'required': true, - 'schema': {'type': 'integer'}, - }, - ], - 'responses': { - '200': { - 'description': 'User found', - 'headers': { - 'X-Rate-Limit': { - 'description': 'Rate limit', - 'schema': {'type': 'integer'}, - }, - }, - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/User', - }, - }, - }, - 'links': { - 'getUserPosts': { - 'operationId': 'getUserPosts', - 'parameters': { - 'userId': '\$response.body#/id', - }, - }, - }, - }, - '404': { - 'description': 'User not found', - }, - }, - }, - }, - }, - 'components': { - 'schemas': { - 'User': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - }, - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - final path = document.paths['/users/{id}']!; - - expect(path.parameters, hasLength(1)); - expect(path.parameters.first.name, equals('id')); - expect(path.parameters.first.location, equals(ParameterLocation.path)); - expect(path.parameters.first.required, isTrue); - - expect(path.responses, hasLength(2)); - final successResponse = path.responses['200']!; - expect(successResponse.headers, hasLength(1)); - expect(successResponse.headers.containsKey('X-Rate-Limit'), isTrue); - expect(successResponse.links, hasLength(1)); - expect(successResponse.links.containsKey('getUserPosts'), isTrue); - }); - - test('parses security schemes and requirements', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'security': [ - {'bearerAuth': []}, - {'apiKey': []}, - ], - 'paths': { - '/protected': { - 'get': { - 'summary': 'Protected endpoint', - 'security': [ - { - 'bearerAuth': ['read:users'] - }, - ], - 'responses': { - '200': {'description': 'Success'}, - }, - }, - }, - }, - 'components': { - 'securitySchemes': { - 'bearerAuth': { - 'type': 'http', - 'scheme': 'bearer', - 'bearerFormat': 'JWT', - }, - 'apiKey': { - 'type': 'apiKey', - 'in': 'header', - 'name': 'X-API-Key', - }, - 'oauth2': { - 'type': 'oauth2', - 'flows': { - 'authorizationCode': { - 'authorizationUrl': 'https://example.com/oauth/authorize', - 'tokenUrl': 'https://example.com/oauth/token', - 'scopes': { - 'read:users': 'Read user data', - 'write:users': 'Write user data', - }, - }, - }, - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - - expect(document.security, hasLength(2)); - expect(document.components.securitySchemes, hasLength(3)); - - final bearerAuth = document.components.securitySchemes['bearerAuth']!; - expect(bearerAuth.type, equals(SecuritySchemeType.http)); - expect(bearerAuth.scheme, equals('bearer')); - expect(bearerAuth.bearerFormat, equals('JWT')); - - final apiKey = document.components.securitySchemes['apiKey']!; - expect(apiKey.type, equals(SecuritySchemeType.apiKey)); - expect(apiKey.location, equals(ApiKeyLocation.header)); - expect(apiKey.name, equals('X-API-Key')); - - final oauth2 = document.components.securitySchemes['oauth2']!; - expect(oauth2.type, equals(SecuritySchemeType.oauth2)); - expect(oauth2.flows, isNotNull); - expect(oauth2.flows!.authorizationCode, isNotNull); - expect(oauth2.flows!.authorizationCode!.scopes, hasLength(2)); - - final path = document.paths['/protected']!; - expect(path.security, hasLength(1)); - expect(path.security.first.schemeNames, contains('bearerAuth')); - }); - }); - - group('Schema Validation', () { - test('parses allOf composition', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'paths': {}, - 'components': { - 'schemas': { - 'Pet': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - }, - 'required': ['name'], - }, - 'Dog': { - 'allOf': [ - {'\$ref': '#/components/schemas/Pet'}, - { - 'type': 'object', - 'properties': { - 'breed': {'type': 'string'}, - }, - 'required': ['breed'], - }, - ], - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - expect(document.models, hasLength(2)); - expect(document.models.containsKey('Pet'), isTrue); - expect(document.models.containsKey('Dog'), isTrue); - - final dog = document.models['Dog']!; - expect(dog.name, equals('Dog')); - // allOf 处理逻辑会在实际实现中更复杂 - }); - - test('parses oneOf and anyOf', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'paths': {}, - 'components': { - 'schemas': { - 'StringOrNumber': { - 'oneOf': [ - {'type': 'string'}, - {'type': 'number'}, - ], - }, - 'FlexibleType': { - 'anyOf': [ - {'type': 'string'}, - {'type': 'integer'}, - {'type': 'boolean'}, - ], - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - expect(document.models, hasLength(2)); - expect(document.models.containsKey('StringOrNumber'), isTrue); - expect(document.models.containsKey('FlexibleType'), isTrue); - }); - - test('parses discriminator', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'paths': {}, - 'components': { - 'schemas': { - 'Pet': { - 'type': 'object', - 'discriminator': { - 'propertyName': 'petType', - 'mapping': { - 'dog': '#/components/schemas/Dog', - 'cat': '#/components/schemas/Cat', - }, - }, - 'properties': { - 'petType': {'type': 'string'}, - 'name': {'type': 'string'}, - }, - 'required': ['petType', 'name'], - }, - 'Dog': { - 'allOf': [ - {'\$ref': '#/components/schemas/Pet'}, - { - 'type': 'object', - 'properties': { - 'breed': {'type': 'string'}, - }, - }, - ], - }, - 'Cat': { - 'allOf': [ - {'\$ref': '#/components/schemas/Pet'}, - { - 'type': 'object', - 'properties': { - 'color': {'type': 'string'}, - }, - }, - ], - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - expect(document.models, hasLength(3)); - - final pet = document.models['Pet']!; - expect(pet.name, equals('Pet')); - // discriminator 处理逻辑会在实际实现中更复杂 - }); - }); - - group('Error Handling', () { - test('handles missing required fields gracefully', () { - final json = { - 'openapi': '3.0.3', - // Missing info object - 'paths': {}, - }; - - expect(() => SwaggerDocument.fromJson(json), - throwsA(isA())); - }); - - test('handles invalid OpenAPI version', () { - final json = { - 'openapi': '2.0', // Invalid version - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'paths': {}, - }; - - // Should still parse but might have warnings - expect(() => SwaggerDocument.fromJson(json), returnsNormally); - }); - - test('handles malformed paths', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'paths': { - '/valid': { - 'get': { - 'responses': { - '200': {'description': 'OK'} - }, - }, - }, - '/invalid': { - 'invalidMethod': { - 'responses': { - '200': {'description': 'OK'} - }, - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - // Should parse valid paths and skip invalid ones - expect(document.paths.length, greaterThanOrEqualTo(1)); - }); - - test('handles circular references', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Test', 'version': '1.0.0'}, - 'paths': {}, - 'components': { - 'schemas': { - 'Node': { - 'type': 'object', - 'properties': { - 'value': {'type': 'string'}, - 'children': { - 'type': 'array', - 'items': {'\$ref': '#/components/schemas/Node'}, - }, - }, - }, - }, - }, - }; - - // Should handle circular references without infinite recursion - expect(() => SwaggerDocument.fromJson(json), returnsNormally); - final document = SwaggerDocument.fromJson(json); - expect(document.models.containsKey('Node'), isTrue); - }); - }); - - group('Edge Cases', () { - test('handles empty document', () { - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Empty API', 'version': '1.0.0'}, - 'paths': {}, - }; - - final document = SwaggerDocument.fromJson(json); - expect(document.title, equals('Empty API')); - expect(document.paths, isEmpty); - expect(document.models, isEmpty); - }); - - test('handles very large documents', () { - final paths = {}; - final schemas = {}; - - // Create a large number of paths and schemas - for (int i = 0; i < 1000; i++) { - paths['/resource$i'] = { - 'get': { - 'summary': 'Get resource $i', - 'responses': { - '200': {'description': 'Success'} - }, - }, - }; - - schemas['Model$i'] = { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - }, - }; - } - - final json = { - 'openapi': '3.0.3', - 'info': {'title': 'Large API', 'version': '1.0.0'}, - 'paths': paths, - 'components': {'schemas': schemas}, - }; - - final stopwatch = Stopwatch()..start(); - final document = SwaggerDocument.fromJson(json); - stopwatch.stop(); - - expect(document.paths.length, greaterThan(500)); - expect(document.models.length, greaterThan(500)); - expect(stopwatch.elapsedMilliseconds, - lessThan(10000)); // Should complete within 10 seconds - }); - - test('handles unicode and special characters', () { - final json = { - 'openapi': '3.0.3', - 'info': { - 'title': 'API with 中文 and émojis 🚀', - 'version': '1.0.0', - 'description': 'Supports unicode: αβγ, 日本語, العربية', - }, - 'paths': { - '/测试': { - 'get': { - 'summary': 'Test with unicode path', - 'responses': { - '200': {'description': 'Success'} - }, - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - expect(document.title, contains('中文')); - expect(document.title, contains('🚀')); - expect(document.description, contains('日本語')); - expect(document.paths.containsKey('/测试'), isTrue); - }); - }); - }); -} diff --git a/tests/encoding_test.dart b/tests/encoding_test.dart deleted file mode 100644 index 104fc13..0000000 --- a/tests/encoding_test.dart +++ /dev/null @@ -1,217 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:test/test.dart'; - -void main() { - group('Encoding Support', () { - test('handles UTF-8 encoding', () { - const testString = 'Hello, 世界! 🌍'; - final encoded = utf8.encode(testString); - final decoded = utf8.decode(encoded); - - expect(decoded, testString); - expect( - encoded.length, - greaterThan( - testString.length)); // UTF-8 uses multiple bytes for non-ASCII - }); - - test('handles ASCII encoding', () { - const testString = 'Hello, World!'; - final encoded = ascii.encode(testString); - final decoded = ascii.decode(encoded); - - expect(decoded, testString); - expect( - encoded.length, testString.length); // ASCII is 1 byte per character - }); - - test('handles Latin1 encoding', () { - const testString = 'Café'; - final encoded = latin1.encode(testString); - final decoded = latin1.decode(encoded); - - expect(decoded, testString); - }); - - test('handles Base64 encoding and decoding', () { - const testString = 'Hello, World!'; - final bytes = utf8.encode(testString); - final encoded = base64Encode(bytes); - final decoded = base64Decode(encoded); - final result = utf8.decode(decoded); - - expect(result, testString); - expect(encoded, 'SGVsbG8sIFdvcmxkIQ=='); - }); - - test('handles URL encoding and decoding', () { - const testString = 'Hello World & Special Characters!@#\$%^&*()'; - final encoded = Uri.encodeComponent(testString); - final decoded = Uri.decodeComponent(encoded); - - expect(decoded, testString); - expect(encoded, contains('%20')); // Space should be encoded as %20 - expect(encoded, contains('%26')); // & should be encoded as %26 - }); - - test('detects BOM for UTF-8', () { - final utf8Bom = [0xEF, 0xBB, 0xBF]; - final testBytes = utf8Bom + utf8.encode('Hello'); - - // 检测 BOM - final bool hasUtf8Bom = testBytes.length >= 3 && - testBytes[0] == 0xEF && - testBytes[1] == 0xBB && - testBytes[2] == 0xBF; - - expect(hasUtf8Bom, true); - }); - - test('detects BOM for UTF-16LE', () { - final utf16leBom = [0xFF, 0xFE]; - - final bool hasUtf16LeBom = utf16leBom.length >= 2 && - utf16leBom[0] == 0xFF && - utf16leBom[1] == 0xFE; - - expect(hasUtf16LeBom, true); - }); - - test('detects BOM for UTF-16BE', () { - final utf16beBom = [0xFE, 0xFF]; - - final bool hasUtf16BeBom = utf16beBom.length >= 2 && - utf16beBom[0] == 0xFE && - utf16beBom[1] == 0xFF; - - expect(hasUtf16BeBom, true); - }); - - test('handles chunked transfer encoding format', () { - // 模拟分块传输编码的数据格式 - const chunkData = '5\r\nHello\r\n5\r\nWorld\r\n0\r\n\r\n'; - final bytes = ascii.encode(chunkData); - - // 简单的分块解码逻辑测试 - final result = []; - var offset = 0; - - while (offset < bytes.length) { - // 查找块大小行的结束 - var lineEnd = offset; - while (lineEnd < bytes.length - 1) { - if (bytes[lineEnd] == 13 && bytes[lineEnd + 1] == 10) break; // \r\n - lineEnd++; - } - if (lineEnd >= bytes.length - 1) break; - - // 解析块大小 - final sizeHex = String.fromCharCodes(bytes.sublist(offset, lineEnd)); - final chunkSize = int.tryParse(sizeHex, radix: 16) ?? 0; - if (chunkSize == 0) break; // 最后一个块 - - // 跳过 \r\n - offset = lineEnd + 2; - - // 读取块数据 - if (offset + chunkSize <= bytes.length) { - result.addAll(bytes.sublist(offset, offset + chunkSize)); - offset += chunkSize + 2; // 跳过块数据后的 \r\n - } else { - break; - } - } - - final decodedString = ascii.decode(result); - expect(decodedString, 'HelloWorld'); - }); - - test('validates encoding compatibility', () { - const testString = 'Hello, World!'; - - // UTF-8 应该能处理任何字符串 - expect(() => utf8.encode(testString), returnsNormally); - - // ASCII 只能处理 ASCII 字符 - expect(() => ascii.encode(testString), returnsNormally); - - // 测试非 ASCII 字符 - const nonAsciiString = 'Hello, 世界!'; - expect(() => utf8.encode(nonAsciiString), returnsNormally); - expect(() => ascii.encode(nonAsciiString), throwsA(isA())); - }); - - test('handles different content encodings', () { - const testData = 'Hello, World!'; - final originalBytes = utf8.encode(testData); - - // 测试 gzip 压缩和解压 - final gzipCompressed = gzip.encode(originalBytes); - final gzipDecompressed = gzip.decode(gzipCompressed); - expect(utf8.decode(gzipDecompressed), testData); - - // 测试 zlib 压缩和解压 - final zlibCompressed = zlib.encode(originalBytes); - final zlibDecompressed = zlib.decode(zlibCompressed); - expect(utf8.decode(zlibDecompressed), testData); - }); - - test('handles form URL encoding', () { - final formData = { - 'name': 'John Doe', - 'email': 'john@example.com', - 'message': 'Hello & welcome!', - }; - - final encodedPairs = []; - formData.forEach((key, value) { - final encodedKey = Uri.encodeComponent(key); - final encodedValue = Uri.encodeComponent(value.toString()); - encodedPairs.add('$encodedKey=$encodedValue'); - }); - - final encoded = encodedPairs.join('&'); - expect(encoded, contains('name=John%20Doe')); - expect(encoded, contains('email=john%40example.com')); - expect(encoded, contains('message=Hello%20%26%20welcome!')); - }); - - test('handles binary data encoding', () { - // 创建一些二进制数据 - final binaryData = List.generate(256, (i) => i); - - // Base64 编码 - final base64Encoded = base64Encode(binaryData); - final base64Decoded = base64Decode(base64Encoded); - expect(base64Decoded, binaryData); - - // 验证 Base64 编码的特征 - expect(base64Encoded.length % 4, 0); // Base64 长度应该是 4 的倍数 - expect(RegExp(r'^[A-Za-z0-9+/]*={0,2}$').hasMatch(base64Encoded), true); - }); - - test('handles mixed encoding scenarios', () { - // 模拟真实场景:JSON 数据包含多种字符 - final jsonData = { - 'name': 'José María', - 'description': 'Café & Restaurant 🍽️', - 'price': 29.99, - 'tags': ['food', 'café', '美食'], - }; - - final jsonString = jsonEncode(jsonData); - final utf8Bytes = utf8.encode(jsonString); - final base64Encoded = base64Encode(utf8Bytes); - - // 解码过程 - final decodedBytes = base64Decode(base64Encoded); - final decodedString = utf8.decode(decodedBytes); - final decodedJson = jsonDecode(decodedString) as Map; - - expect(decodedJson['name'], 'José María'); - expect(decodedJson['description'], 'Café & Restaurant 🍽️'); - expect(decodedJson['tags'], ['food', 'café', '美食']); - }); - }); -} diff --git a/tests/enhanced_validator_test.dart b/tests/enhanced_validator_test.dart deleted file mode 100644 index 1fdd1cb..0000000 --- a/tests/enhanced_validator_test.dart +++ /dev/null @@ -1,476 +0,0 @@ -import 'package:swagger_generator_flutter/core/error_reporter.dart'; -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:swagger_generator_flutter/validators/enhanced_validator.dart'; -import 'package:test/test.dart'; - -void main() { - group('EnhancedValidator', () { - late EnhancedValidator validator; - - setUp(() { - validator = EnhancedValidator( - includeWarnings: true, - ); - }); - - test('validates valid document successfully', () { - const document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'A test API', - servers: [ - ApiServer( - url: 'https://api.example.com', - description: 'Production server', - ), - ], - components: ApiComponents( - schemas: {}, - securitySchemes: {}, - ), - paths: { - '/users': const ApiPath( - path: '/users', - method: HttpMethod.get, - summary: 'Get users', - description: 'Retrieve all users', - operationId: 'getUsers', - tags: ['users'], - parameters: [], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - content: { - 'application/json': const ApiMediaType( - schema: {'type': 'array'}, - ), - }, - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, true); - expect(validator.errorReporter.hasErrorsOrCritical, false); - }); - - test('detects missing required fields', () { - const document = SwaggerDocument( - title: '', // Missing title - version: '', // Missing version - description: '', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: {}, // Empty paths - models: {}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, false); - expect(validator.errorReporter.hasErrorsOrCritical, true); - - final errors = validator.errorReporter.errors; - expect(errors.any((e) => e.id == 'MISSING_INFO_TITLE'), true); - expect(errors.any((e) => e.id == 'MISSING_INFO_VERSION'), true); - expect(errors.any((e) => e.id == 'EMPTY_PATHS'), true); - }); - - test('validates path parameters correctly', () { - const document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/users/{id}': const ApiPath( - path: '/users/{id}', - method: HttpMethod.get, - summary: 'Get user', - description: 'Get user by ID', - operationId: 'getUser', - tags: ['users'], - parameters: [ - // Missing path parameter declaration for 'id' - ], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, false); - - final errors = validator.errorReporter.errors; - expect(errors.any((e) => e.id == 'UNDECLARED_PATH_PARAMETER'), true); - }); - - test('validates path parameter requirements', () { - const document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/users/{id}': const ApiPath( - path: '/users/{id}', - method: HttpMethod.get, - summary: 'Get user', - description: 'Get user by ID', - operationId: 'getUser', - tags: ['users'], - parameters: [ - ApiParameter( - name: 'id', - location: ParameterLocation.path, - required: false, // Path parameters must be required - type: PropertyType.integer, - description: 'User ID', - ), - ], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, false); - - final errors = validator.errorReporter.errors; - expect(errors.any((e) => e.id == 'PATH_PARAMETER_NOT_REQUIRED'), true); - }); - - test('validates security schemes', () { - const document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test', - servers: [], - components: ApiComponents( - schemas: {}, - securitySchemes: { - 'apiKey': const ApiSecurityScheme( - type: SecuritySchemeType.apiKey, - description: 'API Key', - name: '', // Missing name - location: ApiKeyLocation.header, - ), - 'bearer': const ApiSecurityScheme( - type: SecuritySchemeType.http, - description: 'Bearer token', - scheme: '', // Missing scheme - ), - }, - ), - paths: { - '/test': const ApiPath( - path: '/test', - method: HttpMethod.get, - summary: 'Test', - description: 'Test endpoint', - operationId: 'test', - tags: [], - parameters: [], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, false); - - final errors = validator.errorReporter.errors; - expect(errors.any((e) => e.id == 'MISSING_API_KEY_NAME'), true); - expect(errors.any((e) => e.id == 'MISSING_HTTP_SCHEME'), true); - }); - - test('generates warnings for missing optional fields', () { - const document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: '', // Missing description - servers: [], // Missing servers - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/test': const ApiPath( - path: '/test', - method: HttpMethod.get, - summary: '', // Missing summary - description: 'Test endpoint', - operationId: '', // Missing operationId - tags: [], - parameters: [], - responses: { - '200': const ApiResponse( - code: '200', - description: '', // Missing response description - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, true); // Should be valid but with warnings - - final warnings = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.warning); - expect(warnings.isNotEmpty, true); - expect(warnings.any((w) => w.id == 'MISSING_INFO_DESCRIPTION'), true); - expect(warnings.any((w) => w.id == 'MISSING_SERVERS'), true); - expect(warnings.any((w) => w.id == 'MISSING_OPERATION_ID'), true); - expect(warnings.any((w) => w.id == 'MISSING_RESPONSE_DESCRIPTION'), true); - }); - - test('validates responses correctly', () { - const document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/test': const ApiPath( - path: '/test', - method: HttpMethod.get, - summary: 'Test', - description: 'Test endpoint', - operationId: 'test', - tags: [], - parameters: [], - responses: {}, // Missing responses - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, false); - - final errors = validator.errorReporter.errors; - expect(errors.any((e) => e.id == 'MISSING_OPERATION_RESPONSES'), true); - }); - - test('checks for best practices', () { - const document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test API', - servers: [ApiServer(url: 'https://api.example.com')], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/test': const ApiPath( - path: '/test', - method: HttpMethod.get, - summary: 'Test', - description: 'Test endpoint', - operationId: 'test', - tags: [], // No tags - parameters: [], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - ), - // No error responses - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, true); - - final infos = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.info); - expect(infos.any((i) => i.id == 'NO_OPERATION_TAGS'), true); - expect(infos.any((i) => i.id == 'NO_ERROR_RESPONSE'), true); - }); - - test('validates large schemas', () { - // Create a model with many properties - final properties = {}; - for (int i = 0; i < 25; i++) { - properties['property$i'] = ApiProperty( - name: 'property$i', - type: PropertyType.string, - description: 'Property $i', - required: false, - ); - } - - final largeModel = ApiModel( - name: 'LargeModel', - description: 'A model with many properties', - properties: properties, - required: [], - ); - - final document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test API', - servers: [const ApiServer(url: 'https://api.example.com')], - components: ApiComponents( - schemas: {'LargeModel': largeModel}, - securitySchemes: {}, - ), - paths: { - '/test': const ApiPath( - path: '/test', - method: HttpMethod.get, - summary: 'Test', - description: 'Test endpoint', - operationId: 'test', - tags: ['test'], - parameters: [], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {'LargeModel': largeModel}, - controllers: {}, - security: [], - ); - - final isValid = validator.validateDocument(document); - expect(isValid, true); - - final infos = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.info); - expect(infos.any((i) => i.id == 'LARGE_SCHEMA_OBJECT'), true); - }); - - test('generates detailed error report', () { - const document = SwaggerDocument( - title: '', - version: '', - description: '', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: {}, - models: {}, - controllers: {}, - security: [], - ); - - validator.validateDocument(document); - - final report = validator.errorReporter.generateReport(); - expect(report, isNotEmpty); - expect(report, contains('Error Summary')); - expect(report, contains('Missing API Title')); - expect(report, contains('Missing API Version')); - expect(report, contains('Empty Paths Object')); - }); - - test('generates JSON error report', () { - const document = SwaggerDocument( - title: '', - version: '', - description: '', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: {}, - models: {}, - controllers: {}, - security: [], - ); - - validator.validateDocument(document); - - final jsonReport = validator.errorReporter.generateJsonReport(); - expect(jsonReport, isNotEmpty); - expect(jsonReport, contains('"timestamp"')); - expect(jsonReport, contains('"summary"')); - expect(jsonReport, contains('"errors"')); - }); - - test('strict mode validation', () { - final strictValidator = EnhancedValidator( - includeWarnings: false, - ); - - const document = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: '', // Missing description - servers: [], // Missing servers - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/test': const ApiPath( - path: '/test', - method: HttpMethod.get, - summary: 'Test', - description: 'Test endpoint', - operationId: 'test', - tags: ['test'], - parameters: [], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final isValid = strictValidator.validateDocument(document); - expect(isValid, true); - - // Should have no warnings in strict mode with includeWarnings: false - final warnings = strictValidator.errorReporter - .getErrorsBySeverity(ErrorSeverity.warning); - expect(warnings.length, equals(0)); - }); - }); -} diff --git a/tests/integration_test.dart b/tests/integration_test.dart deleted file mode 100644 index 5daf131..0000000 --- a/tests/integration_test.dart +++ /dev/null @@ -1,589 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:swagger_generator_flutter/core/error_reporter.dart'; -import 'package:swagger_generator_flutter/core/performance_parser.dart'; -import 'package:swagger_generator_flutter/generators/optimized_retrofit_generator.dart'; -import 'package:swagger_generator_flutter/generators/retrofit_api_generator.dart'; -import 'package:swagger_generator_flutter/validators/enhanced_validator.dart'; -import 'package:test/test.dart'; - -void main() { - group('Integration Tests', () { - group('End-to-End Workflow', () { - test('complete workflow from JSON to generated code', () async { - // 1. 准备测试数据 - final testApiJson = { - 'openapi': '3.0.3', - 'info': { - 'title': 'Integration Test API', - 'version': '1.0.0', - 'description': 'API for integration testing', - }, - 'servers': [ - { - 'url': 'https://api.example.com', - 'description': 'Production server', - }, - ], - 'paths': { - '/users': { - 'get': { - 'summary': 'Get users', - 'operationId': 'getUsers', - 'tags': ['users'], - 'parameters': [ - { - 'name': 'page', - 'in': 'query', - 'required': false, - 'schema': {'type': 'integer', 'default': 1}, - 'description': 'Page number', - }, - { - 'name': 'limit', - 'in': 'query', - 'required': false, - 'schema': {'type': 'integer', 'default': 20}, - 'description': 'Items per page', - }, - ], - 'responses': { - '200': { - 'description': 'Success', - 'content': { - 'application/json': { - 'schema': { - 'type': 'object', - 'properties': { - 'data': { - 'type': 'array', - 'items': { - '\$ref': '#/components/schemas/User', - }, - }, - 'total': {'type': 'integer'}, - 'page': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - }, - }, - }, - }, - }, - '400': { - 'description': 'Bad request', - }, - }, - }, - 'post': { - 'summary': 'Create user', - 'operationId': 'createUser', - 'tags': ['users'], - 'requestBody': { - 'required': true, - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/CreateUserRequest', - }, - }, - }, - }, - 'responses': { - '201': { - 'description': 'User created', - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/User', - }, - }, - }, - }, - '400': { - 'description': 'Invalid input', - }, - }, - }, - }, - '/users/{id}': { - 'get': { - 'summary': 'Get user by ID', - 'operationId': 'getUserById', - 'tags': ['users'], - 'parameters': [ - { - 'name': 'id', - 'in': 'path', - 'required': true, - 'schema': {'type': 'integer'}, - 'description': 'User ID', - }, - ], - 'responses': { - '200': { - 'description': 'User found', - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/User', - }, - }, - }, - }, - '404': { - 'description': 'User not found', - }, - }, - }, - }, - '/files/upload': { - 'post': { - 'summary': 'Upload file', - 'operationId': 'uploadFile', - 'tags': ['files'], - 'requestBody': { - 'required': true, - 'content': { - 'multipart/form-data': { - 'schema': { - 'type': 'object', - 'properties': { - 'file': { - 'type': 'string', - 'format': 'binary', - }, - 'description': { - 'type': 'string', - }, - }, - 'required': ['file'], - }, - }, - }, - }, - 'responses': { - '200': { - 'description': 'File uploaded', - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/FileUploadResult', - }, - }, - }, - }, - }, - }, - }, - }, - 'components': { - 'schemas': { - 'User': { - 'type': 'object', - 'properties': { - 'id': { - 'type': 'integer', - 'format': 'int64', - }, - 'name': { - 'type': 'string', - 'maxLength': 100, - }, - 'email': { - 'type': 'string', - 'format': 'email', - }, - 'createdAt': { - 'type': 'string', - 'format': 'date-time', - }, - }, - 'required': ['id', 'name', 'email'], - }, - 'CreateUserRequest': { - 'type': 'object', - 'properties': { - 'name': { - 'type': 'string', - 'maxLength': 100, - }, - 'email': { - 'type': 'string', - 'format': 'email', - }, - }, - 'required': ['name', 'email'], - }, - 'FileUploadResult': { - 'type': 'object', - 'properties': { - 'url': { - 'type': 'string', - 'format': 'uri', - }, - 'filename': { - 'type': 'string', - }, - 'size': { - 'type': 'integer', - }, - 'contentType': { - 'type': 'string', - }, - }, - 'required': ['url', 'filename', 'size'], - }, - }, - 'securitySchemes': { - 'bearerAuth': { - 'type': 'http', - 'scheme': 'bearer', - 'bearerFormat': 'JWT', - }, - }, - }, - 'security': [ - { - 'bearerAuth': [], - }, - ], - }; - - final jsonString = jsonEncode(testApiJson); - - // 2. 解析 JSON 为 SwaggerDocument - final parser = PerformanceParser( - config: const ParseConfig( - enablePerformanceStats: true, - enableParallelParsing: false, // 禁用并行解析避免类型转换问题 - ), - ); - - final document = await parser.parseDocument(jsonString); - - // 验证解析结果 - expect(document.title, equals('Integration Test API')); - expect(document.version, equals('1.0.0')); - expect(document.paths.length, equals(3)); - expect(document.models.length, equals(3)); - expect(document.servers.length, equals(1)); - - // 检查解析性能 - final parseStats = parser.lastStats; - expect(parseStats, isNotNull); - expect(parseStats!.totalTime.inMilliseconds, lessThan(5000)); - - // 3. 验证文档 - final validator = EnhancedValidator( - includeWarnings: true, - ); - - final isValid = validator.validateDocument(document); - expect(isValid, isTrue); - - final errors = validator.errorReporter.errors; - final criticalErrors = errors - .where((e) => - e.severity == ErrorSeverity.error || - e.severity == ErrorSeverity.critical) - .toList(); - - expect(criticalErrors, isEmpty, - reason: - 'Document should not have critical errors: ${criticalErrors.map((e) => e.title).join(", ")}'); - - // 4. 生成 Retrofit API 代码 - final retrofitGenerator = RetrofitApiGenerator( - className: 'IntegrationTestApi', - splitByTags: true, - ); - - final retrofitCode = retrofitGenerator.generateFromDocument(document); - - // 验证生成的代码 - expect(retrofitCode, isNotEmpty); - expect(retrofitCode, contains('IntegrationTestApi')); - expect(retrofitCode, contains('@GET(\'/users\')')); - expect(retrofitCode, contains('@POST(\'/users\')')); - expect(retrofitCode, contains('@GET(\'/users/{id}\')')); - expect(retrofitCode, contains('@POST(\'/files/upload\')')); - expect(retrofitCode, contains('@Path(\'id\')')); - expect(retrofitCode, contains('@Query(\'page\')')); - expect(retrofitCode, contains('@MultiPart()')); - - // 5. 生成优化的 API 代码 - final optimizedGenerator = OptimizedRetrofitGenerator( - className: 'OptimizedIntegrationApi', - generateModularApis: true, - generateBaseResult: true, - generatePagination: true, - generateFileUpload: true, - ); - - final optimizedCode = optimizedGenerator.generateFromDocument(document); - - // 验证优化代码 - expect(optimizedCode, isNotEmpty); - expect(optimizedCode, contains('class BaseResult')); - expect(optimizedCode, contains('class BasePageResult')); - expect(optimizedCode, contains('class FileUploadRequest')); - expect(optimizedCode, contains('class ApiUtils')); - expect(optimizedCode, contains('UsersApi')); - expect(optimizedCode, contains('FilesApi')); - - // 6. 性能验证 - print('Integration Test Performance Summary:'); - print(' Parse Time: ${parseStats.totalTime.inMilliseconds}ms'); - print( - ' Document Size: ${(jsonString.length / 1024).toStringAsFixed(2)}KB'); - print(' Paths Parsed: ${parseStats.pathCount}'); - print(' Schemas Parsed: ${parseStats.schemaCount}'); - print( - ' Retrofit Code Size: ${(retrofitCode.length / 1024).toStringAsFixed(2)}KB'); - print( - ' Optimized Code Size: ${(optimizedCode.length / 1024).toStringAsFixed(2)}KB'); - - // 验证性能指标 - expect( - parseStats.totalTime.inMilliseconds, lessThan(2000)); // 解析应在2秒内完成 - expect(retrofitCode.length, greaterThan(1000)); // 应生成足够的代码 - expect(optimizedCode.length, - greaterThan(retrofitCode.length)); // 优化版本应该更丰富 - }); - - test('handles real project swagger.json', () async { - final file = File('swagger.json'); - if (!file.existsSync()) { - print( - 'swagger.json not found, skipping real project integration test'); - return; - } - - final jsonString = await file.readAsString(); - print( - 'Real project swagger.json size: ${(jsonString.length / 1024).toStringAsFixed(2)}KB'); - - // 解析 - final parser = PerformanceParser( - config: const ParseConfig( - enablePerformanceStats: true, - enableParallelParsing: false, // 禁用并行解析 - maxConcurrency: 4, - ), - ); - - final parseStopwatch = Stopwatch()..start(); - final document = await parser.parseDocument(jsonString); - parseStopwatch.stop(); - - expect(document, isNotNull); - expect(document.paths.isNotEmpty, isTrue); - - print('Real project parsing results:'); - print(' Parse Time: ${parseStopwatch.elapsedMilliseconds}ms'); - print(' Paths: ${document.paths.length}'); - print(' Models: ${document.models.length}'); - print(' Servers: ${document.servers.length}'); - - // 验证 - final validator = EnhancedValidator(includeWarnings: false); - final isValid = validator.validateDocument(document); - - final errors = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.error); - final criticalErrors = - validator.errorReporter.getErrorsBySeverity(ErrorSeverity.critical); - - print('Validation results:'); - print(' Valid: $isValid'); - print(' Errors: ${errors.length}'); - print(' Critical: ${criticalErrors.length}'); - - // 生成代码 - final generator = OptimizedRetrofitGenerator( - className: 'OAMobileApiService', - generateModularApis: true, - generateBaseResult: true, - generatePagination: true, - generateFileUpload: true, - ); - - final genStopwatch = Stopwatch()..start(); - final generatedCode = generator.generateFromDocument(document); - genStopwatch.stop(); - - expect(generatedCode, isNotEmpty); - expect(generatedCode, contains('OAMobileApiService')); - - print('Code generation results:'); - print(' Generation Time: ${genStopwatch.elapsedMilliseconds}ms'); - print( - ' Generated Code Size: ${(generatedCode.length / 1024).toStringAsFixed(2)}KB'); - print(' Generated Lines: ${generatedCode.split('\n').length}'); - - // 性能要求 - expect(parseStopwatch.elapsedMilliseconds, lessThan(15000)); // 15秒内解析完成 - expect(genStopwatch.elapsedMilliseconds, lessThan(10000)); // 10秒内生成完成 - expect(generatedCode.length, greaterThan(5000)); // 至少生成5KB代码 - }); - }); - - group('Error Handling Integration', () { - test('handles malformed JSON gracefully', () async { - const malformedJson = - '{"openapi": "3.0.3", "info": {"title": "Test"'; // 缺少闭合括号 - - final parser = PerformanceParser(); - - expect(() => parser.parseDocument(malformedJson), - throwsA(isA())); - }); - - test('handles invalid OpenAPI document', () async { - final invalidDoc = { - 'openapi': '3.0.3', - 'info': { - 'title': 'Invalid API', - // 缺少 version - }, - 'paths': {}, // 空路径 - }; - - final jsonString = jsonEncode(invalidDoc); - final parser = PerformanceParser(); - - expect(() => parser.parseDocument(jsonString), - throwsA(isA())); - }); - - test('validation catches common errors', () async { - final problematicDoc = { - 'openapi': '3.0.3', - 'info': { - 'title': 'Problematic API', - 'version': '1.0.0', - }, - 'paths': { - '/users/{id}': { - 'get': { - 'summary': 'Get user', - 'responses': { - '200': { - 'description': 'Success', - }, - }, - // 缺少路径参数声明 - }, - }, - }, - }; - - final jsonString = jsonEncode(problematicDoc); - final parser = PerformanceParser(); - final document = await parser.parseDocument(jsonString); - - final validator = EnhancedValidator(); - final isValid = validator.validateDocument(document); - - expect(isValid, isFalse); - - final errors = validator.errorReporter.errors; - expect(errors.any((e) => e.id == 'UNDECLARED_PATH_PARAMETER'), isTrue); - }); - }); - - group('Performance Integration', () { - test('handles large documents efficiently', () async { - // 创建大型文档 - final paths = {}; - final schemas = {}; - - for (int i = 0; i < 200; i++) { - paths['/resource$i'] = { - 'get': { - 'summary': 'Get resource $i', - 'operationId': 'getResource$i', - 'tags': ['resources'], - 'responses': { - '200': { - 'description': 'Success', - 'content': { - 'application/json': { - 'schema': { - '\$ref': '#/components/schemas/Resource$i', - }, - }, - }, - }, - }, - }, - }; - - schemas['Resource$i'] = { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - 'value$i': {'type': 'string'}, - }, - 'required': ['id', 'name'], - }; - } - - final largeDoc = { - 'openapi': '3.0.3', - 'info': { - 'title': 'Large API', - 'version': '1.0.0', - }, - 'paths': paths, - 'components': { - 'schemas': schemas, - }, - }; - - final jsonString = jsonEncode(largeDoc); - print( - 'Large document size: ${(jsonString.length / 1024).toStringAsFixed(2)}KB'); - - // 测试解析性能 - final parser = PerformanceParser( - config: const ParseConfig( - enablePerformanceStats: true, - enableParallelParsing: false, // 禁用并行解析 - maxConcurrency: 4, - ), - ); - - final parseStopwatch = Stopwatch()..start(); - final document = await parser.parseDocument(jsonString); - parseStopwatch.stop(); - - expect(document.paths.length, greaterThan(100)); - expect(document.models.length, greaterThan(100)); - expect(parseStopwatch.elapsedMilliseconds, lessThan(10000)); // 10秒内完成 - - // 测试生成性能 - final generator = OptimizedRetrofitGenerator( - generateModularApis: true, - ); - - final genStopwatch = Stopwatch()..start(); - final generatedCode = generator.generateFromDocument(document); - genStopwatch.stop(); - - expect(generatedCode.length, greaterThan(10000)); // 至少10KB代码 - expect(genStopwatch.elapsedMilliseconds, lessThan(15000)); // 15秒内完成 - - print('Large document performance:'); - print(' Parse Time: ${parseStopwatch.elapsedMilliseconds}ms'); - print(' Generation Time: ${genStopwatch.elapsedMilliseconds}ms'); - print(' Paths: ${document.paths.length}'); - print(' Models: ${document.models.length}'); - print( - ' Generated Code: ${(generatedCode.length / 1024).toStringAsFixed(2)}KB'); - }); - }); - }); -} diff --git a/tests/media_type_test.dart b/tests/media_type_test.dart deleted file mode 100644 index 3fbdc1a..0000000 --- a/tests/media_type_test.dart +++ /dev/null @@ -1,451 +0,0 @@ -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:test/test.dart'; - -void main() { - group('MediaType Enum', () { - test('converts media type to string', () { - expect(MediaType.json.value, 'application/json'); - expect(MediaType.xml.value, 'application/xml'); - expect(MediaType.multipartFormData.value, 'multipart/form-data'); - expect( - MediaType.formUrlEncoded.value, 'application/x-www-form-urlencoded'); - expect(MediaType.textPlain.value, 'text/plain'); - expect(MediaType.textHtml.value, 'text/html'); - expect(MediaType.textCsv.value, 'text/csv'); - expect( - MediaType.applicationOctetStream.value, 'application/octet-stream'); - expect(MediaType.applicationPdf.value, 'application/pdf'); - expect(MediaType.imagePng.value, 'image/png'); - expect(MediaType.imageJpeg.value, 'image/jpeg'); - expect(MediaType.imageGif.value, 'image/gif'); - expect(MediaType.imageSvg.value, 'image/svg+xml'); - expect(MediaType.audioMp3.value, 'audio/mpeg'); - expect(MediaType.videoMp4.value, 'video/mp4'); - }); - - test('converts string to media type', () { - expect(MediaTypeExtension.fromString('application/json'), MediaType.json); - expect(MediaTypeExtension.fromString('application/xml'), MediaType.xml); - expect(MediaTypeExtension.fromString('text/xml'), MediaType.xml); - expect(MediaTypeExtension.fromString('multipart/form-data'), - MediaType.multipartFormData); - expect(MediaTypeExtension.fromString('application/x-www-form-urlencoded'), - MediaType.formUrlEncoded); - expect(MediaTypeExtension.fromString('text/plain'), MediaType.textPlain); - expect(MediaTypeExtension.fromString('text/html'), MediaType.textHtml); - expect(MediaTypeExtension.fromString('text/csv'), MediaType.textCsv); - expect(MediaTypeExtension.fromString('application/octet-stream'), - MediaType.applicationOctetStream); - expect(MediaTypeExtension.fromString('application/pdf'), - MediaType.applicationPdf); - expect(MediaTypeExtension.fromString('image/png'), MediaType.imagePng); - expect(MediaTypeExtension.fromString('image/jpeg'), MediaType.imageJpeg); - expect(MediaTypeExtension.fromString('image/jpg'), MediaType.imageJpeg); - expect(MediaTypeExtension.fromString('image/gif'), MediaType.imageGif); - expect( - MediaTypeExtension.fromString('image/svg+xml'), MediaType.imageSvg); - expect(MediaTypeExtension.fromString('audio/mpeg'), MediaType.audioMp3); - expect(MediaTypeExtension.fromString('audio/mp3'), MediaType.audioMp3); - expect(MediaTypeExtension.fromString('video/mp4'), MediaType.videoMp4); - expect(MediaTypeExtension.fromString('unknown/type'), MediaType.custom); - }); - - test('checks text types', () { - expect(MediaType.json.isText, true); - expect(MediaType.xml.isText, true); - expect(MediaType.textPlain.isText, true); - expect(MediaType.textHtml.isText, true); - expect(MediaType.textCsv.isText, true); - expect(MediaType.imagePng.isText, false); - expect(MediaType.applicationOctetStream.isText, false); - }); - - test('checks binary types', () { - expect(MediaType.applicationOctetStream.isBinary, true); - expect(MediaType.applicationPdf.isBinary, true); - expect(MediaType.imagePng.isBinary, true); - expect(MediaType.imageJpeg.isBinary, true); - expect(MediaType.imageGif.isBinary, true); - expect(MediaType.audioMp3.isBinary, true); - expect(MediaType.videoMp4.isBinary, true); - expect(MediaType.json.isBinary, false); - expect(MediaType.textPlain.isBinary, false); - }); - - test('checks form types', () { - expect(MediaType.formData.isForm, true); - expect(MediaType.formUrlEncoded.isForm, true); - expect(MediaType.multipartFormData.isForm, true); - expect(MediaType.json.isForm, false); - expect(MediaType.xml.isForm, false); - }); - - test('checks image types', () { - expect(MediaType.imagePng.isImage, true); - expect(MediaType.imageJpeg.isImage, true); - expect(MediaType.imageGif.isImage, true); - expect(MediaType.imageSvg.isImage, true); - expect(MediaType.json.isImage, false); - expect(MediaType.applicationPdf.isImage, false); - }); - - test('checks audio types', () { - expect(MediaType.audioMp3.isAudio, true); - expect(MediaType.json.isAudio, false); - expect(MediaType.videoMp4.isAudio, false); - }); - - test('checks video types', () { - expect(MediaType.videoMp4.isVideo, true); - expect(MediaType.json.isVideo, false); - expect(MediaType.audioMp3.isVideo, false); - }); - - test('gets correct Dart types', () { - expect(MediaType.json.dartType, 'Map'); - expect(MediaType.xml.dartType, 'String'); - expect(MediaType.multipartFormData.dartType, 'FormData'); - expect(MediaType.formUrlEncoded.dartType, 'FormData'); - expect(MediaType.textPlain.dartType, 'String'); - expect(MediaType.textHtml.dartType, 'String'); - expect(MediaType.textCsv.dartType, 'String'); - expect(MediaType.applicationOctetStream.dartType, 'List'); - expect(MediaType.applicationPdf.dartType, 'List'); - expect(MediaType.imagePng.dartType, 'List'); - expect(MediaType.imageJpeg.dartType, 'List'); - expect(MediaType.imageGif.dartType, 'List'); - expect(MediaType.imageSvg.dartType, 'String'); - expect(MediaType.audioMp3.dartType, 'List'); - expect(MediaType.videoMp4.dartType, 'List'); - expect(MediaType.custom.dartType, 'dynamic'); - }); - }); - - group('ApiMediaType', () { - test('creates ApiMediaType with JSON content type', () { - final json = { - 'schema': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - }, - }, - 'example': { - 'id': 1, - 'name': 'Test', - }, - }; - - final mediaType = ApiMediaType.fromJson(json, 'application/json'); - - expect(mediaType.mediaType, MediaType.json); - expect(mediaType.rawMediaType, 'application/json'); - expect(mediaType.isJson, true); - expect(mediaType.isXml, false); - expect(mediaType.isForm, false); - expect(mediaType.isBinary, false); - expect(mediaType.isText, true); - expect(mediaType.dartType, 'Map'); - }); - - test('creates ApiMediaType with XML content type', () { - final json = { - 'schema': { - 'type': 'string', - }, - 'example': '1Test', - }; - - final mediaType = ApiMediaType.fromJson(json, 'application/xml'); - - expect(mediaType.mediaType, MediaType.xml); - expect(mediaType.rawMediaType, 'application/xml'); - expect(mediaType.isJson, false); - expect(mediaType.isXml, true); - expect(mediaType.isForm, false); - expect(mediaType.isBinary, false); - expect(mediaType.isText, true); - expect(mediaType.dartType, 'String'); - }); - - test('creates ApiMediaType with form data content type', () { - final json = { - 'schema': { - 'type': 'object', - 'properties': { - 'file': {'type': 'string', 'format': 'binary'}, - 'name': {'type': 'string'}, - }, - }, - 'encoding': { - 'file': { - 'contentType': 'image/png', - }, - }, - }; - - final mediaType = ApiMediaType.fromJson(json, 'multipart/form-data'); - - expect(mediaType.mediaType, MediaType.multipartFormData); - expect(mediaType.rawMediaType, 'multipart/form-data'); - expect(mediaType.isJson, false); - expect(mediaType.isXml, false); - expect(mediaType.isForm, true); - expect(mediaType.isFileUpload, true); - expect(mediaType.isBinary, false); - expect(mediaType.isText, false); - expect(mediaType.dartType, 'FormData'); - expect(mediaType.encoding.length, 1); - expect(mediaType.encoding['file'], isNotNull); - }); - - test('creates ApiMediaType with binary content type', () { - final json = { - 'schema': { - 'type': 'string', - 'format': 'binary', - }, - }; - - final mediaType = ApiMediaType.fromJson(json, 'application/octet-stream'); - - expect(mediaType.mediaType, MediaType.applicationOctetStream); - expect(mediaType.rawMediaType, 'application/octet-stream'); - expect(mediaType.isJson, false); - expect(mediaType.isXml, false); - expect(mediaType.isForm, false); - expect(mediaType.isBinary, true); - expect(mediaType.isText, false); - expect(mediaType.dartType, 'List'); - }); - - test('creates ApiMediaType with image content type', () { - final json = { - 'schema': { - 'type': 'string', - 'format': 'binary', - }, - }; - - final mediaType = ApiMediaType.fromJson(json, 'image/png'); - - expect(mediaType.mediaType, MediaType.imagePng); - expect(mediaType.rawMediaType, 'image/png'); - expect(mediaType.isImage, true); - expect(mediaType.isBinary, true); - expect(mediaType.dartType, 'List'); - }); - - test('creates ApiMediaType with custom content type', () { - final json = { - 'schema': { - 'type': 'string', - }, - }; - - final mediaType = ApiMediaType.fromJson(json, 'application/vnd.api+json'); - - expect(mediaType.mediaType, MediaType.custom); - expect(mediaType.rawMediaType, 'application/vnd.api+json'); - expect(mediaType.dartType, 'dynamic'); - }); - - test('creates ApiMediaType with default content type when none provided', - () { - final json = { - 'schema': { - 'type': 'object', - }, - }; - - final mediaType = ApiMediaType.fromJson(json); - - expect(mediaType.mediaType, MediaType.json); - expect(mediaType.rawMediaType, 'application/json'); - expect(mediaType.isJson, true); - }); - - test('creates ApiMediaType with examples', () { - final json = { - 'schema': { - 'type': 'object', - }, - 'examples': { - 'user1': { - 'summary': 'User example 1', - 'value': {'id': 1, 'name': 'John'}, - }, - 'user2': { - 'summary': 'User example 2', - 'value': {'id': 2, 'name': 'Jane'}, - }, - }, - }; - - final mediaType = ApiMediaType.fromJson(json, 'application/json'); - - expect(mediaType.examples.length, 2); - expect(mediaType.examples['user1'], isNotNull); - expect(mediaType.examples['user2'], isNotNull); - expect(mediaType.examples['user1']?.summary, 'User example 1'); - }); - }); - - group('File Upload Support', () { - test('creates ApiEncoding with file content type', () { - final json = { - 'contentType': 'image/png', - 'headers': { - 'X-Custom-Header': { - 'description': 'Custom header for file upload', - 'required': true, - }, - }, - }; - - final encoding = ApiEncoding.fromJson(json); - - expect(encoding.contentType, 'image/png'); - expect(encoding.isFile, true); - expect(encoding.isImage, true); - expect(encoding.isAudio, false); - expect(encoding.isVideo, false); - expect(encoding.hasHeaders, true); - expect(encoding.headers.length, 1); - expect(encoding.headers['X-Custom-Header'], isNotNull); - }); - - test('detects different file types in ApiEncoding', () { - final imageEncoding = ApiEncoding.fromJson({'contentType': 'image/jpeg'}); - expect(imageEncoding.isFile, true); - expect(imageEncoding.isImage, true); - expect(imageEncoding.isAudio, false); - expect(imageEncoding.isVideo, false); - - final audioEncoding = ApiEncoding.fromJson({'contentType': 'audio/mpeg'}); - expect(audioEncoding.isFile, true); - expect(audioEncoding.isImage, false); - expect(audioEncoding.isAudio, true); - expect(audioEncoding.isVideo, false); - - final videoEncoding = ApiEncoding.fromJson({'contentType': 'video/mp4'}); - expect(videoEncoding.isFile, true); - expect(videoEncoding.isImage, false); - expect(videoEncoding.isAudio, false); - expect(videoEncoding.isVideo, true); - - final binaryEncoding = - ApiEncoding.fromJson({'contentType': 'application/octet-stream'}); - expect(binaryEncoding.isFile, true); - expect(binaryEncoding.isImage, false); - expect(binaryEncoding.isAudio, false); - expect(binaryEncoding.isVideo, false); - - final textEncoding = ApiEncoding.fromJson({'contentType': 'text/plain'}); - expect(textEncoding.isFile, false); - expect(textEncoding.isImage, false); - expect(textEncoding.isAudio, false); - expect(textEncoding.isVideo, false); - }); - - test('creates ApiMediaType with file upload encoding', () { - final json = { - 'schema': { - 'type': 'object', - 'properties': { - 'avatar': {'type': 'string', 'format': 'binary'}, - 'name': {'type': 'string'}, - 'documents': { - 'type': 'array', - 'items': {'type': 'string', 'format': 'binary'}, - }, - }, - }, - 'encoding': { - 'avatar': { - 'contentType': 'image/*', - 'headers': { - 'X-File-Type': { - 'description': 'File type validation', - 'required': false, - }, - }, - }, - 'documents': { - 'contentType': 'application/pdf', - 'explode': true, - }, - }, - }; - - final mediaType = ApiMediaType.fromJson(json, 'multipart/form-data'); - - expect(mediaType.isFileUpload, true); - expect(mediaType.encoding.length, 2); - expect(mediaType.encoding['avatar'], isNotNull); - expect(mediaType.encoding['documents'], isNotNull); - expect(mediaType.encoding['avatar']?.contentType, 'image/*'); - expect(mediaType.encoding['documents']?.contentType, 'application/pdf'); - expect(mediaType.encoding['documents']?.explode, true); - }); - - test('handles complex file upload scenarios', () { - final json = { - 'schema': { - 'type': 'object', - 'properties': { - 'profileImage': {'type': 'string', 'format': 'binary'}, - 'thumbnails': { - 'type': 'array', - 'items': {'type': 'string', 'format': 'binary'}, - }, - 'metadata': { - 'type': 'object', - 'properties': { - 'title': {'type': 'string'}, - 'description': {'type': 'string'}, - }, - }, - }, - 'required': ['profileImage', 'metadata'], - }, - 'encoding': { - 'profileImage': { - 'contentType': 'image/png, image/jpeg', - 'headers': { - 'X-Image-Quality': { - 'description': 'Image quality setting', - 'schema': {'type': 'integer', 'minimum': 1, 'maximum': 100}, - }, - }, - }, - 'thumbnails': { - 'contentType': 'image/png', - 'style': 'form', - 'explode': true, - }, - 'metadata': { - 'contentType': 'application/json', - }, - }, - }; - - final mediaType = ApiMediaType.fromJson(json, 'multipart/form-data'); - - expect(mediaType.isFileUpload, true); - expect(mediaType.encoding.length, 3); - - final profileImageEncoding = mediaType.encoding['profileImage']!; - expect(profileImageEncoding.contentType, 'image/png, image/jpeg'); - expect(profileImageEncoding.hasHeaders, true); - - final thumbnailsEncoding = mediaType.encoding['thumbnails']!; - expect(thumbnailsEncoding.explode, true); - expect(thumbnailsEncoding.style, 'form'); - - final metadataEncoding = mediaType.encoding['metadata']!; - expect(metadataEncoding.contentType, 'application/json'); - }); - }); -} diff --git a/tests/models_test.dart b/tests/models_test.dart index 64bb797..372c3d1 100644 --- a/tests/models_test.dart +++ b/tests/models_test.dart @@ -1,6 +1,7 @@ -import 'package:swagger_generator_flutter/core/models.dart'; import 'package:test/test.dart'; +import 'package:swagger_generator_flutter/core/models.dart'; + void main() { group('ApiPath', () { test('creates ApiPath with required fields', () { @@ -41,11 +42,8 @@ void main() { '200': const ApiResponse( code: '200', description: 'Success', - content: { - 'application/json': ApiMediaType( - schema: {'type': 'object'}, - ), - }, + schema: {'type': 'object'}, + content: null, ), }; @@ -53,9 +51,9 @@ void main() { description: 'User data', required: true, content: { - 'application/json': ApiMediaType( - schema: {'type': 'object'}, - ), + 'application/json': { + 'schema': {'type': 'object'} + } }, ); @@ -141,61 +139,42 @@ void main() { const response = ApiResponse( code: '200', description: 'Success', + schema: null, + content: null, ); expect(response.code, '200'); expect(response.description, 'Success'); - expect(response.content, isEmpty); - expect(response.headers, isEmpty); - expect(response.links, isEmpty); + expect(response.schema, isNull); + expect(response.content, isNull); }); - test('creates ApiResponse with content', () { - final content = { - 'application/json': const ApiMediaType( - schema: { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - }, - }, - ), + test('creates ApiResponse with schema', () { + final schema = { + 'type': 'object', + 'properties': { + 'id': {'type': 'integer'}, + 'name': {'type': 'string'}, + }, }; final response = ApiResponse( code: '200', description: 'Success', - content: content, + schema: schema, + content: null, ); - expect(response.content.length, 1); - expect(response.content['application/json']?.schema?['type'], 'object'); - expect(response.supportedMediaTypes, contains('application/json')); - expect(response.supportsMediaType('application/json'), true); - expect(response.hasHeaders, false); - expect(response.hasLinks, false); + expect(response.schema, equals(schema)); }); test('creates ApiResponse from JSON', () { final json = { 'description': 'Success', - 'headers': { - 'X-Rate-Limit': { - 'description': 'Rate limit', - 'schema': {'type': 'integer'}, - }, - }, + 'schema': {'type': 'object'}, 'content': { 'application/json': { 'schema': {'type': 'object'}, - 'example': {'id': 1, 'name': 'test'}, - }, - }, - 'links': { - 'GetUserByName': { - 'operationId': 'getUserByName', - 'parameters': {'username': '\$response.body#/username'}, }, }, }; @@ -204,14 +183,8 @@ void main() { expect(response.code, '200'); expect(response.description, 'Success'); - expect(response.content.length, 1); - expect(response.content['application/json']?.schema?['type'], 'object'); - expect(response.headers.length, 1); - expect(response.headers['X-Rate-Limit']?.description, 'Rate limit'); - expect(response.links.length, 1); - expect(response.links['GetUserByName']?.operationId, 'getUserByName'); - expect(response.hasHeaders, true); - expect(response.hasLinks, true); + expect(response.schema, isNotNull); + expect(response.content, isNotNull); }); }); @@ -220,24 +193,25 @@ void main() { const requestBody = ApiRequestBody( description: 'User data', required: true, + content: null, ); expect(requestBody.description, 'User data'); expect(requestBody.required, true); - expect(requestBody.content, isEmpty); + expect(requestBody.content, isNull); }); test('creates ApiRequestBody with content', () { final content = { - 'application/json': const ApiMediaType( - schema: { + 'application/json': { + 'schema': { 'type': 'object', 'properties': { 'name': {'type': 'string'}, 'email': {'type': 'string'}, }, }, - ), + }, }; final requestBody = ApiRequestBody( @@ -246,11 +220,7 @@ void main() { content: content, ); - expect(requestBody.content.length, 1); - expect( - requestBody.content['application/json']?.schema?['type'], 'object'); - expect(requestBody.supportedMediaTypes, contains('application/json')); - expect(requestBody.supportsMediaType('application/json'), true); + expect(requestBody.content, equals(content)); }); test('creates ApiRequestBody from JSON', () { @@ -468,7 +438,7 @@ void main() { expect(PropertyType.fromString('boolean'), PropertyType.boolean); expect(PropertyType.fromString('array'), PropertyType.array); expect(PropertyType.fromString('object'), PropertyType.object); - expect(PropertyType.fromString('unknown'), PropertyType.unknown); + expect(PropertyType.fromString('unknown'), PropertyType.string); }); test('gets PropertyType value', () { @@ -531,22 +501,11 @@ void main() { title: 'Test API', version: '1.0.0', description: 'Test API description', - servers: [ - ApiServer( - url: 'https://api.example.com/api', - description: 'Production server', - ), - ], - components: ApiComponents( - schemas: { - 'User': ApiModel( - name: 'User', - description: 'User model', - properties: {}, - required: [], - ), - }, - ), + host: 'api.example.com', + basePath: '/api', + schemes: ['https'], + consumes: ['application/json'], + produces: ['application/json'], paths: {}, models: {}, controllers: {}, @@ -555,11 +514,11 @@ void main() { expect(document.title, 'Test API'); expect(document.version, '1.0.0'); expect(document.description, 'Test API description'); - expect(document.servers.length, 1); - expect(document.servers.first.url, 'https://api.example.com/api'); - expect(document.servers.first.description, 'Production server'); - expect(document.components.schemas.length, 1); - expect(document.components.schemas['User']?.name, 'User'); + expect(document.host, 'api.example.com'); + expect(document.basePath, '/api'); + expect(document.schemes, ['https']); + expect(document.consumes, ['application/json']); + expect(document.produces, ['application/json']); expect(document.paths, isEmpty); expect(document.models, isEmpty); expect(document.controllers, isEmpty); @@ -572,51 +531,11 @@ void main() { 'version': '1.0.0', 'description': 'Test API description', }, - 'servers': [ - { - 'url': 'https://api.example.com/api', - 'description': 'Production server', - 'variables': { - 'version': { - 'default': 'v1', - 'enum': ['v1', 'v2'], - 'description': 'API version', - }, - }, - }, - { - 'url': 'http://localhost:3000', - 'description': 'Development server', - }, - ], - 'components': { - 'schemas': { - 'User': { - 'type': 'object', - 'description': 'User model', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - }, - 'required': ['id', 'name'], - }, - }, - 'responses': { - 'NotFound': { - 'description': 'Resource not found', - 'content': { - 'application/json': { - 'schema': { - 'type': 'object', - 'properties': { - 'error': {'type': 'string'}, - }, - }, - }, - }, - }, - }, - }, + 'host': 'api.example.com', + 'basePath': '/api', + 'schemes': ['https', 'http'], + 'consumes': ['application/json', 'application/xml'], + 'produces': ['application/json', 'text/plain'], }; final document = SwaggerDocument.fromJson(json); @@ -624,75 +543,11 @@ void main() { expect(document.title, 'Test API'); expect(document.version, '1.0.0'); expect(document.description, 'Test API description'); - expect(document.servers.length, 2); - expect(document.servers.first.url, 'https://api.example.com/api'); - expect(document.servers.first.description, 'Production server'); - expect(document.servers.first.variables.length, 1); - expect(document.servers.first.variables['version']?.defaultValue, 'v1'); - expect(document.components.schemas.length, 1); - expect(document.components.schemas['User']?.name, 'User'); - expect(document.components.responses.length, 1); - expect(document.components.responses['NotFound']?.description, - 'Resource not found'); - }); - - test('creates SwaggerDocument with composition schemas', () { - final json = { - 'info': { - 'title': 'Test API', - 'version': '1.0.0', - }, - 'components': { - 'schemas': { - 'Pet': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'type': {'type': 'string'}, - }, - 'required': ['name'], - }, - 'Dog': { - 'allOf': [ - {'\$ref': '#/components/schemas/Pet'}, - { - 'type': 'object', - 'properties': { - 'breed': {'type': 'string'}, - }, - }, - ], - }, - 'Animal': { - 'oneOf': [ - {'\$ref': '#/components/schemas/Pet'}, - { - 'type': 'object', - 'properties': { - 'species': {'type': 'string'}, - }, - }, - ], - }, - }, - }, - }; - - final document = SwaggerDocument.fromJson(json); - - expect(document.components.schemas.length, 3); - - // 测试 allOf 组合 - final dogModel = document.components.schemas['Dog']; - expect(dogModel?.isAllOf, true); - expect(dogModel?.allOf.length, 2); - expect(dogModel?.allOf.first.reference, 'Pet'); - - // 测试 oneOf 组合 - final animalModel = document.components.schemas['Animal']; - expect(animalModel?.isOneOf, true); - expect(animalModel?.oneOf.length, 2); - expect(animalModel?.oneOf.first.reference, 'Pet'); + expect(document.host, 'api.example.com'); + expect(document.basePath, '/api'); + expect(document.schemes, ['https', 'http']); + expect(document.consumes, ['application/json', 'application/xml']); + expect(document.produces, ['application/json', 'text/plain']); }); test('creates SwaggerDocument from JSON with minimal fields', () { @@ -703,9 +558,11 @@ void main() { expect(document.title, 'API'); expect(document.version, '1.0.0'); expect(document.description, ''); - expect(document.servers.length, 1); - expect(document.servers.first.url, '/'); - expect(document.servers.first.description, ''); + expect(document.host, ''); + expect(document.basePath, ''); + expect(document.schemes, ['https']); + expect(document.consumes, ['application/json']); + expect(document.produces, ['application/json']); }); test('creates SwaggerDocument from JSON with null info', () { @@ -1030,11 +887,8 @@ void main() { expect(response.code, '200'); expect(response.description, ''); - expect(response.content, isEmpty); - expect(response.headers, isEmpty); - expect(response.links, isEmpty); - expect(response.hasHeaders, false); - expect(response.hasLinks, false); + expect(response.schema, isNull); + expect(response.content, isNull); }); test('ApiRequestBody fromJson handles missing fields gracefully', () { @@ -1044,13 +898,13 @@ void main() { expect(requestBody.description, ''); expect(requestBody.required, false); - expect(requestBody.content, isEmpty); + expect(requestBody.content, isNull); }); test('PropertyType fromString handles unknown types', () { - expect(PropertyType.fromString('unknown'), PropertyType.unknown); - expect(PropertyType.fromString(''), PropertyType.unknown); - expect(PropertyType.fromString('CUSTOM_TYPE'), PropertyType.unknown); + expect(PropertyType.fromString('unknown'), PropertyType.string); + expect(PropertyType.fromString(''), PropertyType.string); + expect(PropertyType.fromString('CUSTOM_TYPE'), PropertyType.string); }); test('ParameterLocation fromString handles unknown locations', () { @@ -1066,522 +920,4 @@ void main() { expect(HttpMethod.fromString('CUSTOM_METHOD'), HttpMethod.get); }); }); - - group('ApiSchema', () { - test('creates ApiSchema with basic properties', () { - const schema = ApiSchema( - type: 'object', - description: 'Test schema', - properties: { - 'name': ApiProperty( - name: 'name', - type: PropertyType.string, - description: 'Name property', - required: true, - ), - }, - required: ['name'], - ); - - expect(schema.type, 'object'); - expect(schema.description, 'Test schema'); - expect(schema.properties.length, 1); - expect(schema.required, ['name']); - expect(schema.isObject, true); - expect(schema.isComposition, false); - }); - - test('creates ApiSchema with composition patterns', () { - const schema = ApiSchema( - allOf: [ - ApiSchema( - reference: 'BaseModel', - ), - ApiSchema( - type: 'object', - properties: { - 'extra': ApiProperty( - name: 'extra', - type: PropertyType.string, - description: 'Extra property', - required: false, - ), - }, - ), - ], - ); - - expect(schema.isComposition, true); - expect(schema.isAllOf, true); - expect(schema.allOf.length, 2); - expect(schema.allOf.first.isReference, true); - expect(schema.allOf.first.reference, 'BaseModel'); - }); - - test('creates ApiSchema from JSON with allOf', () { - final json = { - 'allOf': [ - {'\$ref': '#/components/schemas/Pet'}, - { - 'type': 'object', - 'properties': { - 'breed': {'type': 'string'}, - }, - 'required': ['breed'], - }, - ], - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.isComposition, true); - expect(schema.isAllOf, true); - expect(schema.allOf.length, 2); - expect(schema.allOf.first.reference, 'Pet'); - expect(schema.allOf.last.type, 'object'); - expect(schema.allOf.last.properties.length, 1); - expect(schema.allOf.last.required, ['breed']); - }); - - test('creates ApiSchema from JSON with oneOf', () { - final json = { - 'oneOf': [ - {'\$ref': '#/components/schemas/Cat'}, - {'\$ref': '#/components/schemas/Dog'}, - ], - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.isComposition, true); - expect(schema.isOneOf, true); - expect(schema.oneOf.length, 2); - expect(schema.oneOf.first.reference, 'Cat'); - expect(schema.oneOf.last.reference, 'Dog'); - }); - - test('creates ApiSchema from JSON with validation constraints', () { - final json = { - 'type': 'string', - 'minLength': 1, - 'maxLength': 100, - 'pattern': '^[a-zA-Z]+\$', - 'example': 'example', - 'nullable': true, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.type, 'string'); - expect(schema.minLength, 1); - expect(schema.maxLength, 100); - expect(schema.pattern, '^[a-zA-Z]+\$'); - expect(schema.example, 'example'); - expect(schema.nullable, true); - }); - - test('creates ApiSchema from JSON with discriminator', () { - final json = { - 'oneOf': [ - {'\$ref': '#/components/schemas/Cat'}, - {'\$ref': '#/components/schemas/Dog'}, - ], - 'discriminator': { - 'propertyName': 'petType', - 'mapping': { - 'cat': '#/components/schemas/Cat', - 'dog': '#/components/schemas/Dog', - }, - }, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.isComposition, true); - expect(schema.isOneOf, true); - expect(schema.hasDiscriminator, true); - expect(schema.discriminator?.propertyName, 'petType'); - expect(schema.discriminator?.hasMapping, true); - expect(schema.discriminator?.mapping.length, 2); - expect(schema.discriminator?.getSchemaForValue('cat'), - '#/components/schemas/Cat'); - expect(schema.discriminator?.getSchemaForValue('dog'), - '#/components/schemas/Dog'); - }); - }); - - group('ApiDiscriminator', () { - test('creates ApiDiscriminator with required fields', () { - const discriminator = ApiDiscriminator( - propertyName: 'type', - ); - - expect(discriminator.propertyName, 'type'); - expect(discriminator.mapping, isEmpty); - expect(discriminator.hasMapping, false); - }); - - test('creates ApiDiscriminator with mapping', () { - const discriminator = ApiDiscriminator( - propertyName: 'petType', - mapping: { - 'cat': '#/components/schemas/Cat', - 'dog': '#/components/schemas/Dog', - }, - ); - - expect(discriminator.propertyName, 'petType'); - expect(discriminator.mapping.length, 2); - expect(discriminator.hasMapping, true); - expect( - discriminator.getSchemaForValue('cat'), '#/components/schemas/Cat'); - expect( - discriminator.getSchemaForValue('dog'), '#/components/schemas/Dog'); - expect(discriminator.getSchemaForValue('bird'), isNull); - }); - - test('creates ApiDiscriminator from JSON', () { - final json = { - 'propertyName': 'objectType', - 'mapping': { - 'user': '#/components/schemas/User', - 'admin': '#/components/schemas/Admin', - }, - }; - - final discriminator = ApiDiscriminator.fromJson(json); - - expect(discriminator.propertyName, 'objectType'); - expect(discriminator.mapping.length, 2); - expect(discriminator.hasMapping, true); - expect( - discriminator.getSchemaForValue('user'), '#/components/schemas/User'); - expect(discriminator.getSchemaForValue('admin'), - '#/components/schemas/Admin'); - }); - - test('creates ApiDiscriminator from JSON with minimal fields', () { - final json = { - 'propertyName': 'type', - }; - - final discriminator = ApiDiscriminator.fromJson(json); - - expect(discriminator.propertyName, 'type'); - expect(discriminator.mapping, isEmpty); - expect(discriminator.hasMapping, false); - }); - }); - - group('Complex Nested Types', () { - test('creates ApiProperty with nested object properties', () { - final json = { - 'type': 'object', - 'description': 'User profile', - 'properties': { - 'name': {'type': 'string'}, - 'address': { - 'type': 'object', - 'properties': { - 'street': {'type': 'string'}, - 'city': {'type': 'string'}, - 'coordinates': { - 'type': 'object', - 'properties': { - 'lat': {'type': 'number'}, - 'lng': {'type': 'number'}, - }, - 'required': ['lat', 'lng'], - }, - }, - 'required': ['street', 'city'], - }, - }, - 'required': ['name'], - }; - - final property = ApiProperty.fromJson('profile', json, []); - - expect(property.type, PropertyType.object); - expect(property.hasNestedProperties, true); - expect(property.nestedProperties.length, 2); - expect(property.nestedProperties['name']?.type, PropertyType.string); - expect(property.nestedProperties['address']?.type, PropertyType.object); - expect(property.nestedProperties['address']?.hasNestedProperties, true); - - // 检查深层嵌套 - final addressProperty = property.nestedProperties['address']!; - expect(addressProperty.nestedProperties.length, 3); - expect(addressProperty.nestedProperties['coordinates']?.type, - PropertyType.object); - - final coordinatesProperty = - addressProperty.nestedProperties['coordinates']!; - expect(coordinatesProperty.nestedProperties.length, 2); - expect(coordinatesProperty.nestedProperties['lat']?.type, - PropertyType.number); - expect(coordinatesProperty.nestedProperties['lng']?.type, - PropertyType.number); - }); - - test('creates ApiProperty with array of nested objects', () { - final json = { - 'type': 'array', - 'description': 'List of users', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - 'tags': { - 'type': 'array', - 'items': {'type': 'string'}, - }, - }, - 'required': ['id', 'name'], - }, - }; - - final property = ApiProperty.fromJson('users', json, []); - - expect(property.type, PropertyType.array); - expect(property.items, isNotNull); - expect(property.items!.name, 'usersItem'); - expect(property.items!.properties.length, 3); - expect(property.items!.properties['id']?.type, PropertyType.integer); - expect(property.items!.properties['tags']?.type, PropertyType.array); - }); - - test('handles maximum depth limit', () { - final json = { - 'type': 'object', - 'properties': { - 'level1': { - 'type': 'object', - 'properties': { - 'level2': { - 'type': 'object', - 'properties': { - 'level3': {'type': 'string'}, - }, - }, - }, - }, - }, - }; - - final property = ApiProperty.fromJson('deep', json, [], maxDepth: 2); - - expect(property.type, PropertyType.object); - expect(property.hasNestedProperties, true); - - // 第一层应该正常解析 - final level1 = property.nestedProperties['level1']!; - expect(level1.type, PropertyType.object); - expect(level1.hasNestedProperties, true); - - // 第二层应该达到深度限制 - final level2 = level1.nestedProperties['level2']!; - expect(level2.type, PropertyType.object); - expect(level2.description, '达到最大嵌套深度的对象'); - }); - - test('creates ApiProperty with complex schema composition', () { - final json = { - 'allOf': [ - { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - }, - }, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - }, - }, - ], - }; - - final property = ApiProperty.fromJson('composed', json, []); - - expect(property.hasComplexSchema, true); - expect(property.schema?.isAllOf, true); - expect(property.schema?.allOf.length, 2); - }); - }); - - group('Advanced Schema Features', () { - test('creates ApiSchema with additionalProperties as boolean', () { - final json = { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - }, - 'additionalProperties': false, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.type, 'object'); - expect(schema.additionalProperties, false); - expect(schema.allowsAdditionalProperties, false); - expect(schema.additionalPropertiesSchema, isNull); - }); - - test('creates ApiSchema with additionalProperties as schema', () { - final json = { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - }, - 'additionalProperties': { - 'type': 'string', - 'pattern': '^[a-zA-Z]+\$', - }, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.type, 'object'); - expect(schema.allowsAdditionalProperties, true); - expect(schema.additionalPropertiesSchema, isNotNull); - expect(schema.additionalPropertiesSchema?.type, 'string'); - expect(schema.additionalPropertiesSchema?.pattern, '^[a-zA-Z]+\$'); - }); - - test('creates ApiSchema with patternProperties', () { - final json = { - 'type': 'object', - 'patternProperties': { - '^S_': {'type': 'string'}, - '^I_': {'type': 'integer'}, - }, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.hasPatternProperties, true); - expect(schema.patternProperties.length, 2); - expect(schema.patternProperties['^S_']?.type, 'string'); - expect(schema.patternProperties['^I_']?.type, 'integer'); - }); - - test('creates ApiSchema with propertyNames constraint', () { - final json = { - 'type': 'object', - 'propertyNames': { - 'pattern': '^[A-Za-z_][A-Za-z0-9_]*\$', - }, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.hasPropertyNames, true); - expect(schema.propertyNames?.pattern, '^[A-Za-z_][A-Za-z0-9_]*\$'); - }); - - test('creates ApiSchema with dependencies', () { - final json = { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'credit_card': {'type': 'string'}, - 'billing_address': {'type': 'string'}, - }, - 'dependencies': { - 'credit_card': ['billing_address'], - }, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.hasDependencies, true); - expect(schema.dependencies.length, 1); - expect(schema.dependencies['credit_card'], ['billing_address']); - }); - - test('creates ApiSchema with const value', () { - final json = { - 'const': 'United States of America', - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.hasConstValue, true); - expect(schema.constValue, 'United States of America'); - }); - - test('creates ApiSchema with conditional schema (if/then/else)', () { - final json = { - 'type': 'object', - 'properties': { - 'street_address': {'type': 'string'}, - 'country': {'type': 'string'}, - 'postal_code': {'type': 'string'}, - }, - 'if': { - 'properties': { - 'country': {'const': 'United States of America'}, - }, - }, - 'then': { - 'properties': { - 'postal_code': {'pattern': '[0-9]{5}(-[0-9]{4})?'}, - }, - }, - 'else': { - 'properties': { - 'postal_code': {'pattern': '[A-Z][0-9][A-Z] [0-9][A-Z][0-9]'}, - }, - }, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.hasConditionalSchema, true); - expect(schema.ifSchema, isNotNull); - expect(schema.thenSchema, isNotNull); - expect(schema.elseSchema, isNotNull); - - // 检查基本结构 - expect(schema.ifSchema?.properties.length, 1); - expect(schema.thenSchema?.properties.length, 1); - expect(schema.elseSchema?.properties.length, 1); - - // 检查属性存在性 - expect(schema.ifSchema?.properties.containsKey('country'), true); - expect(schema.thenSchema?.properties.containsKey('postal_code'), true); - expect(schema.elseSchema?.properties.containsKey('postal_code'), true); - }); - - test('creates ApiSchema with multiple advanced features', () { - final json = { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - }, - 'additionalProperties': {'type': 'string'}, - 'patternProperties': { - '^prefix_': {'type': 'integer'}, - }, - 'propertyNames': { - 'pattern': '^[a-z]+\$', - }, - 'dependencies': { - 'name': ['id'], - }, - }; - - final schema = ApiSchema.fromJson(json); - - expect(schema.allowsAdditionalProperties, true); - expect(schema.hasPatternProperties, true); - expect(schema.hasPropertyNames, true); - expect(schema.hasDependencies, true); - expect(schema.patternProperties.length, 1); - expect(schema.dependencies.length, 1); - }); - }); } diff --git a/tests/optimized_generator_test.dart b/tests/optimized_generator_test.dart deleted file mode 100644 index 79b1b54..0000000 --- a/tests/optimized_generator_test.dart +++ /dev/null @@ -1,392 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:swagger_generator_flutter/generators/optimized_retrofit_generator.dart'; -import 'package:test/test.dart'; - -void main() { - group('OptimizedRetrofitGenerator', () { - late OptimizedRetrofitGenerator generator; - late SwaggerDocument testDocument; - - setUp(() { - generator = OptimizedRetrofitGenerator( - className: 'TestApiService', - generateModularApis: true, - generateBaseResult: true, - generatePagination: true, - generateFileUpload: true, - ); - - // 创建测试文档 - testDocument = const SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test API for generator', - servers: [ - ApiServer( - url: 'https://api.example.com', - description: 'Test server', - ), - ], - components: ApiComponents( - schemas: {}, - securitySchemes: {}, - ), - paths: { - '/api/v1/users/{id}': const ApiPath( - path: '/api/v1/users/{id}', - method: HttpMethod.get, - summary: 'Get user by ID', - description: 'Retrieve user information by ID', - operationId: 'getUser', - tags: ['users'], - parameters: [ - ApiParameter( - name: 'id', - location: ParameterLocation.path, - required: true, - type: PropertyType.integer, - description: 'User ID', - ), - ], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - content: { - 'application/json': const ApiMediaType( - schema: {'type': 'object'}, - ), - }, - ), - }, - ), - '/api/v1/users': const ApiPath( - path: '/api/v1/users', - method: HttpMethod.post, - summary: 'Create user', - description: 'Create a new user', - operationId: 'createUser', - tags: ['users'], - parameters: [], - requestBody: ApiRequestBody( - description: 'User data', - required: true, - content: { - 'application/json': const ApiMediaType( - schema: {'type': 'object'}, - ), - }, - ), - responses: { - '201': const ApiResponse( - code: '201', - description: 'Created', - content: { - 'application/json': const ApiMediaType( - schema: {'type': 'object'}, - ), - }, - ), - }, - ), - '/api/v1/files/upload': const ApiPath( - path: '/api/v1/files/upload', - method: HttpMethod.post, - summary: 'Upload file', - description: 'Upload a file', - operationId: 'uploadFile', - tags: ['files'], - parameters: [], - requestBody: ApiRequestBody( - description: 'File to upload', - required: true, - content: { - 'multipart/form-data': const ApiMediaType( - schema: {'type': 'object'}, - ), - }, - ), - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - content: { - 'application/json': const ApiMediaType( - schema: {'type': 'object'}, - ), - }, - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - }); - - test('generates optimized code successfully', () { - expect( - () => generator.generateFromDocument(testDocument), returnsNormally); - - final generatedCode = generator.generateFromDocument(testDocument); - expect(generatedCode, isNotEmpty); - print('Generated code length: ${generatedCode.length} characters'); - }); - - test('includes required imports', () { - final generatedCode = generator.generateFromDocument(testDocument); - - expect(generatedCode, contains('import \'package:dio/dio.dart\';')); - expect(generatedCode, - contains('import \'package:retrofit/retrofit.dart\';')); - expect(generatedCode, - contains('import \'package:json_annotation/json_annotation.dart\';')); - expect(generatedCode, contains('part \'test_api_service_api.g.dart\';')); - }); - - test('generates BaseResult type', () { - final generatedCode = generator.generateFromDocument(testDocument); - - expect(generatedCode, contains('class BaseResult')); - expect(generatedCode, contains('final int code;')); - expect(generatedCode, contains('final String message;')); - expect(generatedCode, contains('final T? data;')); - expect(generatedCode, contains('bool get isSuccess => code == 200;')); - }); - - test('generates pagination types', () { - final generatedCode = generator.generateFromDocument(testDocument); - - expect(generatedCode, contains('class BasePageParameter')); - expect(generatedCode, contains('class BasePageResult')); - expect(generatedCode, contains('final int page;')); - expect(generatedCode, contains('final int size;')); - expect(generatedCode, contains('final int total;')); - expect(generatedCode, contains('int get totalPages')); - expect(generatedCode, contains('bool get hasNext')); - expect(generatedCode, contains('bool get hasPrevious')); - }); - - test('generates file upload types', () { - final generatedCode = generator.generateFromDocument(testDocument); - - expect(generatedCode, contains('class FileUploadRequest')); - expect(generatedCode, contains('class FileUploadResult')); - expect(generatedCode, contains('final MultipartFile file;')); - expect(generatedCode, contains('final String url;')); - expect(generatedCode, contains('final String filename;')); - expect(generatedCode, contains('final int size;')); - }); - - test('generates modular APIs', () { - final generatedCode = generator.generateFromDocument(testDocument); - - expect(generatedCode, contains('class UsersApi')); - expect(generatedCode, contains('class FilesApi')); - expect(generatedCode, contains('class TestApiService')); - expect(generatedCode, contains('late final UsersApi users;')); - expect(generatedCode, contains('late final FilesApi files;')); - }); - - test('generates API methods with correct annotations', () { - final generatedCode = generator.generateFromDocument(testDocument); - - // GET 方法 - expect(generatedCode, contains('@GET(\'/api/v1/users/{id}\')')); - expect(generatedCode, contains('@Path(\'id\') int id')); - - // POST 方法 - expect(generatedCode, contains('@POST(\'/api/v1/users\')')); - expect(generatedCode, contains('@Body() Map body')); - - // 文件上传方法 - expect(generatedCode, contains('@POST(\'/api/v1/files/upload\')')); - expect(generatedCode, contains('@MultiPart()')); - expect(generatedCode, contains('@Part() MultipartFile file')); - }); - - test('generates utility classes', () { - final generatedCode = generator.generateFromDocument(testDocument); - - expect(generatedCode, contains('class ApiUtils')); - expect(generatedCode, - contains('static Future createFileUpload')); - expect( - generatedCode, contains('static BasePageParameter createPageParam')); - }); - - test('handles method name generation correctly', () { - final generatedCode = generator.generateFromDocument(testDocument); - - expect(generatedCode, contains('Future> getUsers(')); - expect(generatedCode, contains('Future> postUsers(')); - expect(generatedCode, - contains('Future> postFilesUpload(')); - }); - - test('generates single API when modular is disabled', () { - final singleApiGenerator = OptimizedRetrofitGenerator( - className: 'SingleApiService', - generateModularApis: false, - ); - - final generatedCode = - singleApiGenerator.generateFromDocument(testDocument); - - expect(generatedCode, contains('abstract class SingleApiService')); - expect(generatedCode, contains('factory SingleApiService(Dio dio')); - expect(generatedCode, isNot(contains('class UsersApi'))); - expect(generatedCode, isNot(contains('class FilesApi'))); - }); - - test('handles custom base result type', () { - final customGenerator = OptimizedRetrofitGenerator( - baseResultType: 'CustomResult', - pageResultType: 'CustomPageResult', - ); - - final generatedCode = customGenerator.generateFromDocument(testDocument); - - expect(generatedCode, contains('class CustomResult')); - expect(generatedCode, contains('class CustomPageResult')); - expect(generatedCode, contains('Future>')); - }); - - test('extracts module names correctly', () { - final generator = OptimizedRetrofitGenerator(); - - // 使用反射或创建测试方法来测试私有方法 - // 这里我们通过生成的代码来验证模块名提取是否正确 - final generatedCode = generator.generateFromDocument(testDocument); - - expect(generatedCode, contains('UsersApi')); // /api/v1/users -> Users - expect(generatedCode, contains('FilesApi')); // /api/v1/files -> Files - }); - - test('handles different parameter types', () { - // 创建包含不同参数类型的测试文档 - const complexDocument = SwaggerDocument( - title: 'Complex API', - version: '1.0.0', - description: 'API with complex parameters', - servers: [ApiServer(url: 'https://api.example.com')], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/api/v1/search': const ApiPath( - path: '/api/v1/search', - method: HttpMethod.get, - summary: 'Search', - description: 'Search with various parameters', - operationId: 'search', - tags: ['search'], - parameters: [ - ApiParameter( - name: 'query', - location: ParameterLocation.query, - required: true, - type: PropertyType.string, - description: 'Search query', - ), - ApiParameter( - name: 'page', - location: ParameterLocation.query, - required: false, - type: PropertyType.integer, - description: 'Page number', - ), - ApiParameter( - name: 'active', - location: ParameterLocation.query, - required: false, - type: PropertyType.boolean, - description: 'Filter active items', - ), - ], - responses: { - '200': const ApiResponse( - code: '200', - description: 'Success', - content: { - 'application/json': - const ApiMediaType(schema: {'type': 'object'}), - }, - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final generatedCode = generator.generateFromDocument(complexDocument); - - expect( - generatedCode, contains('@Query(\'query\') required String query')); - expect(generatedCode, contains('@Query(\'page\') int? page')); - expect(generatedCode, contains('@Query(\'active\') bool? active')); - }); - - test('performance test with complex document', () { - final stopwatch = Stopwatch()..start(); - - final generatedCode = generator.generateFromDocument(testDocument); - - final elapsedMs = stopwatch.elapsedMilliseconds; - stopwatch.stop(); - - print('Generation time: ${elapsedMs}ms'); - print('Generated code size: ${generatedCode.length} characters'); - - expect(elapsedMs, lessThan(1000)); // 应该在1秒内完成 - expect(generatedCode.length, greaterThan(1000)); // 应该生成足够的代码 - }); - }); - - group('Real Project Integration', () { - test('generates code for real swagger.json', () async { - // 读取实际的 swagger.json 文件 - final file = File('swagger.json'); - if (!file.existsSync()) { - print('swagger.json not found, skipping real project test'); - return; - } - - final jsonString = await file.readAsString(); - final swaggerJson = jsonDecode(jsonString) as Map; - final document = SwaggerDocument.fromJson(swaggerJson); - - final generator = OptimizedRetrofitGenerator( - className: 'OAMobileApiService', - generateModularApis: true, - generateBaseResult: true, - generatePagination: true, - generateFileUpload: true, - ); - - final stopwatch = Stopwatch()..start(); - final generatedCode = generator.generateFromDocument(document); - final elapsedMs = stopwatch.elapsedMilliseconds; - - print('Real project generation:'); - print(' Time: ${elapsedMs}ms'); - print(' Code size: ${generatedCode.length} characters'); - print(' Lines: ${generatedCode.split('\n').length}'); - - expect(generatedCode, isNotEmpty); - expect(generatedCode, contains('class OAMobileApiService')); - expect(generatedCode, contains('FollowManagerApi')); - expect(generatedCode, contains('LoginApi')); - expect(generatedCode, contains('IndexApi')); - - // 可选:将生成的代码写入文件以供检查 - // final outputFile = File('generated_oa_mobile_api.dart'); - // await outputFile.writeAsString(generatedCode); - // print('Generated code written to: ${outputFile.path}'); - }); - }); -} diff --git a/tests/performance_test.dart b/tests/performance_test.dart deleted file mode 100644 index cb0be23..0000000 --- a/tests/performance_test.dart +++ /dev/null @@ -1,488 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:swagger_generator_flutter/core/performance_parser.dart'; -import 'package:swagger_generator_flutter/core/smart_cache.dart'; -import 'package:swagger_generator_flutter/generators/performance_generator.dart'; -import 'package:test/test.dart'; - -void main() { - group('Performance Tests', () { - group('PerformanceParser', () { - late PerformanceParser parser; - - setUp(() { - parser = PerformanceParser( - config: ParseConfig( - enableParallelParsing: true, - enableStreamParsing: false, - enablePerformanceStats: true, - maxConcurrency: 4, - ), - ); - }); - - test('parses document with performance tracking', () async { - final jsonString = jsonEncode({ - 'openapi': '3.0.3', - 'info': { - 'title': 'Test API', - 'version': '1.0.0', - }, - 'paths': { - '/users': { - 'get': { - 'summary': 'Get users', - 'responses': { - '200': { - 'description': 'Success', - }, - }, - }, - }, - }, - }); - - final document = await parser.parseDocument(jsonString); - - expect(document.title, equals('Test API')); - expect(document.version, equals('1.0.0')); - expect(document.paths, hasLength(1)); - - final stats = parser.lastStats; - expect(stats, isNotNull); - expect(stats!.totalTime.inMicroseconds, greaterThan(0)); - expect(stats.documentSize, equals(jsonString.length)); - expect(stats.pathCount, equals(1)); - }); - - test('handles large documents efficiently', () async { - // 创建大型文档 - final paths = {}; - for (int i = 0; i < 100; i++) { - paths['/api/v1/resource$i'] = { - 'get': { - 'summary': 'Get resource $i', - 'responses': { - '200': {'description': 'Success'}, - }, - }, - 'post': { - 'summary': 'Create resource $i', - 'responses': { - '201': {'description': 'Created'}, - }, - }, - }; - } - - final largeDoc = { - 'openapi': '3.0.3', - 'info': { - 'title': 'Large API', - 'version': '1.0.0', - }, - 'paths': paths, - }; - - final jsonString = jsonEncode(largeDoc); - final stopwatch = Stopwatch()..start(); - - final document = await parser.parseDocument(jsonString); - - stopwatch.stop(); - - expect(document.paths.length, greaterThan(50)); // 应该解析出多个路径 - expect(stopwatch.elapsedMilliseconds, lessThan(5000)); // 应该在5秒内完成 - - final stats = parser.lastStats; - expect(stats, isNotNull); - expect(stats!.pathsPerSecond, greaterThan(10)); // 每秒至少处理10个路径 - }); - - test('parallel parsing improves performance', () async { - final sequentialParser = PerformanceParser( - config: ParseConfig( - enableParallelParsing: false, - enablePerformanceStats: true, - ), - ); - - final parallelParser = PerformanceParser( - config: ParseConfig( - enableParallelParsing: true, - enablePerformanceStats: true, - maxConcurrency: 4, - ), - ); - - // 创建中等大小的文档 - final paths = {}; - for (int i = 0; i < 50; i++) { - paths['/api/v1/resource$i'] = { - 'get': { - 'summary': 'Get resource $i', - 'responses': { - '200': {'description': 'Success'} - }, - }, - }; - } - - final doc = { - 'openapi': '3.0.3', - 'info': {'title': 'Test API', 'version': '1.0.0'}, - 'paths': paths, - }; - - final jsonString = jsonEncode(doc); - - // 顺序解析 - await sequentialParser.parseDocument(jsonString); - final sequentialTime = sequentialParser.lastStats!.totalTime; - - // 并行解析 - await parallelParser.parseDocument(jsonString); - final parallelTime = parallelParser.lastStats!.totalTime; - - // 并行解析应该更快(在有足够任务的情况下) - print('Sequential: ${sequentialTime.inMilliseconds}ms'); - print('Parallel: ${parallelTime.inMilliseconds}ms'); - - // 注意:在小型文档上,并行可能不会更快,因为开销 - expect(parallelTime.inMilliseconds, - lessThan(sequentialTime.inMilliseconds * 2)); - }); - }); - - group('SmartCache', () { - late SmartCache cache; - - setUp(() { - cache = SmartCache( - maxSize: 10, - strategy: CacheStrategy.smart, - defaultTtl: Duration(seconds: 1), - ); - }); - - test('basic cache operations work correctly', () { - cache.put('key1', 'value1'); - expect(cache.get('key1'), equals('value1')); - expect(cache.containsKey('key1'), isTrue); - - cache.remove('key1'); - expect(cache.get('key1'), isNull); - expect(cache.containsKey('key1'), isFalse); - }); - - test('cache eviction works when full', () { - // 填满缓存 - for (int i = 0; i < 10; i++) { - cache.put('key$i', 'value$i'); - } - - expect(cache.getStats().size, equals(10)); - - // 添加新项应该触发驱逐 - cache.put('key10', 'value10'); - expect(cache.getStats().size, equals(10)); - expect(cache.getStats().evictions, greaterThan(0)); - }); - - test('TTL expiration works', () async { - cache.put('key1', 'value1', ttl: Duration(milliseconds: 100)); - expect(cache.get('key1'), equals('value1')); - - await Future.delayed(Duration(milliseconds: 150)); - expect(cache.get('key1'), isNull); - }); - - test('cache statistics are accurate', () { - cache.put('key1', 'value1'); - cache.get('key1'); // hit - cache.get('key2'); // miss - - final stats = cache.getStats(); - expect(stats.totalRequests, equals(2)); - expect(stats.hits, equals(1)); - expect(stats.misses, equals(1)); - expect(stats.hitRate, equals(0.5)); - }); - - test('smart eviction strategy works', () { - // 添加一些项并模拟不同的访问模式 - cache.put('frequent', 'value1'); - cache.put('recent', 'value2'); - cache.put('old', 'value3'); - - // 频繁访问第一个 - for (int i = 0; i < 5; i++) { - cache.get('frequent'); - } - - // 最近访问第二个 - cache.get('recent'); - - // 第三个很久没访问 - - // 填满缓存以触发驱逐 - for (int i = 0; i < 8; i++) { - cache.put('filler$i', 'value$i'); - } - - // 频繁访问的项应该还在 - expect(cache.get('frequent'), equals('value1')); - - // 旧的项可能被驱逐了 - // expect(cache.get('old'), isNull); - }); - }); - - group('PerformanceGenerator', () { - late PerformanceGenerator generator; - late SwaggerDocument testDocument; - - setUp(() { - generator = PerformanceGenerator( - maxConcurrency: 4, - enableCaching: true, - enableIncremental: true, - enableParallel: true, - ); - - testDocument = SwaggerDocument( - title: 'Performance Test API', - version: '1.0.0', - description: 'API for performance testing', - servers: [ApiServer(url: 'https://api.example.com')], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/users': ApiPath( - path: '/users', - method: HttpMethod.get, - summary: 'Get users', - description: 'Get all users', - operationId: 'getUsers', - tags: ['users'], - parameters: [], - responses: { - '200': ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - '/posts': ApiPath( - path: '/posts', - method: HttpMethod.get, - summary: 'Get posts', - description: 'Get all posts', - operationId: 'getPosts', - tags: ['posts'], - parameters: [], - responses: { - '200': ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: { - 'User': ApiModel( - name: 'User', - description: 'User model', - properties: { - 'id': ApiProperty( - name: 'id', - type: PropertyType.integer, - description: 'User ID', - required: true, - ), - 'name': ApiProperty( - name: 'name', - type: PropertyType.string, - description: 'User name', - required: true, - ), - }, - required: ['id', 'name'], - ), - }, - controllers: {}, - security: [], - ); - }); - - test('generates code with performance tracking', () async { - final result = await generator.generateFromDocument(testDocument); - - expect(result, isNotEmpty); - expect(result, contains('Performance Test API')); - expect(result, contains('class User')); - expect(result, contains('UsersApi')); - expect(result, contains('PostsApi')); - - final stats = generator.getStats(); - expect(stats.totalTasks, greaterThan(0)); - expect(stats.completedTasks, greaterThan(0)); - expect(stats.successRate, equals(1.0)); - }); - - test('caching improves performance on repeated generation', () async { - // 第一次生成 - final stopwatch1 = Stopwatch()..start(); - await generator.generateFromDocument(testDocument); - stopwatch1.stop(); - final firstTime = stopwatch1.elapsedMicroseconds; - - // 第二次生成(应该使用缓存) - final stopwatch2 = Stopwatch()..start(); - await generator.generateFromDocument(testDocument); - stopwatch2.stop(); - final secondTime = stopwatch2.elapsedMicroseconds; - - print('First generation: ${firstTime}μs'); - print('Second generation: ${secondTime}μs'); - - // 第二次应该更快(由于缓存) - expect(secondTime, lessThan(firstTime)); - - final cacheStats = generator.getCacheStats(); - expect(cacheStats.hits, greaterThan(0)); - }); - - test('parallel generation works with multiple modules', () async { - // 创建有多个模块的大型文档 - final largePaths = {}; - final modules = ['users', 'posts', 'comments', 'tags', 'categories']; - - for (final module in modules) { - for (int i = 0; i < 5; i++) { - final path = '/api/v1/$module/$i'; - largePaths[path] = ApiPath( - path: path, - method: HttpMethod.get, - summary: 'Get $module $i', - description: 'Get $module item $i', - operationId: 'get${module.toUpperCase()}$i', - tags: [module], - parameters: [], - responses: { - '200': ApiResponse(code: '200', description: 'Success'), - }, - ); - } - } - - final largeDocument = SwaggerDocument( - title: 'Large API', - version: '1.0.0', - description: 'Large API for testing', - servers: [ApiServer(url: 'https://api.example.com')], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: largePaths, - models: {}, - controllers: {}, - security: [], - ); - - final result = await generator.generateFromDocument(largeDocument); - - expect(result, isNotEmpty); - expect(result, contains('Large API')); - - // 应该包含所有模块的 API - for (final module in modules) { - final className = - '${module[0].toUpperCase()}${module.substring(1)}Api'; - expect(result, contains(className)); - } - - final stats = generator.getStats(); - expect(stats.totalTasks, greaterThan(modules.length)); - expect(stats.parallelEfficiency, greaterThan(0.5)); - }); - - test('incremental generation detects no changes', () async { - // 第一次生成 - await generator.generateFromDocument(testDocument); - final firstStats = generator.getStats(); - - // 第二次生成相同文档(应该检测到无变更) - await generator.generateFromDocument(testDocument); - final secondStats = generator.getStats(); - - // 第二次生成的任务数应该更少(由于增量生成) - expect( - secondStats.totalTasks, lessThanOrEqualTo(firstStats.totalTasks)); - }); - }); - - group('Real Project Performance', () { - test('handles real swagger.json efficiently', () async { - final file = File('swagger.json'); - if (!file.existsSync()) { - print( - 'swagger.json not found, skipping real project performance test'); - return; - } - - final jsonString = await file.readAsString(); - - // 解析性能测试 - final parser = PerformanceParser( - config: ParseConfig( - enableParallelParsing: true, - enablePerformanceStats: true, - maxConcurrency: 4, - ), - ); - - final parseStopwatch = Stopwatch()..start(); - final document = await parser.parseDocument(jsonString); - parseStopwatch.stop(); - - print('Parse Performance:'); - print(' Time: ${parseStopwatch.elapsedMilliseconds}ms'); - print( - ' Document size: ${(jsonString.length / 1024).toStringAsFixed(2)}KB'); - print(' Paths: ${document.paths.length}'); - print(' Models: ${document.models.length}'); - - final parseStats = parser.lastStats!; - print(parseStats.toString()); - - expect( - parseStopwatch.elapsedMilliseconds, lessThan(10000)); // 应该在10秒内完成 - expect(parseStats.pathsPerSecond, greaterThan(1)); // 每秒至少处理1个路径 - - // 生成性能测试 - final generator = PerformanceGenerator( - maxConcurrency: 4, - enableCaching: true, - enableParallel: true, - ); - - final genStopwatch = Stopwatch()..start(); - final result = await generator.generateFromDocument(document); - genStopwatch.stop(); - - print('\nGeneration Performance:'); - print(' Time: ${genStopwatch.elapsedMilliseconds}ms'); - print( - ' Generated size: ${(result.length / 1024).toStringAsFixed(2)}KB'); - print(' Lines: ${result.split('\n').length}'); - - final genStats = generator.getStats(); - print(genStats.toString()); - - expect(genStopwatch.elapsedMilliseconds, lessThan(15000)); // 应该在15秒内完成 - expect(result.length, greaterThan(1000)); // 应该生成足够的代码 - expect(genStats.successRate, greaterThan(0.8)); // 至少80%的任务成功 - }); - }); - }); -} diff --git a/tests/reference_resolver_test.dart b/tests/reference_resolver_test.dart deleted file mode 100644 index 2d02098..0000000 --- a/tests/reference_resolver_test.dart +++ /dev/null @@ -1,325 +0,0 @@ -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:swagger_generator_flutter/utils/reference_resolver.dart'; -import 'package:test/test.dart'; - -void main() { - group('ReferenceResolver', () { - late ReferenceResolver resolver; - - setUp(() { - resolver = ReferenceResolver(); - }); - - tearDown(() { - resolver.clearCache(); - }); - - test('resolves simple models without references', () { - final componentsJson = { - 'schemas': { - 'User': { - 'type': 'object', - 'description': 'User model', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - }, - 'required': ['id', 'name'], - }, - 'Product': { - 'type': 'object', - 'description': 'Product model', - 'properties': { - 'id': {'type': 'integer'}, - 'title': {'type': 'string'}, - 'price': {'type': 'number'}, - }, - 'required': ['id', 'title'], - }, - }, - }; - - final models = resolver.resolveModels(componentsJson); - - expect(models.length, 2); - expect(models['User'], isNotNull); - expect(models['User']!.name, 'User'); - expect(models['User']!.properties.length, 2); - expect(models['User']!.required, ['id', 'name']); - - expect(models['Product'], isNotNull); - expect(models['Product']!.name, 'Product'); - expect(models['Product']!.properties.length, 3); - expect(models['Product']!.required, ['id', 'title']); - }); - - test('resolves models with allOf composition', () { - final componentsJson = { - 'schemas': { - 'BaseEntity': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'createdAt': {'type': 'string', 'format': 'date-time'}, - }, - 'required': ['id'], - }, - 'User': { - 'allOf': [ - {'\$ref': '#/components/schemas/BaseEntity'}, - { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'email': {'type': 'string'}, - }, - 'required': ['name'], - }, - ], - }, - }, - }; - - final models = resolver.resolveModels(componentsJson); - - expect(models.length, 2); - expect(models['User'], isNotNull); - expect(models['User']!.isAllOf, true); - expect(models['User']!.allOf.length, 2); - - // 检查合并的属性 - expect( - models['User']!.properties.length, 4); // id, createdAt, name, email - expect(models['User']!.properties['id'], isNotNull); - expect(models['User']!.properties['name'], isNotNull); - expect(models['User']!.properties['email'], isNotNull); - expect(models['User']!.properties['createdAt'], isNotNull); - }); - - test('detects and handles circular references', () { - final componentsJson = { - 'schemas': { - 'Node': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'parent': {'\$ref': '#/components/schemas/Node'}, - 'children': { - 'type': 'array', - 'items': {'\$ref': '#/components/schemas/Node'}, - }, - }, - 'required': ['id'], - }, - }, - }; - - final models = resolver.resolveModels(componentsJson); - - expect(models.length, 1); - expect(models['Node'], isNotNull); - expect(models['Node']!.name, 'Node'); - expect(models['Node']!.properties.length, 3); - - // 循环引用应该被正确处理,不会导致无限递归 - expect(models['Node']!.properties['parent'], isNotNull); - expect(models['Node']!.properties['children'], isNotNull); - }); - - test('handles complex nested structures', () { - final componentsJson = { - 'schemas': { - 'Address': { - 'type': 'object', - 'properties': { - 'street': {'type': 'string'}, - 'city': {'type': 'string'}, - 'coordinates': { - 'type': 'object', - 'properties': { - 'lat': {'type': 'number'}, - 'lng': {'type': 'number'}, - }, - 'required': ['lat', 'lng'], - }, - }, - 'required': ['street', 'city'], - }, - 'User': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - 'addresses': { - 'type': 'array', - 'items': {'\$ref': '#/components/schemas/Address'}, - }, - }, - 'required': ['id', 'name'], - }, - }, - }; - - final models = resolver.resolveModels(componentsJson); - - expect(models.length, 2); - expect(models['User'], isNotNull); - expect(models['Address'], isNotNull); - - final userModel = models['User']!; - expect(userModel.properties['addresses'], isNotNull); - expect(userModel.properties['addresses']!.type, PropertyType.array); - - final addressModel = models['Address']!; - expect(addressModel.properties['coordinates'], isNotNull); - expect(addressModel.properties['coordinates']!.type, PropertyType.object); - }); - - test('handles enum models', () { - final componentsJson = { - 'schemas': { - 'Status': { - 'type': 'string', - 'enum': ['active', 'inactive', 'pending'], - 'description': 'User status', - }, - 'Priority': { - 'type': 'integer', - 'enum': [1, 2, 3, 4, 5], - 'description': 'Priority level', - }, - }, - }; - - final models = resolver.resolveModels(componentsJson); - - expect(models.length, 2); - - final statusModel = models['Status']!; - expect(statusModel.isEnum, true); - expect(statusModel.enumValues, ['active', 'inactive', 'pending']); - expect(statusModel.enumType, PropertyType.string); - - final priorityModel = models['Priority']!; - expect(priorityModel.isEnum, true); - expect(priorityModel.enumValues, [1, 2, 3, 4, 5]); - expect(priorityModel.enumType, PropertyType.integer); - }); - - test('handles oneOf with discriminator', () { - final componentsJson = { - 'schemas': { - 'Pet': { - 'oneOf': [ - {'\$ref': '#/components/schemas/Cat'}, - {'\$ref': '#/components/schemas/Dog'}, - ], - 'discriminator': { - 'propertyName': 'petType', - 'mapping': { - 'cat': '#/components/schemas/Cat', - 'dog': '#/components/schemas/Dog', - }, - }, - }, - 'Cat': { - 'type': 'object', - 'properties': { - 'petType': {'type': 'string'}, - 'meowSound': {'type': 'string'}, - }, - 'required': ['petType'], - }, - 'Dog': { - 'type': 'object', - 'properties': { - 'petType': {'type': 'string'}, - 'barkSound': {'type': 'string'}, - }, - 'required': ['petType'], - }, - }, - }; - - final models = resolver.resolveModels(componentsJson); - - expect(models.length, 3); - - final petModel = models['Pet']!; - expect(petModel.isOneOf, true); - expect(petModel.hasDiscriminator, true); - expect(petModel.discriminator?.propertyName, 'petType'); - expect(petModel.discriminator?.mapping.length, 2); - - expect(models['Cat'], isNotNull); - expect(models['Dog'], isNotNull); - }); - - test('respects maximum depth limit', () { - final resolver = ReferenceResolver(maxDepth: 3); - - final componentsJson = { - 'schemas': { - 'DeepNested': { - 'type': 'object', - 'properties': { - 'level1': { - 'type': 'object', - 'properties': { - 'level2': { - 'type': 'object', - 'properties': { - 'level3': { - 'type': 'object', - 'properties': { - 'level4': {'type': 'string'}, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }; - - final models = resolver.resolveModels(componentsJson); - - expect(models.length, 1); - expect(models['DeepNested'], isNotNull); - - // 应该能够解析,但深度受限 - final model = models['DeepNested']!; - expect(model.properties['level1'], isNotNull); - }); - - test('handles parsing errors gracefully', () { - final componentsJson = { - 'schemas': { - 'ValidModel': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - }, - }, - 'InvalidModel': { - // 故意创建一个可能导致解析错误的结构 - 'properties': 'invalid_properties_value', // 这会导致类型错误 - 'required': 123, // 这也会导致类型错误 - }, - }, - }; - - final models = resolver.resolveModels(componentsJson); - - expect(models.length, 2); - expect(models['ValidModel'], isNotNull); - expect(models['InvalidModel'], isNotNull); - - // 无效模型应该被创建为后备模型 - final invalidModel = models['InvalidModel']!; - expect(invalidModel.description, '解析失败的模型'); - }); - }); -} diff --git a/tests/security_test.dart b/tests/security_test.dart deleted file mode 100644 index ddf4ffc..0000000 --- a/tests/security_test.dart +++ /dev/null @@ -1,504 +0,0 @@ -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:test/test.dart'; - -void main() { - group('OAuth2 Flow', () { - test('creates OAuth2Flow with all fields', () { - final json = { - 'authorizationUrl': 'https://example.com/oauth/authorize', - 'tokenUrl': 'https://example.com/oauth/token', - 'refreshUrl': 'https://example.com/oauth/refresh', - 'scopes': { - 'read': 'Read access', - 'write': 'Write access', - 'admin': 'Admin access', - }, - }; - - final flow = OAuth2Flow.fromJson(json); - - expect(flow.authorizationUrl, 'https://example.com/oauth/authorize'); - expect(flow.tokenUrl, 'https://example.com/oauth/token'); - expect(flow.refreshUrl, 'https://example.com/oauth/refresh'); - expect(flow.scopes.length, 3); - expect(flow.scopes['read'], 'Read access'); - expect(flow.scopes['write'], 'Write access'); - expect(flow.scopes['admin'], 'Admin access'); - expect(flow.hasAuthorizationUrl, true); - expect(flow.hasTokenUrl, true); - expect(flow.hasRefreshUrl, true); - expect(flow.hasScopes, true); - }); - - test('creates OAuth2Flow with minimal fields', () { - final json = { - 'tokenUrl': 'https://example.com/oauth/token', - 'scopes': {}, - }; - - final flow = OAuth2Flow.fromJson(json); - - expect(flow.authorizationUrl, isNull); - expect(flow.tokenUrl, 'https://example.com/oauth/token'); - expect(flow.refreshUrl, isNull); - expect(flow.scopes, isEmpty); - expect(flow.hasAuthorizationUrl, false); - expect(flow.hasTokenUrl, true); - expect(flow.hasRefreshUrl, false); - expect(flow.hasScopes, false); - }); - }); - - group('OAuth2 Flows', () { - test('creates OAuth2Flows with multiple flow types', () { - final json = { - 'authorizationCode': { - 'authorizationUrl': 'https://example.com/oauth/authorize', - 'tokenUrl': 'https://example.com/oauth/token', - 'scopes': { - 'read': 'Read access', - 'write': 'Write access', - }, - }, - 'implicit': { - 'authorizationUrl': 'https://example.com/oauth/authorize', - 'scopes': { - 'read': 'Read access', - }, - }, - 'clientCredentials': { - 'tokenUrl': 'https://example.com/oauth/token', - 'scopes': { - 'admin': 'Admin access', - }, - }, - }; - - final flows = OAuth2Flows.fromJson(json); - - expect(flows.hasAnyFlow, true); - expect(flows.availableFlows.length, 3); - expect(flows.availableFlows.contains(OAuth2FlowType.authorizationCode), - true); - expect(flows.availableFlows.contains(OAuth2FlowType.implicit), true); - expect(flows.availableFlows.contains(OAuth2FlowType.clientCredentials), - true); - expect(flows.availableFlows.contains(OAuth2FlowType.password), false); - - expect(flows.authorizationCode, isNotNull); - expect(flows.implicit, isNotNull); - expect(flows.password, isNull); - expect(flows.clientCredentials, isNotNull); - - expect(flows.getFlow(OAuth2FlowType.authorizationCode), isNotNull); - expect(flows.getFlow(OAuth2FlowType.password), isNull); - }); - - test('creates empty OAuth2Flows', () { - final json = {}; - - final flows = OAuth2Flows.fromJson(json); - - expect(flows.hasAnyFlow, false); - expect(flows.availableFlows, isEmpty); - expect(flows.authorizationCode, isNull); - expect(flows.implicit, isNull); - expect(flows.password, isNull); - expect(flows.clientCredentials, isNull); - }); - }); - - group('ApiSecurityScheme', () { - test('creates API Key security scheme', () { - final json = { - 'type': 'apiKey', - 'description': 'API Key authentication', - 'name': 'X-API-Key', - 'in': 'header', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.type, SecuritySchemeType.apiKey); - expect(scheme.description, 'API Key authentication'); - expect(scheme.name, 'X-API-Key'); - expect(scheme.location, ApiKeyLocation.header); - expect(scheme.isApiKey, true); - expect(scheme.isHttp, false); - expect(scheme.isOAuth2, false); - expect(scheme.isOpenIdConnect, false); - expect(scheme.apiKeyInfo, 'header:X-API-Key'); - }); - - test('creates HTTP Bearer security scheme', () { - final json = { - 'type': 'http', - 'description': 'Bearer token authentication', - 'scheme': 'bearer', - 'bearerFormat': 'JWT', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.type, SecuritySchemeType.http); - expect(scheme.description, 'Bearer token authentication'); - expect(scheme.scheme, 'bearer'); - expect(scheme.bearerFormat, 'JWT'); - expect(scheme.isHttp, true); - expect(scheme.isBearer, true); - expect(scheme.isBasic, false); - expect(scheme.httpAuthInfo, 'bearer (JWT)'); - }); - - test('creates HTTP Basic security scheme', () { - final json = { - 'type': 'http', - 'description': 'Basic authentication', - 'scheme': 'basic', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.type, SecuritySchemeType.http); - expect(scheme.scheme, 'basic'); - expect(scheme.isHttp, true); - expect(scheme.isBasic, true); - expect(scheme.isBearer, false); - expect(scheme.httpAuthInfo, 'basic'); - }); - - test('creates OAuth2 security scheme', () { - final json = { - 'type': 'oauth2', - 'description': 'OAuth2 authentication', - 'flows': { - 'authorizationCode': { - 'authorizationUrl': 'https://example.com/oauth/authorize', - 'tokenUrl': 'https://example.com/oauth/token', - 'scopes': { - 'read': 'Read access', - 'write': 'Write access', - }, - }, - }, - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.type, SecuritySchemeType.oauth2); - expect(scheme.description, 'OAuth2 authentication'); - expect(scheme.isOAuth2, true); - expect(scheme.hasOAuth2Flows, true); - expect(scheme.flows?.hasAnyFlow, true); - expect(scheme.flows?.authorizationCode, isNotNull); - }); - - test('creates OpenID Connect security scheme', () { - final json = { - 'type': 'openIdConnect', - 'description': 'OpenID Connect authentication', - 'openIdConnectUrl': - 'https://example.com/.well-known/openid_configuration', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.type, SecuritySchemeType.openIdConnect); - expect(scheme.description, 'OpenID Connect authentication'); - expect(scheme.openIdConnectUrl, - 'https://example.com/.well-known/openid_configuration'); - expect(scheme.isOpenIdConnect, true); - }); - }); - - group('ApiSecurityRequirement', () { - test('creates security requirement with scopes', () { - final json = { - 'oauth2': ['read', 'write'], - 'apiKey': [], - }; - - final requirement = ApiSecurityRequirement.fromJson(json); - - expect(requirement.isNotEmpty, true); - expect(requirement.schemeNames.length, 2); - expect(requirement.hasScheme('oauth2'), true); - expect(requirement.hasScheme('apiKey'), true); - expect(requirement.hasScheme('unknown'), false); - expect(requirement.getScopesForScheme('oauth2'), ['read', 'write']); - expect(requirement.getScopesForScheme('apiKey'), isEmpty); - expect(requirement.getScopesForScheme('unknown'), isEmpty); - }); - - test('creates empty security requirement', () { - final json = {}; - - final requirement = ApiSecurityRequirement.fromJson(json); - - expect(requirement.isEmpty, true); - expect(requirement.isNotEmpty, false); - expect(requirement.schemeNames, isEmpty); - }); - }); - - group('Security Scheme Types', () { - test('converts security scheme type to string', () { - expect(SecuritySchemeType.apiKey.value, 'apiKey'); - expect(SecuritySchemeType.http.value, 'http'); - expect(SecuritySchemeType.oauth2.value, 'oauth2'); - expect(SecuritySchemeType.openIdConnect.value, 'openIdConnect'); - }); - - test('converts string to security scheme type', () { - expect(SecuritySchemeTypeExtension.fromString('apiKey'), - SecuritySchemeType.apiKey); - expect(SecuritySchemeTypeExtension.fromString('http'), - SecuritySchemeType.http); - expect(SecuritySchemeTypeExtension.fromString('oauth2'), - SecuritySchemeType.oauth2); - expect(SecuritySchemeTypeExtension.fromString('openIdConnect'), - SecuritySchemeType.openIdConnect); - expect(SecuritySchemeTypeExtension.fromString('unknown'), - SecuritySchemeType.apiKey); - }); - - test('converts API key location to string', () { - expect(ApiKeyLocation.query.value, 'query'); - expect(ApiKeyLocation.header.value, 'header'); - expect(ApiKeyLocation.cookie.value, 'cookie'); - }); - - test('converts string to API key location', () { - expect(ApiKeyLocationExtension.fromString('query'), ApiKeyLocation.query); - expect( - ApiKeyLocationExtension.fromString('header'), ApiKeyLocation.header); - expect( - ApiKeyLocationExtension.fromString('cookie'), ApiKeyLocation.cookie); - expect( - ApiKeyLocationExtension.fromString('unknown'), ApiKeyLocation.header); - }); - - test('converts OAuth2 flow type to string', () { - expect(OAuth2FlowType.authorizationCode.value, 'authorizationCode'); - expect(OAuth2FlowType.implicit.value, 'implicit'); - expect(OAuth2FlowType.password.value, 'password'); - expect(OAuth2FlowType.clientCredentials.value, 'clientCredentials'); - }); - - test('converts string to OAuth2 flow type', () { - expect(OAuth2FlowTypeExtension.fromString('authorizationCode'), - OAuth2FlowType.authorizationCode); - expect(OAuth2FlowTypeExtension.fromString('implicit'), - OAuth2FlowType.implicit); - expect(OAuth2FlowTypeExtension.fromString('password'), - OAuth2FlowType.password); - expect(OAuth2FlowTypeExtension.fromString('clientCredentials'), - OAuth2FlowType.clientCredentials); - expect(OAuth2FlowTypeExtension.fromString('unknown'), - OAuth2FlowType.authorizationCode); - }); - }); - - group('API Key Authentication Integration', () { - test('creates complete API Key security scheme for header', () { - final json = { - 'type': 'apiKey', - 'description': 'API Key in header', - 'name': 'X-API-Key', - 'in': 'header', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.isApiKey, true); - expect(scheme.name, 'X-API-Key'); - expect(scheme.location, ApiKeyLocation.header); - expect(scheme.apiKeyInfo, 'header:X-API-Key'); - }); - - test('creates complete API Key security scheme for query', () { - final json = { - 'type': 'apiKey', - 'description': 'API Key in query parameter', - 'name': 'api_key', - 'in': 'query', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.isApiKey, true); - expect(scheme.name, 'api_key'); - expect(scheme.location, ApiKeyLocation.query); - expect(scheme.apiKeyInfo, 'query:api_key'); - }); - - test('creates complete API Key security scheme for cookie', () { - final json = { - 'type': 'apiKey', - 'description': 'API Key in cookie', - 'name': 'session_token', - 'in': 'cookie', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.isApiKey, true); - expect(scheme.name, 'session_token'); - expect(scheme.location, ApiKeyLocation.cookie); - expect(scheme.apiKeyInfo, 'cookie:session_token'); - }); - - test('handles API Key security requirement', () { - final requirementJson = { - 'api_key': [], - }; - - final requirement = ApiSecurityRequirement.fromJson(requirementJson); - - expect(requirement.hasScheme('api_key'), true); - expect(requirement.getScopesForScheme('api_key'), isEmpty); - }); - }); - - group('Bearer Token Authentication Integration', () { - test('creates complete Bearer token security scheme', () { - final json = { - 'type': 'http', - 'description': 'Bearer token authentication', - 'scheme': 'bearer', - 'bearerFormat': 'JWT', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.isHttp, true); - expect(scheme.isBearer, true); - expect(scheme.scheme, 'bearer'); - expect(scheme.bearerFormat, 'JWT'); - expect(scheme.httpAuthInfo, 'bearer (JWT)'); - }); - - test('creates Bearer token without format', () { - final json = { - 'type': 'http', - 'description': 'Bearer token authentication', - 'scheme': 'bearer', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.isHttp, true); - expect(scheme.isBearer, true); - expect(scheme.scheme, 'bearer'); - expect(scheme.bearerFormat, isNull); - expect(scheme.httpAuthInfo, 'bearer'); - }); - - test('handles Bearer token security requirement', () { - final requirementJson = { - 'bearerAuth': [], - }; - - final requirement = ApiSecurityRequirement.fromJson(requirementJson); - - expect(requirement.hasScheme('bearerAuth'), true); - expect(requirement.getScopesForScheme('bearerAuth'), isEmpty); - }); - }); - - group('HTTP Authentication Schemes', () { - test('creates Basic authentication security scheme', () { - final json = { - 'type': 'http', - 'description': 'Basic authentication', - 'scheme': 'basic', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.type, SecuritySchemeType.http); - expect(scheme.isHttp, true); - expect(scheme.isBasic, true); - expect(scheme.isBearer, false); - expect(scheme.scheme, 'basic'); - expect(scheme.httpAuthInfo, 'basic'); - }); - - test('creates Digest authentication security scheme', () { - final json = { - 'type': 'http', - 'description': 'Digest authentication', - 'scheme': 'digest', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.type, SecuritySchemeType.http); - expect(scheme.isHttp, true); - expect(scheme.isBasic, false); - expect(scheme.isBearer, false); - expect(scheme.scheme, 'digest'); - expect(scheme.httpAuthInfo, 'digest'); - }); - - test('creates custom HTTP authentication security scheme', () { - final json = { - 'type': 'http', - 'description': 'Custom HTTP authentication', - 'scheme': 'custom', - }; - - final scheme = ApiSecurityScheme.fromJson(json); - - expect(scheme.type, SecuritySchemeType.http); - expect(scheme.isHttp, true); - expect(scheme.isBasic, false); - expect(scheme.isBearer, false); - expect(scheme.scheme, 'custom'); - expect(scheme.httpAuthInfo, 'custom'); - }); - - test('handles HTTP authentication security requirement', () { - final requirementJson = { - 'basicAuth': [], - 'digestAuth': [], - }; - - final requirement = ApiSecurityRequirement.fromJson(requirementJson); - - expect(requirement.hasScheme('basicAuth'), true); - expect(requirement.hasScheme('digestAuth'), true); - expect(requirement.getScopesForScheme('basicAuth'), isEmpty); - expect(requirement.getScopesForScheme('digestAuth'), isEmpty); - }); - }); - - group('Mixed Security Requirements', () { - test('handles multiple security schemes in one requirement', () { - final requirementJson = { - 'oauth2': ['read', 'write'], - 'apiKey': [], - 'basicAuth': [], - }; - - final requirement = ApiSecurityRequirement.fromJson(requirementJson); - - expect(requirement.schemeNames.length, 3); - expect(requirement.hasScheme('oauth2'), true); - expect(requirement.hasScheme('apiKey'), true); - expect(requirement.hasScheme('basicAuth'), true); - expect(requirement.getScopesForScheme('oauth2'), ['read', 'write']); - expect(requirement.getScopesForScheme('apiKey'), isEmpty); - expect(requirement.getScopesForScheme('basicAuth'), isEmpty); - }); - - test('handles empty security requirement (no authentication)', () { - final requirementJson = {}; - - final requirement = ApiSecurityRequirement.fromJson(requirementJson); - - expect(requirement.isEmpty, true); - expect(requirement.schemeNames, isEmpty); - }); - }); -} diff --git a/tests/simple_generator_test.dart b/tests/simple_generator_test.dart deleted file mode 100644 index 3369cc2..0000000 --- a/tests/simple_generator_test.dart +++ /dev/null @@ -1,442 +0,0 @@ -import 'package:swagger_generator_flutter/core/models.dart'; -import 'package:swagger_generator_flutter/generators/optimized_retrofit_generator.dart'; -import 'package:swagger_generator_flutter/generators/retrofit_api_generator.dart'; -import 'package:test/test.dart'; - -void main() { - group('Simple Generator Tests', () { - late SwaggerDocument simpleDocument; - - setUp(() { - simpleDocument = SwaggerDocument( - title: 'Simple Test API', - version: '1.0.0', - description: 'A simple test API', - servers: [ - ApiServer( - url: 'https://api.example.com', - description: 'Test server', - ), - ], - components: ApiComponents( - schemas: {}, - securitySchemes: {}, - ), - paths: { - '/users': ApiPath( - path: '/users', - method: HttpMethod.get, - summary: 'Get users', - description: 'Get all users', - operationId: 'getUsers', - tags: ['users'], - parameters: [], - responses: { - '200': ApiResponse( - code: '200', - description: 'Success', - content: { - 'application/json': ApiMediaType( - schema: {'type': 'array'}, - ), - }, - ), - }, - ), - '/users/{id}': ApiPath( - path: '/users/{id}', - method: HttpMethod.get, - summary: 'Get user by ID', - description: 'Get a specific user', - operationId: 'getUserById', - tags: ['users'], - parameters: [ - ApiParameter( - name: 'id', - location: ParameterLocation.path, - required: true, - type: PropertyType.integer, - description: 'User ID', - ), - ], - responses: { - '200': ApiResponse( - code: '200', - description: 'User found', - content: { - 'application/json': ApiMediaType( - schema: {'type': 'object'}, - ), - }, - ), - }, - ), - }, - models: { - 'User': ApiModel( - name: 'User', - description: 'User model', - properties: { - 'id': ApiProperty( - name: 'id', - type: PropertyType.integer, - description: 'User ID', - required: true, - ), - 'name': ApiProperty( - name: 'name', - type: PropertyType.string, - description: 'User name', - required: true, - ), - }, - required: ['id', 'name'], - ), - }, - controllers: {}, - security: [], - ); - }); - - group('RetrofitApiGenerator Basic Tests', () { - test('generates basic API structure', () { - final generator = RetrofitApiGenerator( - className: 'TestApi', - splitByTags: false, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, isNotEmpty); - expect(result, contains('Simple Test API')); - expect(result, contains('TestApi')); - }); - - test('generates imports correctly', () { - final generator = RetrofitApiGenerator(); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('import')); - expect(result, contains('dio')); - expect(result, contains('retrofit')); - }); - - test('generates path annotations', () { - final generator = RetrofitApiGenerator(); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('@GET')); - expect(result, contains('/users')); - expect(result, contains('/users/{id}')); - }); - - test('generates parameter annotations', () { - final generator = RetrofitApiGenerator(); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('@Path')); - expect(result, contains('id')); - }); - - test('handles split by tags', () { - final generator = RetrofitApiGenerator( - splitByTags: true, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, isNotEmpty); - // Should generate modular structure when split by tags - }); - }); - - group('OptimizedRetrofitGenerator Tests', () { - test('generates optimized code structure', () { - final generator = OptimizedRetrofitGenerator( - className: 'OptimizedApi', - generateModularApis: false, - generateBaseResult: true, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, isNotEmpty); - expect(result, contains('Simple Test API')); - expect(result, contains('BaseResult')); - }); - - test('generates base result types', () { - final generator = OptimizedRetrofitGenerator( - generateBaseResult: true, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('class BaseResult')); - expect(result, contains('final int code')); - expect(result, contains('final String message')); - expect(result, contains('bool get isSuccess')); - }); - - test('generates pagination types', () { - final generator = OptimizedRetrofitGenerator( - generatePagination: true, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('BasePageParameter')); - expect(result, contains('BasePageResult')); - expect(result, contains('final int page')); - expect(result, contains('final int size')); - }); - - test('generates file upload types', () { - final generator = OptimizedRetrofitGenerator( - generateFileUpload: true, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('FileUploadRequest')); - expect(result, contains('FileUploadResult')); - expect(result, contains('MultipartFile')); - }); - - test('generates utility classes', () { - final generator = OptimizedRetrofitGenerator( - generateFileUpload: true, - generatePagination: true, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('class ApiUtils')); - expect(result, contains('createFileUpload')); - expect(result, contains('createPageParam')); - }); - - test('generates modular APIs when enabled', () { - final generator = OptimizedRetrofitGenerator( - generateModularApis: true, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('UsersApi')); - expect(result, contains('class ApiService')); - expect(result, contains('late final UsersApi')); - }); - - test('generates single API when modular disabled', () { - final generator = OptimizedRetrofitGenerator( - generateModularApis: false, - className: 'SingleApi', - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('abstract class SingleApi')); - expect(result, isNot(contains('UsersApi'))); - }); - }); - - group('Code Quality Tests', () { - test('generated code has proper structure', () { - final generator = RetrofitApiGenerator(); - final result = generator.generateFromDocument(simpleDocument); - - // Check for basic Dart syntax - expect(result, isNot(contains(';;'))); // No double semicolons - expect(result, isNot(contains(',,'))); // No double commas - - // Check for proper class declarations - final classCount = 'class '.allMatches(result).length; - final abstractClassCount = 'abstract class '.allMatches(result).length; - expect(classCount + abstractClassCount, greaterThan(0)); - }); - - test('handles empty paths gracefully', () { - final emptyDocument = SwaggerDocument( - title: 'Empty API', - version: '1.0.0', - description: 'Empty API', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: {}, - models: {}, - controllers: {}, - security: [], - ); - - final generator = RetrofitApiGenerator(); - final result = generator.generateFromDocument(emptyDocument); - - expect(result, isNotEmpty); - expect(result, contains('Empty API')); - }); - - test('handles special characters in API names', () { - final specialDocument = SwaggerDocument( - title: 'API-with_Special.Characters', - version: '1.0.0', - description: 'Test', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/special-endpoint': ApiPath( - path: '/special-endpoint', - method: HttpMethod.get, - summary: 'Special endpoint', - description: 'Test', - operationId: 'getSpecial', - tags: ['special'], - parameters: [], - responses: { - '200': ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final generator = RetrofitApiGenerator(); - expect(() => generator.generateFromDocument(specialDocument), - returnsNormally); - }); - - test('generates valid JSON annotations', () { - final generator = OptimizedRetrofitGenerator( - generateBaseResult: true, - ); - - final result = generator.generateFromDocument(simpleDocument); - - expect(result, contains('@JsonSerializable')); - expect(result, contains('fromJson')); - expect(result, contains('toJson')); - }); - - test('handles nullable parameters correctly', () { - final documentWithOptionalParams = SwaggerDocument( - title: 'Test API', - version: '1.0.0', - description: 'Test', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: { - '/search': ApiPath( - path: '/search', - method: HttpMethod.get, - summary: 'Search', - description: 'Search endpoint', - operationId: 'search', - tags: ['search'], - parameters: [ - ApiParameter( - name: 'query', - location: ParameterLocation.query, - required: true, - type: PropertyType.string, - description: 'Search query', - ), - ApiParameter( - name: 'page', - location: ParameterLocation.query, - required: false, - type: PropertyType.integer, - description: 'Page number', - ), - ], - responses: { - '200': ApiResponse( - code: '200', - description: 'Success', - ), - }, - ), - }, - models: {}, - controllers: {}, - security: [], - ); - - final generator = RetrofitApiGenerator(); - final result = - generator.generateFromDocument(documentWithOptionalParams); - - // Required parameters should not be nullable - expect(result, contains('String query')); - - // Optional parameters should be nullable - expect(result, contains('int? page')); - }); - }); - - group('Performance Tests', () { - test('handles medium-sized documents efficiently', () { - // Create a document with multiple paths - final paths = {}; - for (int i = 0; i < 50; i++) { - paths['/resource$i'] = ApiPath( - path: '/resource$i', - method: HttpMethod.get, - summary: 'Get resource $i', - description: 'Get resource $i', - operationId: 'getResource$i', - tags: ['resources'], - parameters: [], - responses: { - '200': ApiResponse( - code: '200', - description: 'Success', - ), - }, - ); - } - - final largeDocument = SwaggerDocument( - title: 'Large API', - version: '1.0.0', - description: 'Large API', - servers: [], - components: ApiComponents(schemas: {}, securitySchemes: {}), - paths: paths, - models: {}, - controllers: {}, - security: [], - ); - - final generator = RetrofitApiGenerator(); - final stopwatch = Stopwatch()..start(); - - final result = generator.generateFromDocument(largeDocument); - - stopwatch.stop(); - - expect(result, isNotEmpty); - expect(stopwatch.elapsedMilliseconds, - lessThan(5000)); // Should complete within 5 seconds - expect(result.length, - greaterThan(1000)); // Should generate substantial code - }); - - test('memory usage is reasonable', () { - final generator = RetrofitApiGenerator(); - final result = generator.generateFromDocument(simpleDocument); - - // Basic memory usage check - result should not be excessively large - expect(result.length, - lessThan(100000)); // Less than 100KB for simple document - }); - }); - }); -} diff --git a/tests/string_utils_test.dart b/tests/string_utils_test.dart index 18994b0..f1b6638 100644 --- a/tests/string_utils_test.dart +++ b/tests/string_utils_test.dart @@ -1,6 +1,7 @@ -import 'package:swagger_generator_flutter/utils/string_utils.dart'; import 'package:test/test.dart'; +import 'package:swagger_generator_flutter/utils/string_utils.dart'; + void main() { group('StringUtils', () { group('toDartPropertyName', () { diff --git a/validate.sh b/validate.sh deleted file mode 100755 index 4dc297d..0000000 --- a/validate.sh +++ /dev/null @@ -1,280 +0,0 @@ -#!/bin/bash - -# Augment 代码生成规范验证脚本 -# 用于验证生成的代码是否符合规范要求 - -set -e - -# 颜色定义 -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# 打印带颜色的消息 -print_info() { - echo -e "${BLUE}ℹ️ $1${NC}" -} - -print_success() { - echo -e "${GREEN}✅ $1${NC}" -} - -print_warning() { - echo -e "${YELLOW}⚠️ $1${NC}" -} - -print_error() { - echo -e "${RED}❌ $1${NC}" -} - -print_header() { - echo -e "${BLUE}🔍 Augment 代码生成规范验证${NC}" - echo "==================================================" -} - -# 检查必要的工具 -check_prerequisites() { - print_info "检查必要工具..." - - if ! command -v dart &> /dev/null; then - print_error "Dart SDK 未安装或不在 PATH 中" - exit 1 - fi - - print_success "Dart SDK 已安装" -} - -# 验证 swagger.json -validate_swagger() { - print_info "验证 swagger.json..." - - if [ ! -f "swagger.json" ]; then - print_error "swagger.json 文件不存在" - return 1 - fi - - # 检查 JSON 格式 - if ! jq empty swagger.json 2>/dev/null; then - if ! python3 -m json.tool swagger.json > /dev/null 2>&1; then - print_error "swagger.json 格式错误" - return 1 - fi - fi - - print_success "swagger.json 格式正确" -} - -# 验证生成的文件结构 -validate_file_structure() { - print_info "验证文件结构..." - - if [ ! -d "generator" ]; then - print_error "generator 目录不存在" - return 1 - fi - - if [ ! -d "generator/api" ]; then - print_error "generator/api 目录不存在" - return 1 - fi - - if [ ! -d "generator/api_models" ]; then - print_error "generator/api_models 目录不存在" - return 1 - fi - - print_success "文件结构正确" -} - -# 验证代码质量 -validate_code_quality() { - print_info "验证代码质量..." - - # 检查 generator 目录是否存在 - if [ ! -d "generator" ]; then - print_warning "generator 目录不存在,跳过代码质量检查" - return 0 - fi - - # 运行 dart analyze - if dart analyze generator/ 2>/dev/null; then - print_success "静态分析通过" - else - print_warning "静态分析发现问题,请检查生成的代码" - fi -} - -# 验证命名规范 -validate_naming_conventions() { - print_info "验证命名规范..." - - local errors=0 - - # 检查 API 文件命名 - if [ -d "generator/api" ]; then - for file in generator/api/*.dart; do - if [ -f "$file" ]; then - filename=$(basename "$file") - if [[ ! "$filename" =~ ^[a-z][a-z0-9_]*_api\.dart$ ]] && [[ "$filename" != "api_client.dart" ]]; then - print_error "API 文件命名不规范: $filename" - errors=$((errors + 1)) - fi - fi - done - fi - - # 检查模型文件命名 - if [ -d "generator/api_models" ]; then - for file in generator/api_models/*.dart; do - if [ -f "$file" ]; then - filename=$(basename "$file") - if [[ ! "$filename" =~ ^[a-z][a-z0-9_]*\.dart$ ]] && [[ "$filename" != "index.dart" ]]; then - print_error "模型文件命名不规范: $filename" - errors=$((errors + 1)) - fi - fi - done - fi - - if [ $errors -eq 0 ]; then - print_success "命名规范检查通过" - else - print_error "发现 $errors 个命名规范问题" - return 1 - fi -} - -# 验证类型一致性 -validate_type_consistency() { - print_info "验证类型一致性..." - - local generator_file="lib/generators/retrofit_api_generator.dart" - - if [ ! -f "$generator_file" ]; then - print_warning "生成器文件不存在,跳过类型一致性检查" - return 0 - fi - - # 检查是否有硬编码的类型推断 - local hardcoded_patterns=( - "TaskInfoResult" - "if.*contains.*login.*return" - "if.*contains.*task.*return" - "if.*tag.*contains.*return" - ) - - local errors=0 - for pattern in "${hardcoded_patterns[@]}"; do - if grep -qiE "$pattern" "$generator_file"; then - print_error "发现硬编码类型推断: $pattern" - errors=$((errors + 1)) - fi - done - - if [ $errors -eq 0 ]; then - print_success "类型一致性检查通过" - else - print_error "发现 $errors 个类型一致性问题" - return 1 - fi -} - -# 运行完整验证 -run_full_validation() { - print_header - - local total_errors=0 - - check_prerequisites || total_errors=$((total_errors + 1)) - validate_swagger || total_errors=$((total_errors + 1)) - validate_file_structure || total_errors=$((total_errors + 1)) - validate_code_quality || total_errors=$((total_errors + 1)) - validate_naming_conventions || total_errors=$((total_errors + 1)) - validate_type_consistency || total_errors=$((total_errors + 1)) - - echo "" - echo "==================================================" - - if [ $total_errors -eq 0 ]; then - print_success "所有检查通过!代码符合 Augment 规范。" - exit 0 - else - print_error "验证失败,发现 $total_errors 个问题。" - echo "" - print_info "请参考以下文档进行修复:" - echo " - 代码生成规范: AUGMENT_CODE_GENERATION_STANDARDS.md" - echo " - 快速参考指南: QUICK_REFERENCE.md" - echo " - 代码审查清单: CODE_REVIEW_CHECKLIST.md" - exit 1 - fi -} - -# 显示帮助信息 -show_help() { - echo "Augment 代码生成规范验证脚本" - echo "" - echo "用法:" - echo " $0 [选项]" - echo "" - echo "选项:" - echo " all, -a, --all 运行所有验证检查(默认)" - echo " swagger, -s, --swagger 只验证 swagger.json" - echo " files, -f, --files 只验证文件结构" - echo " quality, -q, --quality 只验证代码质量" - echo " naming, -n, --naming 只验证命名规范" - echo " types, -t, --types 只验证类型一致性" - echo " help, -h, --help 显示此帮助信息" - echo "" - echo "示例:" - echo " $0 # 运行所有检查" - echo " $0 swagger # 只验证 swagger.json" - echo " $0 --quality # 只验证代码质量" -} - -# 主函数 -main() { - case "${1:-all}" in - all|-a|--all) - run_full_validation - ;; - swagger|-s|--swagger) - print_header - check_prerequisites - validate_swagger - print_success "Swagger 验证完成" - ;; - files|-f|--files) - print_header - validate_file_structure - print_success "文件结构验证完成" - ;; - quality|-q|--quality) - print_header - validate_code_quality - print_success "代码质量验证完成" - ;; - naming|-n|--naming) - print_header - validate_naming_conventions - print_success "命名规范验证完成" - ;; - types|-t|--types) - print_header - validate_type_consistency - print_success "类型一致性验证完成" - ;; - help|-h|--help) - show_help - ;; - *) - print_error "未知选项: $1" - show_help - exit 1 - ;; - esac -} - -# 执行主函数 -main "$@" diff --git a/validate_standards.dart b/validate_standards.dart deleted file mode 100644 index 1a503e2..0000000 --- a/validate_standards.dart +++ /dev/null @@ -1,239 +0,0 @@ -#!/usr/bin/env dart - -/// Augment 代码生成规范验证脚本 -/// 用于验证生成的代码是否符合规范要求 - -import 'dart:convert'; -import 'dart:io'; - -void main(List args) async { - print('🔍 Augment 代码生成规范验证'); - print('=' * 50); - - final validator = StandardsValidator(); - - try { - await validator.validateAll(); - print('\n✅ 所有检查通过!代码符合 Augment 规范。'); - } catch (e) { - print('\n❌ 验证失败:$e'); - exit(1); - } -} - -class StandardsValidator { - final List errors = []; - final List warnings = []; - - /// 验证所有规范 - Future validateAll() async { - print('📋 开始验证...\n'); - - await _validateSwaggerJson(); - await _validateGeneratedFiles(); - await _validateCodeQuality(); - await _validateNamingConventions(); - await _validateTypeConsistency(); - - _printResults(); - - if (errors.isNotEmpty) { - throw Exception('发现 ${errors.length} 个错误'); - } - } - - /// 验证 swagger.json - Future _validateSwaggerJson() async { - print('🔍 验证 swagger.json...'); - - final swaggerFile = File('swagger.json'); - if (!swaggerFile.existsSync()) { - errors.add('swagger.json 文件不存在'); - return; - } - - try { - final content = await swaggerFile.readAsString(); - final swagger = jsonDecode(content) as Map; - - // 检查 OpenAPI 版本 - final openapi = swagger['openapi'] as String?; - if (openapi == null || !openapi.startsWith('3.0')) { - errors.add('OpenAPI 版本必须是 3.0.x,当前:$openapi'); - } - - // 检查基本结构 - if (!swagger.containsKey('paths')) { - errors.add('swagger.json 缺少 paths 定义'); - } - - if (!swagger.containsKey('components')) { - warnings.add('swagger.json 缺少 components 定义'); - } - - // 检查 schemas - final components = swagger['components'] as Map?; - if (components != null) { - final schemas = components['schemas'] as Map?; - if (schemas == null || schemas.isEmpty) { - warnings.add('components/schemas 为空,可能影响类型生成'); - } - } - - print(' ✅ swagger.json 格式正确'); - } catch (e) { - errors.add('swagger.json 格式错误:$e'); - } - } - - /// 验证生成的文件 - Future _validateGeneratedFiles() async { - print('🔍 验证生成的文件...'); - - final generatorDir = Directory('generator'); - if (!generatorDir.existsSync()) { - errors.add('generator 目录不存在'); - return; - } - - // 检查目录结构 - final apiDir = Directory('generator/api'); - final modelsDir = Directory('generator/api_models'); - - if (!apiDir.existsSync()) { - errors.add('generator/api 目录不存在'); - } - - if (!modelsDir.existsSync()) { - errors.add('generator/api_models 目录不存在'); - } - - // 检查 index.dart 文件 - final indexFile = File('generator/api_models/index.dart'); - if (!indexFile.existsSync()) { - warnings.add('generator/api_models/index.dart 文件不存在'); - } - - print(' ✅ 文件结构正确'); - } - - /// 验证代码质量 - Future _validateCodeQuality() async { - print('🔍 验证代码质量...'); - - // 运行 dart analyze - final analyzeResult = await Process.run('dart', ['analyze', 'generator/']); - - if (analyzeResult.exitCode != 0) { - final output = analyzeResult.stdout.toString(); - final errorOutput = analyzeResult.stderr.toString(); - - if (output.contains('error') || errorOutput.contains('error')) { - errors.add('dart analyze 发现错误:\n$output\n$errorOutput'); - } else if (output.contains('warning') || - errorOutput.contains('warning')) { - warnings.add('dart analyze 发现警告:\n$output\n$errorOutput'); - } - } else { - print(' ✅ 静态分析通过'); - } - } - - /// 验证命名规范 - Future _validateNamingConventions() async { - print('🔍 验证命名规范...'); - - final apiDir = Directory('generator/api'); - if (apiDir.existsSync()) { - await for (final file in apiDir.list()) { - if (file is File && file.path.endsWith('.dart')) { - final fileName = file.path.split('/').last; - - // API 文件应该以 _api.dart 结尾 - if (!fileName.endsWith('_api.dart')) { - errors.add('API 文件命名不规范:$fileName(应该以 _api.dart 结尾)'); - } - - // 检查文件名是否为 snake_case - final baseName = fileName.replaceAll('_api.dart', ''); - if (!_isSnakeCase(baseName)) { - errors.add('API 文件名不是 snake_case:$fileName'); - } - } - } - } - - final modelsDir = Directory('generator/api_models'); - if (modelsDir.existsSync()) { - await for (final file in modelsDir.list()) { - if (file is File && - file.path.endsWith('.dart') && - !file.path.endsWith('index.dart')) { - final fileName = file.path.split('/').last; - final baseName = fileName.replaceAll('.dart', ''); - - // 检查模型文件名是否为 snake_case - if (!_isSnakeCase(baseName)) { - errors.add('模型文件名不是 snake_case:$fileName'); - } - } - } - } - - print(' ✅ 命名规范检查完成'); - } - - /// 验证类型一致性 - Future _validateTypeConsistency() async { - print('🔍 验证类型一致性...'); - - // 检查是否有硬编码的类型推断 - final generatorFile = File('lib/generators/retrofit_api_generator.dart'); - if (generatorFile.existsSync()) { - final content = await generatorFile.readAsString(); - - // 检查是否还有硬编码的类型映射 - final hardcodedPatterns = [ - 'TaskInfoResult', - 'if.*contains.*login.*return', - 'if.*contains.*task.*return', - 'if.*tag.*contains.*return', - ]; - - for (final pattern in hardcodedPatterns) { - final regex = RegExp(pattern, caseSensitive: false); - if (regex.hasMatch(content)) { - errors.add('发现硬编码类型推断:$pattern'); - } - } - } - - print(' ✅ 类型一致性检查完成'); - } - - /// 检查是否为 snake_case - bool _isSnakeCase(String name) { - return RegExp(r'^[a-z][a-z0-9_]*$').hasMatch(name); - } - - /// 打印验证结果 - void _printResults() { - print('\n📊 验证结果:'); - print(' 错误:${errors.length}'); - print(' 警告:${warnings.length}'); - - if (errors.isNotEmpty) { - print('\n❌ 错误列表:'); - for (int i = 0; i < errors.length; i++) { - print(' ${i + 1}. ${errors[i]}'); - } - } - - if (warnings.isNotEmpty) { - print('\n⚠️ 警告列表:'); - for (int i = 0; i < warnings.length; i++) { - print(' ${i + 1}. ${warnings[i]}'); - } - } - } -}