提交 ed7ea006 authored 作者: 陈泽健's avatar 陈泽健

docs(prd): 删除用例生成相关PRD文档,输出AI用例完善的需求文档实现功能。

- 移除根据PRD文档生成测试用例的需求文档
- 删除用例生成计划执行文档
- 清理相关的PRD规范和实施计划内容
上级 e50d943e
# AI完善测试用例工具 - 环境变量配置文件
#
# 说明:复制此文件为 .env 并填入实际的配置值
# .env 文件已加入 .gitignore,不会被提交到代码仓库
# ==================== Anthropic API 配置 ====================
# 获取API密钥:https://console.anthropic.com/
ANTHROPIC_API_KEY=sk-ant-api03-...
# ==================== API配置(可选)====================
# API基础URL(用于代理服务)
# 官方API可留空或设置为:https://api.anthropic.com
# CCSwitch等代理服务需设置对应endpoint
# API_BASE_URL=https://api.anthropic.com
# ==================== AI服务模式配置 ====================
# AI服务模式选择(可选)
# auto: 自动检测(默认)- 优先使用API,无API密钥时尝试CLI
# api: 强制使用Anthropic API(需要设置ANTHROPIC_API_KEY)
# cli: 强制使用Claude CLI(需要安装:npm install -g @anthropic-ai/claude-code)
# AI_SERVICE_MODE=api
# ==================== 日志配置 ====================
# 日志级别:DEBUG, INFO, WARNING, ERROR
LOG_LEVEL=INFO
# ==================== AI配置(可选)====================
# AI模型:claude-sonnet-4-6, claude-opus-4-6
# AI_MODEL=claude-sonnet-4-6
# AI最大token数
# AI_MAX_TOKENS=8192
# AI温度参数(0-1,越低越稳定)
# AI_TEMPERATURE=0.3
# ==================== 覆盖率目标(可选)====================
# 覆盖率目标(0-1)
# COVERAGE_TARGET=0.9
# AI完善测试用例工具 - Git忽略文件
# 环境变量配置(包含API密钥)
.env
# Python缓存
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
# 虚拟环境
venv/
env/
ENV/
# IDE配置
.vscode/
.idea/
*.swp
*.swo
# 日志文件
logs/*.log
# 输出文件
Perfected/*.xlsx
reports/*.docx
# 临时文件
*.tmp
.DS_Store
Thumbs.db
# 测试文件
*.pyc
# AI完善测试用例工具
## 项目简介
本工具通过结合已有测试用例、需求文档、开发需求PRD文档,利用AI能力对测试用例进行查漏补缺,完善测试用例内容,确保测试用例覆盖全面且符合规范要求。
### 主要功能
- **文档读取**:自动读取需求文档(.docx)、开发PRD文档(.md)、测试用例(.xlsx)
- **功能点提取**:使用AI从需求文档中提取完整的功能点列表
- **覆盖率分析**:分析现有测试用例的覆盖情况
- **缺失检测**:检测功能点、场景、边界条件的缺失
- **用例生成**:使用AI自动生成缺失的测试用例
- **去重处理**:智能去重,确保测试用例不重复
- **报告生成**:生成详细的差异性报告
### 覆盖率目标
- **场景覆盖率目标**:90%
---
## 项目结构
```
AuxiliaryTool/AIPerfectedTestCases/
├── src/ # 源代码目录
│ ├── __init__.py
│ ├── config.py # 配置模块
│ ├── document_reader.py # 文档读取模块
│ ├── test_case_analyzer.py # 测试用例分析模块
│ ├── gap_detector.py # 缺失检测模块
│ ├── case_generator.py # 用例生成模块
│ ├── deduplicator.py # 去重模块
│ ├── report_generator.py # 报告生成模块
│ └── main.py # 主入口模块
├── config/ # 配置文件目录
│ ├── 需求文档/
│ │ └── *.docx # 需求文档
│ ├── 开发PRD/
│ │ └── *.md # 开发PRD文档
│ └── 测试用例/
│ └── 新统一平台权限管理测试用例.xlsx
├── Perfected/ # 输出目录
│ └── 新统一平台权限管理测试用例_完善版本.xlsx
├── reports/ # 报告输出目录
│ └── 新统一平台权限管理测试用例_差异性报告.docx
├── logs/ # 日志目录
├── run.py # 入口脚本
├── requirements.txt # 依赖包列表
└── README.md # 说明文档
```
---
## 安装说明
### 环境要求
- Python 3.10+
- Anthropic API密钥
### 安装步骤
1. **进入项目目录**
```bash
cd AuxiliaryTool/AIPerfectedTestCases
```
2. **安装依赖**
```bash
pip install -r requirements.txt
```
3. **设置API密钥**
**方式一:使用 .env 文件(推荐)**
复制 `.env.example``.env`,然后编辑 `.env` 文件:
```bash
# 复制模板文件
cp .env.example .env
# 编辑 .env 文件,填入你的API密钥
# ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxxxxxxxxx
```
**方式二:环境变量(临时)**
**Windows:**
```bash
set ANTHROPIC_API_KEY=your-api-key-here
```
**Linux/Mac:**
```bash
export ANTHROPIC_API_KEY=your-api-key-here
```
---
## 使用说明
### 基础用法
```bash
# 使用默认配置运行
python run.py
```
### 命令行参数
| 参数 | 说明 | 示例 |
|------|------|------|
| `--log-level` | 日志级别(DEBUG/INFO/WARNING/ERROR) | `--log-level DEBUG` |
| `--show-info` | 显示项目信息 | `--show-info` |
| `--check-only` | 仅检查环境,不执行处理 | `--check-only` |
| `--help` | 显示帮助信息 | `--help` |
### 使用示例
```bash
# 正常运行
python run.py
# 启用详细日志
python run.py --log-level DEBUG
# 仅检查环境
python run.py --check-only
# 显示项目信息
python run.py --show-info
```
---
## 输入文件说明
### 1. 需求文档(.docx)
- **位置**`config/需求文档/`
- **格式**:Word文档
- **内容**:功能需求描述
### 2. 开发PRD文档(.md)
- **位置**`config/开发PRD/`
- **格式**:Markdown文档
- **内容**:功能实现细节、边界条件
### 3. 测试用例(.xlsx)
- **位置**`config/测试用例/`
- **格式**:Excel表格
- **列定义**
| 列名 | 说明 |
|------|------|
| 序列号 | 序号,用于排序 |
| 功能模块 | 功能模块名称 |
| 用例编号 | 用例编号 |
| 功能描述 | 功能描述 |
| 用例等级 | 用例等级(P0/P1/P2/P3) |
| 功能编号 | 功能编号 |
| 用例名称 | 用例名称 |
| 预置条件 | 测试预置条件 |
| STEP | 步骤描述 |
| JSON | 自动化测试用例(暂不涉及) |
| 预期结果 | 预期结果 |
| 测试结果 | 测试结果 |
| 测试频次 | 测试频次 |
| 日志/截图/照片 | 日志/截图/照片 |
| 备注 | 备注 |
---
## 输出文件说明
### 1. 完善后的测试用例
- **位置**`Perfected/新统一平台权限管理测试用例_完善版本.xlsx`
- **内容**:原始用例 + 新增用例
- **标记**:新增用例有浅蓝色背景
### 2. 差异性报告
- **位置**`reports/新统一平台权限管理测试用例_差异性报告.docx`
- **内容**
- 功能点缺失的测试用例列表
- 场景覆盖不足的测试用例列表
- 边界条件不足的测试用例列表
- 去重处理结果
- 用例数量增长统计
- 覆盖率百分比统计
- 总结和建议
---
## 处理流程
```
1. 读取文档
├─ 读取需求文档(.docx)
├─ 读取PRD文档(.md)
└─ 读取测试用例(.xlsx)
2. 提取功能点
└─ 使用AI从需求文档中提取功能点列表
3. 分析覆盖率
└─ 分析现有测试用例的覆盖情况
4. 检测缺失
├─ 功能点缺失
├─ 场景覆盖不足
└─ 边界条件不足
5. 生成新用例
├─ 为功能点缺失生成用例
├─ 为场景覆盖不足生成用例
└─ 为边界条件不足生成用例
6. 去重处理
└─ 检测并去除重复用例
7. 保存结果
├─ 保存完善后的测试用例
└─ 生成差异性报告
```
---
## 配置说明
配置文件位于 `src/config.py`,可修改以下参数:
### AI配置
```python
AI_MODEL = "claude-sonnet-4-6" # AI模型选择
AI_MAX_TOKENS = 8192 # 最大token数
AI_TEMPERATURE = 0.3 # 温度参数
```
### 覆盖率目标
```python
COVERAGE_TARGET = 0.9 # 90%覆盖率目标
```
### 测试用例配置
```python
CASE_LEVELS = ["P0", "P1", "P2", "P3"] # 用例等级
DEFAULT_CASE_LEVEL = "P1" # 默认等级
DEFAULT_TEST_FREQUENCY = "每版本" # 默认测试频次
```
---
## 注意事项
1. **API密钥安全**:请妥善保管Anthropic API密钥,不要泄露
2. **成本控制**:大量API调用可能产生费用,建议先小规模测试
3. **人工审核**:AI生成的测试用例需要人工审核确认
4. **文件占用**:运行时请确保测试用例文件没有被其他程序打开
5. **网络连接**:需要稳定的网络连接调用AI服务
---
## 常见问题
### Q1: 提示API密钥未设置怎么办?
请设置环境变量:
- Windows: `set ANTHROPIC_API_KEY=your-key-here`
- Linux/Mac: `export ANTHROPIC_API_KEY=your-key-here`
### Q2: 如何获取Anthropic API密钥?
访问 Anthropic 官网:https://www.anthropic.com/
### Q3: 支持哪些AI模型?
目前支持 Claude Sonnet 4.6 和 Claude Opus 4.6,可在 `config.py` 中修改。
### Q4: 生成的测试用例可以直接使用吗?
建议对AI生成的测试用例进行人工审核和修改后使用。
### Q5: 如何调整覆盖率目标?
修改 `src/config.py` 中的 `COVERAGE_TARGET` 参数。
---
## 版本历史
| 版本 | 日期 | 说明 |
|------|------|------|
| v1.0.0 | 2026-03-10 | 初始版本 |
---
## 优化功能回填
- [ ] 支持自定义AI提示词模板
- [ ] 支持增量更新(只处理变更的部分)
- [ ] 支持多轮对话优化用例
- [ ] 支持导出为多种格式
- [ ] 添加用例质量评分
- [ ] 支持批量处理多个项目
- [ ] 支持GUI界面
# 权限数据扩展补充
## 概述
1. **配置项数据地址**:`Docs\Temp\licence.js`
2. **权限控制数据地址**:`Docs\Temp\permission.json`
## 任务
1. ✅ 根据配置项数据补充权限控制数据
2. ✅ 补充权限控制数据的国际化
3. ✅ 补充相关说明文档
### 补充权限控制数据要求
1. 配置项数据和权限控制数据中都包含有`xx_yyyy_list`数据,帮我根据配置项数据并参考权限控制数据原数据补充权限控制数据,每个都包含基础的`view、create、edit、delete`
2. 配置项数据中只要是`xx_yyyy_list`里的数据,都要补充到权限控制数据中
3. 当补充完数据后,需要确认一下是不是每一个都包含在权限控制数据里面了
### 补充权限控制数据的国际化要求
1. 配置项数据中有着一些注释比如`set_room_enable`的注释为"区域管理",这个将代表着`set_room_list`的为"区域管理",子集`office_manage`也有着`办公室管理`的注释
2. 帮我根据注释以及上面的规律,找到国际化文件中的`permissionClass``xx_yyyy_enable`的注释作为`xx_yyyy_list`的国际化添加进行,将子集的注释补充到`permission`中,并实现国际化
3. 当补充完国际化后,需要确认一下国际化中的`permissionClass`是否包含了每一个`xx_yyyy_enable`的注释作为`xx_yyyy_list`的value,`permission`中包含每一个子集的注释
### 相关说明文档补充要求
1. **文档位置**`Docs\Temp\权限配置README.md`
2. 由于权限控制数据是一个json文件,为了说明相关的配置有何功能,所以在文档进行说明,我要你将配置项和相关的文件说明整合到文档中
## 国际化
当涉及到国际化时,遵循`Docs\PRD\_PRD_规范文档_国际化.md`规范
\ No newline at end of file
# 权限管理页面新增开发
## 📋 概述
1. 权限管理页面地址: `src\views\Backend\Admin\PermissionManage\index.vue`
2. 相关API文档地址:`Docs\Api\API_权限组管理接口文档.md`
3. 新增/修改权限组页面地址:`src\views\Backend\Admin\PermissionManage\components\AddEditPage\index.vue`
4. 权限绑定弹窗地址:`src\views\Backend\Admin\PermissionManage\components\BindDialog\index.vue`
5. 自定义权限控制指令v-permission地址:`src\utils\permission.js`
6. 权限组弹窗权限勾选组件:`src\views\Backend\Admin\PermissionManage\components\PermissionConfig\index.vue`
## 🎯 任务
1. ✅ 在权限管理页面遵循`Docs\PRD\_PRD_规范文档_新建页面.md`并标准化初始化页面,在`src\router.js`注册路由
2. ✅ 参考页面`src\views\Backend\Admin\Role\index.vue`的设计在初始化后的权限管理页新增功能
3. ✅ 将权限管理页面的新增/修改权限组弹窗和绑定弹窗分别抽离成组件放置在`src\views\Backend\Admin\PermissionManage\components`中,注意数据的传输,并优化一下样式
4. ✅ 实现权限组添加权限
5. ✅ 在新增/修改权限组弹窗继续实现任务4的要求
6. ✅ 帮我参考API接口文档,实现权限组的增删改查、禁用/启用功能,绑定功能先不实现
7. ✅ 进入权限管理页面时,帮我请求API接口文档的接口`/permissionGroup/getAllPermissions`获取所有配置项,然后将`src\views\Backend\Admin\PermissionManage\components\PermissionConfig\index.vue`的permissionList替换为接口请求到的真实数据
8. ✅ 重构权限绑定弹窗及补充功能实现
9. ✅ 数据结构调整
10. ✅ 用户反馈说新增/修改权限组弹窗和权限绑定弹窗这两个弹窗数据比较多,使用弹窗显示不全,帮我改成页面组件,不需要新建router路由,只需要改为页面级组件,并遵循`Docs\PRD\_PRD_规范文档_新建页面.md`与使用ui-ux-pro-max优化页面样式,要求样式紧凑一点,尽可能显示多的页面数据
11. 帮我参考新增/修改权限组页面样式,实现权限查看功能与页面
### 权限页面基础功能
1. 实现功能时提供了API接口,但先不进行对接,先在前端用虚拟数据实现并预留操作方法等,等我要接口对接时再进行接口对接
2. 支持模糊搜索,支持基础的增删改查
3. el-table的主要显示字段获取参考相关API文档的"分页查询权限组"接口,显示字段groupName、isEnable、createTime,支持多选,支持分页,操作有修改、删除、绑定
### 权限组添加权限要求
1. 实现功能时提供了API接口,但先不进行对接,先在前端用虚拟数据实现并预留操作方法等,等我要接口对接时再进行接口对接
2. 我在`src\constant\permissionList.js`模拟了权限数据,帮我使用el-checkbox进行显示
3. 文本显示逻辑:在国际化文件中新建permission子集,通过key值匹配显示文本:例如view=i18n文件中的`permission.view`
4. 页面显示:要同时显示名称和勾选框,比如
```json
functionType_82: {
view: 0,
create: 0,
update: 0,
delete: 0,
},
```
要显示为"办公室管理:查看 新增 编辑 删除"
### 重构权限绑定弹窗及补充功能实现要求
1. 弹窗页面重构,当前的设计不符合产品的功能要求,具体功能要求:权限组支持同时绑定多个用户、角色、部门,取消权限配置功能
2. 页面样式自由发挥,符合系统主题即可,优先使用UI/UX Pro Max
3. 参考`@src/views/Backend/Account/User/index.vue:930-984 `实现用户数据请求获取
4. 参考`@src/views/Backend/Account/User/index.vue:986-1010 `实现角色数据的请求获取
5. 参考`@src/views/Backend/Account/User/index.vue:263-273 ``@src/views/Backend/Account/User/index.vue:1055-1068 `实现部门数据的请求获取
6. 根据权限api文档的`/permissionGroup/bindRelation`实现权限绑定
## 任务执行要求
- 在执行任务前,判断当前文件根目录下有没有"当前文件+'_计划执行.md'"文件,例如"PRD_实时转录_页面整合.md"与"PRD_实时转录_页面整合_计划执行.md",没有则新建一个
- 在执行任务中,将将要执行的计划补充在"当前文件+'_计划执行.md'"文件中,执行的任务以"当前文件+'_计划执行.md'"为主
- 在执行任务后,将任务执行的结果返回补充到"当前文件+'_计划执行.md'"文件中,需要写明实现了什么,以及有什么优化项或者有什么风险等
## 问题排查要求
- 在问题排查前,判断当前文件根目录下有没有"当前文件+'_分析执行.md'"文件,例如"PRD_实时转录_页面整合.md"与"PRD_实时转录_页面整合_分析执行.md",没有则新建一个
- 在问题排查中,将将要执行的操作补充在"当前文件+'_分析执行.md'"文件中,执行的操作以"当前文件+'_分析执行.md'"为主
- 在问题排查后,将问题修复的结果返回补充到"当前文件+'_分析执行.md'"文件中,需要写明实现了什么,以及有什么优化项或者有什么风险等
## 过程总结返填
- 在执行任务时,先了解相关的页面与方法,先看看有什么不清楚的或者需要我确认的,先找我确认,再进行代码开发
- 在我确认完后,需要把我确认的东西反填到当前文档中,确保信息对齐
## 代码规范
- 严格按照`Docs\PRD\_PRD_规范文档_代码规范.md`
## 文档规范
- 严格按照`Docs\PRD\_PRD_规范文档_文档规范.md`
## 测试验证
- 严格按照`Docs\PRD\_PRD_规范文档_测试规范.md`
\ No newline at end of file
# 需求文档
## 概述
**文件**
- **初始化权限组方法**:com.ubains.meeting.system.service.impl.PermissionGroupServiceImpl.initBasePermissionGroupsForAllCompanies
- **数据库初始化文件**:com/ubains/meeting/common/AdjustmentDb.java
- **原基础角色基本权限组开发相关文件**:
- **原始需求文档**:Docs/PRD/系统管理/权限管理/PRD_权限组管理_添加权限组_给基础角色添加基本权限组.md
- **计划执行文档**:Docs/PRD/系统管理/权限管理/PRD_权限组管理_添加权限组_给基础角色添加基本权限组_计划执行.md
### 背景
原来开发的基础角色和基本权限组有点问题,需要优化调整一下:
1. 基础角色中有个id为2的Admin基础角色,该角色与后续添加的系统管理员冲突了,他们本质应该是同一个
2. id为2的Admin基础角色没有基本权限组
## 任务
- 参考`原基础角色基本权限组开发相关文件`,了解之前的开发逻辑
- `数据库初始化文件`从第615行到第668行,调整基础角色
- id为6的系统管理员角色不要了
- 安全管理员和审计管理员的id往前移1位,即7->6(安全管理员),8->7(审计管理员)
- `初始化权限组方法`调整权限组和角色的绑定
- 系统管理员的权限组绑定id为2的原Admin基础角色
- 绑定安全管理员和审计管理员时设置id往前移1位,即7->6(安全管理员),8->7(审计管理员)
- 先给出计划执行方案文档,将文档创建在`Docs/PRD/+同路径+/同名文件+_计划执行.md`,等审批完文档再由我考虑是否按计划执行文档来执行
- 生成的计划执行方案文档需添加任务:生成ai输出的总结内容到`Docs/Doc/+同路径+/Doc_+同名文件(不包含前缀PRD_)+的总结.md`
## 规范
严格执行以下文档
#### 代码规范
- Docs/PRD/_PRD_规范文档_代码规范.md
#### 文档规范
- Docs/PRD/_PRD_规范文档_文档规范.md
#### 测试规范
- Docs/PRD/_PRD_规范文档_测试规范.md
\ No newline at end of file
## Plan: 权限组管理功能设计
本方案设计一个基于权限组的RBAC权限管理系统。通过`sys_permission_group`权限组表和三个独立关联表(部门、角色、用户),实现权限组的增删改查及绑定关系。删除采用物理删除并级联清理关联数据,权限合并采用并集策略。
### 数据库设计
**1. 权限组表 `sys_permission_group`**
| 字段 | 类型 | 说明 |
|------------------|--------------|------------------------------------------------------|
| `group_id` | bigint | 主键,自增 |
| `group_name` | varchar(100) | 权限组名称 |
| `permissions` | text | 权限配置JSON,如 `{"permission1":{"create":1,"delete":0}}` |
| `company_number` | varchar(64) | 公司编号(多租户) |
| `is_enable` | int | 是否启用(0:禁用,1:启用) |
| `is_base` | int | 是否基础权限组(0:否,1:是) |
| `create_time` | datetime | 创建时间 |
| `update_time` | datetime | 更新时间 |
**2. 权限组-部门关联表 `sys_permission_group_department`**
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | bigint | 主键,自增 |
| `group_id` | bigint | 权限组ID |
| `department_id` | bigint | 部门ID |
| `create_time` | datetime | 创建时间 |
**索引**`idx_group_id(group_id)``idx_department_id(department_id)`
**3. 权限组-角色关联表 `sys_permission_group_role`**
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | bigint | 主键,自增 |
| `group_id` | bigint | 权限组ID |
| `role_id` | bigint | 角色ID |
| `create_time` | datetime | 创建时间 |
**索引**`idx_group_id(group_id)``idx_role_id(role_id)`
**4. 权限组-用户关联表 `sys_permission_group_user`**
| 字段 | 类型 | 说明 |
|------|------|------|
| `id` | bigint | 主键,自增 |
| `group_id` | bigint | 权限组ID |
| `user_id` | bigint | 用户ID |
| `create_time` | datetime | 创建时间 |
**索引**`idx_group_id(group_id)``idx_user_id(user_id)`
**3. permission.json 配置文件格式**
```json
{
"permission1": {"create": 0, "delete": 0, "edit": 0},
"permission2": {"create": 0, "delete": 0, "edit": 0, "view": 0}
}
```
### 接口设计
| 接口 | URL | 方法 | 说明 |
|------|-----|------|------|
| 分页查询权限组 | `/permissionGroup/getPage` | POST | 返回权限组分页列表 |
| 获取所有权限配置 | `/permissionGroup/getAllPermissions` | GET | 读取permission.json返回所有可选权限 |
| 新增权限组 | `/permissionGroup/add` | POST | 创建权限组及权限配置 |
| 修改权限组 | `/permissionGroup/update` | PUT | 更新权限组名称和权限配置 |
| 删除权限组 | `/permissionGroup/delete` | POST | 物理删除权限组,级联删除关联记录 |
| 绑定关系 | `/permissionGroup/bindRelation` | POST | 绑定部门/角色/用户(type区分) |
| 解绑关系 | `/permissionGroup/unbindRelation` | POST | 解绑部门/角色/用户 |
| 查询绑定关系 | `/permissionGroup/getRelations` | POST | 查询权限组已绑定的对象列表 |
| 查询用户最终权限 | `/permissionGroup/getUserPermissions` | GET | 返回用户通过所有途径获得的并集权限 |
### 权限合并逻辑
查询用户最终权限时,合并以下三个来源的权限组:
1. **直接绑定**:查询 `sys_permission_group_user` 表中 `user_id=用户ID` 的权限组
2. **部门绑定**:查询 `sys_permission_group_department` 表中 `department_id=用户所属部门ID` 的权限组
3. **角色绑定**:查询 `sys_permission_group_role` 表中 `role_id=用户所属角色ID` 的权限组
合并策略:对所有权限组的`permissions`字段进行JSON并集,同一操作项有任意一个为1则最终为1。
### Steps
1.[ubains-meeting-persistence](ubains-meeting-persistence/src/main) 创建`PermissionGroup``PermissionGroupDepartment``PermissionGroupRole``PermissionGroupUser`四个实体类,Mapper接口继承`BaseMapper`
2.[ubains-meeting-provider](ubains-meeting-provider/src/main) 创建`IPermissionGroupService`接口及实现类,实现CRUD、绑定解绑、权限并集合并逻辑
3.[ubains-meeting-inner-api/resources](ubains-meeting-inner-api/src/main/resources) 创建`permission.json`配置文件
4.[ubains-meeting-inner-api](ubains-meeting-inner-api/src/main) 创建`PermissionGroupController`,实现9个API接口,删除接口使用`@Transactional`保证级联删除的事务一致性
5. 创建`PermissionUtil`工具类封装权限JSON并集合并方法,供Service层和权限校验拦截器调用
6. 在src/main/java/com/ubains/meeting/common/AdjustmentDb.java的adjustmentDb方法创建对应数据库表
7. 输出PermissionGroupController的接口文档到Docs/Doc/权限管理目录下“API_权限组管理接口文档.md”
### SQL参考
```sql
-- 权限组表
CREATE TABLE `sys_permission_group` (
`group_id` bigint NOT NULL AUTO_INCREMENT,
`group_name` varchar(100) NOT NULL COMMENT '权限组名称',
`permissions` text COMMENT '权限配置JSON',
`company_number` varchar(64) DEFAULT NULL COMMENT '公司编号',
`is_enable` int DEFAULT 1 COMMENT '是否启用(0:禁用,1:启用)',
`is_base` int DEFAULT 0 COMMENT '是否基础权限组(0:否,1:是)',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`group_id`),
KEY `idx_company` (`company_number`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限组表';
-- 权限组-部门关联表
CREATE TABLE `sys_permission_group_department` (
`id` bigint NOT NULL AUTO_INCREMENT,
`group_id` bigint NOT NULL COMMENT '权限组ID',
`department_id` bigint NOT NULL COMMENT '部门ID',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_group_id` (`group_id`),
KEY `idx_department_id` (`department_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限组-部门关联表';
-- 权限组-角色关联表
CREATE TABLE `sys_permission_group_role` (
`id` bigint NOT NULL AUTO_INCREMENT,
`group_id` bigint NOT NULL COMMENT '权限组ID',
`role_id` bigint NOT NULL COMMENT '角色ID',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_group_id` (`group_id`),
KEY `idx_role_id` (`role_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限组-角色关联表';
-- 权限组-用户关联表
CREATE TABLE `sys_permission_group_user` (
`id` bigint NOT NULL AUTO_INCREMENT,
`group_id` bigint NOT NULL COMMENT '权限组ID',
`user_id` bigint NOT NULL COMMENT '用户ID',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_group_id` (`group_id`),
KEY `idx_user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='权限组-用户关联表';
```
### 其他
1.把AI的总结内容输出ubains-meeting-parent\Docs\Doc\权限管理目录下的“PRD_权限组管理_增删改查_权限组功能开发设计的总结.md”
2.日志和注释要详细,尤其是日志,详细到每个步骤和返回,采用LogsUtil的logxxxInverted方法
\ No newline at end of file
# 权限组管理_权限结构_调整权限数据结构
## 概述
原开发的设计文档:Docs\PRD\PRD_系统\权限管理\PRD_权限组管理_增删改查_权限组功能开发设计.md
代码:com.ubains.controller.system.PermissionGroupController
## 目标
1.调整读取permission.json权限配置文件(getAllPermissions)和获取用户最终权限方法(getUserPermissions),
原permission.json的数据结构为`{"permission1":{"create":1,"delete":0}}`
调整后的数据结构为`{"class1":{"permission1":{"create":0,"delete":0,"edit":0}},"class2":{"permission1":{"create":0,"delete":0,"edit":0}}}`,原来的基础上增加了一层权限分类。
2.getAllPermissions方法返回的数据要求permission.json的数据顺序一致。
### 其他
1.把AI的总结内容输出ubains-meeting-parent\Docs\Doc\权限管理目录下的“PRD_权限组管理_权限结构_调整权限数据结构的总结.md”
2.日志和注释要详细,尤其是日志,详细到每个步骤和返回,采用LogsUtil的logxxxInverted方法
\ No newline at end of file
# 需求文档
## 概述
给基础角色添加基本权限组。
基础角色:
- `超级管理员` 角色id = 1
- `系统管理员` 角色id = 6
- `安全管理员` 角色id = 7
- `审计管理员` 角色id = 8
相关文件和代码:
- com.ubains.meeting.common.AdjustmentDb.adjustmentDb 数据库迁移方法,系统初始化时执行
- com.ubains.meeting.system.entity.Role 角色实体类
- com.ubains.meeting.system.entity.PermissionGroup 权限组实体类
-
- 权限组设计相关文件:
- Docs/PRD/PRD_系统/权限管理 该目录下的其他文档是原来权限组设计的文档
- ubains-meeting-inner-api/src/main/resources/config/permission.yml 权限文件
### 任务
- 给基础角色添加基本权限组,权限组名称对应角色名称
- **权限组按公司编号隔离**:每个公司都需要创建4个基础权限组,通过`company_number`字段区分
-`PermissionGroupService`中实现初始化逻辑,在`adjustmentDb`方法中调用
- 超级管理员读取`permission.yml`文件获取所有权限,作为权限组的权限,关联角色id为1
- 系统管理员读取`permission-system.yml`文件(需创建)获取所有权限,作为权限组的权限,关联角色id为6
- 安全管理员读取`permission-security.yml`文件(需创建)获取所有权限,作为权限组的权限,关联角色id为7
- 审计管理员读取`permission-audit.yml`文件(需创建)获取所有权限,作为权限组的权限,关联角色id为8
- 基础权限组的`isBase`字段值为1
- **ID说明**`role_id`固定为1/6/7/8,`group_id`和关联表`id`为自增主键,通过`is_base`+`group_name`+`company_number`判断权限组是否存在
- **优化 `PermissionUtil#loadPermissionConfig()` 方法**:新增带参数的重载方法 `loadPermissionConfig(String fileName)`,支持读取指定的权限配置文件(如 `permission-system.yml`
- 开发前先给出计划执行方案文档到在`Docs/PRD/PRD_系统/权限管理/同名文件+_计划执行.md`
- 生成的计划执行方案文档需添加任务:生成ai输出的总结内容到`Docs/Doc/权限管理/Doc_+同名文件(不包含前缀PRD_)+的总结.md`
### 方法总结
- Docs/PRD/PRD模板、规范/_PRD_方法总结_记录文档.md
### 代码规范
- Docs/PRD/PRD模板、规范/_PRD_规范文档_代码规范.md
### 文档规范
- Docs/PRD/PRD模板、规范/_PRD_规范文档_文档规范.md
### 测试规范
- Docs/PRD/PRD模板、规范/_PRD_规范文档_测试规范.md
### 记录文档
- Docs/PRD/PRD模板、规范/_PRD_问题总结_记录文档.md
# 需求文档
## 概述
权限组目前需要查看详情功能,详情除了基本权限组信息外,还需要有已绑定的角色、部门和用户信息。
**权限组的控制层**:com.ubains.controller.system.PermissionGroupController
## 任务
-`权限组的控制层`上添加新的接口,该接口用于查看权限组详情,该详情包含权限组基本信息、已绑定的角色、部门、用户信息
- 角色、部门、用户信息,不需要多余信息,主要显示名称和id即可
- 注意接口返回要结果加密,使用`@EncryptResult`注解
- 先给出计划执行方案文档,将文档创建在`Docs/PRD/系统管理/权限管理/同名文件+_计划执行.md`,等审批完文档再由我考虑是否按计划执行文档来执行
- 生成的计划执行方案文档需添加任务:生成API文档到`Docs/Doc/系统管理/权限管理/Doc_+同名文件(不包含前缀PRD_)+_API.md`
- 生成的计划执行方案文档需添加任务:生成ai输出的总结内容到`Docs/Doc/系统管理/权限管理/Doc_+同名文件(不包含前缀PRD_)+的总结.md`
## 规范
严格执行以下文档
#### 代码规范
- Docs/PRD/_PRD_规范文档_代码规范.md
#### 文档规范
- Docs/PRD/_PRD_规范文档_文档规范.md
#### 测试规范
- Docs/PRD/_PRD_规范文档_测试规范.md
\ No newline at end of file
# AI完善测试用例工具 - 依赖包列表
# Anthropic AI SDK - Claude API
anthropic>=0.18.0
# Excel文件处理
openpyxl>=3.1.0
# Word文档处理
python-docx>=1.1.0
# 数据处理(可选,用于高级分析)
pandas>=2.0.0
# 环境变量管理
python-dotenv>=1.0.0
# 其他依赖
python-dateutil>=2.8.0
# -*- coding: utf-8 -*-
"""
AI完善测试用例工具 - 入口脚本
使用方法:
python run.py # 使用默认配置
python run.py --help # 显示帮助信息
python run.py --log-level DEBUG # 设置日志级别
"""
import sys
import os
import argparse
from pathlib import Path
# 添加项目根目录到Python路径
PROJECT_ROOT = Path(__file__).parent
sys.path.insert(0, str(PROJECT_ROOT))
# 加载环境变量
try:
from dotenv import load_dotenv
env_file = PROJECT_ROOT / ".env"
if env_file.exists():
load_dotenv(env_file)
# 已自动加载 .env 文件
except ImportError:
pass # python-dotenv 未安装,跳过
from src.config import (
REQUIREMENTS_DIR,
PRD_DIR,
TEST_CASE_FILE,
OUTPUT_TEST_CASE,
OUTPUT_REPORT,
API_KEY_ENV,
get_project_info,
AI_MODEL
)
def print_banner() -> None:
"""打印欢迎横幅"""
print("=" * 60)
print(" AI完善测试用例工具 v1.0.0")
print("=" * 60)
print()
def print_project_info() -> None:
"""打印项目信息"""
info = get_project_info()
print("【项目配置】")
print(f" 项目根目录: {info['project_root']}")
print(f" 需求文档目录: {info['requirements_dir']}")
print(f" PRD文档目录: {info['prd_dir']}")
print(f" 测试用例文件: {info['test_case_file']}")
print(f" AI模型: {info['ai_model']}")
print(f" 覆盖率目标: {info['coverage_target'] * 100}%")
print()
def check_environment() -> bool:
"""
检查运行环境
Returns:
环境是否正常
"""
print("【环境检查】")
# 检查API密钥
api_key = os.environ.get(API_KEY_ENV)
if api_key:
masked_key = api_key[:8] + "..." if len(api_key) > 8 else "***"
print(f" ✓ API密钥: {masked_key}")
else:
print(f" ✗ API密钥: 未设置 ({API_KEY_ENV})")
print()
print("请设置API密钥:")
print(f" Windows: set {API_KEY_ENV}=your-key-here")
print(f" Linux/Mac: export {API_KEY_ENV}=your-key-here")
return False
# 检查需求文档目录
if REQUIREMENTS_DIR.exists():
req_files = list(REQUIREMENTS_DIR.glob("*.docx"))
print(f" ✓ 需求文档: {len(req_files)} 份")
else:
print(f" ✗ 需求文档目录不存在: {REQUIREMENTS_DIR}")
return False
# 检查PRD文档目录
if PRD_DIR.exists():
prd_files = list(PRD_DIR.glob("*.md"))
print(f" ✓ PRD文档: {len(prd_files)} 份")
else:
print(f" ✗ PRD文档目录不存在: {PRD_DIR}")
return False
# 检查测试用例文件
if TEST_CASE_FILE.exists():
print(f" ✓ 测试用例文件: {TEST_CASE_FILE.name}")
else:
print(f" ✗ 测试用例文件不存在: {TEST_CASE_FILE}")
return False
print()
return True
def test_api_connection() -> int:
"""
测试API连接
Returns:
退出码(0表示成功,非0表示失败)
"""
print("【测试API连接】")
print()
api_key = os.environ.get(API_KEY_ENV)
if not api_key:
print("✗ 未设置API密钥")
print(f" 请设置环境变量: {API_KEY_ENV}")
print(" 或在 .env 文件中配置")
return 1
# 隐藏密钥显示
masked_key = api_key[:8] + "..." if len(api_key) > 8 else "***"
print(f"API密钥: {masked_key}")
print(f"AI模型: {AI_MODEL}")
print()
try:
import anthropic
client = anthropic.Anthropic(api_key=api_key)
print("发送测试请求...")
response = client.messages.create(
model=AI_MODEL,
max_tokens=50,
messages=[{"role": "user", "content": "请回复:API连接成功"}]
)
result = response.content[0].text
print()
print("✓ API连接正常")
print(f" AI回复: {result}")
return 0
except anthropic.AuthenticationError:
print()
print("✗ API密钥认证失败")
print(" 请检查API密钥是否正确")
return 1
except anthropic.PermissionDeniedError:
print()
print("✗ API权限不足")
print(" 请检查API密钥是否有调用权限")
return 1
except anthropic.RateLimitError:
print()
print("✗ API调用频率超限")
print(" 请稍后再试")
return 1
except anthropic.APIError as e:
print()
print(f"✗ API错误: {e}")
return 1
except Exception as e:
print()
print(f"✗ 连接失败: {e}")
return 1
def parse_arguments() -> argparse.Namespace:
"""
解析命令行参数
Returns:
解析后的参数对象
"""
parser = argparse.ArgumentParser(
description="AI完善测试用例工具 - 通过AI分析需求文档和PRD文档,自动完善测试用例",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
示例用法:
python run.py # 使用默认配置运行
python run.py --log-level DEBUG # 启用详细日志
python run.py --show-info # 显示项目信息
python run.py --mode api # 强制使用API模式
python run.py --mode cli # 强制使用CLI模式
python run.py --api-key sk-ant-... # 指定API密钥
环境变量:
ANTHROPIC_API_KEY # Anthropic API密钥(API模式必需)
AI_SERVICE_MODE # AI服务模式:auto/api/cli
输出文件:
完善后的测试用例: Perfected/新统一平台权限管理测试用例_完善版本.xlsx
差异性报告: reports/新统一平台权限管理测试用例_差异性报告.docx
"""
)
parser.add_argument(
'--log-level',
type=str,
dest='log_level',
default='INFO',
choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
help='日志级别(默认为INFO)'
)
parser.add_argument(
'--show-info',
action='store_true',
dest='show_info',
help='显示项目信息后退出'
)
parser.add_argument(
'--check-only',
action='store_true',
dest='check_only',
help='仅检查环境,不执行处理'
)
parser.add_argument(
'--test-api',
action='store_true',
dest='test_api',
help='测试API连接'
)
parser.add_argument(
'--use-cli',
action='store_true',
dest='use_cli',
help='强制使用Claude CLI模式(已弃用,建议使用--mode cli)'
)
parser.add_argument(
'--mode',
type=str,
dest='mode',
default=None,
choices=['auto', 'api', 'cli'],
help='AI服务模式:auto(自动检测)、api(Anthropic API)、cli(Claude CLI)'
)
parser.add_argument(
'--api-key',
type=str,
dest='api_key',
default=None,
help='Anthropic API密钥(覆盖环境变量)'
)
return parser.parse_args()
def run_cli(args: argparse.Namespace) -> int:
"""
运行命令行程序
Args:
args: 命令行参数
Returns:
退出码(0表示成功,非0表示失败)
"""
# 设置AI服务模式(通过环境变量传递)
if args.mode:
os.environ["AI_SERVICE_MODE"] = args.mode
# 设置API密钥(通过环境变量传递)
if args.api_key:
os.environ[API_KEY_ENV] = args.api_key
# 测试API连接
if args.test_api:
return test_api_connection()
# 打印横幅
print_banner()
# 仅显示信息
if args.show_info:
print_project_info()
return 0
# 仅检查环境
if args.check_only:
if check_environment():
print("✓ 环境检查通过")
return 0
else:
print("✗ 环境检查失败")
return 1
# 检查环境
if not check_environment():
return 1
# 打印项目信息
print_project_info()
# 导入主模块并运行
from src.main import main as run_main
print("【开始处理】")
print()
return run_main(use_cli=args.use_cli)
def main() -> int:
"""
主入口函数
Returns:
退出码
"""
args = parse_arguments()
return run_cli(args)
if __name__ == "__main__":
try:
exit_code = main()
sys.exit(exit_code)
except KeyboardInterrupt:
print("\n\n操作已取消")
sys.exit(130)
except Exception as e:
print(f"\n错误: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
# -*- coding: utf-8 -*-
"""
AI完善测试用例工具
本工具通过结合已有测试用例、需求文档、开发需求PRD文档,
利用AI能力对测试用例进行查漏补缺,完善测试用例内容。
"""
__version__ = "1.0.0"
__author__ = "AI Test Case Enhancer"
# -*- coding: utf-8 -*-
"""
Claude CLI适配器模块
通过subprocess调用claude命令行工具
"""
import subprocess
import json
from typing import Optional, Dict, Any, List
from logging import getLogger
logger = getLogger(__name__)
class ClaudeCLIAdapter:
"""
Claude CLI适配器
通过调用本地的claude命令行工具来使用AI能力
"""
def __init__(self, timeout: int = 300):
"""
初始化适配器
Args:
timeout: 超时时间(秒),默认5分钟
"""
self.timeout = timeout
self.available = None
self.version = None
logger.info("Claude CLI适配器初始化完成")
def check_available(self) -> bool:
"""
检查claude命令是否可用
Returns:
True表示可用,False表示不可用
"""
if self.available is not None:
return self.available
try:
result = subprocess.run(
["claude", "--version"],
capture_output=True,
text=True,
timeout=10,
encoding="utf-8"
)
if result.returncode == 0:
self.version = result.stdout.strip()
self.available = True
logger.info("Claude CLI可用,版本: %s", self.version)
return True
else:
self.available = False
logger.warning("Claude CLI命令返回错误: %s", result.stderr)
return False
except FileNotFoundError:
self.available = False
logger.error("未找到claude命令,请确认已安装Claude Code CLI")
logger.error("安装方式: npm install -g @anthropic-ai/claude-code")
return False
except Exception as e:
self.available = False
logger.error("检查claude命令失败: %s", e)
return False
def ask(self, prompt: str, model: Optional[str] = None) -> str:
"""
调用claude ask命令
Args:
prompt: 提示词
model: 模型名称(可选,默认使用claude配置的默认模型)
Returns:
AI回复文本
"""
if not self.check_available():
raise RuntimeError("Claude CLI不可用")
logger.info("调用Claude CLI...")
logger.debug("提示词长度: %d 字符", len(prompt))
# 构建命令
cmd = ["claude", "ask"]
if model:
cmd.extend(["--model", model])
cmd.append(prompt)
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=self.timeout,
encoding="utf-8"
)
if result.returncode == 0:
response = result.stdout.strip()
logger.info("Claude CLI调用成功,返回 %d 字符", len(response))
return response
else:
error_msg = result.stderr.strip()
logger.error("Claude CLI调用失败: %s", error_msg)
raise RuntimeError(f"Claude CLI error: {error_msg}")
except subprocess.TimeoutExpired:
logger.error("Claude CLI调用超时(%d秒)", self.timeout)
raise TimeoutError(f"Claude CLI调用超时({self.timeout}秒)")
except Exception as e:
logger.error("Claude CLI调用异常: %s", e)
raise
def ask_json(self, prompt: str, model: Optional[str] = None) -> Dict:
"""
调用claude ask命令,并解析JSON返回
Args:
prompt: 提示词
model: 模型名称(可选)
Returns:
解析后的JSON对象
"""
# 确保提示词要求JSON格式
if "JSON" not in prompt and "json" not in prompt.lower():
if prompt.endswith("。"):
prompt = prompt[:-1] + ",请输出JSON格式的结果。"
else:
prompt = prompt + "\n\n请输出JSON格式的结果。"
response = self.ask(prompt, model)
return self._parse_json_response(response)
def ask_json_array(self, prompt: str, model: Optional[str] = None) -> List[Dict]:
"""
调用claude ask命令,并解析JSON数组返回
Args:
prompt: 提示词
model: 模型名称(可选)
Returns:
解析后的JSON数组
"""
# 确保提示词要求JSON数组格式
if "JSON" not in prompt and "json" not in prompt.lower():
if prompt.endswith("。"):
prompt = prompt[:-1] + ",请输出JSON数组格式的结果。"
else:
prompt = prompt + "\n\n请输出JSON数组格式的结果。"
response = self.ask(prompt, model)
return self._parse_json_array_response(response)
def _parse_json_response(self, response: str) -> Dict:
"""
解析JSON响应
Args:
response: AI返回的文本
Returns:
解析后的JSON对象
"""
try:
return json.loads(response)
except json.JSONDecodeError:
# 尝试提取JSON部分
try:
start = response.find("{")
end = response.rfind("}") + 1
if start >= 0 and end > start:
json_str = response[start:end]
return json.loads(json_str)
except:
pass
logger.error("无法解析JSON响应")
logger.debug("响应内容: %s", response[:500])
raise ValueError("响应不是有效的JSON格式")
def _parse_json_array_response(self, response: str) -> List:
"""
解析JSON数组响应
Args:
response: AI返回的文本
Returns:
解析后的JSON数组
"""
try:
result = json.loads(response)
if isinstance(result, list):
return result
else:
# 如果返回的是对象,尝试提取数组字段
if isinstance(result, dict):
for key, value in result.items():
if isinstance(value, list):
logger.info("从JSON对象中提取数组: %s", key)
return value
return [result]
except json.JSONDecodeError:
# 尝试提取JSON部分
try:
start = response.find("[")
end = response.rfind("]") + 1
if start >= 0 and end > start:
json_str = response[start:end]
return json.loads(json_str)
except:
pass
logger.error("无法解析JSON数组响应")
logger.debug("响应内容: %s", response[:500])
raise ValueError("响应不是有效的JSON数组格式")
def test_claude_cli() -> Dict:
"""
测试Claude CLI连接
Returns:
测试结果字典
"""
adapter = ClaudeCLIAdapter()
result = {
"available": False,
"version": None,
"error": None
}
try:
if adapter.check_available():
result["available"] = True
result["version"] = adapter.version
# 测试调用
logger.info("发送测试请求...")
response = adapter.ask("请回复:测试成功", model="claude-sonnet-4-6")
if "测试成功" in response or "test" in response.lower():
result["test_passed"] = True
else:
result["test_passed"] = False
result["response"] = response
else:
result["error"] = "Claude CLI不可用"
except Exception as e:
result["error"] = str(e)
return result
# 便捷函数
def call_claude(prompt: str, model: Optional[str] = None, timeout: int = 300) -> str:
"""
便捷函数:调用Claude CLI
Args:
prompt: 提示词
model: 模型名称(可选)
timeout: 超时时间(秒)
Returns:
AI回复文本
"""
adapter = ClaudeCLIAdapter(timeout=timeout)
return adapter.ask(prompt, model)
def call_claude_json(prompt: str, model: Optional[str] = None, timeout: int = 300) -> Dict:
"""
便捷函数:调用Claude CLI并返回JSON
Args:
prompt: 提示词
model: 模型名称(可选)
timeout: 超时时间(秒)
Returns:
解析后的JSON对象
"""
adapter = ClaudeCLIAdapter(timeout=timeout)
return adapter.ask_json(prompt, model)
# -*- coding: utf-8 -*-
"""
AI完善测试用例工具 - 配置模块
本模块定义项目所需的配置常量和路径
"""
from pathlib import Path
# ==================== 项目路径 ====================
# 项目根目录
PROJECT_ROOT = Path(__file__).parent.parent
# 配置目录
CONFIG_DIR = PROJECT_ROOT / "config"
# 输出目录
PERFECTED_DIR = PROJECT_ROOT / "Perfected"
REPORTS_DIR = PROJECT_ROOT / "reports"
LOGS_DIR = PROJECT_ROOT / "logs"
# ==================== 输入路径 ====================
# 需求文档目录
REQUIREMENTS_DIR = CONFIG_DIR / "需求文档"
# 开发PRD文档目录
PRD_DIR = CONFIG_DIR / "开发PRD"
# 测试用例文件
TEST_CASE_FILE = CONFIG_DIR / "测试用例" / "新统一平台权限管理测试用例.xlsx"
# ==================== 输出路径 ====================
# 输出测试用例文件
OUTPUT_TEST_CASE = PERFECTED_DIR / "新统一平台权限管理测试用例_完善版本.xlsx"
# 输出差异性报告文件
OUTPUT_REPORT = REPORTS_DIR / "新统一平台权限管理测试用例_差异性报告.docx"
# ==================== 测试用例列定义 ====================
# 测试用例Excel表格的列名
TEST_CASE_COLUMNS = [
"序列号", # 序号,用于排序
"功能模块", # 功能模块名称,用于分类
"用例编号", # 用例编号,用于标识用例
"功能描述", # 功能描述,用于描述功能
"用例等级", # 用例等级,用于描述用例的优先级
"功能编号", # 功能编号,用于标识功能
"用例名称", # 用例名称,用于标识用例
"预置条件", # 测试用例的预置条件,用于准备测试环境
"STEP", # 步骤描述
"JSON", # 自动化测试用例,暂不涉及
"预期结果", # 测试用例的预期结果,用于描述测试结果
"测试结果", # 测试用例的测试结果,用于描述测试结果
"测试频次", # 测试用例的测试频次,用于描述测试用例的测试频次
"日志/截图/照片", # 用于记录测试过程中产生的日志、截图、照片
"备注" # 用于记录测试过程中产生的问题,用于问题排查
]
# ==================== AI配置 ====================
# AI模型选择
# 可选值: "claude-sonnet-4-6", "claude-opus-4-6"
AI_MODEL = "claude-sonnet-4-6"
# AI最大token数
AI_MAX_TOKENS = 8192
# AI温度参数(较低温度确保稳定性)
AI_TEMPERATURE = 0.3
# API密钥环境变量名
API_KEY_ENV = "ANTHROPIC_API_KEY"
# API基础URL(可选,用于代理服务)
# 官方API: https://api.anthropic.com
# CCSwitch等代理: 根据服务商提供的地址配置
API_BASE_URL = "https://api.anthropic.com"
# ==================== AI服务模式 ====================
# AI服务模式:auto(自动检测)、api(Anthropic API)、cli(Claude CLI)
AI_SERVICE_MODE = "auto"
# Claude CLI超时时间(秒)
CLI_TIMEOUT = 300
# API密钥格式前缀(用于验证)
API_KEY_PREFIX = "sk-ant-api03-"
# ==================== 覆盖率目标 ====================
# 场景覆盖率目标(90%)
COVERAGE_TARGET = 0.9
# ==================== 日志配置 ====================
# 日志格式
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# 日志日期格式
LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
# 日志文件名
LOG_FILE = LOGS_DIR / "ai_test_case_enhancer.log"
# ==================== 用例编号格式 ====================
# 用例编号前缀
CASE_NUMBER_PREFIX = "TC"
# ==================== 用例等级定义 ====================
# 用例等级选项
CASE_LEVELS = ["P0", "P1", "P2", "P3"]
# 默认用例等级
DEFAULT_CASE_LEVEL = "P1"
# ==================== 测试频次定义 ====================
# 测试频次选项
TEST_FREQUENCIES = ["每次", "每日", "每周", "每月", "每版本", "一次性"]
# 默认测试频次
DEFAULT_TEST_FREQUENCY = "每版本"
def ensure_directories() -> None:
"""
确保所有必要的目录存在
"""
PERFECTED_DIR.mkdir(parents=True, exist_ok=True)
REPORTS_DIR.mkdir(parents=True, exist_ok=True)
LOGS_DIR.mkdir(parents=True, exist_ok=True)
def get_project_info() -> dict:
"""
获取项目信息
Returns:
项目信息字典
"""
return {
"project_root": str(PROJECT_ROOT),
"config_dir": str(CONFIG_DIR),
"requirements_dir": str(REQUIREMENTS_DIR),
"prd_dir": str(PRD_DIR),
"test_case_file": str(TEST_CASE_FILE),
"output_test_case": str(OUTPUT_TEST_CASE),
"output_report": str(OUTPUT_REPORT),
"ai_model": AI_MODEL,
"coverage_target": COVERAGE_TARGET
}
def get_ai_service_mode() -> str:
"""
获取AI服务模式
优先级:环境变量 > 配置文件常量
Returns:
服务模式:'auto', 'api', 'cli'
"""
import os
mode = os.environ.get("AI_SERVICE_MODE", AI_SERVICE_MODE).lower()
# 验证模式值
if mode not in ("auto", "api", "cli"):
return AI_SERVICE_MODE
return mode
def get_api_base_url() -> str:
"""
获取API基础URL
优先级:环境变量 > 配置文件常量
Returns:
API基础URL
"""
import os
return os.environ.get("API_BASE_URL", API_BASE_URL)
# -*- coding: utf-8 -*-
"""
去重模块
本模块负责对生成的测试用例进行去重处理
"""
from typing import List, Dict, Set
from logging import getLogger
import hashlib
logger = getLogger(__name__)
class Deduplicator:
"""
测试用例去重器
主要功能:
1. 检测重复的测试用例
2. 保留唯一用例
3. 生成去重报告
"""
def __init__(self):
"""初始化去重器"""
logger.info("测试用例去重器初始化完成")
def deduplicate(self, existing_cases: List[Dict],
new_cases: List[Dict]) -> Dict:
"""
去重处理
Args:
existing_cases: 现有测试用例列表
new_cases: 新生成的测试用例列表
Returns:
去重结果,包含:
- unique_cases: 唯一用例列表
- duplicate_cases: 重复用例列表
- duplicate_count: 重复用例数量
- summary: 去重统计
"""
logger.info("开始去重处理...")
logger.info("现有用例: %d 条,新生成用例: %d 条",
len(existing_cases), len(new_cases))
# 构建现有用例的指纹集合
existing_fingerprints = set()
for case in existing_cases:
fp = self._generate_fingerprint(case)
existing_fingerprints.add(fp)
logger.debug("现有用例指纹数: %d", len(existing_fingerprints))
# 筛选新用例
unique_cases = []
duplicate_cases = []
new_fingerprints = set()
for i, case in enumerate(new_cases):
fp = self._generate_fingerprint(case)
# 检查是否与现有用例重复
if fp in existing_fingerprints:
duplicate_cases.append({
**case,
"_duplicate_type": "existing",
"_fingerprint": fp
})
logger.debug("新用例 %d 与现有用例重复", i + 1)
continue
# 检查是否与新用例列表中的其他用例重复
if fp in new_fingerprints:
duplicate_cases.append({
**case,
"_duplicate_type": "new",
"_fingerprint": fp
})
logger.debug("新用例 %d 在新用例列表中重复", i + 1)
continue
# 唯一用例
unique_cases.append(case)
new_fingerprints.add(fp)
# 生成统计报告
summary = {
"existing_cases": len(existing_cases),
"new_cases": len(new_cases),
"unique_cases": len(unique_cases),
"duplicate_with_existing": len([c for c in duplicate_cases if c.get("_duplicate_type") == "existing"]),
"duplicate_within_new": len([c for c in duplicate_cases if c.get("_duplicate_type") == "new"]),
"total_duplicates": len(duplicate_cases),
"deduplication_rate": len(unique_cases) / len(new_cases) if new_cases else 0
}
logger.info("去重完成:")
logger.info(" 唯一新用例: %d 条", summary["unique_cases"])
logger.info(" 与现有用例重复: %d 条", summary["duplicate_with_existing"])
logger.info(" 新用例内部重复: %d 条", summary["duplicate_within_new"])
logger.info(" 总计重复: %d 条", summary["total_duplicates"])
logger.info(" 去重率: %.1f%%", summary["deduplication_rate"] * 100)
return {
"unique_cases": unique_cases,
"duplicate_cases": duplicate_cases,
"summary": summary
}
def _generate_fingerprint(self, case: Dict) -> str:
"""
生成用例指纹(用于去重)
Args:
case: 测试用例字典
Returns:
用例指纹字符串
"""
# 使用关键字段生成唯一标识
key_parts = [
str(case.get("功能描述", "")).strip(),
str(case.get("用例名称", "")).strip(),
str(case.get("功能编号", "")).strip()
]
# 将关键字段拼接后生成哈希
content = "|".join(key_parts).strip().lower()
# 如果内容为空,返回空字符串
if not content:
return ""
# 生成MD5哈希
return hashlib.md5(content.encode('utf-8')).hexdigest()
def fuzzy_deduplicate(self, cases: List[Dict],
similarity_threshold: float = 0.85) -> Dict:
"""
模糊去重(基于相似度)
Args:
cases: 测试用例列表
similarity_threshold: 相似度阈值
Returns:
模糊去重结果
"""
logger.info("开始模糊去重(相似度阈值: %.2f)...", similarity_threshold)
unique_cases = []
duplicate_cases = []
checked_indices = set()
for i, case1 in enumerate(cases):
if i in checked_indices:
continue
is_duplicate = False
for j, case2 in enumerate(cases):
if i >= j or j in checked_indices:
continue
similarity = self._calculate_similarity(case1, case2)
if similarity >= similarity_threshold:
# case2 与 case1 相似,标记为重复
duplicate_cases.append({
**case2,
"_duplicate_type": "fuzzy",
"_similar_to": i,
"_similarity": similarity
})
checked_indices.add(j)
is_duplicate = True
logger.debug("用例 %d 与用例 %d 相似(%.2f)", i, j, similarity)
if not is_duplicate:
unique_cases.append(case1)
checked_indices.add(i)
logger.info("模糊去重完成:")
logger.info(" 唯一用例: %d 条", len(unique_cases))
logger.info(" 相似重复: %d 条", len(duplicate_cases))
return {
"unique_cases": unique_cases,
"duplicate_cases": duplicate_cases
}
def _calculate_similarity(self, case1: Dict, case2: Dict) -> float:
"""
计算两个测试用例的相似度
Args:
case1: 测试用例1
case2: 测试用例2
Returns:
相似度(0-1之间)
"""
# 简单的文本相似度计算
def text_similarity(text1: str, text2: str) -> float:
"""计算两个文本的相似度"""
if not text1 or not text2:
return 0.0
words1 = set(text1.lower().split())
words2 = set(text2.lower().split())
if not words1 or not words2:
return 0.0
intersection = words1 & words2
union = words1 | words2
return len(intersection) / len(union) if union else 0.0
# 比较多个字段
fields = ["用例名称", "功能描述", "预期结果"]
similarities = []
for field in fields:
text1 = str(case1.get(field, ""))
text2 = str(case2.get(field, ""))
sim = text_similarity(text1, text2)
similarities.append(sim)
# 返回平均相似度
return sum(similarities) / len(similarities) if similarities else 0.0
def find_similar_cases(self, target_case: Dict,
case_list: List[Dict],
top_n: int = 5) -> List[Dict]:
"""
查找相似的测试用例
Args:
target_case: 目标测试用例
case_list: 测试用例列表
top_n: 返回前N个最相似的用例
Returns:
相似用例列表,每项包含用例和相似度
"""
similarities = []
for i, case in enumerate(case_list):
sim = self._calculate_similarity(target_case, case)
similarities.append({
"index": i,
"case": case,
"similarity": sim
})
# 按相似度降序排序
similarities.sort(key=lambda x: x["similarity"], reverse=True)
return similarities[:top_n]
def merge_test_cases(existing_cases: List[Dict],
new_cases: List[Dict]) -> List[Dict]:
"""
合并测试用例(不进行去重)
Args:
existing_cases: 现有测试用例列表
new_cases: 新测试用例列表
Returns:
合并后的测试用例列表
"""
# 更新序列号
max_seq = 0
for case in existing_cases:
seq = case.get("序列号")
if isinstance(seq, int):
max_seq = max(max_seq, seq)
# 为新用例分配序列号
for i, case in enumerate(new_cases):
max_seq += 1
case["序列号"] = max_seq
return existing_cases + new_cases
此差异已折叠。
此差异已折叠。
# 问题描述
## 问题现象
- 运行强制使用API模式时,提示AI服务无法初始化,提示未检测到有效的Anthropic API密钥。
# 日志信息
```ignorelang
2026-03-10 17:49:49 - src.main - INFO - 【步骤3】提取功能点
2026-03-10 17:49:49 - src.main - INFO - ------------------------------------------------------------
2026-03-10 17:49:49 - src.test_case_analyzer - INFO - 未检测到有效API密钥,尝试使用Claude CLI模式
2026-03-10 17:49:49 - src.claude_cli_adapter - INFO - Claude CLI适配器初始化完成
2026-03-10 17:49:49 - src.claude_cli_adapter - ERROR - 未找到claude命令,请确认已安装Claude Code CLI
2026-03-10 17:49:49 - src.claude_cli_adapter - ERROR - 安装方式: npm install -g @anthropic-ai/claude-code
2026-03-10 17:49:49 - src.main - ERROR - 处理失败: 无法初始化AI服务:
1. 未检测到有效的Anthropic API密钥
2. Claude CLI工具不可用
请至少配置其中一种方式
PS E:\GithubData\ubains-module-test\AuxiliaryTool\AIPerfectedTestCases>
```
# AI服务初始化失败_问题处理_计划执行
## 问题分析
### 问题现象
运行 `python run.py --mode api` 时,在步骤3提取功能点时失败,提示"未检测到有效的Anthropic API密钥"。
### 日志信息
```
2026-03-10 17:49:49 - src.test_case_analyzer - INFO - 未检测到有效API密钥,尝试使用Claude CLI模式
2026-03-10 17:49:49 - src.claude_cli_adapter - ERROR - 未找到claude命令
2026-03-10 17:49:49 - src.main - ERROR - 处理失败: 无法初始化AI服务:
1. 未检测到有效的Anthropic API密钥
2. Claude CLI工具不可用
```
### 根本原因
**main.py 已修复前缀验证**,但 `TestCaseAnalyzer``AIServiceManager` 类中仍然存在前缀验证逻辑:
1. **test_case_analyzer.py**(第93行、第100行):
```python
elif api_key and api_key.startswith(API_KEY_PREFIX): # ❌
```
2. **ai_service_manager.py**(第54行、第59行、第205行):
```python
if api_key and api_key.startswith(API_KEY_PREFIX): # ❌
```
**问题流程**
1. main.py 通过了 API 模式检查(传入 `use_cli=False` `api_key`
2. TestCaseAnalyzer 初始化时,检查 `api_key.startswith(API_KEY_PREFIX)`
3. CCSwitch 格式的密钥不是 `sk-ant-api03-` 开头,检查失败
4. 尝试 CLI 模式,失败后抛出异常
## 修复方案
### 方案概述
移除所有类中的 `API_KEY_PREFIX` 前缀验证,改为仅检查密钥是否存在且非空。
### 详细实施步骤
#### 步骤1:修复 test_case_analyzer.py
- [ ] 93行:移除 `api_key.startswith(API_KEY_PREFIX)` 检查
- [ ] 100行:移除 `api_key_from_env.startswith(API_KEY_PREFIX)` 检查
#### 步骤2:修复 ai_service_manager.py
- [ ] 54行:移除前缀检查
- [ ] 59行:移除前缀检查
- [ ] 205行:移除前缀检查
#### 步骤3:清理不再使用的导入
- [ ] main.py 中移除 `API_KEY_PREFIX` 导入(可选,保留也无影响)
## 实施细节
### test_case_analyzer.py 修改内容
**88-96行修改前**
```python
if use_cli:
logger.info("强制使用Claude CLI模式")
self.ai_client = ClaudeCLIClient()
self.mode = "cli"
elif api_key and api_key.startswith(API_KEY_PREFIX):
logger.info("使用Anthropic API模式")
self.ai_client = AnthropicAPIClient(api_key)
self.mode = "api"
```
**修改后**:
```python
if use_cli:
logger.info("强制使用Claude CLI模式")
self.ai_client = ClaudeCLIClient()
self.mode = "cli"
elif api_key and api_key.strip():
logger.info("使用Anthropic API模式")
self.ai_client = AnthropicAPIClient(api_key)
self.mode = "api"
```
**第97-115行修改前**:
```python
else:
api_key_from_env = os.environ.get(API_KEY_ENV, "")
if api_key_from_env.startswith(API_KEY_PREFIX):
logger.info("检测到有效API密钥,使用Anthropic API模式")
self.ai_client = AnthropicAPIClient(api_key_from_env)
self.mode = "api"
else:
logger.info("未检测到有效API密钥,尝试使用Claude CLI模式")
try:
self.ai_client = ClaudeCLIClient()
self.mode = "cli"
except RuntimeError:
raise RuntimeError(...)
```
**修改后**:
```python
else:
api_key_from_env = os.environ.get(API_KEY_ENV, "")
if api_key_from_env and api_key_from_env.strip():
logger.info("检测到API密钥,使用Anthropic API模式")
self.ai_client = AnthropicAPIClient(api_key_from_env)
self.mode = "api"
else:
logger.info("未检测到API密钥,尝试使用Claude CLI模式")
try:
self.ai_client = ClaudeCLIClient()
self.mode = "cli"
except RuntimeError:
raise RuntimeError(
"无法初始化AI服务:\n"
"1. 未设置Anthropic API密钥\n"
"2. Claude CLI工具不可用\n"
"请至少配置其中一种方式"
)
```
### ai_service_manager.py 修改内容
需要将所有 `api_key.startswith(API_KEY_PREFIX)` 改为 `api_key and api_key.strip()`
## 优化功能回填
### 已完成的优化
- [x] 修复 test_case_analyzer.py 前缀验证(第93行、第100行)
- [x] 修复 ai_service_manager.py 前缀验证(第54行、第59行、第205行)
- [x] 更新错误提示信息(不再强调sk-ant-api03-格式)
### 待完成的优化
-
# 问题描述
## 问题现象
- 运行代码时提示,AI调用失败,Extra data: line 51 column 4 (char 1198)
# 日志信息
```ignorelang
2026-03-10 17:59:22 - src.main - INFO - ------------------------------------------------------------
2026-03-10 17:59:22 - src.ai_service_manager - INFO - 使用自定义API endpoint: https://open.bigmodel.cn/api/anthropic
2026-03-10 17:59:22 - src.ai_service_manager - INFO - Anthropic API模式已启用
2026-03-10 17:59:22 - src.ai_service_manager - INFO - AI服务管理器初始化完成,模式: api
2026-03-10 17:59:22 - src.gap_detector - INFO - 缺失检测器初始化完成
2026-03-10 17:59:22 - src.gap_detector - INFO - 开始检测测试用例缺失...
2026-03-10 17:59:39 - httpx - INFO - HTTP Request: POST https://open.bigmodel.cn/api/anthropic/v1/messages "HTTP/1.1 200 OK"
2026-03-10 17:59:39 - src.gap_detector - ERROR - AI调用失败: Extra data: line 51 column 4 (char 1198)
2026-03-10 17:59:39 - src.gap_detector - INFO - 缺失检测完成:
2026-03-10 17:59:39 - src.gap_detector - INFO - 功能点缺失: 0 项
2026-03-10 17:59:39 - src.gap_detector - INFO - 场景覆盖不足: 0 项
2026-03-10 17:59:39 - src.gap_detector - INFO - 边界条件不足: 0 项
2026-03-10 17:59:39 - src.gap_detector - WARNING - ⚠️ 覆盖率未达标: 0.0% < 90.0%, 差距: 90.0%
2026-03-10 17:59:39 - src.gap_detector - INFO - 估算需新增测试用例: 0 条
2026-03-10 17:59:39 - src.main - INFO -
2026-03-10 17:59:39 - src.main - INFO - 【步骤6】生成新测试用例
2026-03-10 17:59:39 - src.main - INFO - ------------------------------------------------------------
```
# 问题描述
## 问题现象
- 运行强制使用API模式时,提示API调用失败,提示错误码为403 Forbidden,错误信息为Request not allowed,导致缺失检测无法完成。
# 日志信息
```ignorelang
2026-03-10 17:52:54 - src.main - INFO - ------------------------------------------------------------
2026-03-10 17:52:54 - src.ai_service_manager - INFO - Anthropic API模式已启用
2026-03-10 17:52:54 - src.ai_service_manager - INFO - AI服务管理器初始化完成,模式: api
2026-03-10 17:52:54 - src.gap_detector - INFO - 缺失检测器初始化完成
2026-03-10 17:52:54 - src.gap_detector - INFO - 开始检测测试用例缺失...
2026-03-10 17:52:55 - httpx - INFO - HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 403 Forbidden"
2026-03-10 17:52:55 - src.gap_detector - ERROR - AI调用失败: Error code: 403 - {'error': {'type': 'forbidden', 'message': 'Request not allowed'}}
2026-03-10 17:52:55 - src.gap_detector - INFO - 缺失检测完成:
2026-03-10 17:52:55 - src.gap_detector - INFO - 功能点缺失: 0 项
2026-03-10 17:52:55 - src.gap_detector - INFO - 场景覆盖不足: 0 项
2026-03-10 17:52:55 - src.gap_detector - INFO - 边界条件不足: 0 项
2026-03-10 17:52:55 - src.gap_detector - WARNING - ⚠️ 覆盖率未达标: 0.0% < 90.0%, 差距: 90.0%
2026-03-10 17:52:55 - src.gap_detector - INFO - 估算需新增测试用例: 0 条
2026-03-10 17:52:55 - src.main - INFO -
2026-03-10 17:52:55 - src.main - INFO - 【步骤6】生成新测试用例
2026-03-10 17:52:55 - src.main - INFO - ------------------------------------------------------------
```
# API模式执行提示调用失败_问题处理_计划执行
## 问题分析
### 问题现象
运行 `python run.py --mode api` 时,API调用返回 403 Forbidden 错误,错误信息为 "Request not allowed"。
### 日志信息
```
2026-03-10 17:52:55 - httpx - INFO - HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 403 Forbidden"
2026-03-10 17:52:55 - src.gap_detector - ERROR - AI调用失败: Error code: 403 - {'error': {'type': 'forbidden', 'message': 'Request not allowed'}}
```
### 根本原因
1. **用户的API密钥格式**`845694a2ffd64b6c93cc7359d760234d.j3FuzTgfmreM9qNU`
- 这是CCSwitch等代理服务的密钥格式
- 不是官方Anthropic API的密钥格式
2. **代码调用的是官方endpoint**
- 当前代码请求:`https://api.anthropic.com/v1/messages`
- CCSwitch等代理需要使用其自定义endpoint
3. **Anthropic客户端初始化缺少base_url参数**
```python
# 当前代码
self.client = anthropic.Anthropic(api_key=api_key)
# 需要改为
self.client = anthropic.Anthropic(
api_key=api_key,
base_url=custom_endpoint # 支持自定义endpoint
)
```
## 修复方案
### 方案概述
添加自定义API endpoint支持,允许用户通过环境变量配置代理服务的API地址。
### 详细实施步骤
#### 步骤1:修改 config.py
- [ ] 添加 `API_BASE_URL` 配置常量
- [ ] 添加 `get_api_base_url()` 函数,从环境变量读取自定义endpoint
- [ ] 更新 `get_project_info()` 返回endpoint信息
#### 步骤2:修改 test_case_analyzer.py
- [ ] 修改 `AnthropicAPIClient` 初始化,支持自定义base_url
- [ ] 添加endpoint日志输出
#### 步骤3:修改 ai_service_manager.py
- [ ] 修改 `_init_api_mode` 方法,支持自定义base_url
#### 步骤4:更新 .env.example
- [ ] 添加 `API_BASE_URL` 配置说明
## 实施细节
### config.py 修改内容
```python
# ==================== AI配置 ====================
# API基础URL(可选,用于代理服务)
# 官方API: https://api.anthropic.com
# CCSwitch等代理: 根据服务商提供的地址配置
API_BASE_URL = "https://api.anthropic.com"
def get_api_base_url() -> str:
"""
获取API基础URL
优先级:环境变量 > 配置文件常量
Returns:
API基础URL
"""
import os
return os.environ.get("API_BASE_URL", API_BASE_URL)
```
### test_case_analyzer.py 修改内容
```python
class AnthropicAPIClient(AIClientInterface):
"""Anthropic API客户端"""
def __init__(self, api_key: str, base_url: Optional[str] = None):
if anthropic is None:
raise ImportError("未安装anthropic库,请运行: pip install anthropic")
kwargs = {"api_key": api_key}
if base_url:
kwargs["base_url"] = base_url
logger.info("使用自定义API endpoint: %s", base_url)
self.client = anthropic.Anthropic(**kwargs)
```
同时修改TestCaseAnalyzer的初始化:
```python
from src.config import get_api_base_url
class TestCaseAnalyzer:
def __init__(self, api_key: Optional[str] = None, use_cli: bool = False):
# ... 原有逻辑 ...
elif api_key and api_key.strip():
base_url = get_api_base_url()
logger.info("使用Anthropic API模式")
self.ai_client = AnthropicAPIClient(api_key, base_url)
# ...
```
### ai_service_manager.py 修改内容
```python
def _init_api_mode(self, api_key: str):
"""初始化API模式"""
from src.config import get_api_base_url
try:
import anthropic
base_url = get_api_base_url()
kwargs = {"api_key": api_key}
if base_url != "https://api.anthropic.com":
kwargs["base_url"] = base_url
logger.info("使用自定义API endpoint: %s", base_url)
self.api_client = anthropic.Anthropic(**kwargs)
logger.info("Anthropic API模式已启用")
except ImportError:
raise RuntimeError("未安装anthropic库,请运行: pip install anthropic")
```
### .env.example 更新内容
```bash
# ==================== API配置(可选)====================
# API基础URL(用于代理服务)
# 官方API可留空或设置为:https://api.anthropic.com
# CCSwitch等代理服务需设置对应endpoint
API_BASE_URL=https://api.anthropic.com
```
## 使用说明
### 官方API用户
无需额外配置,使用默认endpoint即可。
### CCSwitch等代理用户
在 `.env` 文件中配置:
```bash
ANTHROPIC_API_KEY=your-key-here
API_BASE_URL=https://your-proxy-endpoint.com
```
## 优化功能回填
### 已完成的优化
- [x] 添加API_BASE_URL配置支持(config.py)
- [x] 添加get_api_base_url()函数(从环境变量读取)
- [x] 修改AnthropicAPIClient支持自定义endpoint(test_case_analyzer.py)
- [x] 修改TestCaseAnalyzer传入base_url参数
- [x] 修改AIServiceManager._init_api_mode支持自定义endpoint
- [x] 更新.env.example配置说明
### 待完成的优化
-
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论