@clawhub-hellotombruce-70592929d5
Integrate with ZenTao Legacy API 1.0 to manage projects, tasks, bugs, products, and workflows with session persistence and role-specific operations.
---
name: zentao
description: ZenTao Project Management API Integration | 禅道项目管理 API 集成。支持产品、项目、任务、Bug 全生命周期管理。Triggers: 禅道, zentao, 项目管理, 任务, bug
license: MIT
version: 0.1.0
author: zhangyingwu
config:
required_files:
- path: TOOLS.md
description: ZenTao API credentials | 禅道 API 凭证配置
required_sections:
- "## 禅道 API"
- "## ZenTao API"
dependencies:
- python3
- requests
---
# 适用 Zentao Legacy API 1.0
# 禅道项目管理技能
> 快速参考指南,帮助 AI 助手高效调用禅道 API
---
## 🚀 快速开始
### 1. 初始化客户端
```python
from pathlib import Path
import sys
# 导入禅道客户端
lib_path = Path(__file__).parent.parent / 'lib'
sys.path.insert(0, str(lib_path))
from zentao_client import ZenTaoClient, read_credentials
# 读取凭证
credentials = read_credentials()
# 创建客户端
client = ZenTaoClient(
credentials['endpoint'],
credentials['username'],
credentials['password']
)
# 获取会话(首次登录,后续自动加载持久化的 Session)
sid = client.get_session()
```
### 1.1 Session 持久化
客户端自动管理 Session,无需每次都登录:
```python
# 首次调用自动登录并保存 Session
sid = client.get_session()
# 新实例自动加载已有 Session
client2 = ZenTaoClient(credentials['endpoint'], credentials['username'], credentials['password'])
sid2 = client2.get_session() # 直接加载,无需登录
# 强制刷新 Session
client.get_session(force_refresh=True)
# 清除保存的 Session
client.clear_session()
```
**存储位置**:项目根目录 `.zentao/sessions/`
### 2. 快速查询
```python
# 查看我的任务
success, tasks = client.get_my_tasks("assignedTo")
# 查看我的Bug
success, bugs = client.get_my_bugs("assignedTo")
# 查看产品列表
success, products = client.get_products()
# 查看项目列表
projects = client.get_project_list_old("all")
# 查看项目任务
tasks = client.get_project_tasks_old(project_id, "all")
```
---
## 📊 API 分类速查
### 按使用频率分级
#### ⭐⭐⭐⭐⭐ 最高频(日常必用)
| 角色 | API | 场景 |
| ---- | ----------------------------------- | ------------------ |
| 全员 | `get_my_tasks("assignedTo")` | 查看指派给我的任务 |
| 全员 | `get_my_bugs("assignedTo")` | 查看指派给我的Bug |
| 研发 | `start_task(task_id)` | 开始任务 |
| 研发 | `record_estimate(task_id, records)` | 记录工时 |
| 研发 | `finish_task(task_id)` | 完成任务 |
| 测试 | `create_bug(...)` | 创建Bug |
| 测试 | `resolve_bug(bug_id, ...)` | 解决Bug |
#### ⭐⭐⭐⭐ 高频(日常工作)
| 角色 | API | 场景 |
| -------- | ---------------------------- | ------------ |
| 产品 | `create_story(...)` | 创建需求 |
| 项目经理 | `create_subtasks(...)` | 创建子任务 |
| 项目经理 | `assign_task(task_id, user)` | 指派任务 |
| 全员 | `get_task_detail(task_id)` | 查看任务详情 |
| 全员 | `get_bug(bug_id)` | 查看Bug详情 |
| 测试 | `close_bug(bug_id)` | 关闭Bug |
| 研发 | `pause_task(task_id)` | 暂停任务 |
#### ⭐⭐⭐ 中频(项目管理)
| 角色 | API | 场景 |
| -------- | ------------------------- | ------------ |
| 产品 | `create_product(...)` | 创建产品 |
| 产品 | `get_products()` | 查询产品列表 |
| 产品 | `create_plan(...)` | 创建发布计划 |
| 项目经理 | `create_project(...)` | 创建项目 |
| 项目经理 | `get_project(project_id)` | 查询项目详情 |
| 项目经理 | `start_project(...)` | 启动项目 |
| 项目经理 | `get_project_list_old()` | 查询项目列表 |
| 项目经理 | `get_project_tasks_old()` | 查询项目任务 |
| 测试 | `create_testcase(...)` | 创建测试用例 |
| 测试 | `create_testtask(...)` | 创建测试任务 |
---
## 👥 角色场景速查
### 产品经理
```python
# ========== 需求管理 ==========
# 创建需求
success, result = client.create_story(
product_id="1",
title="用户登录功能",
pri="3", # 优先级: 0-4
estimate="8", # 预计工时
spec="实现用户登录功能",
reviewer="admin"
)
# 查看我的需求
success, stories = client.get_my_stories("assignedTo")
# 类型: assignedTo(指派给我), openedBy(我创建的), reviewedBy(我评审的)
# 编辑需求
success, result = client.edit_story(story_id, title="新标题", pri="2")
# 关闭需求
success, result = client.close_story(story_id)
# ========== 产品管理 ==========
# 创建产品
success, result = client.create_product(
name="新产品",
code="NEW",
po="admin", # 产品负责人
status="normal"
)
# 查询产品列表
success, products = client.get_products()
# 创建发布计划
success, result = client.create_plan(
product_id="1",
title="V1.0版本",
begin="2026-03-01",
end="2026-03-31"
)
# 查询发布计划
success, plans = client.get_plans(product_id)
```
### 项目经理
```python
# ========== 项目管理 ==========
# 创建项目
success, result = client.create_project(
name="V1.0开发项目",
begin="2026-04-01",
end="2026-04-30",
code="V1",
days="22",
products=["1"], # 关联产品ID列表
plans=["1"], # 关联计划ID列表
desc="项目描述"
)
# 查询项目详情
success, project = client.get_project("1")
print(f"项目: {project['name']}, 状态: {project['status']}")
# 启动项目 (wait → doing)
success, result = client.start_project("1")
# 关闭项目
success, result = client.close_project("1")
# ========== 项目查询 ==========
# 查询项目列表
projects = client.get_project_list_old("all") # 状态: all, doing, done, suspended
# 查询项目任务
tasks = client.get_project_tasks_old(project_id, "all") # 状态: all, wait, doing, done, pause, cancel
# ========== 任务分解 ==========
# 创建任务
success, result = client.create_task(
project_id="1", # 项目ID
name="用户登录功能开发",
type="devel", # 任务类型: devel, test, design, study, discuss, ui, affair, misc
assignedTo="dev1",
pri="3", # 优先级: 0-4
estimate="8", # 预计工时
desc="实现用户登录功能"
)
# 批量创建任务
success, result = client.create_tasks(
project_id="1",
tasks=[
{"name": "前端开发", "type": "devel", "assignedTo": "dev1", "estimate": "8", "pri": "3"},
{"name": "后端开发", "type": "devel", "assignedTo": "dev2", "estimate": "16", "pri": "3"},
{"name": "接口联调", "type": "devel", "assignedTo": "dev1", "estimate": "4", "pri": "3"}
]
)
# 创建子任务
success, result = client.create_subtasks(
execution_id="1", # 项目/执行ID
parent_id="100", # 父任务ID
tasks=[
{"name": "前端开发", "estimate": "8", "assignedTo": "dev1", "type": "devel", "pri": "3"},
{"name": "后端开发", "estimate": "16", "assignedTo": "dev2", "type": "devel", "pri": "3"},
{"name": "接口联调", "estimate": "4", "assignedTo": "dev1", "type": "devel", "pri": "3"}
]
)
# ========== 任务指派 ==========
# 指派任务
success, result = client.assign_task(task_id, "zhangsan", "请处理")
# ========== 任务管理 ==========
# 取消任务
success, result = client.cancel_task(task_id)
# 删除任务
success, result = client.delete_task(task_id)
```
### 研发工程师
```python
# ========== 日常查询 ==========
# 查看我的任务
success, tasks = client.get_my_tasks("assignedTo")
# 类型: assignedTo(指派给我), openedBy(我创建的), finishedBy(我完成的)
# 查看任务详情
success, task = client.get_task_detail(task_id)
print(f"状态: {task['status']}") # wait, doing, pause, done, cancel, closed
print(f"预计: {task['estimate']}h") # 预计工时
print(f"消耗: {task['consumed']}h") # 已消耗工时
print(f"剩余: {task['left']}h") # 剩余工时
# ========== 任务流转 ==========
# 开始任务 (wait → doing)
success, result = client.start_task(task_id, "开始开发")
# 记录工时
from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d")
success, result = client.record_estimate(task_id, [
{
"date": today,
"consumed": "3", # 本次消耗
"left": "5", # 剩余
"work": "完成了登录功能开发"
}
])
# 暂停任务 (doing → pause)
success, result = client.pause_task(task_id, "等待依赖接口")
# 继续任务 (pause → doing)
success, result = client.restart_task(task_id, "依赖已就绪")
# 完成任务 (doing → done) - 重要:先记录工时left=0,再完成
client.record_estimate(task_id, [
{"date": today, "consumed": "5", "left": "0", "work": "全部完成"}
])
success, result = client.finish_task(task_id, "开发完成")
# 关闭任务 (done → closed)
success, result = client.close_task(task_id, "已验收")
# 激活任务 (done/closed → doing)
success, result = client.activate_task(task_id, "重新开始")
# ========== Bug处理 ==========
# 查看我的Bug
success, bugs = client.get_my_bugs("assignedTo")
# 类型: assignedTo(指派给我), openedBy(我创建的), resolvedBy(我解决的)
# 查看Bug详情
success, bug = client.get_bug(bug_id)
# 解决Bug
success, result = client.resolve_bug(
bug_id=bug_id,
resolution="fixed", # fixed, postponed, willnotfix, duplicate, tostory
resolved_build="trunk",
comment="已修复登录校验问题"
)
```
### 测试工程师
```python
# ========== Bug管理 ==========
# 创建Bug
success, result = client.create_bug(
product_id="1",
title="登录页面报错:500错误",
severity="3", # 严重程度: 1-4 (1最严重)
pri="3", # 优先级: 0-4
type="codeerror", # 类型: codeerror, config, install, security, etc.
steps="1.打开登录页\n2.输入账号密码\n3.点击登录\n4.出现500错误",
assignedTo="dev1",
project_id="1"
)
# 确认Bug
success, result = client.confirm_bug(bug_id, "确认是有效Bug")
# 指派Bug
success, result = client.assign_bug(bug_id, "dev1", "请处理")
# 关闭Bug (resolved → closed)
success, result = client.close_bug(bug_id, "验证通过")
# 激活Bug (closed → active)
success, result = client.activate_bug(bug_id, "问题重现")
# ========== 测试用例 ==========
# 创建测试用例
success, result = client.create_testcase(
product_id="1",
title="登录功能测试",
case_type="feature", # feature, performance, config, install, security, etc.
steps="1.打开登录页\n2.输入账号密码\n3.点击登录",
expect="登录成功"
)
# 查询测试用例
success, cases = client.get_testcases(product_id, "all")
# ========== 测试任务 ==========
# 创建测试任务
success, result = client.create_testtask(
product_id="1",
name="Sprint1测试",
begin="2026-03-20",
end="2026-03-25"
)
# 开始测试任务
success, result = client.start_testtask(task_id)
# 关闭测试任务
success, result = client.close_testtask(task_id)
```
---
## 🔄 状态流转图
### 任务状态流转
```
┌─────────────┐
│ wait │ 待开始
└──────┬──────┘
│ start_task()
▼
┌─────────────┐
┌───────│ doing │ 进行中◀───────┐
│ └──────┬──────┘ │
│ │ │
pause_task() finish_task() activate_task()
│ │ │
│ ▼ │
│ ┌─────────────┐ │
│ │ done │ 已完成 │
│ └──────┬──────┘ │
│ │ │
│ close_task() restart_task()
│ │ │
│ ▼ │
┌──────┴──────┐ ┌─────────────┐ │
│ pause │ │ closed │ 已关闭 │
│ 暂停 │ └─────────────┘ │
└──────┬──────┘ │
│ │
└─────────────────────────────────────┘
restart_task()
cancel_task() ──────▶ cancel (已取消)
```
**API调用顺序**:
| 当前状态 | 目标状态 | API | 说明 |
| ----------- | -------- | ------------------------ | -------------------------------- |
| wait | doing | `start_task(task_id)` | 开始任务 |
| doing | pause | `pause_task(task_id)` | 暂停任务 |
| pause | doing | `restart_task(task_id)` | 继续任务 |
| doing | done | `finish_task(task_id)` | 完成任务(建议先记录工时left=0) |
| done | closed | `close_task(task_id)` | 关闭任务 |
| done/closed | doing | `activate_task(task_id)` | 激活任务 |
| any | cancel | `cancel_task(task_id)` | 取消任务 |
### Bug状态流转
```
┌─────────────┐
│ active │ 激活
└──────┬──────┘
│ resolve_bug()
▼
┌─────────────┐
│ resolved │ 已解决
└──────┬──────┘
│ close_bug()
▼
┌─────────────┐
│ closed │ 已关闭
└──────┬──────┘
│ activate_bug()
└──────────────┐
▼
┌─────────────┐
│ active │ 激活
└─────────────┘
```
**API调用顺序**:
| 当前状态 | 目标状态 | API | 说明 |
| -------- | -------- | --------------------------------- | ------- |
| active | resolved | `resolve_bug(bug_id, resolution)` | 解决Bug |
| resolved | closed | `close_bug(bug_id)` | 关闭Bug |
| closed | active | `activate_bug(bug_id)` | 激活Bug |
---
## 📝 重要注意事项
### 1. 工时记录是批量接口
```python
# ✅ 正确:一次提交多条记录
client.record_estimate(task_id, [
{"date": "2026-03-27", "consumed": "2", "left": "6", "work": "开发"},
{"date": "2026-03-28", "consumed": "3", "left": "3", "work": "测试"}
])
# ❌ 错误:多次调用会覆盖之前记录
client.record_estimate(task_id, [{"date": "2026-03-27", "consumed": "2", ...}])
client.record_estimate(task_id, [{"date": "2026-03-28", "consumed": "3", ...}]) # 会覆盖!
```
### 2. 完成任务前先记录工时
```python
# ✅ 正确流程
client.record_estimate(task_id, [
{"date": "2026-03-27", "consumed": "8", "left": "0", "work": "完成"}
])
client.finish_task(task_id, "开发完成")
# ❌ 错误:直接完成任务,没有记录最终工时
client.finish_task(task_id)
```
### 3. 获取任务详情验证操作结果
```python
# 很多API返回HTML而非JSON,解析会失败,但操作实际成功
success, result = client.start_task(task_id)
# 建议:用get_task_detail验证
ok, task = client.get_task_detail(task_id)
print(f"状态: {task['status']}") # 应为 'doing'
```
### 4. 解决Bug用专用接口
```python
# ✅ 正确:使用resolve_bug
client.resolve_bug(bug_id, "fixed", "trunk", "已修复")
# ❌ 错误:不要用edit_bug修改状态,会丢失其他字段
# client.edit_bug(bug_id, status="resolved") # 会丢失产品、项目关联!
```
### 5. 创建子任务注意ditto
```python
# 子任务数组参数,第一个任务用实际值,后续用ditto继承
client.create_subtasks(execution_id, parent_id, [
{"name": "前端", "estimate": "8", "assignedTo": "dev1", "type": "devel", "pri": "3"},
{"name": "后端", "estimate": "16", "assignedTo": "dev2", "type": "devel", "pri": "3"}
# 第二个任务会继承第一个任务的type和pri(API内部处理)
])
```
### 6. 查看我的任务/bug返回格式
```python
# get_my_tasks和get_my_bugs返回的是列表,不是字典
success, tasks = client.get_my_tasks("assignedTo")
if success:
for task in tasks: # tasks是列表
print(f"[{task['id']}] {task['name']} ({task['status']})")
```
---
## 🎯 典型使用场景
### 场景1:每日站会查询
```python
# 查看我的任务
success, tasks = client.get_my_tasks("assignedTo")
# 统计状态
stats = {"wait": 0, "doing": 0, "pause": 0, "done": 0}
for task in tasks:
status = task.get("status", "unknown")
if status in stats:
stats[status] += 1
print(f"我的任务: 待开始{stats['wait']}, 进行中{stats['doing']}, 暂停{stats['pause']}, 已完成{stats['done']}")
```
### 场景2:开始新任务
```python
# 1. 查看任务详情
success, task = client.get_task_detail(task_id)
print(f"任务: {task['name']}, 预计工时: {task['estimate']}h")
# 2. 开始任务
success, result = client.start_task(task_id, "开始开发")
# 3. 验证
ok, task = client.get_task_detail(task_id)
print(f"状态: {task['status']}") # doing
```
### 场景3:每日记录工时
```python
from datetime import datetime
# 记录今天的工时
today = datetime.now().strftime("%Y-%m-%d")
success, result = client.record_estimate(task_id, [
{
"date": today,
"consumed": "3", # 今天消耗3小时
"left": "5", # 剩余5小时
"work": "完成了用户登录功能开发"
}
])
# 验证
ok, task = client.get_task_detail(task_id)
print(f"总消耗: {task['consumed']}h, 剩余: {task['left']}h")
```
### 场景4:完成任务
```python
from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d")
# 1. 记录最终工时
client.record_estimate(task_id, [
{"date": today, "consumed": "5", "left": "0", "work": "全部完成"}
])
# 2. 完成任务
success, result = client.finish_task(task_id, "开发完成,已自测")
# 3. 验证
ok, task = client.get_task_detail(task_id)
print(f"状态: {task['status']}") # done
print(f"完成人: {task['finishedBy']}") # admin
```
### 场景5:提交Bug
```python
# 创建Bug
success, result = client.create_bug(
product_id="1",
title="登录页面500错误",
severity="2", # 严重
pri="3",
type="codeerror",
steps="1.打开登录页\n2.输入admin/admin\n3.点击登录\n4.出现500错误",
assignedTo="dev1",
comment="优先处理"
)
# 查看我的Bug
success, bugs = client.get_my_bugs("openedBy")
for bug in bugs:
print(f"[{bug['id']}] {bug['title']} ({bug['status']})")
```
### 场景6:解决和关闭Bug
```python
# 1. 查看Bug详情
success, bug = client.get_bug(bug_id)
print(f"标题: {bug['title']}, 状态: {bug['status']}")
# 2. 解决Bug
success, result = client.resolve_bug(
bug_id=bug_id,
resolution="fixed",
resolved_build="trunk",
comment="已修复登录校验逻辑"
)
# 3. 关闭Bug
success, result = client.close_bug(bug_id, "验证通过,问题已修复")
# 4. 验证
ok, bug = client.get_bug(bug_id)
print(f"状态: {bug['status']}") # closed
print(f"关闭人: {bug['closedBy']}")
```
### 场景7:创建子任务分解
```python
# 查询父任务
tasks = client.get_project_tasks_old(project_id, "all")
parent_task_id = list(tasks.keys())[0]
# 创建子任务
success, result = client.create_subtasks(
execution_id=project_id,
parent_id=parent_task_id,
tasks=[
{"name": "前端开发", "estimate": "8", "assignedTo": "dev1"},
{"name": "后端开发", "estimate": "16", "assignedTo": "dev2"},
{"name": "接口联调", "estimate": "4", "assignedTo": "dev1"}
]
)
```
---
## 🔧 高级用法
### 批量操作
```python
# 批量创建需求
requirements = ["用户登录", "商品浏览", "购物车", "订单管理"]
for req in requirements:
client.create_story(product_id, req, pri="3", estimate="8")
# 批量记录工时
from datetime import datetime, timedelta
today = datetime.now()
records = []
for i in range(5):
records.append({
"date": (today - timedelta(days=i)).strftime("%Y-%m-%d"),
"consumed": "2",
"left": str(10 - i * 2),
"work": f"开发进度{i*20}%"
})
client.record_estimate(task_id, records)
```
### 状态统计
```python
# 项目任务状态统计
tasks = client.get_project_tasks_old(project_id, "all")
stats = {}
for tid, task in tasks.items():
status = task.get("status", "unknown")
stats[status] = stats.get(status, 0) + 1
print(f"任务统计: {stats}")
# 输出: {'wait': 5, 'doing': 3, 'done': 10, 'pause': 1, 'cancel': 2}
```
### 数据导出
```python
import json
# 导出我的任务
success, tasks = client.get_my_tasks("assignedTo")
with open("my_tasks.json", "w", encoding="utf-8") as f:
json.dump(tasks, f, ensure_ascii=False, indent=2)
# 导出我的Bug
success, bugs = client.get_my_bugs("assignedTo")
with open("my_bugs.json", "w", encoding="utf-8") as f:
json.dump(bugs, f, ensure_ascii=False, indent=2)
```
---
## 📚 API完整列表
### 产品管理
| API | 说明 | 参数 |
| --------------------------------- | ------------ | ------------------------------------------ |
| `create_product(name, code, ...)` | 创建产品 | name, code, type, po, qd, rd, status, desc |
| `get_products()` | 查询产品列表 | - |
| `get_product(product_id)` | 查询产品详情 | product_id |
| `edit_product(product_id, ...)` | 编辑产品 | product_id, \*\*kwargs |
| `close_product(product_id)` | 关闭产品 | product_id |
| `delete_product(product_id)` | 删除产品 | product_id |
### 需求管理
| API | 说明 | 参数 |
| -------------------------------------- | ------------ | ------------------------------------------------------ |
| `create_story(product_id, title, ...)` | 创建需求 | product_id, title, pri, estimate, spec, ... |
| `get_story(story_id)` | 查询需求详情 | story_id |
| `get_my_stories(story_type)` | 查询我的需求 | story_type: assignedTo, openedBy, reviewedBy, closedBy |
| `edit_story(story_id, ...)` | 编辑需求 | story_id, \*\*kwargs |
| `close_story(story_id)` | 关闭需求 | story_id |
| `activate_story(story_id)` | 激活需求 | story_id |
| `delete_story(story_id)` | 删除需求 | story_id |
### 计划管理
| API | 说明 | 参数 |
| ------------------------------------- | ------------ | ----------------------------------- |
| `create_plan(product_id, title, ...)` | 创建计划 | product_id, title, begin, end, desc |
| `get_plans(product_id)` | 查询计划列表 | product_id |
| `delete_plan(plan_id)` | 删除计划 | plan_id |
### 项目管理
| API | 说明 | 参数 |
| ------------------------------------------- | ------------ | --------------------------------------------------- |
| `create_project(name, begin, end, ...)` | 创建项目 | name, begin, end, code, days, products, plans, desc |
| `get_project(project_id)` | 查询项目详情 | project_id |
| `start_project(project_id)` | 启动项目 | project_id |
| `close_project(project_id)` | 关闭项目 | project_id |
| `get_project_list_old(status)` | 查询项目列表 | status: all, doing, done, suspended |
| `get_project_tasks_old(project_id, status)` | 查询项目任务 | project_id, status |
| `get_project_bugs(project_id, status)` | 查询项目Bug | project_id, status |
### 任务管理
| API | 说明 | 参数 |
| ------------------------------------------------- | ------------ | ------------------------------------------------------------------- |
| `create_task(project, name, type, ...)` | 创建任务 | project, name, type, story, module, assignedTo, pri, estimate, desc |
| `create_tasks(project, tasks)` | 批量创建任务 | project, tasks列表 |
| `get_my_tasks(task_type)` | 查询我的任务 | task_type: assignedTo, openedBy, finishedBy, closedBy, canceledBy |
| `get_task_detail(task_id)` | 查询任务详情 | task_id |
| `create_subtasks(execution_id, parent_id, tasks)` | 创建子任务 | execution_id, parent_id, tasks列表 |
| `start_task(task_id, comment)` | 开始任务 | task_id, comment |
| `pause_task(task_id, comment)` | 暂停任务 | task_id, comment |
| `restart_task(task_id, comment)` | 继续任务 | task_id, comment |
| `finish_task(task_id, comment)` | 完成任务 | task_id, comment |
| `close_task(task_id, comment)` | 关闭任务 | task_id, comment |
| `activate_task(task_id, comment)` | 激活任务 | task_id, comment |
| `cancel_task(task_id)` | 取消任务 | task_id |
| `delete_task(task_id)` | 删除任务 | task_id |
| `assign_task(task_id, assigned_to, comment)` | 指派任务 | task_id, assigned_to, comment |
| `record_estimate(task_id, records)` | 记录工时 | task_id, records列表 |
### Bug管理
| API | 说明 | 参数 |
| ------------------------------------------ | ----------- | -------------------------------------------------------------- |
| `get_my_bugs(bug_type)` | 查询我的Bug | bug_type: assignedTo, openedBy, resolvedBy, closedBy |
| `get_bug(bug_id)` | 查询Bug详情 | bug_id |
| `create_bug(product_id, title, ...)` | 创建Bug | product_id, title, severity, pri, type, steps, assignedTo, ... |
| `resolve_bug(bug_id, resolution, ...)` | 解决Bug | bug_id, resolution, resolved_build, comment |
| `close_bug(bug_id, comment)` | 关闭Bug | bug_id, comment |
| `activate_bug(bug_id, comment)` | 激活Bug | bug_id, comment |
| `assign_bug(bug_id, assigned_to, comment)` | 指派Bug | bug_id, assigned_to, comment |
| `confirm_bug(bug_id, comment)` | 确认Bug | bug_id, comment |
| `delete_bug(bug_id)` | 删除Bug | bug_id |
### 测试管理
| API | 说明 | 参数 |
| ------------------------------------------ | ------------ | ------------------------------------------------ |
| `get_testcases(product_id, browse_type)` | 查询测试用例 | product_id, browse_type |
| `get_testcase(case_id)` | 查询用例详情 | case_id |
| `create_testcase(product_id, title, ...)` | 创建测试用例 | product_id, title, case_type, steps, expect, ... |
| `delete_testcase(case_id)` | 删除测试用例 | case_id |
| `get_testsuites(product_id)` | 查询测试套件 | product_id |
| `create_testsuite(product_id, name, desc)` | 创建测试套件 | product_id, name, desc |
| `get_testtasks(product_id, task_type)` | 查询测试任务 | product_id, task_type |
| `create_testtask(product_id, name, ...)` | 创建测试任务 | product_id, name, begin, end, desc |
| `start_testtask(task_id)` | 开始测试任务 | task_id |
| `close_testtask(task_id)` | 关闭测试任务 | task_id |
---
## 🆘 故障排查
### 常见问题
**Q: 认证失败怎么办?**
```python
# 检查凭证
credentials = read_credentials()
print(credentials) # 确保endpoint, username, password正确
# 手动获取session
sid = client.get_session()
if not sid:
print("认证失败,请检查用户名密码")
```
**Q: API返回success=False但操作成功?**
```python
# 很多API返回HTML而非JSON,解析会失败
# 建议:用查询接口验证操作结果
success, result = client.start_task(task_id)
# 返回False但实际成功
ok, task = client.get_task_detail(task_id)
print(task['status']) # 验证状态是否变为doing
```
**Q: 工时记录不生效?**
```python
# 确保参数格式正确
from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d") # 必须是YYYY-MM-DD格式
success, result = client.record_estimate(task_id, [
{
"date": today,
"consumed": "2", # 字符串格式
"left": "6", # 字符串格式
"work": "开发中"
}
])
# 验证
ok, task = client.get_task_detail(task_id)
print(f"消耗: {task['consumed']}, 剩余: {task['left']}")
```
**Q: 创建子任务失败?**
```python
# 确保参数完整
tasks = [
{
"name": "前端开发", # 必需
"estimate": "8", # 必需
"assignedTo": "admin", # 必需
"type": "devel", # 可选,默认devel
"pri": "3" # 可选,默认3
}
]
success, result = client.create_subtasks(
execution_id="1", # 项目/执行ID
parent_id="100", # 父任务ID
tasks=tasks
)
```
---
## 📖 参考资料
- 禅道官网: https://www.zentao.net/
- 禅道API文档: https://www.zentao.net/book/zentaopmshelp/562.html
- 客户端源码: `lib/zentao_client.py`
- 测试报告: `docs/测试报告-工单客服系统.md`
---
## 📄 许可证
MIT License - 自由使用、修改和分发
FILE:requirements.txt
# ZenTao Skill Dependencies
# Install with: pip3 install -r requirements.txt
requests>=2.28.0
FILE:docs/repo.md
# 代码 (Repo) API 文档
## 概述
代码仓库管理相关的API接口。
## API 列表
### 代码仓库首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/repo.json` |
| 描述 | 代码仓库首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览代码仓库
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/repo-browse-[repoID]-[objectID]-[type].json` |
| 描述 | 浏览代码仓库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| objectID | int | 否 | 对象ID |
| type | string | 否 | 类型 |
---
### 创建代码仓库
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/repo-create-[productID]-[projectID].json` |
| 描述 | 创建代码仓库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| projectID | int | 否 | 项目ID |
---
### 编辑代码仓库
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/repo-edit-[repoID].json` |
| 描述 | 编辑代码仓库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 删除代码仓库
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/repo-delete-[repoID]-[confirm].json` |
| 描述 | 删除代码仓库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| confirm | string | 否 | 确认删除 |
---
### 查看代码仓库详情
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/repo-view-[repoID].json` |
| 描述 | 查看代码仓库详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 代码仓库关联
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/repo-link-[repoID]-[objectID].json` |
| 描述 | 关联代码仓库到产品或项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| objectID | int | 否 | 对象ID |
---
### 代码仓库同步
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/repo-sync-[repoID].json` |
| 描述 | 同步代码仓库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 代码提交记录
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/repo-commits-[repoID].json` |
| 描述 | 查看代码提交记录 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 代码统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/repo-statistic-[repoID].json` |
| 描述 | 代码仓库统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
FILE:docs/jenkins.md
# Jenkins API 文档
## 概述
Jenkins集成管理相关的API接口。
## API 列表
### 浏览Jenkins
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/jenkins-browse-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览Jenkins服务器列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建Jenkins
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/jenkins-create.json` |
| 描述 | 添加新的Jenkins服务器 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 编辑Jenkins
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/jenkins-edit-[id].json` |
| 描述 | 编辑Jenkins服务器配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | Jenkins服务器ID |
---
### 删除Jenkins
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/jenkins-delete-[id].json` |
| 描述 | 删除Jenkins服务器配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | Jenkins服务器ID |
---
### AJAX获取任务列表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/jenkins-ajaxGetTasks-[id].json` |
| 描述 | AJAX获取Jenkins的Job列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | Jenkins服务器ID |
---
### 测试Jenkins连接
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/jenkins-test-[id].json` |
| 描述 | 测试Jenkins服务器连接 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | Jenkins服务器ID |
---
### Jenkins任务管理
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/jenkins-jobs-[id].json` |
| 描述 | 查看Jenkins任务列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | Jenkins服务器ID |
---
### Jenkins构建历史
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/jenkins-builds-[id]-[job].json` |
| 描述 | 查看Jenkins构建历史 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | Jenkins服务器ID |
| job | string | 否 | 任务名称 |
FILE:docs/entry.md
# 应用 (Entry) API 文档
## 概述
第三方应用管理相关的API接口。
## API 列表
### 应用首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/entry.json` |
| 描述 | 应用管理首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览应用
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/entry-browse-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览应用列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建应用
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/entry-create.json` |
| 描述 | 创建新的第三方应用 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 编辑应用
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/entry-edit-[entryID].json` |
| 描述 | 编辑应用配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| entryID | int | 否 | 应用ID |
---
### 删除应用
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/entry-delete-[entryID]-[confirm].json` |
| 描述 | 删除应用 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| entryID | int | 否 | 应用ID |
| confirm | string | 否 | 确认删除 |
---
### 查看应用
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/entry-view-[entryID].json` |
| 描述 | 查看应用详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| entryID | int | 否 | 应用ID |
---
### 应用权限管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/entry-permission-[entryID].json` |
| 描述 | 管理应用权限 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| entryID | int | 否 | 应用ID |
---
### 应用API密钥
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/entry-apiKey-[entryID].json` |
| 描述 | 管理应用API密钥 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| entryID | int | 否 | 应用ID |
FILE:docs/compile.md
# 编译 (Compile) API 文档
## 概述
编译管理相关的API接口。
## API 列表
### 浏览Jenkins构建
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/compile-browse-[jobID]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览指定Jenkins job的构建历史 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| jobID | int | 否 | Jenkins job ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 查看Jenkins构建日志
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/compile-logs-[buildID].json` |
| 描述 | 查看指定Jenkins构建的详细日志 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | Jenkins构建ID |
---
### 触发构建
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/compile-trigger-[jobID].json` |
| 描述 | 触发Jenkins job开始构建 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| jobID | int | 否 | Jenkins job ID |
---
### 获取构建状态
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/compile-status-[buildID].json` |
| 描述 | 获取Jenkins构建的当前状态 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|-----|------|------|
| buildID | int | 否 | Jenkins构建ID |
---
### 取消构建
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/compile-cancel-[buildID].json` |
| 描述 | 取消正在进行的Jenkins构建 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | Jenkins构建ID |
---
### 重试构建
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/compile-retry-[buildID].json` |
| 描述 | 重试失败的Jenkins构建 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | Jenkins构建ID |
---
### 获取构建产物
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/compile-artifacts-[buildID].json` |
| 描述 | 获取Jenkins构建的产物列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | Jenkins构建ID |
---
### 下载构建产物
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/compile-download-[buildID]-[artifact].json` |
| 描述 | 下载指定的构建产物 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | Jenkins构建ID |
| artifact | string | 否 | 产物名称 |
---
### 构建统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/compile-statistic-[jobID].json` |
| 描述 | 获取Jenkins job的构建统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| jobID | int | 否 | Jenkins job ID |
---
### 配置构建参数
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/config-params-[jobID].json` |
| 描述 | 配置Jenkins job的构建参数 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| jobID | int | 否 | Jenkins job ID |
---
### 获取构建历史图表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/compile-chart-[jobID].json` |
| 描述 | 获取Jenkins构建历史的图表数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| jobID | int | 否 | Jenkins job ID |
---
### 构建通知设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/compile-notify-[jobID].json` |
| 描述 | 设置构建完成的通知方式 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| jobID | int | 否 | Jenkins job ID |
FILE:docs/doc.md
# 文档 (Doc) API 文档
## 概述
文档管理相关的API接口。
## API 列表
### 文档首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc.json` |
| 描述 | 文档首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览文档
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-browse-[libID]-[moduleID]-[productID]-[projectID]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览文档库中的文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| libID | int | 否 | 文档库ID |
| moduleID | int | 否 | 模块ID |
| productID | int | 否 | 产品ID |
| projectID | int | 否 | 项目ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建文档库
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-createLib-[type]-[objectID].json` |
| 描述 | 创建文档库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 文档库类型 |
| objectID | int | 否 | 对象ID(产品ID或项目ID) |
---
### 创建文档
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-create-[libID]-[moduleID]-[productID]-[projectID]-[from].json` |
| 描述 | 在文档库中创建文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| libID | int | 否 | 文档库ID |
| moduleID | int | 否 | 模块ID |
| productID | int | 否 | 产品ID |
| projectID | int | 否 | 项目ID |
| from | string | 否 | 来源 |
---
### 编辑文档
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-edit-[docID].json` |
| 描述 | 编辑文档内容 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
---
### 查看文档
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-view-[docID].json` |
| 描述 | 查看文档详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
---
### 删除文档
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-delete-[docID]-[confirm].json` |
| 描述 | 删除文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
| confirm | string | 否 | 确认删除 |
---
### 文档版本管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-version-[docID].json` |
| 描述 | 管理文档版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
---
### 文档历史版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-history-[docID].json` |
| 描述 | 查看文档历史版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
---
### 文档导出
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-export-[docID]-[format].json` |
| 描述 | 导出文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
| format | string | 否 | 导出格式(html/pdf/markdown) |
---
### 文档搜索
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-search-[keyword]-[type].json` |
| 描述 | 搜索文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| keyword | string | 否 | 搜索关键词 |
| type | string | 否 | 搜索类型 |
---
### 文档统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-statistic-[libID].json` |
| 描述 | 文档库统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| libID | int | 否 | 文档库ID |
---
### 文档权限设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-permission-[docID].json` |
| 描述 | 设置文档权限 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
---
### 文档评论
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-comment-[docID].json` |
| 描述 | 管理文档评论 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
---
### 文档附件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-attachment-[docID].json` |
| 描述 | 获取文档附件列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
---
### 文档标签
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-tags-[docID].json` |
| 描述 | 管理文档标签 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
---
### 文档分类
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-category-[libID].json` |
| 描述 | 获取文档分类列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| libID | int | 否 | 文档库ID |
---
### 文档模板
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-template-[type].json` |
| 描述 | 获取文档模板 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 模板类型 |
---
### 文档批量操作
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/doc-batchAction-[action].json` |
| 描述 | 批量操作文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| action | string | 否 | 操作类型(move/copy/delete) |
---
### 文档目录结构
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-toc-[libID].json` |
| 描述 | 获取文档目录结构 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| libID | int | 否 | 文档库ID |
---
### 文档引用关系
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/doc-ref-[docID].json` |
| 描述 | 获取文档引用关系 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| docID | int | 否 | 文档ID |
FILE:docs/extension.md
# 插件 (Extension) API 文档
## 概述
插件管理相关的API接口。
## API 列表
### 插件首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/extension.json` |
| 描述 | 插件首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览插件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/extension-browse-[type]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览已安装的插件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 插件类型 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 安装插件
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/extension-install-[extensionID].json` |
| 描述 | 安装插件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| extensionID | string | 否 | 插件ID |
---
### 卸载插件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/extension-uninstall-[extensionID]-[confirm].json` |
| 描述 | 卸载插件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| extensionID | string | 否 | 插件ID |
| confirm | string | 否 | 确认 |
---
### 启用插件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/extension-enable-[extensionID].json` |
| 描述 | 启用插件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| extensionID | string | 否 | 插件ID |
---
### 禁用插件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/extension-disable-[extensionID].json` |
| 描述 | 禁用插件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| extensionID | string | 否 | 插件ID |
---
### 插件设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/extension-setting-[extensionID].json` |
| 描述 | 插件设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| extensionID | string | 否 | 插件ID |
---
### 插件市场
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/extension-market.json` |
| 描述 | 插件市场 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/license.md
# License API 文档
## 概述
授权许可相关的API接口。
## API 列表
### License首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/license.json` |
| 描述 | 授权许可首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 激活License
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/license-activate.json` |
| 描述 | 激活授权许可 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/product.md
# 产品 (Product) API 文档
## 概述
产品管理相关的API接口。
## API 列表
### 产品列表页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-index-[locate]-[productID]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取产品列表页面 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| locate | - | 否 | 定位 |
| productID | - | 否 | 产品ID |
| orderBy | - | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 项目列表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-project-[status]-[productID].json` |
| 描述 | 获取产品关联的项目列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| status | - | 否 | 状态 |
| productID | - | 否 | 产品ID |
---
### 浏览产品
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-browse-[productID]-[browseType]-[param]-[storyType]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览产品需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | - | 否 | 产品ID |
| browseType | - | 否 | 浏览类型 |
| param | - | 否 | 参数 |
| storyType | - | 否 | 需求类型 |
| orderBy | - | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建产品
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/product-create.json` |
| 描述 | 创建新产品 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 编辑产品
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/product-edit-[productID].json` |
| 描述 | 编辑产品信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 批量编辑产品
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/product-batchEdit-[productID].json` |
| 描述 | 批量编辑产品 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 关闭产品
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/product-close-[productID].json` |
| 描述 | 关闭产品 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 查看产品
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-view-[productID].json` |
| 描述 | 查看产品详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 删除产品
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-delete-[productID]-[confirm].json` |
| 描述 | 删除产品 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| confirm | string | 否 | 确认 |
---
### 产品路线图
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-roadmap-[productID].json` |
| 描述 | 查看产品路线图 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 产品动态
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-dynamic-[type]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 查看产品动态 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | - | 否 | 类型 |
| orderBy | - | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### AJAX获取项目
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-ajaxGetProjects-[productID]-[projectID]-[number].json` |
| 描述 | AJAX获取产品关联的项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| projectID | - | 否 | 项目ID |
| number | - | 否 | 数量 |
---
### AJAX获取计划
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/product-ajaxGetPlans-[productID]-[planID]-[needCreate]-[expired].json` |
| 描述 | AJAX获取产品计划 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| planID | - | 否 | 计划ID |
| needCreate | - | 否 | 是否需要创建 |
| expired | - | 否 | 是否过期 |
---
### 更新排序
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/product-updateOrder.json` |
| 描述 | 更新产品排序 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导出产品
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/product-export-[status]-[orderBy].json` |
| 描述 | 导出产品数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| status | - | 否 | 状态 |
| orderBy | - | 否 | 排序方式 |
FILE:docs/search.md
# 搜索 (Search) API 文档
## 概述
搜索功能相关的API接口。
## API 列表
### 搜索首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/search.json` |
| 描述 | 搜索首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 执行搜索
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/search-index-[keywords]-[type]-[module]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 执行全局搜索 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| keywords | string | 否 | 搜索关键词 |
| type | string | 否 | 搜索类型 |
| module | string | 否 | 搜索模块 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 搜索建议
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/search-suggest-[keywords].json` |
| 描述 | 获取搜索建议 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| keywords | string | 否 | 搜索关键词 |
FILE:docs/group.md
# 用户组 (Group) API 文档
## 概述
用户组管理相关的API接口。
## API 列表
### 用户组首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/group.json` |
| 描述 | 用户组首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览用户组
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/group-browse.json` |
| 描述 | 浏览用户组列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 创建用户组
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/group-create.json` |
| 描述 | 创建用户组 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 编辑用户组
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/group-edit-[groupID].json` |
| 描述 | 编辑用户组 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| groupID | int | 否 | 用户组ID |
---
### 删除用户组
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/group-delete-[groupID]-[confirm].json` |
| 描述 | 删除用户组 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| groupID | int | 否 | 用户组ID |
| confirm | string | 否 | 确认删除 |
---
### 管理用户组成员
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/group-manageGroupMember-[groupID].json` |
| 描述 | 管理用户组成员 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| groupID | int | 否 | 用户组ID |
---
### 用户组权限管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/group-managePriv-[groupID].json` |
| 描述 | 管理用户组权限 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| groupID | int | 否 | 用户组ID |
---
### 用户组排序
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/group-updateOrder.json` |
| 描述 | 更新用户组排序 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/im.md
# IM API 文档
## 概述
即时通讯(IM)相关的API接口。
## API 列表
### IM首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/im.json` |
| 描述 | IM首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取在线用户
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/im-onlineUsers.json` |
| 描述 | 获取当前在线用户列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 发送消息
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/im-sendMessage-[userID].json` |
| 描述 | 发送即时消息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| userID | int | 否 | 接收用户ID |
---
### 获取消息历史
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/im-history-[userID].json` |
| 描述 | 获取与指定用户的聊天历史 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| userID | int | 否 | 用户ID |
---
### 创建群组
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/im-createGroup.json` |
| 描述 | 创建即时通讯群组 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 群组管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/im-manageGroup-[groupID].json` |
| 描述 | 管理群组成员 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| groupID | int | 否 | 群组ID |
---
### 文件传输
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/im-transfer-[userID].json` |
| 描述 | 文件传输功能 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| userID | int | 否 | 用户ID |
---
### 消息提醒设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/im-notify-[type].json` |
| 描述 | 设置消息提醒方式 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 提醒类型 |
FILE:docs/api.md
# API 接口 (API) API 文档
## 概述
通用API接口相关的API接口。
## API 列表
### 获取会话ID
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-getSessionID.json` |
| 描述 | 返回客户端会话ID |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 执行模块方法
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-getModel-[moduleName]-[methodName]-[params].json` |
| 描述 | 执行指定模块的方法并返回结果 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| moduleName | string | 否 | 模块名称 |
| methodName | string | 否 | 方法名称 |
| params | string | 否 | 参数(JSON格式) |
---
### API调试接口
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/api-debug-[filePath]-[action].json` |
| 描述 | API调试接口 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| filePath | int | 否 | 文件路径 |
| action | int | 否 | 操作类型 |
---
### 查询SQL
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/api-sql-[keyField].json` |
| 描述 | 执行SQL查询 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| keyField | string | 否 | 关键字段 |
---
### API版本信息
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-version.json` |
| 描述 | 获取API版本信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### API文档
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-doc-[module].json` |
| 描述 | 获取API文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
---
### API权限检查
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-checkPermission-[module]-[method].json` |
| 描述 | 检查API权限 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
| method | string | 否 | 方法名称 |
---
### API日志
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-log-[date].json` |
| 描述 | 获取API日志 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| date | string | 否 | 日期 |
---
### API统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-statistic-[period].json` |
| 描述 | 获取API使用统计 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| period | string | 否 | 统计周期(day/week/month) |
---
### API限流配置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/api-rateLimit-[module]-[method].json` |
| 描述 | 配置API限流 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
| method | string | 否 | 方法名称 |
---
### API缓存设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/api-cache-[module]-[method].json` |
| 描述 | 配置API缓存 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
| method | string | 否 | 方法名称 |
---
### API测试工具
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/api-test.json` |
| 描述 | API测试工具 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### API认证信息
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-auth.json` |
| 描述 | 获取API认证信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### API密钥管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/api-key.json` |
| 描述 | 管理API密钥 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### API错误码
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-errorCodes.json` |
| 描述 | 获取API错误码列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### API示例
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/api-example-[module]-[method].json` |
| 描述 | 获取API调用示例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
| method | string | 否 | 方法名称 |
FILE:docs/testtask.md
# 测试版本 (Testtask) API 文档
## 概述
测试版本管理相关的API接口。
## API 列表
### 测试版本首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testtask.json` |
| 描述 | 测试版本首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testtask-browse-[productID]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览测试版本列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testtask-create-[productID].json` |
| 描述 | 创建测试版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 编辑测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testtask-edit-[taskID].json` |
| 描述 | 编辑测试版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 测试版本ID |
---
### 查看测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testtask-view-[taskID].json` |
| 描述 | 查看测试版本详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 测试版本ID |
---
### 删除测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testtask-delete-[taskID]-[confirm].json` |
| 描述 | 删除测试版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 测试版本ID |
| confirm | string | 否 | 确认删除 |
---
### 开始测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testtask-start-[taskID].json` |
| 描述 | 开始测试版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 测试版本ID |
---
### 关闭测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testtask-close-[taskID].json` |
| 描述 | 关闭测试版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 测试版本ID |
---
### 激活测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testtask-activate-[taskID].json` |
| 描述 | 激活测试版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 测试版本ID |
---
### 关联测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testtask-linkCase-[taskID].json` |
| 描述 | 关联测试用例到测试版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 测试版本ID |
---
### 测试版本报告
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testtask-report-[taskID].json` |
| 描述 | 获取测试版本报告 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 测试版本ID |
FILE:docs/admin.md
# 后台管理 (Admin) API 文档
## 概述
后台管理相关的API接口。
## API 列表
### 后台首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/admin.json` |
| 描述 | 后台管理首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 系统信息
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/admin-systemInfo.json` |
| 描述 | 获取系统信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 用户管理
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/admin-user.json` |
| 描述 | 用户管理入口 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 权限管理
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/admin-privilege.json` |
| 描述 | 权限管理入口 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 流程设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/admin-workflow.json` |
| 描述 | 工作流设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 自定义字段
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/admin-customField.json` |
| 描述 | 自定义字段设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 系统配置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/admin-config.json` |
| 描述 | 系统配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 菜单管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/admin-menu.json` |
| 描述 | 菜单管理 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 模板管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/admin-template.json` |
| 描述 | 模板管理 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 插件管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/admin-plugin.json` |
| 描述 | 插件管理 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 缓存管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/admin-cache.json` |
| 描述 | 缓存管理 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 系统优化
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/admin-optimize.json` |
| 描述 | 系统优化 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/file.md
# 附件 (File) API 文档
## 概述
附件管理相关的API接口。
## API 列表
### 构建上传表单
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/file-buildForm-[fileCount]-[percent]-[filesName]-[labelsName].json` |
| 描述 | 构建文件上传表单 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| fileCount | - | 否 | 文件数量 |
| percent | - | 否 | 上传进度百分比 |
| filesName | - | 否 | 文件名称 |
| labelsName | - | 否 | 标签名称 |
---
### AJAX上传
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/file-ajaxUpload.json` |
| 描述 | AJAX方式上传文件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 下载文件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/file-download-[fileID]-[mouse].json` |
| 描述 | 下载文件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| fileID | int | 否 | 文件ID |
| mouse | string | 否 | 鼠标事件 |
---
### 导出CSV
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/file-export2CSV.json` |
| 描述 | 导出数据为CSV格式 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导出XML
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/file-export2XML.json` |
| 描述 | 导出数据为XML格式 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导出HTML
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/file-export2HTML.json` |
| 描述 | 导出数据为HTML格式 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 删除文件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/file-delete-[fileID]-[confirm].json` |
| 描述 | 删除文件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| fileID | int | 否 | 文件ID |
| confirm | string | 否 | 确认删除 |
---
### 编辑文件名
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/file-edit-[fileID].json` |
| 描述 | 编辑文件名 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| fileID | int | 否 | 文件ID |
FILE:docs/qa.md
# 测试 (QA) API 文档
## 概述
测试管理相关的API接口。
## API 列表
### 测试首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/qa.json` |
| 描述 | 测试首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览测试
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/qa-browse-[productID]-[branch]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览测试列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 测试统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/qa-statistic-[productID].json` |
| 描述 | 获取测试统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 测试报告
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/qa-report-[productID].json` |
| 描述 | 获取测试报告 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 测试需求覆盖
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/qa-coverage-[productID].json` |
| 描述 | 获取需求测试覆盖率 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
FILE:docs/report.md
# 统计 (Report) API 文档
## 概述
统计报表相关的API接口。
## API 列表
### 统计首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/report.json` |
| 描述 | 统计首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 产品统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/report-product-[productID].json` |
| 描述 | 产品统计报表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 项目统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/report-project-[projectID].json` |
| 描述 | 项目统计报表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 测试统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/report-qa-[productID].json` |
| 描述 | 测试统计报表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 团队统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/report-team.json` |
| 描述 | 团队统计报表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 自定义报表
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/report-custom-[reportID].json` |
| 描述 | 自定义统计报表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| reportID | int | 否 | 报表ID |
FILE:docs/dept.md
# 部门 (Dept) API 文档
## 概述
部门管理相关的API接口。
## API 列表
### 浏览部门
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dept-browse-[deptID].json` |
| 描述 | 浏览部门详情及其子部门 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
---
### 更新部门排序
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-updateOrder.json` |
| 描述 | 更新部门的排序顺序 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 管理子部门
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-manageChild.json` |
| 描述 | 管理部门的子部门 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 编辑部门
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-edit-[deptID].json` |
| 描述 | 编辑部门信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
---
### 删除部门
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dept-delete-[deptID]-[confirm].json` |
| 描述 | 删除部门 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
| confirm | string | 否 | 确认删除 |
---
### AJAX获取用户列表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dept-ajaxGetUsers-[dept]-[user].json` |
| 描述 | AJAX获取部门下的用户列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| dept | int | 否 | 部门ID |
| user | string | 否 | 用户筛选 |
---
### 创建子部门
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-createChild.json` |
| 描述 | 创建子部门 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 移动部门
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-move-[deptID]-[parentDeptID].json` |
| 描述 | 移动部门到新的父部门 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
| parentDeptID | int | 否 | 父部门ID |
---
### 部门统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dept-statistic-[deptID].json` |
| 描述 | 获取部门统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
---
### 部门树结构
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dept-tree.json` |
| 描述 | 获取部门树结构 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 部门负责人设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-setManager-[deptID]-[userID].json` |
| 描述 | 设置部门负责人 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
| userID | int | 否 | 用户ID |
---
### 部门成员管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-members-[deptID].json` |
| 描述 | 管理部门成员 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
---
### 部门权限设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-permission-[deptID].json` |
| 描述 | 设置部门权限 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
---
### 部门预算设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dept-budget-[deptID].json` |
| 描述 | 设置部门预算 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
FILE:docs/testsuite.md
# 测试套件 (Testsuite) API 文档
## 概述
测试套件管理相关的API接口。
## API 列表
### 测试套件首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testsuite.json` |
| 描述 | 测试套件首页,跳转到浏览页面 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览测试套件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testsuite-browse-[productID]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览产品下的测试套件列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建测试套件
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testsuite-create-[productID].json` |
| 描述 | 为产品创建测试套件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 查看测试套件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testsuite-view-[suiteID]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 查看测试套件详情及关联的测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| suiteID | int | 否 | 测试套件ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 编辑测试套件
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testsuite-edit-[suiteID].json` |
| 描述 | 编辑测试套件信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| suiteID | int | 否 | 测试套件ID |
---
### 删除测试套件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testsuite-delete-[suiteID]-[confirm].json` |
| 描述 | 删除测试套件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| suiteID | int | 否 | 测试套件ID |
| confirm | string | 否 | 确认删除 |
---
### 关联测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testsuite-linkCase-[suiteID]-[param]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 向测试套件中关联测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| suiteID | int | 否 | 测试套件ID |
| param | int | 否 | 参数 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 移除测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testsuite-unlinkCase-[suiteID]-[rowID]-[confirm].json` |
| 描述 | 从测试套件中移除测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| suiteID | int | 否 | 测试套件ID |
| rowID | int | 否 | 行ID |
| confirm | string | 否 | 确认删除 |
---
### 批量移除测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testsuite-batchUnlinkCases-[suiteID].json` |
| 描述 | 批量从测试套件中移除测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| suiteID | int | 否 | 测试套件ID |
FILE:docs/caselib.md
# Caselib API 文档
## 概述
用例库管理相关的API接口。
## API 列表
### 用例库首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/caselib.json` |
| 描述 | 用例库首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览用例库
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/caselib-browse-[libID]-[orderBy].json` |
| 描述 | 浏览用例库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| libID | int | 否 | 用例库ID |
| orderBy | string | 否 | 排序方式 |
FILE:docs/score.md
# 积分 (Score) API 文档
## 概述
积分管理相关的API接口。
## API 列表
### 积分首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/score.json` |
| 描述 | 积分首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 积分规则
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/score-rule.json` |
| 描述 | 积分规则设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 积分记录
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/score-log-[account].json` |
| 描述 | 查看积分记录 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| account | string | 否 | 用户账号 |
---
### 积分排名
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/score-ranking-[period].json` |
| 描述 | 积分排行榜 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| period | string | 否 | 统计周期 |
---
### 积分统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/score-statistic-[account].json` |
| 描述 | 积分统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| account | string | 否 | 用户账号 |
FILE:docs/project.md
# 项目 (Project) API 文档
## 概述
项目管理相关的API接口。
## API 列表
### 项目首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-index-[locate]-[status]-[projectID].json` |
| 描述 | 项目首页视图 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| locate | - | 否 | 定位 |
| status | - | 否 | 状态 |
| projectID | - | 否 | 项目ID |
---
### 浏览项目
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-browse-[projectID].json` |
| 描述 | 浏览项目详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-task-[projectID]-[status]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取项目任务列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| status | string | 否 | 状态 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 分组任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-grouptask-[projectID]-[groupBy].json` |
| 描述 | 按组获取项目任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| groupBy | string | 否 | 分组方式 |
---
### 项目需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-story-[projectID]-[orderBy].json` |
| 描述 | 获取项目需求列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| orderBy | string | 否 | 排序方式 |
---
### 项目Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-bug-[projectID]-[orderBy]-[build]-[type]-[param]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取项目Bug列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| orderBy | string | 否 | 排序方式 |
| build | - | 否 | 版本 |
| type | - | 否 | 类型 |
| param | - | 否 | 参数 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 项目燃尽图
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-burn-[projectID]-[type]-[interval].json` |
| 描述 | 获取项目燃尽图数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| type | - | 否 | 类型 |
| interval | - | 否 | 间隔 |
---
### 创建项目
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/project-create-[projectID]-[copyProjectID]-[planID].json` |
| 描述 | 创建项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| copyProjectID | int | 否 | 复制项目ID |
| planID | int | 否 | 计划ID |
---
### 编辑项目
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/project-edit-[projectID]-[action]-[extra].json` |
| 描述 | 编辑项目信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| action | string | 否 | 操作 |
| extra | string | 否 | 额外参数 |
---
### 开始项目
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/project-start-[projectID].json` |
| 描述 | 开始项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 关闭项目
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/project-close-[projectID].json` |
| 描述 | 关闭项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 查看项目
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-view-[projectID].json` |
| 描述 | 查看项目详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目看板视图
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-kanban-[projectID]-[type]-[orderBy].json` |
| 描述 | 项目看板视图 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| type | string | 否 | 类型 |
| orderBy | string | 否 | 排序方式 |
---
### 管理项目成员
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/project-manageMembers-[projectID]-[team2Import].json` |
| 描述 | 管理项目成员 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| team2Import | - | 否 | 团队导入 |
---
### 关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/project-linkStory-[projectID].json` |
| 描述 | 关联需求到项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 移除需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-unlinkStory-[projectID]-[storyID].json` |
| 描述 | 从项目中移除需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| storyID | int | 否 | 需求ID |
---
### 批量移除需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-batchUnlinkStory-[projectID].json` |
| 描述 | 批量从项目中移除需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目进度
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-progress-[projectID].json` |
| 描述 | 获取项目进度信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目动态
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-dynamic-[projectID]-[type]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取项目动态信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| type | - | 否 | 类型 |
| orderBy | - | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 项目统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-statistic-[projectID]-[by]-[type].json` |
| 描述 | 获取项目统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| by | - | 否 | 按什么统计 |
| type | - | 否 | 类型 |
---
### 项目报表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-report-[projectID]-[reportType].json` |
| 描述 | 获取项目报表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| reportType | string | 否 | 报表类型 |
---
### 项目甘特图
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-gantt-[projectID].json` |
| 描述 | 获取项目甘特图数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目风险
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-risk-[projectID].json` |
| 描述 | 获取项目风险信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目团队
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-team-[projectID].json` |
| 描述 | 获取项目团队信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目里程碑
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-milestone-[projectID].json` |
| 描述 | 获取项目里程碑信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目预算
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-budget-[projectID].json` |
| 描述 | 获取项目预算信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目文档
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-document-[projectID].json` |
| 描述 | 获取项目文档信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目附件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-attachment-[projectID].json` |
| 描述 | 获取项目附件信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
---
### 项目审批
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/project-approval-[projectID].json` |
| 描述 | 获取项目审批信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
FILE:docs/block.md
# 区块 (Block) API 文档
## 概述
页面区块管理相关的API接口。
## API 列表
### 区块管理
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-admin-[id]-[module].json` |
| 描述 | 管理区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | 区块ID |
| module | string | 否 | 模块名称 |
---
### 设置区块参数
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/block-set-[id]-[type].json` |
| 描述 | 设置区块参数(RSS或HTML类型) |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | 区块ID |
| type | string | 否 | 区块类型 |
---
### 删除区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-delete-[id]-[sys]-[type].json` |
| 描述 | 删除区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | 区块ID |
| sys | string | 否 | 系统标识 |
| type | string | 否 | 区块类型 |
---
### 排序区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-sort-[oldOrder]-[newOrder]-[module].json` |
| 描述 | 调整区块排序 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| oldOrder | string | 否 | 原始顺序 |
| newOrder | string | 否 | 新顺序 |
| module | string | 否 | 模块名称 |
---
### 调整区块大小
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-resize-[id].json` |
| 描述 | 调整区块尺寸 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | 区块ID |
---
### 仪表盘
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-dashboard-[module].json` |
| 描述 | 显示应用的仪表盘视图 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
---
### 最新动态
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-dynamic.json` |
| 描述 | 显示最新动态区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 欢迎区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-welcome.json` |
| 描述 | 显示欢迎信息区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 打印区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printBlock-[id].json` |
| 描述 | 打印指定区块内容 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | 区块ID |
---
### 主区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-main.json` |
| 描述 | 主区块功能 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 列表区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printListBlock.json` |
| 描述 | 打印列表区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 待办区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printTodoBlock.json` |
| 描述 | 打印待办区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 任务区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printTaskBlock.json` |
| 描述 | 打印任务区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### Bug区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printBugBlock.json` |
| 描述 | 打印Bug区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 用例区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printCaseBlock.json` |
| 描述 | 打印测试用例区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 测试版本区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printTesttaskBlock.json` |
| 描述 | 打印测试版本区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 需求区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printStoryBlock.json` |
| 描述 | 打印需求区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 计划区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printPlanBlock.json` |
| 描述 | 打印计划区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 发布区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printReleaseBlock.json` |
| 描述 | 打印发布区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 版本区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printBuildBlock.json` |
| 描述 | 打印版本区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 产品区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printProductBlock.json` |
| 描述 | 打印产品区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 统计区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printStatisticBlock-[module].json` |
| 描述 | 打印统计区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
---
### 产品统计区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printProductStatisticBlock-[storyType].json` |
| 描述 | 打印产品统计区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyType | string | 否 | 需求类型 |
---
### 项目统计区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printProjectStatisticBlock.json` |
| 描述 | 打印项目统计区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 测试统计区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printQaStatisticBlock.json` |
| 描述 | 打印测试统计区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 概览区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printOverviewBlock.json` |
| 描述 | 打印概览区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 产品概览区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printProductOverviewBlock.json` |
| 描述 | 打印产品概览区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 项目概览区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printProjectOverviewBlock.json` |
| 描述 | 打印项目概览区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 测试概览区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printQaOverviewBlock.json` |
| 描述 | 打印测试概览区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 项目区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printProjectBlock.json` |
| 描述 | 打印项目区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 分配给我的区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-printAssignToMeBlock.json` |
| 描述 | 打印分配给我的区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 流程图区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-flowchart.json` |
| 描述 | 打印流程图区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关闭区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-close-[blockID].json` |
| 描述 | 永久关闭区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| blockID | int | 否 | 区块ID |
---
### AJAX重置区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-ajaxReset-[module]-[confirm].json` |
| 描述 | AJAX重置区块配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
| confirm | string | 否 | 确认操作 |
---
### AJAX使用新区块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/block-ajaxUseNew-[module]-[confirm].json` |
| 描述 | AJAX使用新区块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
| confirm | string | 否 | 确认操作 |
FILE:docs/dev.md
# 二次开发 (Dev) API 文档
## 概述
二次开发相关的API接口。
## API 列表
### 二次开发首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dev.json` |
| 描述 | 二次开发首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### API文档
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dev-api.json` |
| 描述 | API开发文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 数据库文档
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dev-db.json` |
| 描述 | 数据库结构文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 二次开发指南
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dev-guide.json` |
| 描述 | 二次开发指南 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 扩展机制
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dev-extension.json` |
| 描述 | 扩展机制说明 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 钩子配置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/dev-hook.json` |
| 描述 | 钩子配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 模块开发
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/dev-module.json` |
| 描述 | 模块开发文档 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/install.md
# 安装 (Install) API 文档
## 概述
系统安装相关的API接口。
## API 列表
### 安装首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/install.json` |
| 描述 | 系统安装首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 环境检查
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/install-check.json` |
| 描述 | 检查安装环境 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 安装数据库
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/install-db.json` |
| 描述 | 安装数据库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 创建管理员
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/install-admin.json` |
| 描述 | 创建管理员账号 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 完成安装
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/install-finish.json` |
| 描述 | 完成安装过程 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/todo.md
# 待办 (Todo) API 文档
## 概述
待办事项管理相关的API接口。
## API 列表
### 创建待办
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-create-[date]-[account].json` |
| 描述 | 创建待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| date | string/date | 否 | 日期 |
| account | string | 否 | 用户账号 |
---
### 批量创建待办
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-batchCreate-[date]-[account].json` |
| 描述 | 批量创建待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| date | string | 否 | 日期 |
| account | string | 否 | 用户账号 |
---
### 编辑待办
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-edit-[todoID].json` |
| 描述 | 编辑待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| todoID | int | 否 | 待办ID |
---
### 批量编辑待办
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-batchEdit-[from]-[type]-[account]-[status].json` |
| 描述 | 批量编辑待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| from | string | 否 | 来源 |
| type | string | 否 | 类型 |
| account | string | 否 | 用户账号 |
| status | string | 否 | 状态 |
---
### 激活待办
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/todo-activate.json` |
| 描述 | 激活待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| todoID | - | 否 | 待办ID |
---
### 关闭待办
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/todo-close.json` |
| 描述 | 关闭待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| todoID | - | 否 | 待办ID |
---
### 分配待办
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-assignTo.json` |
| 描述 | 分配待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| todoID | - | 否 | 待办ID |
---
### 查看待办
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/todo-view-[todoID]-[from].json` |
| 描述 | 查看待办详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| todoID | int | 否 | 待办ID |
| from | string | 否 | 来源 |
---
### 删除待办
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/todo-delete-[todoID]-[confirm].json` |
| 描述 | 删除待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| todoID | int | 否 | 待办ID |
| confirm | string | 否 | 确认 |
---
### 完成待办
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/todo-finish-[todoID].json` |
| 描述 | 完成待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| todoID | int | 否 | 待办ID |
---
### 批量完成待办
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-batchFinish.json` |
| 描述 | 批量完成待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 批量关闭待办
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-batchClose.json` |
| 描述 | 批量关闭待办事项 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导入到今天
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-import2Today.json` |
| 描述 | 将选中的待办导入到今天 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导出待办
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/todo-export-[productID]-[orderBy].json` |
| 描述 | 导出待办数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | string | 否 | 产品ID |
| orderBy | string | 否 | 排序方式 |
---
### 获取待办详情
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/todo-ajaxGetDetail-[todoID].json` |
| 描述 | AJAX获取待办的操作历史 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| todoID | int | 否 | 待办ID |
---
### 创建循环待办
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/todo-createCycle.json` |
| 描述 | 创建循环待办 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/productplan.md
# 产品计划 (Productplan) API 文档
## 概述
产品计划管理相关的API接口。
## API 列表
### 产品计划首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/productplan.json` |
| 描述 | 产品计划首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览产品计划
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/productplan-browse-[productID]-[branch]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览产品计划列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建产品计划
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/productplan-create-[productID]-[branch].json` |
| 描述 | 创建产品计划 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
---
### 编辑产品计划
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/productplan-edit-[planID].json` |
| 描述 | 编辑产品计划 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| planID | int | 否 | 计划ID |
---
### 查看产品计划
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/productplan-view-[planID].json` |
| 描述 | 查看产品计划详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| planID | int | 否 | 计划ID |
---
### 删除产品计划
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/productplan-delete-[planID]-[confirm].json` |
| 描述 | 删除产品计划 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| planID | int | 否 | 计划ID |
| confirm | string | 否 | 确认删除 |
---
### 关联需求到计划
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/productplan-linkStory-[planID]-[browseType]-[param]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 关联需求到产品计划 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| planID | int | 否 | 计划ID |
| browseType | string | 否 | 浏览类型 |
| param | - | 否 | 参数 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 取消关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/productplan-unlinkStory-[planID]-[storyID].json` |
| 描述 | 取消需求与计划的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| planID | int | 否 | 计划ID |
| storyID | int | 否 | 需求ID |
---
### 批量取消关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/productplan-batchUnlinkStory-[planID].json` |
| 描述 | 批量取消需求与计划的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| planID | int | 否 | 计划ID |
---
### 产品计划排序
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/productplan-updateOrder.json` |
| 描述 | 更新产品计划排序 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 产品计划统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/productplan-statistic-[productID].json` |
| 描述 | 获取产品计划统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
FILE:docs/company.md
# 公司 (Company) API 文档
## 概述
公司管理相关的API接口。
## API 列表
### 公司首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/company.json` |
| 描述 | 公司首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览公司
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/company-browse-[deptID].json` |
| 描述 | 浏览公司部门结构 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
---
### 编辑公司信息
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/company-edit-[companyID].json` |
| 描述 | 编辑公司信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| companyID | int | 否 | 公司ID |
---
### 公司用户管理
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/company-users-[companyID].json` |
| 描述 | 查看公司用户列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| companyID | int | 否 | 公司ID |
---
### 公司部门管理
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/company-depts-[companyID].json` |
| 描述 | 查看公司部门列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| companyID | int | 否 | 公司ID |
---
### 公司权限管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/company-permission-[companyID].json` |
| 描述 | 管理公司权限 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| companyID | int | 否 | 公司ID |
---
### 公司设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/company-setting-[companyID].json` |
| 描述 | 公司系统设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| companyID | int | 否 | 公司ID |
FILE:docs/datatable.md
# 数据表格 (Datatable) API 文档
## 概述
数据表格相关的API接口。
## API 列表
### 数据表格首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/datatable.json` |
| 描述 | 数据表格首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取表格数据
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/datatable-getData-[tableName]-[conditions]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取表格数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| tableName | string | 否 | 表名 |
| conditions | string | 否 | 查询条件 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 保存表格配置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/datatable-saveConfig-[tableName].json` |
| 描述 | 保存表格配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| tableName | string | 否 | 表名 |
FILE:docs/release.md
# 发布 (Release) API 文档
## 概述
产品发布管理相关的API接口。
## API 列表
### 通用操作
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-commonAction-[productID]-[branch].json` |
| 描述 | 获取发布通用操作 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
---
### 浏览发布
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-browse-[productID]-[branch]-[type].json` |
| 描述 | 浏览产品发布列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
| type | string | 否 | 类型 |
---
### 创建发布
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/release-create-[productID]-[branch].json` |
| 描述 | 创建产品发布 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
---
### 编辑发布
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/release-edit-[releaseID].json` |
| 描述 | 编辑发布信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
---
### 查看发布
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-view-[releaseID]-[type]-[link]-[param]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 查看发布详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
| type | string | 否 | 类型 |
| link | string | 否 | 链接 |
| param | string | 否 | 参数 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 删除发布
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-delete-[releaseID]-[confirm].json` |
| 描述 | 删除发布 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
| confirm | string | 否 | 确认 |
---
### 导出发布
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/release-export.json` |
| 描述 | 导出发布的需求到HTML |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/release-linkStory-[releaseID]-[browseType]-[param]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 关联需求到发布 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
| browseType | string | 否 | 浏览类型 |
| param | int | 否 | 参数 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 取消关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-unlinkStory-[releaseID]-[storyID].json` |
| 描述 | 取消关联需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
| storyID | int | 否 | 需求ID |
---
### 批量取消关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-batchUnlinkStory-[releaseID].json` |
| 描述 | 批量取消关联需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
---
### 关联Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/release-linkBug-[releaseID]-[browseType]-[param]-[type]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 关联Bug到发布 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
| browseType | string | 否 | 浏览类型 |
| param | int | 否 | 参数 |
| type | string | 否 | 类型 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 取消关联Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-unlinkBug-[releaseID]-[bugID]-[type].json` |
| 描述 | 取消关联Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
| bugID | int | 否 | BugID |
| type | string | 否 | 类型 |
---
### 批量取消关联Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-batchUnlinkBug-[releaseID]-[type].json` |
| 描述 | 批量取消关联Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
| type | string | 否 | 类型 |
---
### 更改状态
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/release-changeStatus-[releaseID]-[status].json` |
| 描述 | 更改发布状态 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| releaseID | int | 否 | 发布ID |
| status | string | 否 | 状态 |
FILE:docs/webhook.md
# WebHook API 文档
## 概述
WebHook管理相关的API接口。
## API 列表
### 浏览WebHook
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/webhook-browse-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览WebHook列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建WebHook
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-create.json` |
| 描述 | 创建新的WebHook |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 编辑WebHook
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-edit-[id].json` |
| 描述 | 编辑WebHook配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### 删除WebHook
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/webhook-delete-[id].json` |
| 描述 | 删除WebHook |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### 浏览WebHook日志
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/webhook-log-[id]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览特定WebHook的执行日志 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 绑钉钉用户ID
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-bind-[id]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 绑定钉钉用户ID到WebHook |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 选择部门
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/webhook-chooseDept-[id].json` |
| 描述 | 为WebHook选择部门 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### 异步发送数据
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-asyncSend.json` |
| 描述 | 异步发送WebHook数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 测试WebHook
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-test-[id].json` |
| 描述 | 测试WebHook是否正常工作 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### 暂停WebHook
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-pause-[id].json` |
| 描述 | 暂停WebHook执行 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### 恢复WebHook
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-resume-[id].json` |
| 描述 | 恢复WebHook执行 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### WebHook模板管理
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-template-[type].json` |
| 描述 | 管理WebHook模板 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 模板类型 |
---
### WebHook事件类型
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/webhook-events.json` |
| 描述 | 获取支持的WebHook事件类型 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### WebHook认证设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-auth-[id].json` |
| 描述 | 设置WebHook认证信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### WebHook重试机制
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-retry-[id].json` |
| 描述 | 配置WebHook重试机制 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### WebHook超时设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/webhook-timeout-[id].json` |
| 描述 | 设置WebHook超时时间 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
---
### WebHook统计信息
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/webhook-statistic-[id].json` |
| 描述 | 获取WebHook统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| id | int | 否 | WebHook ID |
FILE:docs/my.md
# 我的地盘 (My) API 文档
## 概述
用户个人中心相关的API接口。
## API 列表
### 首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my.json` |
| 描述 | 首页,跳转到待办 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 积分列表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-score-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取积分列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 日历
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-calendar.json` |
| 描述 | 日历视图 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 我的待办
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-todo-[type]-[account]-[status]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取当前用户的待办列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 类型 |
| account | string | 否 | 用户账号 |
| status | string | 否 | 状态 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 我的需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-story-[type]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取当前用户的需求列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 类型 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 我的任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-task-[type]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取当前用户的任务列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 类型 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 我的Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-bug-[type]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取当前用户的Bug列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 类型 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 我的测试版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-testtask.json` |
| 描述 | 获取当前用户的测试版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 我的测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-testcase-[type]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取当前用户的测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 类型 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 我的项目
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-project.json` |
| 描述 | 获取当前用户参与的项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 编辑个人资料
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/my-editProfile.json` |
| 描述 | 编辑用户个人资料 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 修改密码
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/my-changePassword.json` |
| 描述 | 修改用户密码 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 管理联系人
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/my-manageContacts-[listID]-[mode].json` |
| 描述 | 管理联系人列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| listID | int | 否 | 列表ID |
| mode | string | 否 | 模式 |
---
### 删除联系人
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-deleteContacts-[listID]-[confirm].json` |
| 描述 | 删除联系人列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| listID | int | 否 | 列表ID |
| confirm | string | 否 | 确认 |
---
### 构建联系人列表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-buildContactLists.json` |
| 描述 | 构建联系人列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 查看个人资料
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-profile.json` |
| 描述 | 查看当前用户资料 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 我的动态
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-dynamic-[type]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取当前用户的动态信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 类型 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 解除绑定
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/my-unbind-[confirm].json` |
| 描述 | 解除与然之的绑定 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| confirm | string | 否 | 确认 |
FILE:docs/sso.md
# 单点登录 (SSO) API 文档
## 概述
单点登录相关的API接口。
## API 列表
### SSO首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/sso.json` |
| 描述 | 单点登录首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### SSO设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/sso-setting.json` |
| 描述 | 配置单点登录 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 测试SSO连接
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/sso-test.json` |
| 描述 | 测试SSO连接 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/svn.md
# SVN API 文档
## 概述
SVN代码管理相关的API接口。
## API 列表
### SVN首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/svn.json` |
| 描述 | SVN首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览SVN仓库
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/svn-browse-[repoID].json` |
| 描述 | 浏览SVN仓库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 查看提交历史
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/svn-log-[repoID]-[revision].json` |
| 描述 | 查看SVN提交历史 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| revision | string | 否 | 版本号 |
---
### 查看版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/svn-versions-[repoID].json` |
| 描述 | 查看仓库版本列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 查看版本详情
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/svn-viewVersion-[repoID]-[revision].json` |
| 描述 | 查看指定版本详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| revision | string | 否 | 版本号 |
---
### 查看文件差异
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/svn-diff-[repoID]-[from]-[to].json` |
| 描述 | 查看文件差异 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| from | string | 否 | 起始版本 |
| to | string | 否 | 结束版本 |
FILE:docs/testcase.md
# 测试用例 (Testcase) API 文档
## 概述
测试用例管理相关的API接口。
## API 列表
### 测试用例首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testcase.json` |
| 描述 | 测试用例首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testcase-browse-[productID]-[branch]-[browseType]-[param]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览测试用例列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
| browseType | string | 否 | 浏览类型 |
| param | - | 否 | 参数 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testcase-create-[productID]-[branch]-[moduleID]-[storyID].json` |
| 描述 | 创建测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
| moduleID | int | 否 | 模块ID |
| storyID | int | 否 | 需求ID |
---
### 编辑测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testcase-edit-[caseID].json` |
| 描述 | 编辑测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| caseID | int | 否 | 测试用例ID |
---
### 查看测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testcase-view-[caseID]-[version].json` |
| 描述 | 查看测试用例详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| caseID | int | 否 | 测试用例ID |
| version | string | 否 | 版本号 |
---
### 删除测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testcase-delete-[caseID]-[confirm].json` |
| 描述 | 删除测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| caseID | int | 否 | 测试用例ID |
| confirm | string | 否 | 确认删除 |
---
### 批量创建测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testcase-batchCreate-[productID].json` |
| 描述 | 批量创建测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 批量编辑测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testcase-batchEdit.json` |
| 描述 | 批量编辑测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导入测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testcase-import-[productID].json` |
| 描述 | 从文件导入测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 导出测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testcase-export-[productID].json` |
| 描述 | 导出测试用例到文件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testcase-linkStory-[caseID]-[storyID].json` |
| 描述 | 关联需求到测试用例 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| caseID | int | 否 | 测试用例ID |
| storyID | int | 否 | 需求ID |
---
### 取消关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testcase-unlinkStory-[caseID]-[storyID].json` |
| 描述 | 取消需求与测试用例的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| caseID | int | 否 | 测试用例ID |
| storyID | int | 否 | 需求ID |
---
### 测试用例版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testcase-version-[caseID].json` |
| 描述 | 查看测试用例版本历史 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| caseID | int | 否 | 测试用例ID |
---
### 测试用例模板
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testcase-template-[type].json` |
| 描述 | 获取测试用例模板 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 模板类型 |
FILE:docs/tutorial.md
# 新手教程 (Tutorial) API 文档
## 概述
新手教程管理相关的API接口。
## API 列表
### 开始教程
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-start.json` |
| 描述 | 新手教程开始页面 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 教程首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial.json` |
| 描述 | 新手教程首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### AJAX设置教程任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/tutorial-ajaxSetTasks-[finish].json` |
| 描述 | AJAX设置教程任务进度 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| finish | string | 否 | 完成状态 |
---
### 退出教程模式
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-quit-[referer].json` |
| 描述 | 退出新手教程模式 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| referer | string | 否 | 来源页面 |
---
### AJAX退出教程模式
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-ajaxQuit.json` |
| 描述 | AJAX方式退出新手教程模式 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 向导
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/tutorial-wizard-[module]-[method]-[params].json` |
| 描述 | 新手教程向导功能 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
| method | string | 否 | 方法名称 |
| params | string | 否 | 参数(JSON格式) |
---
### AJAX保存新手进度
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-ajaxSaveNovice-[novice]-[reload].json` |
| 描述 | AJAX保存新手教程进度 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| novice | string | 否 | 新手进度数据 |
| reload | string | 否 | 是否重新加载 |
---
### AJAX保存教程得分
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-ajaxFinish.json` |
| 描述 | AJAX保存新手教程完成得分 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 教程进度查询
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-progress.json` |
| 描述 | 查询教程进度 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 教程任务清单
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-tasks.json` |
| 描述 | 获取教程任务清单 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 教程章节
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-chapter-[chapter].json` |
| 描述 | 获取教程章节内容 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| chapter | string | 否 | 章节编号 |
---
### 教程测试
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-test-[testID].json` |
| 描述 | 教程测试环节 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| testID | string | 否 | 测试ID |
---
### 教程奖励
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-reward.json` |
| 描述 | 教程奖励系统 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 教程统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-statistic.json` |
| 描述 | 教程统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 教程提示
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-tip-[step].json` |
| 描述 | 获取教程提示信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| step | string | 否 | 步骤编号 |
---
### 教程视频
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tutorial-video-[topic].json` |
| 描述 | 教程视频播放 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| topic | string | 否 | 视频主题 |
FILE:docs/index.md
# 首页 (Index) API 文档
## 概述
禅道系统首页相关的API接口。
## API 列表
### 获取首页数据
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/index.json` |
| 描述 | 获取禅道系统首页数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 测试扩展引擎
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/index-testext.json` |
| 描述 | 测试扩展引擎是否正常工作 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/custom.md
# 自定义 (Custom) API 文档
## 概述
自定义设置相关的API接口。
## API 列表
### 自定义首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/custom.json` |
| 描述 | 自定义设置首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 模块设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/custom-module-[module].json` |
| 描述 | 自定义模块设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
---
### 字段设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/custom-field-[module].json` |
| 描述 | 自定义字段设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
---
### 列表视图
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/custom-view-[module].json` |
| 描述 | 自定义列表视图 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| module | string | 否 | 模块名称 |
---
### 页面样式
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/custom-style.json` |
| 描述 | 页面样式自定义 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 主题设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/custom-theme.json` |
| 描述 | 主题设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/testreport.md
# 测试报告 (Testreport) API 文档
## 概述
测试报告管理相关的API接口。
## API 列表
### 测试报告首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testreport.json` |
| 描述 | 测试报告首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览测试报告
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testreport-browse-[productID]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览测试报告列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建测试报告
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testreport-create-[objectType]-[objectID].json` |
| 描述 | 创建测试报告 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| objectType | string | 否 | 对象类型 |
| objectID | int | 否 | 对象ID |
---
### 编辑测试报告
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testreport-edit-[reportID].json` |
| 描述 | 编辑测试报告 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| reportID | int | 否 | 报告ID |
---
### 查看测试报告
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testreport-view-[reportID].json` |
| 描述 | 查看测试报告详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| reportID | int | 否 | 报告ID |
---
### 删除测试报告
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testreport-delete-[reportID]-[confirm].json` |
| 描述 | 删除测试报告 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| reportID | int | 否 | 报告ID |
| confirm | string | 否 | 确认删除 |
---
### 导出测试报告
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/testreport-export-[reportID].json` |
| 描述 | 导出测试报告 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| reportID | int | 否 | 报告ID |
---
### 测试报告模板
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/testreport-template.json` |
| 描述 | 获取测试报告模板 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/build.md
# 版本 (Build) API 文档
## 概述
项目版本/Build管理相关的API接口。
## API 列表
### 创建版本
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/build-create-[projectID]-[productID].json` |
| 描述 | 创建项目版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| productID | int | 否 | 产品ID |
---
### 编辑版本
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/build-edit-[buildID].json` |
| 描述 | 编辑版本信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | 版本ID |
---
### 查看版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/build-view-[buildID]-[type]-[link]-[param]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 查看版本详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | 版本ID |
| type | string | 否 | 类型 |
| link | string | 否 | 链接 |
| param | string | 否 | 参数 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 删除版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/build-delete-[buildID]-[confirm].json` |
| 描述 | 删除版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | 版本ID |
| confirm | string | 否 | 确认 |
---
### 获取产品版本列表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/build-ajaxGetProductBuilds-[productID]-[varName]-[build]-[branch]-[index]-[type].json` |
| 描述 | AJAX获取产品的版本下拉列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| varName | string | 否 | 变量名 |
| build | string | 否 | 版本 |
| branch | int | 否 | 分支ID |
| index | int | 否 | 索引 |
| type | string | 否 | 类型 |
---
### 获取项目版本列表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/build-ajaxGetProjectBuilds-[projectID]-[varName]-[build]-[branch]-[index]-[needCreate]-[type].json` |
| 描述 | AJAX获取项目的版本下拉列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| varName | string | 否 | 变量名 |
| build | string | 否 | 版本 |
| branch | int | 否 | 分支ID |
| index | int | 否 | 索引 |
| needCreate | bool | 否 | 是否需要创建 |
| type | string | 否 | 类型 |
---
### 关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/build-linkStory-[buildID]-[browseType]-[param]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 关联需求到版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | 版本ID |
| browseType | string | 否 | 浏览类型 |
| param | int | 否 | 参数 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 取消关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/build-unlinkStory-[storyID]-[confirm].json` |
| 描述 | 取消关联需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
| confirm | string | 否 | 确认 |
---
### 批量取消关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/build-batchUnlinkStory-[confirm].json` |
| 描述 | 批量取消关联需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| confirm | string | 否 | 确认 |
---
### 关联Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/build-linkBug-[buildID]-[browseType]-[param]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 关联Bug到版本 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | 版本ID |
| browseType | string | 否 | 浏览类型 |
| param | int | 否 | 参数 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 取消关联Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/build-unlinkBug-[buildID]-[bugID].json` |
| 描述 | 取消关联Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | 版本ID |
| bugID | int | 否 | BugID |
---
### 批量取消关联Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/build-batchUnlinkBug-[buildID].json` |
| 描述 | 批量取消关联Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| buildID | int | 否 | 版本ID |
FILE:docs/mail.md
# 邮箱 (Mail) API 文档
## 概述
邮件管理相关的API接口。
## API 列表
### 邮箱首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/mail.json` |
| 描述 | 邮箱设置首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 邮箱设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/mail-settings.json` |
| 描述 | 配置邮箱服务器设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 发送邮件
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/mail-send.json` |
| 描述 | 发送邮件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 邮件测试
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/mail-test.json` |
| 描述 | 测试邮箱配置是否正确 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 邮件日志
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/mail-log-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 查看邮件发送日志 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 邮件模板
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/mail-template-[type].json` |
| 描述 | 管理邮件模板 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 模板类型 |
---
### 邮件队列
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/mail-queue.json` |
| 描述 | 查看邮件发送队列 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 清除邮件队列
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/mail-clearQueue.json` |
| 描述 | 清除邮件发送队列 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/bug.md
# Bug 管理 API 文档
## 概述
Bug管理相关的API接口。
## API 列表
### Bug首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug.json` |
| 描述 | Bug管理首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-browse-[productID]-[branch]-[browseType]-[param]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览产品Bug列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
| browseType | string | 否 | 浏览类型 |
| param | - | 否 | 参数 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-create-[productID]-[branch]-[extras].json` |
| 描述 | 创建新的Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
| extras | - | 否 | 额外参数 |
---
### 编辑Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-edit-[bugID].json` |
| 描述 | 编辑Bug信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 查看Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-view-[bugID]-[form].json` |
| 描述 | 查看Bug详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| form | string | 否 | 表单类型 |
---
### 分配Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-assignTo-[bugID].json` |
| 描述 | 分配Bug给处理人员 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 确认Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-confirmBug-[bugID].json` |
| 描述 | 确认Bug有效性 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 解决Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-resolve-[bugID].json` |
| 描述 | 标记Bug已解决 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 激活Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-activate-[bugID].json` |
| 描述 | 激活Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 关闭Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-close-[bugID].json` |
| 描述 | 关闭Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 删除Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-delete-[bugID]-[confirm].json` |
| 描述 | 删除Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| confirm | string | 否 | 确认删除 |
---
### 关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-linkStory-[bugID]-[storyID].json` |
| 描述 | 关联需求到Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| storyID | int | 否 | 需求ID |
---
### 移除关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-unlinkStory-[bugID]-[storyID].json` |
| 描述 | 移除Bug与需求的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| storyID | int | 否 | 需求ID |
---
### 批量移除关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-batchUnlinkStory-[bugID].json` |
| 描述 | 批量移除Bug与需求的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 关联任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-linkTask-[bugID]-[taskID].json` |
| 描述 | 关联任务到Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| taskID | int | 否 | 任务ID |
---
### 移除关联任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-unlinkTask-[bugID]-[taskID].json` |
| 描述 | 移除Bug与任务的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| taskID | int | 否 | 任务ID |
---
### 批量移除关联任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-batchUnlinkTask-[bugID].json` |
| 描述 | 批量移除Bug与任务的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 关联版本
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-linkBuild-[bugID]-[buildID].json` |
| 描述 | 关联版本到Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| buildID | int | 否 | 版本ID |
---
### 移除关联版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-unlinkBuild-[bugID]-[buildID].json` |
| 描述 | 移除Bug与版本的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| buildID | int | 否 | 版本ID |
---
### 批量移除关联版本
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-batchUnlinkBuild-[bugID].json` |
| 描述 | 批量移除Bug与版本的关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 更新Bug状态
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-changeStatus-[bugID]-[status].json` |
| 描述 | 更新Bug状态 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
| status | string | 否 | 状态 |
---
### Bug统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-statistic-[productID]-[branch].json` |
| 描述 | 获取Bug统计数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
---
### Bug趋势分析
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-trend-[productID]-[type].json` |
| 描述 | 获取Bug趋势分析数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| type | string | 否 | 趋势类型 |
---
### Bug报告导出
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-export.json` |
| 描述 | 导出Bug报告 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### Bug优先级分析
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-priority-[productID].json` |
| 描述 | 获取Bug优先级分布 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### Bug严重性分析
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-severity-[productID].json` |
| 描述 | 获取Bug严重性分布 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### Bug处理时间分析
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-resolutionTime-[productID].json` |
| 描述 | 获取Bug处理时间分析 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### Bug重复检测
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-duplicate-[bugID].json` |
| 描述 | 检测重复Bug |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### Bug附件管理
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-attachment-[bugID].json` |
| 描述 | 获取Bug附件列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### Bug评论管理
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/bug-comment-[bugID].json` |
| 描述 | 获取Bug评论列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
---
### 添加Bug评论
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/bug-addComment-[bugID].json` |
| 描述 | 添加Bug评论 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| bugID | int | 否 | BugID |
FILE:docs/backup.md
# 备份 (Backup) API 文档
## 概述
数据备份管理相关的API接口。
## API 列表
### 备份首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/backup.json` |
| 描述 | 备份首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览备份文件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/backup-browse-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览备份文件列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建备份
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/backup-create.json` |
| 描述 | 创建数据备份 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 恢复数据
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/backup-restore-[fileID].json` |
| 描述 | 从备份恢复数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| fileID | int | 否 | 备份文件ID |
---
### 下载备份
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/backup-download-[fileID].json` |
| 描述 | 下载备份文件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| fileID | int | 否 | 备份文件ID |
---
### 删除备份
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/backup-delete-[fileID]-[confirm].json` |
| 描述 | 删除备份文件 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| fileID | int | 否 | 备份文件ID |
| confirm | string | 否 | 确认删除 |
---
### 备份设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/backup-setting.json` |
| 描述 | 备份设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/git.md
# GIT API 文档
## 概述
GIT代码管理相关的API接口。
## API 列表
### GIT首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/git.json` |
| 描述 | GIT首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览GIT仓库
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/git-browse-[repoID].json` |
| 描述 | 浏览GIT仓库 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 查看提交历史
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/git-log-[repoID]-[branch].json` |
| 描述 | 查看GIT提交历史 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| branch | string | 否 | 分支名称 |
---
### 查看分支
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/git-branches-[repoID].json` |
| 描述 | 查看仓库分支 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 查看标签
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/git-tags-[repoID].json` |
| 描述 | 查看仓库标签 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
---
### 查看提交详情
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/git-commit-[repoID]-[commitID].json` |
| 描述 | 查看提交详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| commitID | string | 否 | 提交ID |
---
### 查看文件差异
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/git-diff-[repoID]-[from]-[to].json` |
| 描述 | 查看文件差异 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| repoID | int | 否 | 仓库ID |
| from | string | 否 | 起始版本 |
| to | string | 否 | 结束版本 |
FILE:docs/task.md
# 任务 (Task) API 文档
## 概述
任务管理相关的API接口。
## API 列表
### 创建任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-create-[projectID]-[storyID]-[moduleID]-[taskID]-[todoID].json` |
| 描述 | 创建新任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
| storyID | int | 否 | 需求ID |
| moduleID | int | 否 | 模块ID |
| taskID | int | 否 | 父任务ID |
| todoID | int | 否 | 待办ID |
---
### 编辑任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-edit-[taskID].json` |
| 描述 | 编辑任务信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 查看任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/task-view-[taskID].json` |
| 描述 | 查看任务详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 开始任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-start-[taskID].json` |
| 描述 | 开始执行任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 完成任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-finish-[taskID].json` |
| 描述 | 完成任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 关闭任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-close-[taskID].json` |
| 描述 | 关闭任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 取消任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-cancel-[taskID].json` |
| 描述 | 取消任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 激活任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-activate-[taskID].json` |
| 描述 | 激活任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 分配任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-assignTo-[requestID].json` |
| 描述 | 分配任务给指定用户 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| requestID | string | 否 | 请求ID(格式:taskID-userID) |
---
### 记录工时
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-recordEstimate-[taskID].json` |
| 描述 | 记录任务工时估算 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 记录实际工时
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-recordConsumed-[taskID].json` |
| 描述 | 记录任务实际工时 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 记录剩余工时
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-recordLeft-[taskID].json` |
| 描述 | 记录任务剩余工时 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 暂停任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-pause-[taskID].json` |
| 描述 | 暂停任务执行 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 恢复任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-resume-[taskID].json` |
| 描述 | 恢复任务执行 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 移动任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-move-[taskID]-[projectID].json` |
| 描述 | 移动任务到其他项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
| projectID | int | 否 | 目标项目ID |
---
### 复制任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-copy-[taskID]-[projectID].json` |
| 描述 | 复制任务到其他项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 源任务ID |
| projectID | int | 否 | 目标项目ID |
---
### 删除任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/task-delete-[taskID]-[confirm].json` |
| 描述 | 删除任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
| confirm | string | 否 | 确认删除 |
---
### 创建子任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-createSubtask-[taskID].json` |
| 描述 | 创建子任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 父任务ID |
---
### 查看子任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/task-viewSubtasks-[taskID].json` |
| 描述 | 查看任务的所有子任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 父任务ID |
---
### 任务关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-linkStory-[taskID]-[storyID].json` |
| 描述 | 关联需求到任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
| storyID | int | 否 | 需求ID |
---
### 任务关联Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-linkBug-[taskID]-[bugID].json` |
| 描述 | 关联Bug到任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
| bugID | int | 否 | BugID |
---
### 任务关联文档
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-linkDoc-[taskID]-[docID].json` |
| 描述 | 关联文档到任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
| docID | int | 否 | 文档ID |
---
### 任务历史记录
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/task-history-[taskID].json` |
| 描述 | 获取任务历史记录 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 任务日志
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/task-log-[taskID].json` |
| 描述 | 获取任务执行日志 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 任务进度更新
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-progress-[taskID].json` |
| 描述 | 更新任务进度 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 任务优先级
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-priority-[taskID].json` |
| 描述 | 更新任务优先级 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 任务标签
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-tags-[taskID].json` |
| 描述 | 管理任务标签 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 任务分配给团队
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-assignTeam-[taskID].json` |
| 描述 | 分配任务给团队 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
---
### 任务移动到迭代
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/task-moveToSprint-[taskID]-[sprintID].json` |
| 描述 | 移动任务到迭代 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| taskID | int | 否 | 任务ID |
| sprintID | int | 否 | 迭代ID |
---
### 任务泳道视图
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/task-swimlane-[projectID].json` |
| 描述 | 获取任务泳道视图数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| projectID | int | 否 | 项目ID |
FILE:docs/user.md
# 用户 (User) API 文档
## 概述
用户管理相关的API接口。
## API 列表
### 查看用户
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-view-[account].json` |
| 描述 | 查看用户详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| account | string | 否 | 用户账号 |
---
### 用户待办
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-todo-[account]-[type]-[status]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取用户待办列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| account | string | 否 | 用户账号 |
| type | string | 否 | 类型 |
| status | string | 否 | 状态 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 用户需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-story-[account]-[type]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取用户需求列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| account | string | 否 | 用户账号 |
| type | string | 否 | 类型 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 用户任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-task-[account]-[type]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取用户任务列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| account | string | 否 | 用户账号 |
| type | string | 否 | 类型 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 用户Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-bug-[account]-[type]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 获取用户Bug列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| account | string | 否 | 用户账号 |
| type | string | 否 | 类型 |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 创建用户
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-create-[deptID].json` |
| 描述 | 创建新用户 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| deptID | int | 否 | 部门ID |
---
### 编辑用户
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-edit-[userID].json` |
| 描述 | 编辑用户信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| userID | int | 否 | 用户ID |
---
### 删除用户
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-delete-[userID]-[confirm].json` |
| 描述 | 删除用户 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| userID | int | 否 | 用户ID |
| confirm | string | 否 | 确认 |
---
### 用户登录
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-login-[referer]-[from].json` |
| 描述 | 用户登录接口 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| referer | string | 否 | 来源 |
| from | string | 否 | 来源 |
---
### 用户登出
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-logout.json` |
| 描述 | 用户登出 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 重置密码
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-reset.json` |
| 描述 | 重置用户密码 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 管理账户
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-manage.json` |
| 描述 | 管理用户账户 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关联公司
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-link2Company.json` |
| 描述 | 关联用户到公司 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关联部门
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-link2Dept.json` |
| 描述 | 关联用户到部门 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关联角色
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-link2Group.json` |
| 描述 | 关联用户到用户组 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关联项目
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-link2Project.json` |
| 描述 | 关联用户到项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关联产品
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-link2Product.json` |
| 描述 | 关联用户到产品 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关联测试项目
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-linkTestProject.json` |
| 描述 | 关联用户到测试项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 关联测试产品
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-linkTestProduct.json` |
| 描述 | 关联用户到测试产品 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 保存用户信息
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-save.json` |
| 描述 | 保存用户信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 验证邮箱
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-validateEmail.json` |
| 描述 | 验证用户邮箱 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 验证手机号
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-validateMobile.json` |
| 描述 | 验证用户手机号 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 解除关联
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-unlink.json` |
| 描述 | 解除用户关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 保存权限
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-savePrivilege.json` |
| 描述 | 保存用户权限 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取权限
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-getPrivilege.json` |
| 描述 | 获取用户权限 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取视图
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-getView.json` |
| 描述 | 获取用户视图配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 保存视图
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-saveView.json` |
| 描述 | 保存用户视图配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 保存偏好设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-saveConfig.json` |
| 描述 | 保存用户偏好设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取偏好设置
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-getConfig.json` |
| 描述 | 获取用户偏好设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 保存API密钥
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-saveAPIKey.json` |
| 描述 | 保存用户API密钥 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取API密钥
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-getAPIKey.json` |
| 描述 | 获取用户API密钥 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 保存API配置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/user-saveAPIConfig.json` |
| 描述 | 保存用户API配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取API配置
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/user-getAPIConfig.json` |
| 描述 | 获取用户API配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/story.md
# 需求 (Story) API 文档
## 概述
需求管理相关的API接口。
## API 列表
### 创建需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-create-[productID]-[branch]-[moduleID]-[storyID]-[projectID]-[bugID]-[planID]-[todoID]-[extra]-[type].json` |
| 描述 | 创建新的需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| branch | int | 否 | 分支ID |
| moduleID | int | 否 | 模块ID |
| storyID | int | 否 | 父需求ID |
| projectID | int | 否 | 项目ID |
| bugID | int | 否 | BugID |
| planID | int | 否 | 计划ID |
| todoID | int | 否 | 待办ID |
| extra | - | 否 | 额外参数 |
| type | string | 否 | 需求类型 |
---
### 编辑需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-edit-[storyID].json` |
| 描述 | 编辑需求信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 查看需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-view-[storyID]-[version].json` |
| 描述 | 查看需求详情 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
| version | string | 否 | 版本号 |
---
### 变更需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-change-[storyID].json` |
| 描述 | 变更需求信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 评审需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-review-[storyID].json` |
| 描述 | 评审需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 关闭需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-close-[storyID].json` |
| 描述 | 关闭需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 激活需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-activate-[storyID].json` |
| 描述 | 激活需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 需求关联任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-tasks-[storyID]-[projectID].json` |
| 描述 | 获取需求关联的任务列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
| projectID | int | 否 | 项目ID |
---
### 需求关联Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-bugs-[storyID].json` |
| 描述 | 获取需求关联的Bug列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 需求关联测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-cases-[storyID].json` |
| 描述 | 获取需求关联的测试用例列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 删除需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-delete-[storyID]-[confirm].json` |
| 描述 | 删除需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
| confirm | string | 否 | 确认删除 |
---
### 需求变更记录
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-history-[storyID].json` |
| 描述 | 获取需求变更历史 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 需求评论
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-comment-[storyID].json` |
| 描述 | 管理需求评论 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-linkStory-[storyID]-[targetStoryID].json` |
| 描述 | 关联目标需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 源需求ID |
| targetStoryID | int | 否 | 目标需求ID |
---
### 移除关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-unlinkStory-[storyID]-[targetStoryID].json` |
| 描述 | 移除需求关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 源需求ID |
| targetStoryID | int | 否 | 目标需求ID |
---
### 批量移除关联需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-batchUnlinkStory-[storyID].json` |
| 描述 | 批量移除需求关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 源需求ID |
---
### 需求关联发布
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-linkRelease-[storyID]-[releaseID].json` |
| 描述 | 关联发布 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
| releaseID | int | 否 | 发布ID |
---
### 移除关联发布
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-unlinkRelease-[storyID]-[releaseID].json` |
| 描述 | 移除发布关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
| releaseID | int | 否 | 发布ID |
---
### 需求优先级
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-priority-[storyID].json` |
| 描述 | 更新需求优先级 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 需求估算
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-estimate-[storyID].json` |
| 描述 | 更新需求估算 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 需求状态流程
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-flow-[storyID].json` |
| 描述 | 更新需求状态流程 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 需求创建子需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-createChild-[storyID].json` |
| 描述 | 创建子需求 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 父需求ID |
---
### 查看子需求
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-viewChildren-[storyID].json` |
| 描述 | 查看子需求列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 父需求ID |
---
### 需求统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-statistic-[productID]-[type].json` |
| 描述 | 获取需求统计数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| type | string | 否 | 统计类型 |
---
### 需求趋势分析
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-trend-[productID].json` |
| 描述 | 获取需求趋势分析 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 需求导出
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-export-[productID]-[type].json` |
| 描述 | 导需求数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| type | string | 否 | 导出类型 |
---
### 需求附件
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-attachment-[storyID].json` |
| 描述 | 获取需求附件列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
---
### 关联项目
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-linkProject-[storyID]-[projectID].json` |
| 描述 | 关联项目 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
| projectID | int | 否 | 项目ID |
---
### 移除关联项目
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/story-unlinkProject-[storyID]-[projectID].json` |
| 描述 | 移除项目关联 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
| projectID | int | 否 | 项目ID |
---
### 需求标签
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/story-tags-[storyID].json` |
| 描述 | 管理需求标签 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| storyID | int | 否 | 需求ID |
FILE:docs/misc.md
# 杂项 (Misc) API 文档
## 概述
杂项功能相关的API接口。
## API 列表
### 杂项首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/misc.json` |
| 描述 | 杂项首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 验证码
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/misc-captcha.json` |
| 描述 | 生成验证码 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 国际化
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/misc-i18n-[lang].json` |
| 描述 | 国际化语言包 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| lang | string | 否 | 语言代码 |
---
### 附件上传
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/misc-upload.json` |
| 描述 | 通用附件上传 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/tree.md
# 模块关系 (Tree) API 文档
## 概述
模块关系管理相关的API接口。
## API 列表
### 模块关系首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tree.json` |
| 描述 | 模块关系首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览模块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tree-browse-[rootModuleID]-[productID].json` |
| 描述 | 浏览模块结构 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| rootModuleID | int | 否 | 根模块ID |
| productID | int | 否 | 产品ID |
---
### 创建模块
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/tree-create-[parentModuleID]-[productID].json` |
| 描述 | 创建模块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| parentModuleID | int | 否 | 父模块ID |
| productID | int | 否 | 产品ID |
---
### 编辑模块
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/tree-edit-[moduleID].json` |
| 描述 | 编辑模块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| moduleID | int | 否 | 模块ID |
---
### 删除模块
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/tree-delete-[moduleID]-[confirm].json` |
| 描述 | 删除模块 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| moduleID | int | 否 | 模块ID |
| confirm | string | 否 | 确认删除 |
---
### 排序模块
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/tree-updateOrder.json` |
| 描述 | 更新模块排序 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/branch.md
# 平台/分支 (Branch) API 文档
## 概述
产品平台/分支管理相关的API接口。
## API 列表
### 管理分支
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/branch-manage-[productID].json` |
| 描述 | 管理产品的分支 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
---
### 排序分支
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/branch-sort.json` |
| 描述 | 对分支进行排序 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取下拉菜单
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/branch-ajaxGetDropMenu-[productID]-[module]-[method]-[extra].json` |
| 描述 | AJAX获取下拉菜单 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| module | string | 否 | 模块 |
| method | string | 否 | 方法 |
| extra | string | 否 | 额外参数 |
---
### 删除分支
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/branch-delete-[branchID]-[confirm].json` |
| 描述 | 删除分支 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| branchID | int | 否 | 分支ID |
| confirm | string | 否 | 确认 |
---
### 获取分支列表
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/branch-ajaxGetBranches-[productID]-[oldBranch].json` |
| 描述 | AJAX获取分支列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| productID | int | 否 | 产品ID |
| oldBranch | int | 否 | 旧分支ID |
FILE:docs/message.md
# 消息 (Message) API 文档
## 概述
消息管理相关的API接口。
## API 列表
### 消息首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/message.json` |
| 描述 | 消息首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 获取未读消息
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/message-unread.json` |
| 描述 | 获取未读消息数量 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览消息
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/message-browse-[type]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览消息列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| type | string | 否 | 消息类型 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 标记已读
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/message-markRead-[messageID].json` |
| 描述 | 标记消息为已读 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| messageID | int | 否 | 消息ID |
---
### 删除消息
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/message-delete-[messageID].json` |
| 描述 | 删除消息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| messageID | int | 否 | 消息ID |
---
### 消息设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/message-setting.json` |
| 描述 | 消息接收设置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 消息中心
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/message-center.json` |
| 描述 | 消息中心 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/upgrade.md
# 更新 (Upgrade) API 文档
## 概述
系统升级相关的API接口。
## API 列表
### 升级首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/upgrade.json` |
| 描述 | 系统升级首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 检查更新
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/upgrade-check.json` |
| 描述 | 检查系统更新 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 执行升级
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/upgrade-execute.json` |
| 描述 | 执行系统升级 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/action.md
# 系统日志 (Action) API 文档
## 概述
系统日志管理相关的API接口。
## API 列表
### 系统日志首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/action.json` |
| 描述 | 系统日志首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 浏览系统日志
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/action-browse-[objectType]-[objectID]-[orderBy]-[recTotal]-[recPerPage]-[pageID].json` |
| 描述 | 浏览系统日志列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| objectType | string | 否 | 对象类型 |
| objectID | int | 否 | 对象ID |
| orderBy | string | 否 | 排序方式 |
| recTotal | int | 否 | 总记录数 |
| recPerPage | int | 否 | 每页记录数 |
| pageID | int | 否 | 页码 |
---
### 查看操作详情
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/action-view-[actionID].json` |
| 描述 | 查看具体操作的详细信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| actionID | int | 否 | 操作ID |
---
### 删除日志
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/action-delete-[confirm].json` |
| 描述 | 清理系统日志 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| confirm | string | 否 | 确认删除 |
---
### 日志统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/action-statistic-[period].json` |
| 描述 | 获取日志统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| period | string | 否 | 统计周期 |
FILE:docs/job.md
# Job API 文档
## 概述
任务调度相关的API接口。
## API 列表
### Job首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/job.json` |
| 描述 | 任务调度首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/cron.md
# 定时任务 (Cron) API 文档
## 概述
定时任务管理相关的API接口。
## API 列表
### 定时任务首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron.json` |
| 描述 | 定时任务首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 开启定时任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-turnon.json` |
| 描述 | 开启定时任务功能 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 打开定时任务进程
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-openProcess.json` |
| 描述 | 打开定时任务执行进程 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 创建定时任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/cron-create.json` |
| 描述 | 创建新的定时任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 编辑定时任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/cron-edit-[cronID].json` |
| 描述 | 编辑定时任务配置 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
---
### 切换定时任务执行状态
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-toggle-[cronID]-[status].json` |
| 描述 | 启动或停止定时任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
| status | int | 否 | 状态(1:启动,0:停止) |
---
### 删除定时任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-delete-[cronID]-[confirm].json` |
| 描述 | 删除定时任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
| confirm | string | 否 | 确认删除 |
---
### AJAX执行定时任务
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-ajaxExec-[restart].json` |
| 描述 | AJAX方式执行定时任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| restart | bool | 否 | 是否重启任务 |
---
### 定时任务日志
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-log-[cronID].json` |
| 描述 | 查看定时任务执行日志 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
---
### 定时任务历史记录
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-history-[cronID].json` |
| 描述 | 查看定时任务历史执行记录 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
---
### 定时任务统计
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-statistic.json` |
| 描述 | 查看定时任务统计信息 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 定时任务模板
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-template.json` |
| 描述 | 获取定时任务模板列表 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 复制定时任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/cron-copy-[cronID].json` |
| 描述 | 复制定时任务 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 源定时任务ID |
---
### 验证定时任务配置
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/cron-validate-[cronID].json` |
| 描述 | 验证定时任务配置是否正确 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
---
### 设置定时任务通知
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/cron-notify-[cronID].json` |
| 描述 | 设置定时任务执行通知 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
---
### 定时任务依赖
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/cron-dependency-[cronID].json` |
| 描述 | 设置定时任务依赖关系 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
---
### 定时任务超时设置
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/cron-timeout-[cronID].json` |
| 描述 | 设置定时任务超时时间 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
---
### 定时任务重试策略
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/cron-retry-[cronID].json` |
| 描述 | 设置定时任务重试策略 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| cronID | int | 否 | 定时任务ID |
FILE:docs/ci.md
# CI API 文档
## 概述
持续集成(CI)相关的API接口。
## API 列表
### CI首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/ci.json` |
| 描述 | 持续集成首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/owt.md
# OWT API 文档
## 概述
OWT相关的API接口。
## API 列表
### OWT首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/owt.json` |
| 描述 | OWT首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:docs/convert.md
# 导入 (Convert) API 文档
## 概述
数据导入管理相关的API接口。
## API 列表
### 导入首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/convert.json` |
| 描述 | 数据导入首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导入用户
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/convert-user.json` |
| 描述 | 导入用户数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导入需求
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/convert-story.json` |
| 描述 | 导入需求数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导入任务
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/convert-task.json` |
| 描述 | 导入任务数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导入Bug
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/convert-bug.json` |
| 描述 | 导入Bug数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导入测试用例
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/convert-testcase.json` |
| 描述 | 导入测试用例数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 导入文档
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/convert-doc.json` |
| 描述 | 导入文档数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
---
### 数据迁移
| 属性 | 值 |
|------|-----|
| 方法 | GET/POST |
| 路径 | `/convert-migrate-[system].json` |
| 描述 | 从其他系统迁移数据 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| system | string | 否 | 源系统名称 |
FILE:docs/client.md
# Client API 文档
## 概述
客户端相关的API接口。
## API 列表
### Client首页
| 属性 | 值 |
|------|-----|
| 方法 | GET |
| 路径 | `/client.json` |
| 描述 | 客户端首页 |
**参数列表**
| 参数名 | 类型 | 必填 | 描述 |
|--------|------|------|------|
| 无参数 | - | - | - |
FILE:zentao_roadmap.md
# 禅道项目生命周期
┌─────────────────────────────────────────────────────────────────────────────┐
│ 禅道项目生命周期 │
└─────────────────────────────────────────────────────────────────────────────┘
产品阶段 立项阶段 开发阶段 测试阶段 发布阶段
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐
│ 产品 │ → │ 项目 │ → │ 研发 │ → │ 测试 │ → │ 发布 │
└───────┘ └───────┘ └───────┘ └───────┘ └───────┘
┌─────────────────────────────────────────────────────────────────────────────┐
│ 完整项目生命周期 │
└─────────────────────────────────────────────────────────────────────────────┘
产品经理 项目经理 研发 测试
│ │ │ │
│ 1.创建产品 │ │ │
│ create_product │ │ │
│─────────────────► │ │ │
│ │ │ │
│ 2.创建需求 │ │ │
│ create_story │ │ │
│─────────────────► │ │ │
│ │ │ │
│ 3.创建计划 │ │ │
│ create_plan │ │ │
│─────────────────► │ │ │
│ │ │ │
│ │ 4.创建项目 │ │
│ │ (Web界面) │ │
│ │────────────────► │ │
│ │ │ │
│ │ 5.导入需求 │ │
│ │ create_story │ │
│ │────────────────► │ │
│ │ │ │
│ │ 6.创建任务 │ │
│ │ create_subtasks │ │
│ │────────────────► │ │
│ │ │ │
│ │ │ 7.开始任务 │
│ │ │ start_task │
│ │ │────────────────► │
│ │ │ │
│ │ │ 8.记录工时 │
│ │ │ record_estimate │
│ │ │────────────────► │
│ │ │ │
│ │ │ 9.完成任务 │
│ │ │ finish_task │
│ │ │────────────────► │
│ │ │ │
│ │ │ │ 10.创建用例
│ │ │ │ create_testcase
│ │ │ │────────────►
│ │ │ │
│ │ │ │ 11.创建测试任务
│ │ │ │ create_testtask
│ │ │ │────────────►
│ │ │ │
│ │ │ │ 12.提交Bug
│ │ │ │ create_bug
│ │ │ │────────────►
│ │ │ │
│ │ │ 13.解决Bug │
│ │ │ resolve_bug │
│ │ │◄────────────────────│
│ │ │ │
│ │ │ │ 14.关闭Bug
│ │ │ │ close_bug
│ │ │ │────────────►
│ │ │ │
│ 15.关闭需求 │ │ │
│ close_story │ │ │
│─────────────────► │ │ │
│ │ │ │
│ │ 16.关闭项目 │ │
│ │ (Web界面) │ │
│ │────────────────► │ │
│ │ │ │
▼ ▼ ▼ ▼
## 产品
┌──────────────────────────────────────────────────────────────┐
│ 1. 创建产品 │
│ API: create_product(name, code, po, qd, rd) │
│ 产出: 产品ID │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 2. 创建需求 │
│ API: create_story(product_id, title, spec, pri, ...) │
│ 产出: 需求ID列表 │
│ │
│ 需求字段: │
│ - title: 需求标题 │
│ - spec: 需求描述 │
│ - pri: 优先级 (0-4) │
│ - source: 需求来源 │
│ - estimate: 预计工时 │
│ - reviewer: 评审人 │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 3. 需求评审 │
│ 状态: draft → active │
│ API: edit_story(story_id, status="active") │
│ │
│ 或直接创建时指定: │
│ API: create_story(..., reviewer="xxx") │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 4. 创建发布计划 │
│ API: create_plan(product_id, title, begin, end) │
│ 产出: 计划ID │
│ │
│ 关联需求到计划: │
│ API: edit_story(story_id, plan=plan_id) │
└──────────────────────────────────────────────────────────────┘
## 项目
┌──────────────────────────────────────────────────────────────┐
│ 1. 创建项目 │
│ 注: 禅道老API不直接提供创建项目接口 │
│ 通常通过Web界面创建 │
│ API: get_project_list_old() 可查看已有项目 │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 2. 关联产品 │
│ 项目需要关联产品,才能看到产品的需求 │
│ (Web界面操作) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 3. 导入需求到项目 │
│ 将产品需求关联到项目执行 │
│ API: create_story(product_id, execution_id, title, ...) │
│ 参数: execution_id = 项目/执行ID │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 4. 创建任务分解 │
│ API: create_subtasks(execution_id, parent_id, tasks) │
│ │
│ tasks 参数结构: │
│ [ │
│ {name: "前端开发", estimate: "8", assignedTo: "dev1"}, │
│ {name: "后端开发", estimate: "16", assignedTo: "dev2"},│
│ {name: "接口联调", estimate: "4", assignedTo: "dev1"} │
│ ] │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 5. 指派任务 │
│ API: assign_task(task_id, assigned_to) │
│ │
│ 查看项目任务: │
│ API: get_project_tasks_old(project_id, status) │
└──────────────────────────────────────────────────────────────┘
## 开发
┌──────────────────────────────────────────────────────────────┐
│ 状态流转图: │
│ │
│ wait ──开始──→ doing ──完成──→ done ──关闭──→ closed │
│ │ │ ↑ │
│ │ │ │ │
│ │ ↓ │ │
│ │ pause ─┘ │
│ │ ↑ │
│ │ └── 继续任务 │
│ │ │
│ └──取消──→ cancel │
│ │
│ done/closed ──激活──→ doing │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ 1. 查看我的任务 │
│ API: get_my_tasks("assignedTo") │
│ │
│ 返回字段: │
│ - id: 任务ID │
│ - name: 任务名称 │
│ - status: 状态 │
│ - estimate: 预计工时 │
│ - consumed: 已消耗 │
│ - left: 剩余 │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 2. 开始任务 │
│ API: start_task(task_id, comment) │
│ 状态: wait → doing │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 3. 记录工时(每日/按进度) │
│ API: record_estimate(task_id, records) │
│ │
│ records 结构: │
│ [{ │
│ date: "2026-03-27", │
│ consumed: "3", # 本次消耗 │
│ left: "5", # 剩余 │
│ work: "完成了登录页面开发" │
│ }] │
│ │
│ 注意: 可一次提交多条工时记录 │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 4. 暂停/继续任务 │
│ 暂停: API: pause_task(task_id) │
│ 状态: doing → pause │
│ │
│ 继续: API: restart_task(task_id) │
│ 状态: pause → doing │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 5. 完成任务 │
│ 建议先记录工时(left=0),再完成任务 │
│ │
│ # 先记录工时 │
│ API: record_estimate(task_id, [{..., left: "0"}]) │
│ │
│ # 再完成 │
│ API: finish_task(task_id, comment) │
│ 状态: doing → done │
└──────────────────────────────────────────────────────────────┘
## 测试
┌──────────────────────────────────────────────────────────────┐
│ Bug 状态流转图: │
│ │
│ active ──解决──→ resolved ──关闭──→ closed │
│ ↑ │ │
│ │ │ │
│ └──激活──────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────┐
│ 1. 创建测试用例 │
│ API: create_testcase(product_id, title, type, ...) │
│ │
│ 参数: │
│ - title: 用例标题 │
│ - type: 用例类型 │
│ - steps: 测试步骤 │
│ - expect: 预期结果 │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 2. 创建测试套件 │
│ API: create_testsuite(product_id, name, desc) │
│ 用例分组管理 │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 3. 创建测试任务 │
│ API: create_testtask(product_id, name, begin, end) │
│ │
│ # 开始测试任务 │
│ API: start_testtask(task_id) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 4. 提交Bug │
│ API: create_bug(product_id, title, severity, ...) │
│ │
│ 参数: │
│ - title: Bug标题 │
│ - severity: �重程度 (1-4, 1最严重) │
│ - pri: 优先级 (0-4) │
│ - type: Bug类型│
│ - steps: 重现步骤 │
│ - assignedTo: 指派给 │
│ - project_id: 关联项目 │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 5. Bug流转 │
│ │
│ # 确认Bug │
│ API: confirm_bug(bug_id) │
│ │
│ # 指派Bug │
│ API: assign_bug(bug_id, assigned_to) │
│ │
│ # 解决Bug (研发) │
│ API: resolve_bug(bug_id, resolution, resolved_build) │
│ resolution: fixed, postponed, willnotfix, duplicate... │
│ │
│ # 关闭Bug (测试验证后) │
│ API: close_bug(bug_id, comment) │
│ │
│ # 激活Bug (问题重现) │
│ API: activate_bug(bug_id, comment) │
└──────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────┐
│ 6. 关闭测试任务 │
│ API: close_testtask(task_id) │
└──────────────────────────────────────────────────────────────┘
FILE:README.md
# ZenTao API Client
禅道(ZenTao)项目管理系统的 Python API 客户端,支持产品、项目、任务、Bug、需求、测试、版本、发布全生命周期管理。
## 目录
- [特性](#特性)
- [支持的禅道版本](#支持的禅道版本)
- [安装](#安装)
- [接入方式](#接入方式)
- [方式一:OpenClaw 接入(推荐)](#方式一openclaw-接入推荐)
- [方式二:直接使用客户端](#方式二直接使用客户端)
- [功能概览](#功能概览)
- [状态流转](#状态流转)
- [注意事项](#注意事项)
- [常见问题](#常见问题)
- [项目结构](#项目结构)
- [许可证](#许可证)
---
## 特性
- 禅道老 API (Legacy API v1.0) 封装
- Session 认证方式
- **137+ 个 API 方法**,覆盖完整开发流程
- 返回格式统一处理(兼容 text/html 返回 JSON 的情况)
- 丰富的类型提示和文档注释
- 支持需求、任务、Bug、项目、测试、版本、发布、计划全流程管理
---
## 支持的禅道版本
本客户端基于禅道 **老 API (Legacy API v1.0)** 开发,兼容范围广泛。
### 兼容版本
| 版本类型 | 兼容版本 | 说明 |
| ---------- | ----------- | --------------------- |
| **开源版** | 12.x - 20.x | 12.x 起全面支持老 API |
| **旗舰版** | 4.x - 7.x | 全系列支持 |
| **企业版** | 13.x 及以上 | 企业版全系列支持 |
| **IPD版** | 1.x - 5.x | IPD 系列全支持 |
> **实测反馈**:禅道 12.3.3 版本测试通过。
### 关于新 API (v2.0)
禅道 **21.7+** 版本引入了全新的 **API v2.0**,采用 RESTful 风格和 Token 认证方式:
- **新 API (v2.0)**:禅道 21.7+ 推荐使用
- **老 API (v1.0)**:本客户端使用,21.7 仍可使用但逐步废弃
---
## 安装
### 环境要求
- Python 3.8+
- requests 库
### 安装依赖
```bash
pip install -r requirements.txt
```
或直接安装:
```bash
pip install requests>=2.28.0
```
---
## 接入方式
提供两种接入方式,推荐使用 **OpenClaw 接入**。
### 方式一:OpenClaw 接入(推荐)
OpenClaw 是一个智能开发助手,可以自动化执行禅道工作流。
#### 1. 配置凭证
在项目根目录创建 `TOOLS.md` 文件:
```markdown
## 禅道 API
- **API 地址:** http://your-zentao-host/
- **用户名:** your-username
- **密码:** your-password
```
#### 2. 使用示例
直接告诉 OpenClaw 你的需求,它会自动调用禅道 API:
```
用户:帮我创建一个用户登录功能的需求,包括前端和后端开发
OpenClaw:
✓ 已创建需求:用户登录功能开发 (ID: 123)
✓ 已创建任务:
- 前端登录页面开发 (ID: 456)
- 后端登录接口开发 (ID: 457)
- 前后端联调 (ID: 458)
```
```
用户:记录一下今天做了什么
OpenClaw:
✓ 已记录工时:
- 前端登录页面开发:3小时(剩余:0小时)
- 任务状态已更新为:done
```
```
用户:有个bug,登录页面输入特殊字符报错
OpenClaw:
✓ 已创建Bug:登录页面输入特殊字符报错 (ID: 789)
- 严重程度:3
- 类型:代码错误
- 指派给:admin
```
#### 3. 支持的工作流
OpenClaw 自动化支持完整的开发工作流:
```
需求管理 → 任务分解 → 任务执行 → 工时记录 → Bug管理 → 版本发布
↓ ↓ ↓ ↓ ↓ ↓
创建需求 创建任务 开始/完成 记录工时 创建/解决 创建发布
评审需求 分配任务 暂停/继续 验证工时 指派Bug 关联需求
变更需求 移动任务 激活任务 关闭Bug 关联Bug
```
#### 4. 优势
- ✅ **自然语言交互**:无需编写代码,直接描述需求
- ✅ **自动化工作流**:自动创建需求、分解任务、记录工时
- ✅ **智能推荐**:根据上下文推荐最佳实践
- ✅ **完整流程追踪**:从需求到发布全程可追溯
#### 5. 常用命令示例
| 用户说 | OpenClaw 执行 |
|--------|--------------|
| "创建需求:xxx" | 创建需求 + 关联项目 |
| "分解任务" | 自动分解需求为多个任务 |
| "开始做xxx" | 查找任务 → 开始任务 |
| "记录今天的工时" | 记录工时 + 更新剩余时间 |
| "完成这个任务" | 记录最终工时 → 完成任务 |
| "有个bug:xxx" | 创建Bug → 关联需求/任务 |
| "bug已修复" | 解决Bug → 关闭Bug |
| "发布版本1.0" | 创建版本 → 关联需求/Bug → 创建发布 |
---
### 方式二:直接使用客户端
如果需要在代码中直接使用 API,可以使用 Python 客户端。
#### 1. 导入客户端
```python
from pathlib import Path
import sys
# 导入禅道客户端
lib_path = Path(__file__).parent / 'lib'
sys.path.insert(0, str(lib_path))
from zentao_client import ZenTaoClient, read_credentials
# 读取凭证
credentials = read_credentials()
# 创建客户端
client = ZenTaoClient(
credentials['endpoint'],
credentials['username'],
credentials['password']
)
# 获取会话(首次登录,后续自动加载持久化的 Session)
sid = client.get_session()
print(f"登录成功,Session ID: {sid}")
```
#### 2. Session 持久化
客户端支持 Session 持久化,无需每次都登录:
```python
client = ZenTaoClient('http://127.0.0.1:8080', 'admin', 'password')
# 首次调用自动登录并保存 Session
sid = client.get_session() # 登录 + 保存
# 新实例自动加载已有 Session
client2 = ZenTaoClient('http://127.0.0.1:8080', 'admin', 'password')
sid2 = client2.get_session() # 直接加载,无需登录
# 强制刷新 Session
sid3 = client.get_session(force_refresh=True) # 重新登录
# 清除保存的 Session
client.clear_session()
```
**存储位置**:项目根目录 `.zentao/sessions/` 目录下
```
项目目录/
├── .zentao/
│ └── sessions/
│ └── {hash}.json # Session 文件
└── ...
```
#### 3. 快速示例
```python
# 创建需求
client.create_story(
product_id="1",
title="用户登录功能",
execution_id="1",
pri="3"
)
# 批量创建任务
client.create_tasks(
project="1",
tasks=[
{"name": "前端开发", "type": "devel", "assignedTo": "admin", "estimate": "8"},
{"name": "后端开发", "type": "devel", "assignedTo": "admin", "estimate": "16"},
{"name": "测试", "type": "test", "assignedTo": "qa", "estimate": "4"}
]
)
# 开始任务
client.start_task(task_id, "开始开发")
# 记录工时
from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d")
client.record_estimate(task_id, [
{"date": today, "consumed": "8", "left": "0", "work": "完成开发"}
])
# 完成任务
client.finish_task(task_id, "开发完成")
# 创建Bug
client.create_bug(
product_id="1",
title="登录页面报错",
severity="3",
pri="3",
assignedTo="admin"
)
# 解决Bug
client.resolve_bug(bug_id, "fixed", "trunk", "已修复")
# 关闭Bug
client.close_bug(bug_id, "验证通过")
```
---
## 功能概览
ZenTaoClient 提供 **137+ 个 API 方法**,覆盖完整的开发工作流:
### 核心模块
| 模块 | 方法数 | 主要功能 |
|-----|-------|---------|
| **任务管理** | 26个 | 创建、编辑、状态流转、工时记录、移动、复制、关联 |
| **Bug管理** | 18个 | 创建、编辑、状态流转、关联需求/任务、统计、评论 |
| **需求管理** | 13个 | 创建、编辑、变更、评审、关联项目/任务/Bug/用例 |
| **项目管理** | 13个 | 创建、编辑、成员管理、需求关联、团队、动态查询 |
| **测试管理** | 23个 | 测试用例、测试套件、测试任务、测试报告的CRUD操作 |
| **发布管理** | 9个 | 创建、编辑、关联需求/Bug |
| **版本管理** | 8个 | 创建、编辑、关联需求/Bug |
| **计划管理** | 7个 | 创建、编辑、关联需求 |
| **产品管理** | 7个 | 创建、编辑、查询 |
### 完整生命周期管理
✅ **需求管理**
- 创建、编辑、变更、评审需求
- 需求关联项目、任务、Bug、测试用例
- 需求状态查询和统计
✅ **任务管理**
- 创建任务、批量创建、创建子任务
- 任务状态流转:wait → doing → done → closed
- 任务移动、复制、指派
- 工时记录和管理
✅ **Bug管理**
- 创建Bug、从测试用例创建Bug
- Bug状态流转:active → resolved → closed
- Bug关联需求、任务
- Bug统计和评论
✅ **项目协作**
- 项目创建、编辑、启动、关闭
- 项目成员管理
- 项目需求关联
- 项目团队和动态查询
✅ **测试管理**
- 测试用例创建、编辑、批量创建
- 测试套件管理
- 测试任务创建和状态管理
- 测试报告
✅ **版本发布**
- 版本创建和管理
- 发布创建和管理
- 需求和Bug关联
详细 API 文档请参考:
- **新增接口清单**:`new_apis_added.md`
- **缺失接口清单**:`missing_apis.md`
---
## 状态流转
### 任务状态流转
```
wait ──开始──→ doing ──完成──→ done ──关闭──→ closed
│ │ ↑
│ │ │
│ ↓ │
│ pause ─┘
│ ↑
│ └── 继续
└──取消──→ cancel
done/closed ──激活──→ doing
```
### Bug 状态流转
```
active ──解决──→ resolved ──关闭──→ closed
↑ │
│ │
└──激活──────────┘
```
### 需求状态流转
```
draft ──评审──→ active ──开发──→ developed ──测试──→ testing ──发布──→ released
│ │ │ │ │
└──关闭────────┴────────────────┴───────────────┴──────────────┘
```
---
## 注意事项
### 1. 工时记录是批量接口
```python
# ✅ 正确:一次提交多条记录
client.record_estimate(task_id, [
{"date": "2026-03-27", "consumed": "2", "left": "6", "work": "开发"},
{"date": "2026-03-28", "consumed": "3", "left": "3", "work": "测试"}
])
# ❌ 错误:多次调用会覆盖之前记录
```
### 2. 完成任务前先记录工时
```python
# ✅ 正确流程
client.record_estimate(task_id, [
{"date": today, "consumed": "8", "left": "0", "work": "完成"}
])
client.finish_task(task_id, "开发完成")
```
### 3. 验证操作结果
很多 API 返回 HTML 而非 JSON,建议用查询接口验证:
```python
success, result = client.start_task(task_id)
ok, task = client.get_task_detail(task_id)
print(task['status']) # 验证是否为 'doing'
```
### 4. 统一的返回格式
所有 API 方法都返回 `(success, result)` 元组:
```python
success, result = client.create_task(...)
if success:
print(f"操作成功: {result}")
else:
print(f"操作失败: {result}")
```
---
## 常见问题
### Q: 认证失败怎么办?
```python
credentials = read_credentials()
print(credentials) # 检查凭证是否正确
sid = client.get_session()
if not sid:
print("认证失败,请检查用户名密码")
```
### Q: API 返回 success=False 但操作成功?
禅道老 API 有时返回 HTML 而非 JSON。解决方案:
1. 使用查询接口验证操作结果
2. 检查 `get_task_detail` 或 `get_bug` 的状态
### Q: 工时记录不生效?
确保参数格式正确:
- `date` 必须是 `YYYY-MM-DD` 格式
- `consumed` 和 `left` 必须是字符串
```python
from datetime import datetime
today = datetime.now().strftime("%Y-%m-%d")
```
### Q: 如何查看所有支持的 API?
```python
# 查看客户端所有方法
import inspect
for name, method in inspect.getmembers(client, predicate=inspect.ismethod):
if not name.startswith('_'):
print(name)
```
或参考以下文档:
- `new_apis_added.md` - 新增接口清单
- `missing_apis.md` - 缺失接口清单
- `SKILL.md` - OpenClaw 使用指南
---
## 项目结构
```
zentao-api/
├── lib/
│ └── zentao_client.py # 核心客户端(137+ API方法)
├── docs/
│ └── *.md # 禅道 API 文档
├── scripts/ # 辅助脚本
├── new_apis_added.md # 新增接口清单
├── missing_apis.md # 缺失接口清单
├── SKILL_UPDATE_SUMMARY.md # SKILL 更新总结
├── SKILL.md # OpenClaw 使用指南
├── README.md # 本文件
├── package.json # npm包配置
└── requirements.txt # Python依赖
```
---
## 参考资料
- [禅道官网](https://www.zentao.net/)
- [禅道 API 文档 v1](https://zentao.net/book/apidoc-v1/apidoc-v1.html)
- [禅道二次开发手册](https://zentao.net/book/api/c634.html)
- [禅道 21.7 新 API v2.0](https://www.zentao.net/download/pms21.7.8-85834.html)
---
## 许可证
MIT License
FILE:scripts/zentao_cli.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
禅道项目管理命令行工具
"""
import sys
import re
from pathlib import Path
from datetime import datetime
# 添加 lib 目录到 Python 路径
script_dir = Path(__file__).parent.absolute()
lib_path = script_dir.parent / 'lib'
sys.path.insert(0, str(lib_path))
# 直接导入
import importlib.util
client_path = lib_path / "zentao_client.py"
spec = importlib.util.spec_from_file_location("zentao_client", client_path)
zentao_client = importlib.util.module_from_spec(spec)
spec.loader.exec_module(zentao_client)
ZenTaoClient = zentao_client.ZenTaoClient
read_credentials = zentao_client.read_credentials
def format_table(headers: list, rows: list, max_width: int = 30) -> str:
"""格式化表格输出"""
if not rows:
return "无数据"
# 计算列宽
col_widths = [len(h) for h in headers]
for row in rows:
for i, cell in enumerate(row):
if i < len(col_widths):
cell_str = str(cell)[:max_width]
col_widths[i] = max(col_widths[i], len(cell_str))
# 构建表格
lines = []
header_line = " | ".join(h.ljust(col_widths[i]) for i, h in enumerate(headers))
lines.append(header_line)
lines.append("-+-".join("-" * w for w in col_widths))
for row in rows:
row_line = " | ".join(str(cell)[:max_width].ljust(col_widths[i]) for i, cell in enumerate(row))
lines.append(row_line)
return "\n".join(lines)
def cmd_products(client: ZenTaoClient) -> None:
"""查询产品列表"""
print("📦 查询禅道产品列表...\n")
# 优先使用 REST API
success, products = client.get_products()
if success and isinstance(products, list):
print(f"✅ 共查询到 {len(products)} 个产品\n")
headers = ['ID', '产品名称', '状态', '负责人']
rows = []
for p in products:
rows.append([
p.get('id', ''),
p.get('name', ''),
p.get('status', ''),
p.get('owner', '')
])
print(format_table(headers, rows))
else:
# 降级到老 API
print("⚠️ REST API 失败,尝试老 API...\n")
product_dict = client.get_product_list_old()
if product_dict:
print(f"✅ 共查询到 {len(product_dict)} 个产品\n")
headers = ['产品名称', 'ID']
rows = [[name, pid] for name, pid in product_dict.items()]
print(format_table(headers, rows))
else:
print("❌ 查询失败")
def cmd_projects(client: ZenTaoClient, status: str = 'doing') -> None:
"""查询项目列表"""
print(f"📋 查询禅道项目列表(状态:{status})...\n")
# 优先使用 REST API
success, projects = client.get_projects(status)
if success and isinstance(projects, list):
print(f"✅ 共查询到 {len(projects)} 个项目\n")
headers = ['ID', '项目名称', '状态', '开始日期', '结束日期']
rows = []
for p in projects:
rows.append([
p.get('id', ''),
p.get('name', ''),
p.get('status', ''),
p.get('begin', ''),
p.get('end', '')
])
print(format_table(headers, rows))
else:
# 降级到老 API
print("⚠️ REST API 失败,尝试老 API...\n")
project_dict = client.get_project_list_old()
if project_dict:
print(f"✅ 共查询到 {len(project_dict)} 个项目\n")
headers = ['项目名称', 'ID']
rows = [[name, pid] for name, pid in project_dict.items()]
print(format_table(headers, rows))
else:
print("❌ 查询失败")
def cmd_executions(client: ZenTaoClient, project_id: str) -> None:
"""查询执行列表"""
print(f"🔄 查询项目 {project_id} 的执行列表...\n")
success, executions = client.get_executions(project_id)
if success and isinstance(executions, list):
print(f"✅ 共查询到 {len(executions)} 个执行\n")
headers = ['ID', '执行名称', '状态', '开始日期', '结束日期']
rows = []
for e in executions:
rows.append([
e.get('id', ''),
e.get('name', ''),
e.get('status', ''),
e.get('begin', ''),
e.get('end', '')
])
print(format_table(headers, rows))
else:
print(f"❌ 查询失败:{executions}")
def cmd_stories(client: ZenTaoClient, project_id: str, limit: int = 50) -> None:
"""查询需求列表"""
print(f"📖 查询项目 {project_id} 的需求列表...\n")
success, stories = client.get_stories(project_id)
if success and isinstance(stories, list):
print(f"✅ 共查询到 {len(stories)} 个需求")
if len(stories) > limit:
print(f"(显示前 {limit} 条)\n")
stories = stories[:limit]
else:
print()
headers = ['ID', '需求标题', '状态', '优先级', '指派给']
rows = []
for s in stories:
rows.append([
s.get('id', ''),
s.get('title', '')[:40],
s.get('status', ''),
s.get('priority', ''),
s.get('assignedTo', '')
])
print(format_table(headers, rows, max_width=40))
else:
print(f"❌ 查询失败:{stories}")
def cmd_tasks(client: ZenTaoClient, execution_id: str, limit: int = 50) -> None:
"""查询任务列表"""
print(f"📝 查询执行 {execution_id} 的任务列表...\n")
success, tasks = client.get_tasks(execution_id)
if success and isinstance(tasks, list):
print(f"✅ 共查询到 {len(tasks)} 个任务")
if len(tasks) > limit:
print(f"(显示前 {limit} 条)\n")
tasks = tasks[:limit]
else:
print()
headers = ['ID', '任务名称', '状态', '优先级', '指派给']
rows = []
for t in tasks:
rows.append([
t.get('id', ''),
t.get('name', '')[:40],
t.get('status', ''),
t.get('priority', ''),
t.get('assignedTo', '')
])
print(format_table(headers, rows, max_width=40))
else:
print(f"❌ 查询失败:{tasks}")
def cmd_bugs(client: ZenTaoClient, product_id: str, limit: int = 50) -> None:
"""查询缺陷列表"""
print(f"🐛 查询产品 {product_id} 的缺陷列表...\n")
# 尝试 REST API
success, bugs = client.get_bugs(product_id)
if success and isinstance(bugs, list):
print(f"✅ 共查询到 {len(bugs)} 个缺陷")
if len(bugs) > limit:
print(f"(显示前 {limit} 条)\n")
bugs = bugs[:limit]
else:
print()
headers = ['ID', '缺陷标题', '严重程度', '状态', '指派给']
rows = []
for b in bugs:
rows.append([
b.get('id', ''),
b.get('title', '')[:40],
b.get('severity', ''),
b.get('status', ''),
b.get('assignedTo', '')
])
print(format_table(headers, rows, max_width=40))
else:
# 降级到老 API
print("⚠️ REST API 失败,尝试老 API...\n")
bugs = client.get_bug_list_old(product_id)
if bugs:
print(f"✅ 共查询到 {len(bugs)} 个缺陷\n")
# 老 API 返回格式可能不同,需要适配
headers = ['ID', '缺陷标题', '状态']
rows = []
for b in bugs[:limit]:
if isinstance(b, dict):
rows.append([
b.get('id', ''),
b.get('title', '')[:40],
b.get('status', '')
])
print(format_table(headers, rows, max_width=40))
else:
print("❌ 查询失败")
def cmd_productplans(client: ZenTaoClient, product_id: str) -> None:
"""查询发布计划列表"""
print(f"📅 查询产品 {product_id} 的发布计划...\n")
productplan_dict = client.get_productplan_list_old(product_id)
if productplan_dict:
print(f"✅ 共查询到 {len(productplan_dict)} 个发布计划\n")
headers = ['计划名称', 'ID']
rows = [[name, pid] for name, pid in productplan_dict.items()]
print(format_table(headers, rows))
else:
print("❌ 查询失败或无数据")
def confirm_action(action_name: str, details: dict) -> bool:
"""确认操作"""
print(f"\n⚠️ 确认执行操作:{action_name}")
print("-" * 50)
for k, v in details.items():
print(f" {k}: {v}")
print("-" * 50)
response = input("确认执行?(y/n): ").strip().lower()
return response in ['y', 'yes', '是']
def cmd_create_story(client: ZenTaoClient, product_id: str, execution_id: str,
title: str, plan_id: str = '0', reviewer: str = '') -> None:
"""新建需求"""
if not confirm_action("新建需求", {
'产品 ID': product_id,
'执行 ID': execution_id,
'需求标题': title,
'计划 ID': plan_id,
'评审人': reviewer or '默认'
}):
print("❌ 操作已取消")
return
success, result = client.create_story(product_id, execution_id, title, plan_id, reviewer)
if success:
msg = result.get('message', '新建成功') if isinstance(result, dict) else '新建成功'
story_id = result.get('id', '未知') if isinstance(result, dict) else '未知'
print(f"✅ {msg},需求 ID: {story_id}")
else:
print(f"❌ 新建失败:{result}")
def cmd_create_task(client: ZenTaoClient, execution_id: str, story_id: str,
name: str, assign_to: str, parent_id: str = None) -> None:
"""新建任务,支持创建子任务"""
info = {
'执行 ID': execution_id,
'需求 ID': story_id,
'任务名称': name,
'指派给': assign_to
}
if parent_id:
info['父任务 ID'] = parent_id
if not confirm_action("新建任务", info):
print("❌ 操作已取消")
return
success, result = client.create_task(execution_id, story_id, name, assign_to, parent_id)
if success:
msg = result.get('message', '新建成功') if isinstance(result, dict) else '新建成功'
task_id = result.get('id', '未知') if isinstance(result, dict) else '未知'
print(f"✅ {msg},任务 ID: {task_id}")
else:
print(f"❌ 新建失败:{result}")
def cmd_batch_create_tasks(client: ZenTaoClient, execution_id: str, parent_id: str,
tasks_str: str) -> None:
"""批量创建子任务
tasks_str 格式: 任务1名称:工时,任务2名称:工时
例如: 8个前端面试:16,4个后端面试:8
"""
# 解析任务列表
tasks = []
for item in tasks_str.split(','):
parts = item.strip().split(':')
if len(parts) >= 1:
task = {'name': parts[0].strip()}
if len(parts) >= 2:
task['estimate'] = parts[1].strip()
tasks.append(task)
if not tasks:
print("❌ 未提供有效的任务信息")
return
if not confirm_action("批量创建子任务", {
'执行 ID': execution_id,
'父任务 ID': parent_id,
'任务数量': len(tasks),
'任务列表': ', '.join([f"{t['name']}({t.get('estimate', 'N/A')}h)" for t in tasks])
}):
print("❌ 操作已取消")
return
success, result = client.batch_create_tasks(execution_id, parent_id, tasks)
if success:
print(f"✅ {result.get('message', '创建成功')}")
else:
print(f"❌ 创建失败:{result}")
def cmd_create_productplan(client: ZenTaoClient, product_id: str, title: str) -> None:
"""新建发布计划"""
if not confirm_action("新建发布计划", {
'产品 ID': product_id,
'计划名称': title
}):
print("❌ 操作已取消")
return
success, result = client.create_productplan(product_id, title)
if success:
msg = result.get('message', '新建成功') if isinstance(result, dict) else '新建成功'
plan_id = result.get('id', '未知') if isinstance(result, dict) else '未知'
print(f"✅ {msg},计划 ID: {plan_id}")
else:
print(f"❌ 新建失败:{result}")
def cmd_review_story(client: ZenTaoClient, story_id: str) -> None:
"""评审需求"""
if not confirm_action("评审需求", {
'需求 ID': story_id,
'评审结果': '通过'
}):
print("❌ 操作已取消")
return
success, result = client.review_story(story_id)
if success:
print(f"✅ 需求 {story_id} 评审通过")
else:
print(f"❌ 评审失败:{result}")
def parse_args(args: list) -> dict:
"""解析命令行参数"""
result = {'command': None, 'params': {}}
if not args:
return result
args_str = ' '.join(args)
# 提取命令 - 按优先级匹配(长的关键字优先)
command_keywords = [
('新建需求', 'create_story'),
('新建任务', 'create_task'),
('批量创建子任务', 'batch_create_tasks'),
('新建计划', 'create_productplan'),
('评审需求', 'review_story'),
('产品列表', 'products'),
('项目列表', 'projects'),
('执行列表', 'executions'),
('需求列表', 'stories'),
('任务列表', 'tasks'),
('缺陷列表', 'bugs'),
('计划列表', 'productplans'),
('产品', 'products'),
('项目', 'projects'),
('执行', 'executions'),
('需求', 'stories'),
('任务', 'tasks'),
('缺陷', 'bugs'),
('计划', 'productplans'),
]
# 匹配命令
for kw, cmd in command_keywords:
if kw in args_str:
result['command'] = cmd
break
# 提取参数
param_patterns = [
(r'产品\s*[=:]\s*(\S+)', 'product_id'),
(r'项目\s*[=:]\s*(\S+)', 'project_id'),
(r'执行\s*[=:]\s*(\S+)', 'execution_id'),
(r'需求\s*[=:]\s*(\S+)', 'story_id'),
(r'标题\s*[=:]\s*(.+?)(?:\s+\w+\s*[=:]|$)', 'title'),
(r'计划\s*[=:]\s*(\S+)', 'plan_id'),
(r'指派\s*[=:]\s*(\S+)', 'assign_to'),
(r'评审人\s*[=:]\s*(\S+)', 'reviewer'),
(r'状态\s*[=:]\s*(\S+)', 'status'),
(r'限制\s*[=:]\s*(\d+)', 'limit'),
]
for pattern, param_name in param_patterns:
match = re.search(pattern, args_str)
if match:
result['params'][param_name] = match.group(1).strip()
return result
def main():
"""主函数"""
print("🔷 禅道项目管理工具")
print("=" * 50)
# 读取凭证
credentials = read_credentials()
if not credentials:
print("\n❌ 错误:未找到禅道 API 凭证")
print("\n请在 TOOLS.md 文件中添加以下配置:")
print("\n```markdown")
print("## 禅道 API")
print("")
print("- **API 地址:** http://<your-zentao-host>/")
print("- **用户名:** <your-username>")
print("- **密码:** <your-password>")
print("```")
return 1
print(f"\n📍 API 地址:{credentials['endpoint']}")
print(f"👤 用户:{credentials['username']}")
# 创建客户端
client = ZenTaoClient(
credentials['endpoint'],
credentials['username'],
credentials['password']
)
# 解析命令
args = sys.argv[1:]
parsed = parse_args(args)
command = parsed.get('command')
params = parsed.get('params', {})
print(f"\n📋 命令:{command or '无'}")
print(f"📝 参数:{params}\n")
# 执行命令
if command == 'products':
cmd_products(client)
elif command == 'projects':
cmd_projects(client, params.get('status', 'doing'))
elif command == 'executions':
if 'project_id' in params:
cmd_executions(client, params['project_id'])
else:
print("❌ 请指定项目 ID,例如:项目=176")
elif command == 'stories':
if 'project_id' in params:
cmd_stories(client, params['project_id'], int(params.get('limit', 50)))
else:
print("❌ 请指定项目 ID,例如:项目=176")
elif command == 'tasks':
if 'execution_id' in params:
cmd_tasks(client, params['execution_id'], int(params.get('limit', 50)))
else:
print("❌ 请指定执行 ID,例如:执行=176")
elif command == 'bugs':
if 'product_id' in params:
cmd_bugs(client, params['product_id'], int(params.get('limit', 50)))
else:
print("❌ 请指定产品 ID,例如:产品=21")
elif command == 'productplans':
if 'product_id' in params:
cmd_productplans(client, params['product_id'])
else:
print("❌ 请指定产品 ID,例如:产品=21")
elif command == 'create_story':
required = ['product_id', 'execution_id', 'title']
if all(p in params for p in required):
cmd_create_story(client, params['product_id'], params['execution_id'],
params['title'], params.get('plan_id', '0'), params.get('reviewer', ''))
else:
print(f"❌ 缺少必需参数:{[p for p in required if p not in params]}")
elif command == 'create_task':
required = ['execution_id', 'story_id', 'name', 'assign_to']
if all(p in params for p in required):
cmd_create_task(client, params['execution_id'], params['story_id'],
params['name'], params['assign_to'])
else:
print(f"❌ 缺少必需参数:{[p for p in required if p not in params]}")
elif command == 'create_productplan':
required = ['product_id', 'title']
if all(p in params for p in required):
cmd_create_productplan(client, params['product_id'], params['title'])
else:
print(f"❌ 缺少必需参数:{[p for p in required if p not in params]}")
elif command == 'review_story':
if 'story_id' in params:
cmd_review_story(client, params['story_id'])
else:
print("❌ 请指定需求 ID,例如:需求=1234")
else:
print("\n📖 可用命令:")
print(" 禅道产品列表 - 查询所有产品")
print(" 禅道项目列表 - 查询进行中的项目")
print(" 禅道执行列表 项目=ID - 查询项目的执行列表")
print(" 禅道需求列表 项目=ID - 查询项目的需求列表")
print(" 禅道任务列表 执行=ID - 查询执行的任务列表")
print(" 禅道缺陷列表 产品=ID - 查询产品的缺陷列表")
print(" 禅道计划列表 产品=ID - 查询产品的发布计划")
print("\n (需要确认的操作)")
print(" 禅道新建需求 产品=ID 执行=ID 标题=xxx 计划=xxx")
print(" 禅道新建任务 执行=ID 需求=ID 标题=xxx 指派=xxx [父任务=ID]")
print(" 禅道批量创建子任务 执行=ID 父任务=ID 任务=任务1:工时,任务2:工时")
print(" 禅道新建计划 产品=ID 标题=xxx")
print(" 禅道评审需求 需求=ID")
return 0
if __name__ == "__main__":
sys.exit(main())
FILE:lib/zentao_client.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
禅道 API 客户端 - 老 API (Legacy API)
"""
import json
import hashlib
import requests
from pathlib import Path
from typing import Dict, List, Optional, Tuple, Any
class ZenTaoClient:
"""禅道 API 客户端(老 API)"""
def __init__(
self,
endpoint: str,
username: str,
password: str,
session_dir: Optional[str] = None,
auto_save: bool = True,
auto_load: bool = True,
):
"""初始化禅道客户端
Args:
endpoint: 禅道地址,如 http://127.0.0.1:8080
username: 用户名
password: 密码
session_dir: Session 存储目录
- 默认 None: 存储在项目根目录的 .zentao/sessions/
- 也可指定其他路径
auto_save: 是否自动保存 Session
auto_load: 是否自动加载已有 Session
"""
self.endpoint = endpoint.rstrip("/")
self.username = username
self.password = password
self.auto_save = auto_save
self.auto_load = auto_load
# 老 API 配置
self.old_api_base = self.endpoint
self.session = None
self.sid = None
# Session 存储目录
if session_dir:
self.session_dir = Path(session_dir)
else:
# 默认存储在项目根目录的 .zentao/sessions/
self.session_dir = Path(__file__).parent.parent / ".zentao" / "sessions"
self.session_dir.mkdir(parents=True, exist_ok=True)
def _get_session_file(self) -> Path:
"""获取 Session 文件路径"""
key = f"{self.endpoint}:{self.username}"
key_hash = hashlib.md5(key.encode()).hexdigest()[:16]
return self.session_dir / f"{key_hash}.json"
def _save_session(self) -> bool:
"""保存 Session 到文件"""
try:
if not self.sid or not self.session:
return False
session_file = self._get_session_file()
data = {
"endpoint": self.endpoint,
"username": self.username,
"sid": self.sid,
"cookies": self.session.cookies.get_dict(),
}
session_file.write_text(json.dumps(data, ensure_ascii=False, indent=2))
return True
except Exception as e:
print(f"Session 保存失败:{e}")
return False
def _load_session(self) -> bool:
"""从文件加载 Session"""
try:
session_file = self._get_session_file()
if not session_file.exists():
return False
data = json.loads(session_file.read_text())
# 验证 endpoint 和 username 匹配
if (
data.get("endpoint") != self.endpoint
or data.get("username") != self.username
):
return False
self.sid = data.get("sid")
self.session = requests.session()
self.session.cookies.update(data.get("cookies", {}))
# 验证 Session 是否有效
if self._validate_session():
return True
else:
self.sid = None
self.session = None
return False
except Exception as e:
print(f"Session 加载失败:{e}")
return False
def _validate_session(self) -> bool:
"""验证 Session 是否有效"""
try:
url = f"{self.old_api_base}/user-refresh.html"
response = self.session.get(url, timeout=10)
# 如果返回登录页面,说明 Session 无效
if "登录" in response.text or "login" in response.text.lower():
return False
return True
except Exception:
return False
def clear_session(self) -> bool:
"""清除保存的 Session"""
try:
session_file = self._get_session_file()
if session_file.exists():
session_file.unlink()
self.sid = None
self.session = None
return True
except Exception as e:
print(f"Session 清除失败:{e}")
return False
# ==================== 认证相关 ====================
def get_session(self, force_refresh: bool = False) -> Optional[str]:
"""获取 Session
Args:
force_refresh: 是否强制刷新 Session
Returns:
sessionID 或 None
"""
# 尝试加载已有 Session
if not force_refresh and self.auto_load and not self.sid:
if self._load_session():
return self.sid
# 获取新 Session
try:
sid_url = f"{self.old_api_base}/api-getSessionID.json"
response = requests.get(sid_url, timeout=30)
if response.status_code == 200:
result = response.json()
if result.get("status") == "success":
self.sid = json.loads(result["data"])["sessionID"]
# 登录
login_url = (
f"{self.old_api_base}/user-login.json?zentaosid={self.sid}"
)
self.session = requests.session()
login_data = {
"account": self.username,
"password": self.password,
"keepLogin[]": "on",
"referer": f"{self.old_api_base}/my/",
}
login_response = self.session.post(
login_url, data=login_data, timeout=30
)
if login_response.status_code == 200:
login_result = login_response.json()
if login_result.get("status") == "success":
# 自动保存 Session
if self.auto_save:
self._save_session()
return self.sid
return None
except Exception as e:
print(f"Session 获取异常:{e}")
return None
def old_request(
self, method: str, path: str, data: Optional[Dict] = None
) -> Tuple[bool, Any]:
"""老 API 请求"""
if not self.sid:
self.get_session()
if not self.sid:
return False, "认证失败"
url = f"{self.old_api_base}/{path.lstrip('/')}"
if "?" in url:
url += f"&zentaosid={self.sid}"
else:
url += f"?zentaosid={self.sid}"
try:
if method.upper() == "GET":
response = self.session.get(url, timeout=30)
elif method.upper() == "POST":
response = self.session.post(url, data=data, timeout=30)
else:
return False, f"不支持的方法:{method}"
if response.status_code == 200:
try:
result = response.json()
except Exception:
try:
result = json.loads(response.text)
except Exception:
result = {"raw": response.text}
if (
result.get("status") == "success"
or result.get("result") == "success"
):
return True, result
else:
return False, result
else:
return False, f"HTTP {response.status_code}"
except Exception as e:
return False, str(e)
# ==================== 老 API 方法 ====================
def get_product_list_old(self) -> Dict[str, str]:
"""获取产品列表(老 API)- 返回 {产品名:ID}"""
success, result = self.old_request("GET", "/product-index-no.json")
if success and "data" in result:
data = json.loads(result["data"])
products = data.get("products", [])
return {p["name"]: str(p["id"]) for p in products}
return {}
def get_project_list_old(self, status: str = "all") -> Dict[str, str]:
"""获取项目列表(老 API)
Returns:
{项目ID: 项目名} 例如 {'1': 'config', '2': 'project2'}
"""
success, result = self.old_request("GET", "/project-browse-all.json")
if success and "data" in result:
data = json.loads(result["data"])
projects = data.get("projects", {})
return projects
return {}
def get_bug_list_old(self, product_id: str, branch: str = "0") -> List[Dict]:
"""获取缺陷列表(老 API)
Args:
product_id: 产品ID
branch: 分支ID,默认 "0"
Returns:
Bug列表
"""
success, result = self.old_request(
"GET", f"/bug-browse-{product_id}-{branch}-all.json"
)
if success and "data" in result:
return json.loads(result["data"])
return []
def get_productplan_list_old(
self, product_id: str, branch: str = "0"
) -> Dict[str, str]:
"""获取发布计划列表(老 API)
Args:
product_id: 产品ID
branch: 分支ID,默认 "0"
Returns:
{计划名:ID}
"""
success, result = self.old_request(
"GET", f"/productplan-browse-{product_id}-{branch}-all.json"
)
if success and "data" in result:
data = json.loads(result["data"])
plans = data.get("productPlansNum", {})
return {v["title"]: v["id"] for k, v in plans.items()}
return {}
def get_project_tasks_old(
self,
project_id: str,
status: str = "all",
module_id: str = "0",
limit: int = 2000,
page: int = 1,
) -> Dict:
"""获取项目任务列表(老 API)
Args:
project_id: 项目ID
status: 任务状态,默认 "all" 获取所有状态
module_id: 模块ID,默认 "0" 获取所有模块
limit: 每页数量,默认 2000
page: 页码,默认 1
Returns:
任务字典 {任务ID: 任务信息}
Note:
已取消的任务可能不显示在列表中,请使用 get_task_detail 查询单个任务状态
"""
success, result = self.old_request(
"GET",
f"/project-task-{project_id}-{status}-id_desc-{module_id}-{limit}-{page}.json",
)
if success and "data" in result:
data = json.loads(result["data"])
tasks = data.get("tasks", {})
return tasks
return {}
def get_task_detail(self, task_id: str) -> Tuple[bool, Dict]:
"""获取单个任务详情(老 API)
Args:
task_id: 任务ID
Returns:
(success, task_info) task_info 包含 id, name, status, parent, assignedTo 等字段
Note:
此方法可获取任务的真实状态(包括已取消状态),适用于验证操作结果
"""
success, result = self.old_request("GET", f"/task-view-{task_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
task = data.get("task", {})
return True, task
return False, {}
# ==================== 写操作方法(需要确认)====================
def create_story(
self,
product_id: str,
execution_id: str,
title: str,
module: str = "0",
plan_id: str = "0",
branch: str = "0",
reviewer: str = "",
) -> Tuple[bool, Dict]:
"""新建需求(老 API)
Args:
product_id: 产品ID
execution_id: 执行/项目ID
title: 需求标题
module: 模块ID,默认 "0"
plan_id: 计划ID,默认 "0"
branch: 分支ID,默认 "0"
reviewer: 评审人,默认为空
Returns:
(success, result)
"""
post_data = {
"product": product_id,
"module": module,
"modules[0]": module,
"plans[0]": plan_id,
"title": title,
"plan": plan_id,
"reviewer[]": reviewer or "xuzn",
}
# URL: /story-create-{product}-{module}-{story}-{plan}-{execution}-{branch}-{module}-{type}.json
return self.old_request(
"POST",
f"/story-create-{product_id}-{module}-0-{plan_id}-{execution_id}-{branch}-{module}-0-story.json",
post_data,
)
def create_subtasks(
self,
execution_id: str,
parent_id: str,
tasks: list,
story_id: str = "0",
module_id: str = "0",
) -> Tuple[bool, Dict]:
"""创建子任务(老 API)
Args:
execution_id: 执行/项目ID
parent_id: 父任务ID
tasks: 任务列表,每个任务包含 name, estimate, assignedTo 等
story_id: 需求ID,默认 "0"
module_id: 模块ID,默认 "0"
Returns:
(success, result)
"""
# 构建 multipart/form-data
boundary = "----WebKitFormBoundary" + "".join(
[chr(ord("A") + i % 26) for i in range(16)]
)
lines = []
for i, task in enumerate(tasks):
name = task.get("name", "")
estimate = task.get("estimate", "")
assigned_to = task.get("assignedTo", "admin")
task_type = task.get("type", "devel")
pri = task.get("pri", "3")
# 第一个任务用实际值
if i == 0:
lines.append(f"--{boundary}")
lines.append('Content-Disposition: form-data; name="module[0]"')
lines.append("")
lines.append("0")
lines.append(f"--{boundary}")
lines.append('Content-Disposition: form-data; name="parent[0]"')
lines.append("")
lines.append(parent_id)
lines.append(f"--{boundary}")
lines.append('Content-Disposition: form-data; name="name[0]"')
lines.append("")
lines.append(name)
lines.append(f"--{boundary}")
lines.append('Content-Disposition: form-data; name="type[0]"')
lines.append("")
lines.append(task_type)
lines.append(f"--{boundary}")
lines.append('Content-Disposition: form-data; name="assignedTo[0]"')
lines.append("")
lines.append(assigned_to)
lines.append(f"--{boundary}")
lines.append('Content-Disposition: form-data; name="estimate[0]"')
lines.append("")
lines.append(str(estimate))
lines.append(f"--{boundary}")
lines.append('Content-Disposition: form-data; name="pri[0]"')
lines.append("")
lines.append(str(pri))
else:
# 后续任务用 ditto
for field in ["module", "parent", "story"]:
lines.append(f"--{boundary}")
lines.append(f'Content-Disposition: form-data; name="{field}[{i}]"')
lines.append("")
lines.append("ditto" if field in ["parent", "story"] else "0")
lines.append(f"--{boundary}")
lines.append(f'Content-Disposition: form-data; name="name[{i}]"')
lines.append("")
lines.append(name)
lines.append(f"--{boundary}")
lines.append(f'Content-Disposition: form-data; name="type[{i}]"')
lines.append("")
lines.append("ditto")
lines.append(f"--{boundary}")
lines.append(f'Content-Disposition: form-data; name="assignedTo[{i}]"')
lines.append("")
lines.append("ditto")
lines.append(f"--{boundary}")
lines.append(f'Content-Disposition: form-data; name="estimate[{i}]"')
lines.append("")
lines.append(str(estimate))
lines.append(f"--{boundary}")
lines.append(f'Content-Disposition: form-data; name="pri[{i}]"')
lines.append("")
lines.append("ditto")
lines.append(f"--{boundary}--")
body = "\r\n".join(lines)
url = f"{self.old_api_base}/task-batchCreate-{execution_id}-{story_id}-{module_id}-{parent_id}.html"
headers = {"Content-Type": f"multipart/form-data; boundary={boundary}"}
response = self.session.post(
url, data=body, headers=headers, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {
"message": "创建子任务成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"创建失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def delete_task(self, task_id: str) -> Tuple[bool, Dict]:
"""删除任务(老 API)
Args:
task_id: 任务ID
Returns:
(success, result)
"""
return self.old_request("POST", f"/task-delete-{task_id}.json")
def cancel_task(self, task_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""取消任务(老 API)
Args:
task_id: 任务ID
comment: 取消原因
Returns:
(success, result) result 包含 status 和 data
Note:
取消后任务状态变为 'cancel',但可能不显示在项目任务列表中。
建议使用 get_task_detail(task_id) 验证取消结果。
Example:
>>> success, result = client.cancel_task("6", "功能暂缓开发")
>>> if success:
>>> # 验证取消结果
>>> ok, task = client.get_task_detail("6")
>>> print(f"任务状态: {task.get('status')}") # 应为 'cancel'
"""
# 先获取任务详情
success, task = self.get_task_detail(task_id)
if not success:
return False, {"message": f"获取任务失败: {task}"}
# 基础字段
data = {
"status": "cancel",
"assignedTo": task.get("assignedTo", ""),
"name": task.get("name", ""),
"type": task.get("type", "devel"),
"pri": str(task.get("pri", "3")),
"estimate": str(task.get("estimate", "0")),
"left": str(task.get("left", "0")),
"consumed": str(task.get("consumed", "0")),
}
# 子任务需要传 parent,一级任务不需要
parent = task.get("parent", "0")
if parent and parent != "0":
data["parent"] = str(parent)
if comment:
data["comment"] = comment
url = f"{self.old_api_base}/task-edit-{task_id}.json?zentaosid={self.sid}"
response = self.session.post(url, data=data, timeout=30)
if response.status_code == 200:
return True, {
"message": "取消任务成功",
"status_code": response.status_code,
}
else:
return False, {"message": f"取消失败: HTTP {response.status_code}"}
def close_task(self, task_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""关闭任务(老 API)
Args:
task_id: 任务ID
comment: 关闭备注(可选)
Returns:
(success, result)
注意:即使返回 success=False(因为返回HTML),任务也可能已关闭。
请使用 get_task_detail(task_id) 验证结果。
Note:
关闭后任务状态变为 'closed'。
可直接关闭 wait 状态的任务,无需先完成。
Example:
>>> success, result = client.close_task("7", "已完成")
>>> # 验证关闭结果
>>> ok, task = client.get_task_detail("7")
>>> print(f"任务状态: {task.get('status')}") # 应为 'closed'
>>> print(f"关闭人: {task.get('closedBy')}")
"""
data = {}
if comment:
data["comment"] = comment
return self.old_request("POST", f"/task-close-{task_id}.json", data=data)
def start_task(self, task_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""开始任务(老 API)
Args:
task_id: 任务ID
comment: 开始备注(可选)
Returns:
(success, result)
注意:即使返回 success=False(因为返回HTML),任务也可能已开始。
请使用 get_task_detail(task_id) 验证结果。
Note:
开始后任务状态变为 'doing'。
实际使用 task-edit 接口修改状态,因为 task-start 接口会直接完成任务。
Example:
>>> success, result = client.start_task("10", "开始开发")
>>> # 验证开始结果
>>> ok, task = client.get_task_detail("10")
>>> print(f"任务状态: {task.get('status')}") # 应为 'doing'
"""
# 先获取任务详情
ok, task = self.get_task_detail(task_id)
if not ok:
return False, {"error": "无法获取任务详情"}
# 用 task-edit 修改状态为 doing
edit_data = {
"id": task_id,
"parent": task.get("parent", "0"),
"project": task.get("project", "0"),
"module": task.get("module", "0"),
"story": task.get("story", "0"),
"name": task.get("name", ""),
"type": task.get("type", "devel"),
"pri": task.get("pri", "3"),
"estimate": task.get("estimate", "0"),
"left": task.get("left", "0"),
"consumed": task.get("consumed", "0"),
"assignedTo": task.get("assignedTo", "admin"),
"status": "doing",
}
if comment:
edit_data["comment"] = comment
return self.old_request("POST", f"/task-edit-{task_id}.json", edit_data)
def record_estimate(
self, task_id: str, records: List[Dict[str, str]]
) -> Tuple[bool, Dict]:
"""记录任务工时(老 API)
Args:
task_id: 任务ID
records: 工时记录列表,每条记录包含:
- date: 日期 (YYYY-MM-DD)
- consumed: 本次消耗工时
- left: 剩余工时
- work: 工作内容
Returns:
(success, result) 注意:返回 HTML 页面,解析会失败。
请使用 get_task_detail(task_id) 验证 consumed 和 left 是否更新。
Note:
- 索引从 1 开始,不是 0
- 必须使用 .html?onlybody=yes 端点
- 可以一次提交多条工时记录
Example:
>>> from datetime import datetime
>>> today = datetime.now().strftime("%Y-%m-%d")
>>> records = [
... {"date": today, "consumed": "2", "left": "6", "work": "开发功能A"},
... {"date": today, "consumed": "1", "left": "5", "work": "测试"}
... ]
>>> success, result = client.record_estimate("13", records)
>>> ok, task = client.get_task_detail("13")
>>> print(f"消耗: {task['consumed']}, 剩余: {task['left']}")
"""
data = {}
for i, record in enumerate(records, start=1):
data[f"id[{i}]"] = record.get("id", "")
data[f"dates[{i}]"] = record.get("date", "")
data[f"consumed[{i}]"] = record.get("consumed", "")
data[f"left[{i}]"] = record.get("left", "")
data[f"work[{i}]"] = record.get("work", "")
url = f"{self.old_api_base}/task-recordEstimate-{task_id}.html?onlybody=yes"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {
"message": "记录工时成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"记录失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def get_estimate(self, estimate_id: str) -> Tuple[bool, Dict]:
"""获取工时记录详情(老 API)
Args:
estimate_id: 工时记录ID
Returns:
(success, estimate_info)
"""
success, result = self.old_request(
"GET", f"/task-editEstimate-{estimate_id}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
estimate = data.get("estimate", {})
return True, estimate
return False, {}
def edit_estimate(
self, estimate_id: str, consumed: str = None, left: str = None, work: str = None
) -> Tuple[bool, Dict]:
"""编辑工时记录(老 API)
Args:
estimate_id: 工时记录ID
consumed: 消耗工时(可选)
left: 剩余工时(可选)
work: 工作内容(可选)
Returns:
(success, result) 注意:返回 HTML 页面。
请使用 get_estimate(estimate_id) 验证修改结果。
Example:
>>> success, result = client.edit_estimate("1", consumed="5", left="3", work="修改记录")
>>> ok, estimate = client.get_estimate("1")
>>> print(f"消耗: {estimate['consumed']}, 剩余: {estimate['left']}")
"""
data = {}
if consumed is not None:
data["consumed"] = consumed
if left is not None:
data["left"] = left
if work is not None:
data["work"] = work
url = f"{self.old_api_base}/task-editEstimate-{estimate_id}.json"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {
"message": "编辑工时成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"编辑失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def delete_estimate(self, estimate_id: str) -> Tuple[bool, Dict]:
"""删除工时记录(老 API)
Args:
estimate_id: 工时记录ID
Returns:
(success, result) 注意:返回 HTML 页面。
请使用 get_estimate(estimate_id) 验证删除结果(应返回失败)。
Note:
删除工时记录后,任务的 consumed 和 left 会自动更新。
Example:
>>> success, result = client.delete_estimate("1")
>>> ok, estimate = client.get_estimate("1")
>>> if not ok:
>>> print("工时记录已删除")
"""
url = f"{self.old_api_base}/task-deleteEstimate-{estimate_id}-yes.json"
response = self.session.get(url, params={"zentaosid": self.sid}, timeout=30)
if response.status_code == 200:
return True, {
"message": "删除工时成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"删除失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def finish_task(self, task_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""完成任务(老 API)
Args:
task_id: 任务ID
comment: 完成备注(可选)
Returns:
(success, result) 注意:返回 HTML 页面。
请使用 get_task_detail(task_id) 验证完成结果。
Note:
- 任务状态变为 'done'
- 会记录 finishedBy 和 finishedDate
- 建议先记录工时(left=0)再完成任务
Example:
>>> # 先记录工时
>>> client.record_estimate("15", [{"date": "2026-03-27", "consumed": "3", "left": "0", "work": "完成"}])
>>> # 再完成任务
>>> success, result = client.finish_task("15", "已完成")
>>> ok, task = client.get_task_detail("15")
>>> print(f"状态: {task['status']}") # done
>>> print(f"完成人: {task['finishedBy']}")
"""
data = {}
if comment:
data["comment"] = comment
url = f"{self.old_api_base}/task-finish-{task_id}.json"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {
"message": "完成任务成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"完成失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def pause_task(self, task_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""暂停任务(老 API)
Args:
task_id: 任务ID
comment: 暂停备注(可选)
Returns:
(success, result) 注意:返回 HTML 页面。
请使用 get_task_detail(task_id) 验证暂停结果。
Note:
- 任务状态变为 'pause'
- 仅对 doing 状态的任务有效
Example:
>>> success, result = client.pause_task("17", "暂停开发")
>>> ok, task = client.get_task_detail("17")
>>> print(f"状态: {task['status']}") # pause
"""
data = {}
if comment:
data["comment"] = comment
url = f"{self.old_api_base}/task-pause-{task_id}.json"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {
"message": "暂停任务成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"暂停失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def restart_task(self, task_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""继续任务(老 API)
Args:
task_id: 任务ID
comment: 继续备注(可选)
Returns:
(success, result) 注意:返回 HTML 页面。
请使用 get_task_detail(task_id) 验证继续结果。
Note:
- 将 pause 状态的任务恢复为 doing
- 仅对 pause 状态的任务有效
Example:
>>> success, result = client.restart_task("17", "继续开发")
>>> ok, task = client.get_task_detail("17")
>>> print(f"状态: {task['status']}") # doing
"""
data = {}
if comment:
data["comment"] = comment
url = f"{self.old_api_base}/task-restart-{task_id}.json"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {
"message": "继续任务成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"继续失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def activate_task(self, task_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""激活任务(老 API)
Args:
task_id: 任务ID
comment: 激活备注(可选)
Returns:
(success, result) 注意:返回 HTML 页面。
请使用 get_task_detail(task_id) 验证激活结果。
Note:
- 将 done/closed 状态的任务恢复为 doing
- 对于 cancel 状态的任务可能无法激活
Example:
>>> success, result = client.activate_task("17", "重新开始")
>>> ok, task = client.get_task_detail("17")
>>> print(f"状态: {task['status']}") # doing
"""
data = {}
if comment:
data["comment"] = comment
url = f"{self.old_api_base}/task-activate-{task_id}.json"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {
"message": "激活任务成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"激活失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def assign_task(
self, task_id: str, assigned_to: str, comment: str = ""
) -> Tuple[bool, Dict]:
"""指派任务(老 API)
Args:
task_id: 任务ID
assigned_to: 指派给谁(用户名)
comment: 指派备注(可选)
Returns:
(success, result) 注意:返回空响应。
请使用 get_task_detail(task_id) 验证指派结果。
Example:
>>> success, result = client.assign_task("17", "zhangsan", "请处理")
>>> ok, task = client.get_task_detail("17")
>>> print(f"指派给: {task['assignedTo']}") # zhangsan
"""
data = {"assignedTo": assigned_to}
if comment:
data["comment"] = comment
url = f"{self.old_api_base}/task-assignTo-{task_id}.json"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {
"message": "指派任务成功",
"status_code": response.status_code,
}
else:
return False, {
"message": f"指派失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def create_task(
self,
project: str,
name: str,
type: str = "devel",
story: str = "0",
module: str = "0",
assignedTo: str = "",
pri: str = "3",
desc: str = "",
estimate: str = "0",
**kwargs,
) -> Tuple[bool, Dict]:
"""创建任务(老 API)
Args:
project: 所属项目ID *必填
name: 任务名称 *必填
type: 任务类型 *必填,取值: design, devel, test, study, discuss, ui, affair, misc
story: 相关需求ID
module: 所属模块ID
assignedTo: 指派给(用户名)
pri: 优先级 (0-4)
desc: 任务描述
estimate: 预计工时
Returns:
(success, result)
Example:
>>> success, result = client.create_task(
... project="1",
... name="用户登录功能开发",
... type="devel",
... assignedTo="admin",
... pri="3"
... )
"""
return self.create_tasks(
project=project,
tasks=[
{
"name": name,
"type": type,
"story": story,
"module": module,
"assignedTo": assignedTo or "admin",
"pri": pri,
"desc": desc,
"estimate": estimate,
}
],
**kwargs,
)
def create_tasks(
self,
project: str,
tasks: List[Dict],
story_id: str = "0",
module_id: str = "0",
parent_id: str = "0",
**kwargs,
) -> Tuple[bool, Dict]:
"""批量创建任务(老 API)
Args:
project: 所属项目ID *必填
tasks: 任务列表,每个任务包含 name, type, story, module, assignedTo, pri, desc, estimate
story_id: 需求ID,默认 "0"
module_id: 模块ID,默认 "0"
parent_id: 父任务ID,默认 "0"
Returns:
(success, result)
Example:
>>> success, result = client.create_tasks(
... project="1",
... tasks=[
... {"name": "任务1", "type": "devel", "assignedTo": "admin"},
... {"name": "任务2", "type": "test", "assignedTo": "admin"}
... ]
... )
"""
if not self.sid:
self.get_session()
data = {}
for i, task in enumerate(tasks):
data[f"module[{i}]"] = task.get("module", "0")
data[f"story[{i}]"] = task.get("story", "0")
data[f"parent[{i}]"] = task.get("parent", "0")
data[f"name[{i}]"] = task.get("name", "")
data[f"type[{i}]"] = task.get("type", "devel")
data[f"assignedTo[{i}]"] = task.get("assignedTo", "admin")
data[f"estimate[{i}]"] = str(task.get("estimate", "0"))
data[f"pri[{i}]"] = str(task.get("pri", "3"))
data[f"desc[{i}]"] = task.get("desc", "")
return self.old_request(
"POST",
f"/task-batchCreate-{project}-{story_id}-{module_id}-{parent_id}.json",
data,
)
def get_my_tasks(self, task_type: str = "assignedTo") -> Tuple[bool, List[Dict]]:
"""获取我的任务列表(老 API)
Args:
task_type: 任务类型,可选值: assignedTo(指派给我), openedBy(由我创建), finishedBy(由我完成), closedBy(由我关闭), canceledBy(由我取消)
Returns:
(success, tasks) 任务列表
Example:
>>> success, tasks = client.get_my_tasks("assignedTo")
>>> for task in tasks:
... print(f"[{task['id']}] {task['name']} ({task['status']})")
"""
success, result = self.old_request("GET", f"/my-task-{task_type}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("tasks", [])
return False, []
def get_my_bugs(
self, bug_type: str = "assignedTo", order_by: str = "id_desc"
) -> Tuple[bool, List[Dict]]:
"""获取我的Bug列表(老 API)
Args:
bug_type: Bug类型,可选值: assignedTo(指派给我), openedBy(由我创建), resolvedBy(由我解决), closedBy(由我关闭)
order_by: 排序字段,默认 id_desc
Returns:
(success, bugs) Bug列表
Example:
>>> success, bugs = client.get_my_bugs("assignedTo")
>>> for bug in bugs:
... print(f"[{bug['id']}] {bug['title']} ({bug['status']})")
"""
success, result = self.old_request("GET", f"/my-bug-{bug_type}-{order_by}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("bugs", [])
return False, []
def get_my_stories(self, story_type: str = "assignedTo") -> Tuple[bool, List[Dict]]:
"""获取我的需求列表(老 API)
Args:
story_type: 需求类型,可选值: assignedTo(指派给我), openedBy(由我创建), reviewedBy(由我评审), closedBy(由我关闭)
Returns:
(success, stories) 需求列表
Example:
>>> success, stories = client.get_my_stories("assignedTo")
>>> for story in stories:
... print(f"[{story['id']}] {story['title']} ({story['status']})")
"""
success, result = self.old_request("GET", f"/my-story-{story_type}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("stories", [])
return False, []
def get_my_projects(self) -> Tuple[bool, List[Dict]]:
"""获取我的项目列表(老 API)
Returns:
(success, projects) 项目列表
Example:
>>> success, projects = client.get_my_projects()
>>> for project in projects:
... print(f"[{project['id']}] {project['name']}")
"""
success, result = self.old_request("GET", "/my-project.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("projects", [])
return False, []
# ==================== Bug 相关方法 ====================
def get_project_bugs(
self, project_id: str, status: str = "all"
) -> Tuple[bool, List[Dict]]:
"""获取项目的Bug列表(老 API)
Args:
project_id: 项目ID
status: Bug状态,默认 "all" 获取所有状态
Returns:
(success, bugs) Bug列表
Example:
>>> success, bugs = client.get_project_bugs("1")
>>> for bug in bugs:
... print(f"[{bug['id']}] {bug['title']} ({bug['status']})")
"""
success, result = self.old_request("GET", f"/project-bug-{project_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("bugs", [])
return False, []
def get_bug(self, bug_id: str) -> Tuple[bool, Dict]:
"""获取Bug详情(老 API)
Args:
bug_id: BugID
Returns:
(success, bug_info) Bug详情
Example:
>>> success, bug = client.get_bug("1")
>>> print(f"标题: {bug['title']}, 状态: {bug['status']}")
"""
success, result = self.old_request("GET", f"/bug-view-{bug_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("bug", {})
return False, {}
def create_bug(
self,
product_id: str,
title: str,
opened_build: str = "trunk",
project_id: str = None,
case_id: str = None,
**kwargs,
) -> Tuple[bool, Dict]:
"""创建Bug(老 API)
Args:
product_id: 产品ID
title: Bug标题
opened_build: 影响版本,默认 "trunk"
project_id: 项目ID(可选)
case_id: 测试用例ID(可选,用于关联测试用例)
**kwargs: 其他参数,如:
- module: 模块ID
- severity: 严重程度 (1-4)
- pri: 优先级 (0-4)
- type: Bug类型 (codeerror, config, install, security, performance, standard, automation, designdefect, others)
- steps: 重现步骤
- assignedTo: 指派给
- deadline: 截止日期 (YYYY-MM-DD)
Returns:
(success, result) 创建结果
Note:
创建Bug需要产品存在且有权限。
传入 case_id 可以关联测试用例。
Example:
>>> success, result = client.create_bug(
... product_id="1",
... title="测试Bug",
... severity="3",
... pri="3",
... assignedTo="admin"
... )
>>> # 从测试用例创建Bug
>>> success, result = client.create_bug(
... product_id="1",
... title="从测试用例创建的Bug",
... case_id="8",
... steps="测试用例8发现的问题"
... )
"""
data = {
"product": product_id,
"title": title,
"openedBuild": opened_build,
}
if project_id:
data["project"] = project_id
if case_id:
data["case"] = case_id
data.update(kwargs)
# 构建URL
url = f"/bug-create-{product_id}-0"
if project_id:
url += f"-projectID={project_id}"
url += ".json"
success, result = self.old_request("POST", url, data)
if success:
return True, {"message": "创建Bug请求已发送", "result": result}
else:
return False, result
def create_bug_from_testcase(
self,
case_id: str,
product_id: str = None,
title: str = None,
**kwargs,
) -> Tuple[bool, Dict]:
"""从测试用例创建Bug(老 API)
Args:
case_id: 测试用例ID *必填
product_id: 产品ID(可选,不传则从测试用例获取)
title: Bug标题(可选,不传则使用测试用例标题)
**kwargs: 其他参数,如:
- severity: 严重程度 (1-4)
- pri: 优先级 (0-4)
- type: Bug类型
- steps: 重现步骤(可选,不传则使用测试用例步骤)
- assignedTo: 指派给
- opened_build: 影响版本,默认 "trunk"
Returns:
(success, result) 创建结果
Example:
>>> success, result = client.create_bug_from_testcase(
... case_id="8",
... title="登录功能测试发现Bug",
... severity="3"
... )
"""
# 获取测试用例详情
success, case = self.get_testcase(case_id)
if not success:
return False, {"message": f"测试用例 {case_id} 不存在"}
# 使用测试用例信息填充默认值
if not product_id:
product_id = case.get("product", "0")
if not title:
title = f"[测试用例{case_id}] {case.get('title', '')}"
# 准备Bug数据
data = {
"case": case_id,
"product": product_id,
"title": title,
"openedBuild": kwargs.pop("opened_build", "trunk"),
}
# 如果测试用例有步骤,转换为Bug重现步骤
if "steps" not in kwargs and case.get("steps"):
steps_text = ""
for step_id, step in case.get("steps", {}).items():
if isinstance(step, dict):
desc = step.get("desc", "")
expect = step.get("expect", "")
if desc:
steps_text += f"{desc}"
if expect:
steps_text += f" (预期: {expect})"
steps_text += "\n"
if steps_text:
data["steps"] = steps_text.strip()
data.update(kwargs)
# 构建URL
url = f"/bug-create-{product_id}-0.json"
success, result = self.old_request("POST", url, data)
if success:
return True, {
"message": "从测试用例创建Bug成功",
"case_id": case_id,
"result": result,
}
else:
return False, result
def resolve_bug(
self,
bug_id: str,
resolution: str = "fixed",
resolved_build: str = "trunk",
comment: str = "",
) -> Tuple[bool, Dict]:
"""解决Bug(老 API)
Args:
bug_id: BugID
resolution: 解决方案,可选值: fixed, postponed, willnotfix, duplicate, tostory
resolved_build: 解决版本,默认 "trunk"
comment: 解决备注
Returns:
(success, result)
Note:
解决后Bug状态变为 'resolved'。
建议使用 .html 端点。
Example:
>>> success, result = client.resolve_bug("1", "fixed", "trunk", "已修复")
"""
data = {
"resolution": resolution,
"resolvedBuild": resolved_build,
"comment": comment,
}
url = f"{self.old_api_base}/bug-resolve-{bug_id}.html?onlybody=yes"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {"message": "解决Bug成功", "status_code": response.status_code}
else:
return False, {
"message": f"解决失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def close_bug(self, bug_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""关闭Bug(老 API)
Args:
bug_id: BugID
comment: 关闭备注
Returns:
(success, result)
Note:
关闭后Bug状态变为 'closed'。
Example:
>>> success, result = client.close_bug("1", "已验证关闭")
"""
data = {}
if comment:
data["comment"] = comment
success, result = self.old_request("POST", f"/bug-close-{bug_id}.json", data)
return success, result
def activate_bug(self, bug_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""激活Bug(老 API)
Args:
bug_id: BugID
comment: 激活备注
Returns:
(success, result)
Note:
激活后Bug状态变为 'active'。
Example:
>>> success, result = client.activate_bug("1", "问题重现,重新打开")
"""
data = {}
if comment:
data["comment"] = comment
success, result = self.old_request("POST", f"/bug-activate-{bug_id}.json", data)
return success, result
def assign_bug(
self, bug_id: str, assigned_to: str, comment: str = ""
) -> Tuple[bool, Dict]:
"""指派Bug(老 API)
Args:
bug_id: BugID
assigned_to: 指派给谁(用户名)
comment: 指派备注
Returns:
(success, result)
Example:
>>> success, result = client.assign_bug("1", "zhangsan", "请处理")
"""
data = {"assignedTo": assigned_to}
if comment:
data["comment"] = comment
url = f"{self.old_api_base}/bug-assignTo-{bug_id}.json"
response = self.session.post(
url, data=data, params={"zentaosid": self.sid}, timeout=30
)
if response.status_code == 200:
return True, {"message": "指派Bug成功", "status_code": response.status_code}
else:
return False, {
"message": f"指派失败: HTTP {response.status_code}",
"status_code": response.status_code,
}
def confirm_bug(self, bug_id: str, comment: str = "") -> Tuple[bool, Dict]:
"""确认Bug(老 API)
Args:
bug_id: BugID
comment: 确认备注
Returns:
(success, result)
Example:
>>> success, result = client.confirm_bug("1", "确认是Bug")
"""
data = {}
if comment:
data["comment"] = comment
success, result = self.old_request(
"POST", f"/bug-confirmBug-{bug_id}.json", data
)
return success, result
def delete_bug(self, bug_id: str) -> Tuple[bool, Dict]:
"""删除Bug(老 API)
Args:
bug_id: BugID
Returns:
(success, result)
Example:
>>> success, result = client.delete_bug("1")
"""
return self.old_request("GET", f"/bug-delete-{bug_id}-yes.json")
# ==================== 产品相关方法 ====================
def get_products(self) -> Tuple[bool, List[Dict]]:
"""获取所有产品列表(老 API)
Returns:
(success, products) 产品列表
Example:
>>> success, products = client.get_products()
>>> for pid, name in products.items():
... print(f"[{pid}] {name}")
"""
success, result = self.old_request("GET", "/product-all.json")
if success and "data" in result:
data = json.loads(result["data"])
products = data.get("products", {})
return True, products
return False, {}
def get_product(self, product_id: str) -> Tuple[bool, Dict]:
"""获取产品详情(老 API)
Args:
product_id: 产品ID
Returns:
(success, product_info) 产品详情
Example:
>>> success, product = client.get_product("1")
>>> print(f"产品名: {product['name']}")
"""
success, result = self.old_request("GET", f"/product-view-{product_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("product", {})
return False, {}
def create_product(
self,
name: str,
code: str,
type: str = "normal",
po: str = "",
qd: str = "",
rd: str = "",
status: str = "normal",
desc: str = "",
) -> Tuple[bool, Dict]:
"""创建产品(老 API)
Args:
name: 产品名称
code: 产品代码
type: 产品类型 (normal, branch, platform)
po: 产品负责人
qd: 测试负责人
rd: 发布负责人
status: 状态 (normal, closed)
desc: 产品描述
Returns:
(success, result)
Example:
>>> success, result = client.create_product(
... name="新产品",
... code="NEW",
... po="admin"
... )
"""
data = {
"name": name,
"code": code,
"type": type,
"status": status,
"desc": desc,
}
if po:
data["PO"] = po
if qd:
data["QD"] = qd
if rd:
data["RD"] = rd
return self.old_request("POST", "/product-create.json", data)
def edit_product(self, product_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑产品(老 API)
Args:
product_id: 产品ID
**kwargs: 要修改的字段 (name, code, type, PO, QD, RD, status, desc等)
Returns:
(success, result)
Example:
>>> success, result = client.edit_product("1", name="新名称", status="closed")
"""
return self.old_request("POST", f"/product-edit-{product_id}.json", kwargs)
def close_product(self, product_id: str) -> Tuple[bool, Dict]:
"""关闭产品(老 API)
Args:
product_id: 产品ID
Returns:
(success, result)
Example:
>>> success, result = client.close_product("1")
"""
return self.old_request("POST", f"/product-close-{product_id}.json")
def delete_product(self, product_id: str) -> Tuple[bool, Dict]:
"""删除产品(老 API)
Args:
product_id: 产品ID
Returns:
(success, result)
Example:
>>> success, result = client.delete_product("1")
"""
return self.old_request("GET", f"/product-delete-{product_id}-yes.json")
# ==================== 需求相关方法 ====================
def get_story(self, story_id: str) -> Tuple[bool, Dict]:
"""获取需求详情(老 API)
Args:
story_id: 需求ID
Returns:
(success, story_info) 需求详情
Example:
>>> success, story = client.get_story("1")
>>> print(f"需求标题: {story['title']}")
"""
success, result = self.old_request("GET", f"/story-view-{story_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("story", {})
return False, {}
def create_story(
self,
product_id: str,
title: str,
module: str = "0",
plan: str = "0",
execution_id: str = "0",
branch: str = "0",
**kwargs,
) -> Tuple[bool, Dict]:
"""创建需求(老 API)
Args:
product_id: 产品ID
title: 需求标题
module: 模块ID,默认 "0"
plan: 计划ID,默认 "0"
execution_id: 执行/项目ID,默认 "0"
branch: 分支ID,默认 "0"
**kwargs: 其他参数:
- source: 需求来源
- pri: 优先级 (0-4)
- estimate: 预计工时
- spec: 需求描述
- verify: 验收标准
- assignedTo: 指派给
- reviewer: 评审人
Returns:
(success, result)
Example:
>>> success, result = client.create_story(
... product_id="1",
... title="新需求",
... pri="3",
... spec="需求描述"
... )
"""
data = {
"product": product_id,
"title": title,
"module": module,
}
data.update(kwargs)
# URL: /story-create-{product}-{module}-{story}-{plan}-{execution}-{branch}-{module}-{type}.json
return self.old_request(
"POST",
f"/story-create-{product_id}-{module}-0-{plan}-{execution_id}-{branch}-{module}-0-story.json",
data,
)
def edit_story(self, story_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑需求(老 API)
Args:
story_id: 需求ID
**kwargs: 要修改的字段
Returns:
(success, result)
Example:
>>> success, result = client.edit_story("1", title="新标题", pri="2")
"""
return self.old_request("POST", f"/story-edit-{story_id}.json", kwargs)
def close_story(self, story_id: str) -> Tuple[bool, Dict]:
"""关闭需求(老 API)
Args:
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.close_story("1")
"""
return self.old_request("POST", f"/story-close-{story_id}.json")
def activate_story(self, story_id: str) -> Tuple[bool, Dict]:
"""激活需求(老 API)
Args:
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.activate_story("1")
"""
return self.old_request("POST", f"/story-activate-{story_id}.json")
def delete_story(self, story_id: str) -> Tuple[bool, Dict]:
"""删除需求(老 API)
Args:
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.delete_story("1")
"""
return self.old_request("GET", f"/story-delete-{story_id}-yes.json")
# ==================== 计划相关方法 ====================
def get_plans(self, product_id: str) -> Tuple[bool, List[Dict]]:
"""获取产品计划列表(老 API)
Args:
product_id: 产品ID
Returns:
(success, plans) 计划列表
Example:
>>> success, plans = client.get_plans("1")
>>> for plan in plans:
... print(f"[{plan['id']}] {plan['title']}")
"""
success, result = self.old_request(
"GET", f"/productplan-browse-{product_id}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("plans", [])
return False, []
def create_plan(
self,
product_id: str,
title: str,
begin: str = "",
end: str = "",
desc: str = "",
) -> Tuple[bool, Dict]:
"""创建产品计划(老 API)
Args:
product_id: 产品ID
title: 计划标题
begin: 开始日期 (YYYY-MM-DD)
end: 结束日期 (YYYY-MM-DD)
desc: 计划描述
Returns:
(success, result)
Example:
>>> success, result = client.create_plan(
... product_id="1",
... title="1.0版本",
... begin="2026-03-01",
... end="2026-03-31"
... )
"""
data = {
"product": product_id,
"title": title,
"begin": begin,
"end": end,
"desc": desc,
}
return self.old_request("POST", f"/productplan-create-{product_id}.json", data)
def delete_plan(self, plan_id: str) -> Tuple[bool, Dict]:
"""删除产品计划(老 API)
Args:
plan_id: 计划ID
Returns:
(success, result)
Example:
>>> success, result = client.delete_plan("1")
"""
return self.old_request("GET", f"/productplan-delete-{plan_id}-yes.json")
# ==================== 项目管理方法 ====================
def create_project(
self,
name: str,
begin: str,
end: str,
code: str = "",
days: str = "",
products: List[str] = None,
plans: List[str] = None,
desc: str = "",
**kwargs,
) -> Tuple[bool, Dict]:
"""创建项目(老 API)
Args:
name: 项目名称
begin: 开始日期 (YYYY-MM-DD)
end: 结束日期 (YYYY-MM-DD)
code: 项目代号
days: 可用工时天数
products: 关联产品ID列表
plans: 关联计划ID列表(需与products一一对应)
desc: 项目描述
**kwargs: 其他参数 (acl, whitelist, team, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.create_project(
... name="V1.0开发项目",
... begin="2026-04-01",
... end="2026-04-30",
... code="V1",
... days="22",
... products=["1"],
... plans=["1"]
... )
"""
data = {
"name": name,
"begin": begin,
"end": end,
}
if code:
data["code"] = code
if days:
data["days"] = days
if desc:
data["desc"] = desc
# 关联产品和计划
if products:
for i, product_id in enumerate(products):
data[f"products[{i}]"] = product_id
if plans and i < len(plans):
data[f"plans[{i}]"] = plans[i]
data.update(kwargs)
return self.old_request("POST", "/project-create.json", data)
def get_project(self, project_id: str) -> Tuple[bool, Dict]:
"""获取项目详情(老 API)
Args:
project_id: 项目ID
Returns:
(success, project)
Example:
>>> success, project = client.get_project("1")
>>> print(project['name'])
"""
success, result = self.old_request("GET", f"/project-view-{project_id}.json")
if success and "data" in result:
data = result["data"]
if isinstance(data, str):
data = json.loads(data)
return True, data.get("project", data)
return success, result
def start_project(self, project_id: str) -> Tuple[bool, Dict]:
"""启动项目(老 API)
Args:
project_id: 项目ID
Returns:
(success, result)
Example:
>>> success, result = client.start_project("1")
"""
return self.old_request("GET", f"/project-start-{project_id}.json")
def close_project(self, project_id: str) -> Tuple[bool, Dict]:
"""关闭项目(老 API)
Args:
project_id: 项目ID
Returns:
(success, result)
Example:
>>> success, result = client.close_project("1")
"""
return self.old_request("GET", f"/project-close-{project_id}.json")
# ==================== 发布相关方法 ====================
def get_releases(self, product_id: str) -> Tuple[bool, List[Dict]]:
"""获取产品发布列表(老 API)
Args:
product_id: 产品ID
Returns:
(success, releases) 发布列表
Example:
>>> success, releases = client.get_releases("1")
>>> for release in releases:
... print(f"[{release['id']}] {release['name']}")
"""
success, result = self.old_request("GET", f"/release-browse-{product_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("releases", [])
return False, []
# ==================== 测试相关方法 ====================
def get_testcases(
self, product_id: str, browse_type: str = "all"
) -> Tuple[bool, List[Dict]]:
"""获取测试用例列表(老 API)
Args:
product_id: 产品ID
browse_type: 浏览类型 (all, bymodule, assignedtome)
Returns:
(success, cases) 测试用例列表
Example:
>>> success, cases = client.get_testcases("1")
>>> for case in cases:
... print(f"[{case['id']}] {case['title']}")
"""
success, result = self.old_request(
"GET", f"/testcase-browse-{product_id}-{browse_type}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("cases", [])
return False, []
def get_testcase(self, case_id: str) -> Tuple[bool, Dict]:
"""获取测试用例详情(老 API)
Args:
case_id: 用例ID
Returns:
(success, case_info) 用例详情
Example:
>>> success, case = client.get_testcase("1")
>>> print(f"标题: {case['title']}")
"""
success, result = self.old_request("GET", f"/testcase-view-{case_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("case", {})
return False, {}
def create_testcase(
self,
product_id: str,
title: str,
case_type: str = "feature",
module: str = "0",
story: str = "0",
branch: str = "0",
**kwargs,
) -> Tuple[bool, Dict]:
"""创建测试用例(老 API)
Args:
product_id: 产品ID
title: 用例标题
case_type: 用例类型 (feature, performance, config, install, security, interface, unit, other)
module: 模块ID,默认 "0"
story: 需求ID,默认 "0"
branch: 分支ID,默认 "0"
**kwargs: 其他参数:
- stage: 适用阶段 (unittest, feature, intergrate, system, smoke, bvt)
- pri: 优先级 (0-4)
- precondition: 前置条件
- steps: 用例步骤(字符串,按换行分割)
- expect: 预期结果(字符串,按换行分割)
- steps_list: 步骤列表(列表格式,与steps二选一)
- expects_list: 预期结果列表(列表格式,与expect二选一)
Returns:
(success, result)
Example:
>>> # 字符串格式(自动按换行分割)
>>> success, result = client.create_testcase(
... product_id="1",
... title="测试登录功能",
... case_type="feature",
... steps="1. 打开登录页面\\n2. 输入用户名密码\\n3. 点击登录",
... expect="登录成功"
... )
>>> # 列表格式(精确控制)
>>> success, result = client.create_testcase(
... product_id="1",
... title="测试登录功能",
... module="1",
... story="5",
... steps_list=["打开登录页面", "输入用户名密码", "点击登录"],
... expects_list=["显示登录表单", "输入成功", "登录成功"]
... )
"""
data = {
"product": product_id,
"title": title,
"type": case_type,
}
# 处理步骤和预期结果
steps_text = kwargs.pop("steps", None)
expect_text = kwargs.pop("expect", None)
steps_list = kwargs.pop("steps_list", None)
expects_list = kwargs.pop("expects_list", None)
# 转换步骤格式
if steps_list:
# 直接使用列表
for i, step in enumerate(steps_list, start=1):
data[f"steps[{i}]"] = step
elif steps_text:
# 按换行分割
steps = [s.strip() for s in steps_text.split("\n") if s.strip()]
for i, step in enumerate(steps, start=1):
data[f"steps[{i}]"] = step
# 转换预期结果格式
if expects_list:
# 直接使用列表
for i, exp in enumerate(expects_list, start=1):
data[f"expects[{i}]"] = exp
elif expect_text:
# 按换行分割
expects = [e.strip() for e in expect_text.split("\n") if e.strip()]
for i, exp in enumerate(expects, start=1):
data[f"expects[{i}]"] = exp
# 其他参数
data.update(kwargs)
# 构建URL: /testcase-create-{product}-{module}-{story}-{branch}-{0}
return self.old_request(
"POST",
f"/testcase-create-{product_id}-{module}-{story}-{branch}-0.json",
data,
)
def delete_testcase(self, case_id: str, confirm: str = "yes") -> Tuple[bool, Dict]:
"""删除测试用例(老 API)
Args:
case_id: 用例ID
confirm: 确认删除,可选值: "yes"(删除)| "no"(不删除),默认 "yes"
Returns:
(success, result)
Note:
- 禅道使用软删除机制,删除后用例的 deleted 字段标记为 '1'
- 删除后用例不再显示在列表中,但数据仍保留在数据库
- 返回 HTML 响应表示删除成功
Example:
>>> success, result = client.delete_testcase("10")
>>> # 验证删除
>>> success, case = client.get_testcase("10")
>>> if case.get('deleted') == '1':
... print("已删除")
"""
return self.old_request("GET", f"/testcase-delete-{case_id}-{confirm}.json")
def get_testsuites(self, product_id: str) -> Tuple[bool, List[Dict]]:
"""获取测试套件列表(老 API)
Args:
product_id: 产品ID
Returns:
(success, suites) 测试套件列表
Example:
>>> success, suites = client.get_testsuites("1")
>>> for suite in suites:
... print(f"[{suite['id']}] {suite['name']}")
"""
success, result = self.old_request(
"GET", f"/testsuite-browse-{product_id}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("suites", [])
return False, []
def get_testsuite(self, suite_id: str) -> Tuple[bool, Dict]:
"""获取测试套件详情(老 API)
Args:
suite_id: 套件ID
Returns:
(success, suite_info) 套件详情
Example:
>>> success, suite = client.get_testsuite("1")
>>> print(f"套件名: {suite['name']}")
"""
success, result = self.old_request("GET", f"/testsuite-view-{suite_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("suite", {})
return False, {}
def create_testsuite(
self, product_id: str, name: str, desc: str = ""
) -> Tuple[bool, Dict]:
"""创建测试套件(老 API)
Args:
product_id: 产品ID
name: 套件名称
desc: 套件描述
Returns:
(success, result)
Example:
>>> success, result = client.create_testsuite("1", "冒烟测试套件", "冒烟测试用例集合")
"""
data = {"product": product_id, "name": name, "desc": desc}
return self.old_request("POST", f"/testsuite-create-{product_id}.json", data)
def delete_testsuite(self, suite_id: str) -> Tuple[bool, Dict]:
"""删除测试套件(老 API)
Args:
suite_id: 套件ID
Returns:
(success, result)
Example:
>>> success, result = client.delete_testsuite("1")
"""
return self.old_request("GET", f"/testsuite-delete-{suite_id}-yes.json")
def get_testtasks(
self, product_id: str, task_type: str = "all"
) -> Tuple[bool, List[Dict]]:
"""获取测试任务列表(老 API)
Args:
product_id: 产品ID
task_type: 任务类型 (all, wait, doing, done, blocked)
Returns:
(success, tasks) 测试任务列表
Example:
>>> success, tasks = client.get_testtasks("1")
>>> for task in tasks:
... print(f"[{task['id']}] {task['name']}")
"""
success, result = self.old_request(
"GET", f"/testtask-browse-{product_id}-{task_type}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("tasks", [])
return False, []
def get_testtask(self, task_id: str) -> Tuple[bool, Dict]:
"""获取测试任务详情(老 API)
Args:
task_id: 任务ID
Returns:
(success, task_info) 任务详情
Example:
>>> success, task = client.get_testtask("1")
>>> print(f"任务名: {task['name']}")
"""
success, result = self.old_request("GET", f"/testtask-view-{task_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("task", {})
return False, {}
def create_testtask(
self, product_id: str, name: str, begin: str = "", end: str = "", desc: str = ""
) -> Tuple[bool, Dict]:
"""创建测试任务(老 API)
Args:
product_id: 产品ID
name: 任务名称
begin: 开始日期 (YYYY-MM-DD)
end: 结束日期 (YYYY-MM-DD)
desc: 任务描述
Returns:
(success, result) 注意:可能返回HTML
Example:
>>> success, result = client.create_testtask(
... product_id="1",
... name="Sprint1测试",
... begin="2026-03-01",
... end="2026-03-15"
... )
"""
data = {
"product": product_id,
"name": name,
"begin": begin,
"end": end,
"desc": desc,
}
return self.old_request("POST", f"/testtask-create-{product_id}.json", data)
def delete_testtask(self, task_id: str) -> Tuple[bool, Dict]:
"""删除测试任务(老 API)
Args:
task_id: 任务ID
Returns:
(success, result)
Example:
>>> success, result = client.delete_testtask("1")
"""
return self.old_request("GET", f"/testtask-delete-{task_id}-yes.json")
def start_testtask(self, task_id: str) -> Tuple[bool, Dict]:
"""开始测试任务(老 API)
Args:
task_id: 任务ID
Returns:
(success, result)
Example:
>>> success, result = client.start_testtask("1")
"""
return self.old_request("POST", f"/testtask-start-{task_id}.json")
def close_testtask(self, task_id: str) -> Tuple[bool, Dict]:
"""关闭测试任务(老 API)
Args:
task_id: 任务ID
Returns:
(success, result)
Example:
>>> success, result = client.close_testtask("1")
"""
return self.old_request("POST", f"/testtask-close-{task_id}.json")
def block_testtask(self, task_id: str) -> Tuple[bool, Dict]:
"""阻塞测试任务(老 API)
Args:
task_id: 任务ID
Returns:
(success, result)
Example:
>>> success, result = client.block_testtask("1")
"""
return self.old_request("POST", f"/testtask-block-{task_id}.json")
def activate_testtask(self, task_id: str) -> Tuple[bool, Dict]:
"""激活测试任务(老 API)
Args:
task_id: 任务ID
Returns:
(success, result)
Example:
>>> success, result = client.activate_testtask("1")
"""
return self.old_request("POST", f"/testtask-activate-{task_id}.json")
def get_testreports(
self, product_id: str, project_id: str = "0"
) -> Tuple[bool, List[Dict]]:
"""获取测试报告列表(老 API)
Args:
product_id: 产品ID
project_id: 项目ID,默认 "0"
Returns:
(success, reports) 测试报告列表
Example:
>>> success, reports = client.get_testreports("1")
>>> for report in reports:
... print(f"[{report['id']}] {report['title']}")
"""
success, result = self.old_request(
"GET", f"/testreport-browse-{product_id}-product-{project_id}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("reports", [])
return False, []
def delete_testreport(self, report_id: str) -> Tuple[bool, Dict]:
"""删除测试报告(老 API)
Args:
report_id: 报告ID
Returns:
(success, result)
Example:
>>> success, result = client.delete_testreport("1")
"""
return self.old_request("GET", f"/testreport-delete-{report_id}-yes.json")
# ==================== 任务模块补充方法 ====================
def edit_task(self, task_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑任务(老 API)
Args:
task_id: 任务ID
**kwargs: 要修改的字段 (name, type, pri, estimate, left, assignedTo, status, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.edit_task("10", name="新任务名", pri="2")
"""
return self.old_request("POST", f"/task-edit-{task_id}.json", kwargs)
def move_task(self, task_id: str, project_id: str) -> Tuple[bool, Dict]:
"""移动任务到其他项目(老 API)
Args:
task_id: 任务ID
project_id: 目标项目ID
Returns:
(success, result)
Example:
>>> success, result = client.move_task("10", "2")
"""
return self.old_request("POST", f"/task-move-{task_id}-{project_id}.json")
def copy_task(self, task_id: str, project_id: str = None) -> Tuple[bool, Dict]:
"""复制任务(老 API)
Args:
task_id: 任务ID
project_id: 目标项目ID(可选,不传则复制到当前项目)
Returns:
(success, result)
Example:
>>> success, result = client.copy_task("10", "2")
"""
if project_id:
return self.old_request("POST", f"/task-copy-{task_id}-{project_id}.json")
return self.old_request("POST", f"/task-copy-{task_id}.json")
def get_task_subtasks(self, task_id: str) -> Tuple[bool, List[Dict]]:
"""获取任务的子任务列表(老 API)
Args:
task_id: 任务ID
Returns:
(success, subtasks) 子任务列表
Example:
>>> success, subtasks = client.get_task_subtasks("10")
>>> for task in subtasks:
... print(f"[{task['id']}] {task['name']}")
"""
success, result = self.old_request("GET", f"/task-viewSubtasks-{task_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("children", [])
return False, []
def link_task_story(self, task_id: str, story_id: str) -> Tuple[bool, Dict]:
"""任务关联需求(老 API)
Args:
task_id: 任务ID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.link_task_story("10", "5")
"""
return self.old_request("POST", f"/task-linkStory-{task_id}-{story_id}.json")
def link_task_bug(self, task_id: str, bug_id: str) -> Tuple[bool, Dict]:
"""任务关联Bug(老 API)
Args:
task_id: 任务ID
bug_id: BugID
Returns:
(success, result)
Example:
>>> success, result = client.link_task_bug("10", "3")
"""
return self.old_request("POST", f"/task-linkBug-{task_id}-{bug_id}.json")
def get_task_history(self, task_id: str) -> Tuple[bool, List[Dict]]:
"""获取任务历史记录(老 API)
Args:
task_id: 任务ID
Returns:
(success, history) 历史记录列表
Example:
>>> success, history = client.get_task_history("10")
>>> for record in history:
... print(f"{record['date']}: {record['action']}")
"""
success, result = self.old_request("GET", f"/task-history-{task_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("history", [])
return False, []
# ==================== Bug模块补充方法 ====================
def edit_bug(self, bug_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑Bug(老 API)
Args:
bug_id: BugID
**kwargs: 要修改的字段 (title, severity, pri, type, status, assignedTo, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.edit_bug("1", title="新标题", severity="2")
"""
return self.old_request("POST", f"/bug-edit-{bug_id}.json", kwargs)
def link_bug_story(self, bug_id: str, story_id: str) -> Tuple[bool, Dict]:
"""Bug关联需求(老 API)
Args:
bug_id: BugID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.link_bug_story("1", "5")
"""
return self.old_request("POST", f"/bug-linkStory-{bug_id}-{story_id}.json")
def unlink_bug_story(self, bug_id: str, story_id: str) -> Tuple[bool, Dict]:
"""取消Bug关联需求(老 API)
Args:
bug_id: BugID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_bug_story("1", "5")
"""
return self.old_request("GET", f"/bug-unlinkStory-{bug_id}-{story_id}.json")
def link_bug_task(self, bug_id: str, task_id: str) -> Tuple[bool, Dict]:
"""Bug关联任务(老 API)
Args:
bug_id: BugID
task_id: 任务ID
Returns:
(success, result)
Example:
>>> success, result = client.link_bug_task("1", "10")
"""
return self.old_request("POST", f"/bug-linkTask-{bug_id}-{task_id}.json")
def unlink_bug_task(self, bug_id: str, task_id: str) -> Tuple[bool, Dict]:
"""取消Bug关联任务(老 API)
Args:
bug_id: BugID
task_id: 任务ID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_bug_task("1", "10")
"""
return self.old_request("GET", f"/bug-unlinkTask-{bug_id}-{task_id}.json")
def get_bug_statistics(
self, product_id: str, branch: str = "0"
) -> Tuple[bool, Dict]:
"""获取Bug统计信息(老 API)
Args:
product_id: 产品ID
branch: 分支ID,默认 "0"
Returns:
(success, statistics) Bug统计信息
Example:
>>> success, stats = client.get_bug_statistics("1")
>>> print(f"总Bug数: {stats['total']}, 未解决: {stats['active']}")
"""
success, result = self.old_request(
"GET", f"/bug-statistic-{product_id}-{branch}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data
return False, {}
def add_bug_comment(self, bug_id: str, comment: str) -> Tuple[bool, Dict]:
"""添加Bug评论(老 API)
Args:
bug_id: BugID
comment: 评论内容
Returns:
(success, result)
Example:
>>> success, result = client.add_bug_comment("1", "这是一个测试评论")
"""
return self.old_request(
"POST", f"/bug-addComment-{bug_id}.json", {"comment": comment}
)
# ==================== 需求模块补充方法 ====================
def change_story(self, story_id: str, **kwargs) -> Tuple[bool, Dict]:
"""变更需求(老 API)
Args:
story_id: 需求ID
**kwargs: 变更参数 (title, spec, verify, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.change_story("1", title="新标题", spec="新描述")
"""
return self.old_request("POST", f"/story-change-{story_id}.json", kwargs)
def review_story(
self, story_id: str, result: str, comment: str = ""
) -> Tuple[bool, Dict]:
"""评审需求(老 API)
Args:
story_id: 需求ID
result: 评审结果 (pass, revert, clarify, reject)
comment: 评审意见
Returns:
(success, result)
Example:
>>> success, result = client.review_story("1", "pass", "评审通过")
"""
data = {"result": result}
if comment:
data["comment"] = comment
return self.old_request("POST", f"/story-review-{story_id}.json", data)
def get_story_tasks(
self, story_id: str, project_id: str = "0"
) -> Tuple[bool, List[Dict]]:
"""获取需求关联的任务(老 API)
Args:
story_id: 需求ID
project_id: 项目ID,默认 "0" 获取所有项目
Returns:
(success, tasks) 任务列表
Example:
>>> success, tasks = client.get_story_tasks("1")
>>> for task in tasks:
... print(f"[{task['id']}] {task['name']}")
"""
success, result = self.old_request(
"GET", f"/story-tasks-{story_id}-{project_id}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("tasks", [])
return False, []
def get_story_bugs(self, story_id: str) -> Tuple[bool, List[Dict]]:
"""获取需求关联的Bug(老 API)
Args:
story_id: 需求ID
Returns:
(success, bugs) Bug列表
Example:
>>> success, bugs = client.get_story_bugs("1")
>>> for bug in bugs:
... print(f"[{bug['id']}] {bug['title']}")
"""
success, result = self.old_request("GET", f"/story-bugs-{story_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("bugs", [])
return False, []
def get_story_cases(self, story_id: str) -> Tuple[bool, List[Dict]]:
"""获取需求关联的测试用例(老 API)
Args:
story_id: 需求ID
Returns:
(success, cases) 测试用例列表
Example:
>>> success, cases = client.get_story_cases("1")
>>> for case in cases:
... print(f"[{case['id']}] {case['title']}")
"""
success, result = self.old_request("GET", f"/story-cases-{story_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("cases", [])
return False, []
def link_story_project(self, story_id: str, project_id: str) -> Tuple[bool, Dict]:
"""需求关联项目(老 API)
Args:
story_id: 需求ID
project_id: 项目ID
Returns:
(success, result)
Example:
>>> success, result = client.link_story_project("1", "2")
"""
return self.old_request(
"POST", f"/story-linkProject-{story_id}-{project_id}.json"
)
def unlink_story_project(self, story_id: str, project_id: str) -> Tuple[bool, Dict]:
"""取消需求关联项目(老 API)
Args:
story_id: 需求ID
project_id: 项目ID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_story_project("1", "2")
"""
return self.old_request(
"GET", f"/story-unlinkProject-{story_id}-{project_id}.json"
)
# ==================== 项目模块补充方法 ====================
def edit_project(self, project_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑项目(老 API)
Args:
project_id: 项目ID
**kwargs: 要修改的字段 (name, code, begin, end, days, status, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.edit_project("1", name="新项目名", status="doing")
"""
return self.old_request("POST", f"/project-edit-{project_id}.json", kwargs)
def get_project_stories(
self, project_id: str, order_by: str = "id_desc"
) -> Tuple[bool, List[Dict]]:
"""获取项目需求列表(老 API)
Args:
project_id: 项目ID
order_by: 排序方式,默认 "id_desc"
Returns:
(success, stories) 需求列表
Example:
>>> success, stories = client.get_project_stories("1")
>>> for story in stories:
... print(f"[{story['id']}] {story['title']}")
"""
success, result = self.old_request(
"GET", f"/project-story-{project_id}-{order_by}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("stories", [])
return False, []
def manage_project_members(
self, project_id: str, members: List[Dict]
) -> Tuple[bool, Dict]:
"""管理项目成员(老 API)
Args:
project_id: 项目ID
members: 成员列表,每个成员包含:
- account: 用户账号
- role: 角色 (如 developer, tester, pm)
- hours: 可用工时
Returns:
(success, result)
Example:
>>> members = [
... {"account": "user1", "role": "developer", "hours": "8"},
... {"account": "user2", "role": "tester", "hours": "8"}
... ]
>>> success, result = client.manage_project_members("1", members)
"""
data = {}
for i, member in enumerate(members):
data[f"accounts[{i}]"] = member.get("account", "")
data[f"roles[{i}]"] = member.get("role", "developer")
data[f"hours[{i}]"] = member.get("hours", "8")
return self.old_request(
"POST", f"/project-manageMembers-{project_id}.json", data
)
def link_project_story(self, project_id: str, story_id: str) -> Tuple[bool, Dict]:
"""项目关联需求(老 API)
Args:
project_id: 项目ID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.link_project_story("1", "5")
"""
return self.old_request(
"POST", f"/project-linkStory-{project_id}.json", {"story": story_id}
)
def unlink_project_story(self, project_id: str, story_id: str) -> Tuple[bool, Dict]:
"""取消项目关联需求(老 API)
Args:
project_id: 项目ID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_project_story("1", "5")
"""
return self.old_request(
"GET", f"/project-unlinkStory-{project_id}-{story_id}.json"
)
def get_project_team(self, project_id: str) -> Tuple[bool, List[Dict]]:
"""获取项目团队成员(老 API)
Args:
project_id: 项目ID
Returns:
(success, team) 团队成员列表
Example:
>>> success, team = client.get_project_team("1")
>>> for member in team:
... print(f"{member['account']}: {member['role']}")
"""
success, result = self.old_request("GET", f"/project-team-{project_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("team", [])
return False, []
def get_project_dynamic(
self, project_id: str, dynamic_type: str = "all"
) -> Tuple[bool, List[Dict]]:
"""获取项目动态(老 API)
Args:
project_id: 项目ID
dynamic_type: 动态类型 (all, today, yesterday, thisweek, lastweek, thismonth, lastmonth)
Returns:
(success, dynamics) 动态列表
Example:
>>> success, dynamics = client.get_project_dynamic("1", "today")
>>> for dynamic in dynamics:
... print(f"{dynamic['date']}: {dynamic['action']}")
"""
success, result = self.old_request(
"GET", f"/project-dynamic-{project_id}-{dynamic_type}.json"
)
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("dynamics", [])
return False, []
# ==================== 测试用例模块补充方法 ====================
def edit_testcase(self, case_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑测试用例(老 API)
Args:
case_id: 用例ID
**kwargs: 要修改的字段 (title, type, pri, module, story, steps, expects, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.edit_testcase("1", title="新标题", pri="2")
"""
return self.old_request("POST", f"/testcase-edit-{case_id}.json", kwargs)
def batch_create_testcases(
self, product_id: str, cases: List[Dict]
) -> Tuple[bool, Dict]:
"""批量创建测试用例(老 API)
Args:
product_id: 产品ID
cases: 用例列表,每个用例包含:
- title: 用例标题
- type: 用例类型
- module: 模块ID
- story: 需求ID
- steps: 步骤列表
- expects: 预期结果列表
Returns:
(success, result)
Example:
>>> cases = [
... {"title": "测试用例1", "type": "feature"},
... {"title": "测试用例2", "type": "performance"}
... ]
>>> success, result = client.batch_create_testcases("1", cases)
"""
data = {}
for i, case in enumerate(cases):
data[f"title[{i}]"] = case.get("title", "")
data[f"type[{i}]"] = case.get("type", "feature")
if case.get("module"):
data[f"module[{i}]"] = case.get("module")
if case.get("story"):
data[f"story[{i}]"] = case.get("story")
return self.old_request(
"POST", f"/testcase-batchCreate-{product_id}.json", data
)
def import_testcases(self, product_id: str, file_path: str) -> Tuple[bool, Dict]:
"""导入测试用例(老 API)
Args:
product_id: 产品ID
file_path: 导入文件路径
Returns:
(success, result)
Note:
这个方法需要上传文件,暂时返回错误信息
Example:
>>> success, result = client.import_testcases("1", "/path/to/import.csv")
"""
# TODO: 需要实现文件上传
return False, {"message": "文件导入功能暂未实现"}
def export_testcases(self, product_id: str) -> Tuple[bool, Dict]:
"""导出测试用例(老 API)
Args:
product_id: 产品ID
Returns:
(success, result) 注意:返回文件内容
Example:
>>> success, result = client.export_testcases("1")
"""
return self.old_request("POST", f"/testcase-export-{product_id}.json")
def link_testcase_story(self, case_id: str, story_id: str) -> Tuple[bool, Dict]:
"""测试用例关联需求(老 API)
Args:
case_id: 用例ID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.link_testcase_story("1", "5")
"""
return self.old_request(
"POST", f"/testcase-linkStory-{case_id}-{story_id}.json"
)
def unlink_testcase_story(self, case_id: str, story_id: str) -> Tuple[bool, Dict]:
"""取消测试用例关联需求(老 API)
Args:
case_id: 用例ID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_testcase_story("1", "5")
"""
return self.old_request(
"GET", f"/testcase-unlinkStory-{case_id}-{story_id}.json"
)
# ==================== 发布模块补充方法 ====================
def create_release(
self,
product_id: str,
name: str,
branch: str = "0",
build: str = "",
date: str = "",
desc: str = "",
) -> Tuple[bool, Dict]:
"""创建发布(老 API)
Args:
product_id: 产品ID
name: 发布名称
branch: 分支ID,默认 "0"
build: 版本ID
date: 发布日期 (YYYY-MM-DD)
desc: 发布描述
Returns:
(success, result)
Example:
>>> success, result = client.create_release(
... product_id="1",
... name="V1.0",
... build="1",
... date="2026-04-01"
... )
"""
data = {
"product": product_id,
"name": name,
"branch": branch,
}
if build:
data["build"] = build
if date:
data["date"] = date
if desc:
data["desc"] = desc
return self.old_request(
"POST", f"/release-create-{product_id}-{branch}.json", data
)
def edit_release(self, release_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑发布(老 API)
Args:
release_id: 发布ID
**kwargs: 要修改的字段 (name, date, build, desc, status, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.edit_release("1", name="V1.0.1", status="released")
"""
return self.old_request("POST", f"/release-edit-{release_id}.json", kwargs)
def get_release(self, release_id: str) -> Tuple[bool, Dict]:
"""获取发布详情(老 API)
Args:
release_id: 发布ID
Returns:
(success, release_info) 发布详情
Example:
>>> success, release = client.get_release("1")
>>> print(f"发布名: {release['name']}")
"""
success, result = self.old_request("GET", f"/release-view-{release_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("release", {})
return False, {}
def delete_release(self, release_id: str) -> Tuple[bool, Dict]:
"""删除发布(老 API)
Args:
release_id: 发布ID
Returns:
(success, result)
Example:
>>> success, result = client.delete_release("1")
"""
return self.old_request("GET", f"/release-delete-{release_id}-yes.json")
def link_release_story(
self, release_id: str, story_ids: List[str]
) -> Tuple[bool, Dict]:
"""发布关联需求(老 API)
Args:
release_id: 发布ID
story_ids: 需求ID列表
Returns:
(success, result)
Example:
>>> success, result = client.link_release_story("1", ["5", "6", "7"])
"""
data = {}
for i, story_id in enumerate(story_ids):
data[f"stories[{i}]"] = story_id
return self.old_request("POST", f"/release-linkStory-{release_id}.json", data)
def unlink_release_story(self, release_id: str, story_id: str) -> Tuple[bool, Dict]:
"""取消发布关联需求(老 API)
Args:
release_id: 发布ID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_release_story("1", "5")
"""
return self.old_request(
"GET", f"/release-unlinkStory-{release_id}-{story_id}.json"
)
def link_release_bug(
self, release_id: str, bug_ids: List[str], bug_type: str = "bug"
) -> Tuple[bool, Dict]:
"""发布关联Bug(老 API)
Args:
release_id: 发布ID
bug_ids: BugID列表
bug_type: Bug类型 (bug, leftBug)
Returns:
(success, result)
Example:
>>> success, result = client.link_release_bug("1", ["10", "11"])
"""
data = {}
for i, bug_id in enumerate(bug_ids):
data[f"bugs[{i}]"] = bug_id
return self.old_request(
"POST", f"/release-linkBug-{release_id}-all-all-bug.json", data
)
def unlink_release_bug(
self, release_id: str, bug_id: str, bug_type: str = "bug"
) -> Tuple[bool, Dict]:
"""取消发布关联Bug(老 API)
Args:
release_id: 发布ID
bug_id: BugID
bug_type: Bug类型 (bug, leftBug)
Returns:
(success, result)
Example:
>>> success, result = client.unlink_release_bug("1", "10")
"""
return self.old_request(
"GET", f"/release-unlinkBug-{release_id}-{bug_id}-{bug_type}.json"
)
# ==================== 版本模块补充方法 ====================
def create_build(
self,
project_id: str,
name: str,
product_id: str = "0",
build: str = "",
desc: str = "",
) -> Tuple[bool, Dict]:
"""创建版本(老 API)
Args:
project_id: 项目ID
name: 版本名称
product_id: 产品ID,默认 "0"
build: 版本号
desc: 版本描述
Returns:
(success, result)
Example:
>>> success, result = client.create_build(
... project_id="1",
... name="Sprint1 Build",
... product_id="1",
... build="1.0.0"
... )
"""
data = {
"project": project_id,
"name": name,
}
if product_id:
data["product"] = product_id
if build:
data["build"] = build
if desc:
data["desc"] = desc
return self.old_request(
"POST", f"/build-create-{project_id}-{product_id}.json", data
)
def edit_build(self, build_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑版本(老 API)
Args:
build_id: 版本ID
**kwargs: 要修改的字段 (name, build, desc, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.edit_build("1", name="New Build Name")
"""
return self.old_request("POST", f"/build-edit-{build_id}.json", kwargs)
def get_build(self, build_id: str) -> Tuple[bool, Dict]:
"""获取版本详情(老 API)
Args:
build_id: 版本ID
Returns:
(success, build_info) 版本详情
Example:
>>> success, build = client.get_build("1")
>>> print(f"版本名: {build['name']}")
"""
success, result = self.old_request("GET", f"/build-view-{build_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("build", {})
return False, {}
def delete_build(self, build_id: str) -> Tuple[bool, Dict]:
"""删除版本(老 API)
Args:
build_id: 版本ID
Returns:
(success, result)
Example:
>>> success, result = client.delete_build("1")
"""
return self.old_request("GET", f"/build-delete-{build_id}-yes.json")
def link_build_story(
self, build_id: str, story_ids: List[str]
) -> Tuple[bool, Dict]:
"""版本关联需求(老 API)
Args:
build_id: 版本ID
story_ids: 需求ID列表
Returns:
(success, result)
Example:
>>> success, result = client.link_build_story("1", ["5", "6"])
"""
data = {}
for i, story_id in enumerate(story_ids):
data[f"stories[{i}]"] = story_id
return self.old_request("POST", f"/build-linkStory-{build_id}.json", data)
def unlink_build_story(self, build_id: str, story_id: str) -> Tuple[bool, Dict]:
"""取消版本关联需求(老 API)
Args:
build_id: 版本ID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_build_story("1", "5")
"""
return self.old_request("GET", f"/build-unlinkStory-{story_id}-yes.json")
def link_build_bug(self, build_id: str, bug_ids: List[str]) -> Tuple[bool, Dict]:
"""版本关联Bug(老 API)
Args:
build_id: 版本ID
bug_ids: BugID列表
Returns:
(success, result)
Example:
>>> success, result = client.link_build_bug("1", ["10", "11"])
"""
data = {}
for i, bug_id in enumerate(bug_ids):
data[f"bugs[{i}]"] = bug_id
return self.old_request("POST", f"/build-linkBug-{build_id}.json", data)
def unlink_build_bug(self, build_id: str, bug_id: str) -> Tuple[bool, Dict]:
"""取消版本关联Bug(老 API)
Args:
build_id: 版本ID
bug_id: BugID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_build_bug("1", "10")
"""
return self.old_request("GET", f"/build-unlinkBug-{build_id}-{bug_id}.json")
# ==================== 计划模块补充方法 ====================
def get_plan(self, plan_id: str) -> Tuple[bool, Dict]:
"""获取计划详情(老 API)
Args:
plan_id: 计划ID
Returns:
(success, plan_info) 计划详情
Example:
>>> success, plan = client.get_plan("1")
>>> print(f"计划名: {plan['title']}")
"""
success, result = self.old_request("GET", f"/productplan-view-{plan_id}.json")
if success and "data" in result:
data = json.loads(result["data"])
return True, data.get("plan", {})
return False, {}
def edit_plan(self, plan_id: str, **kwargs) -> Tuple[bool, Dict]:
"""编辑计划(老 API)
Args:
plan_id: 计划ID
**kwargs: 要修改的字段 (title, begin, end, desc, etc.)
Returns:
(success, result)
Example:
>>> success, result = client.edit_plan("1", title="新计划名", begin="2026-04-01")
"""
return self.old_request("POST", f"/productplan-edit-{plan_id}.json", kwargs)
def link_plan_story(self, plan_id: str, story_ids: List[str]) -> Tuple[bool, Dict]:
"""计划关联需求(老 API)
Args:
plan_id: 计划ID
story_ids: 需求ID列表
Returns:
(success, result)
Example:
>>> success, result = client.link_plan_story("1", ["5", "6", "7"])
"""
data = {}
for i, story_id in enumerate(story_ids):
data[f"stories[{i}]"] = story_id
return self.old_request("POST", f"/productplan-linkStory-{plan_id}.json", data)
def unlink_plan_story(self, plan_id: str, story_id: str) -> Tuple[bool, Dict]:
"""取消计划关联需求(老 API)
Args:
plan_id: 计划ID
story_id: 需求ID
Returns:
(success, result)
Example:
>>> success, result = client.unlink_plan_story("1", "5")
"""
return self.old_request(
"GET", f"/productplan-unlinkStory-{plan_id}-{story_id}.json"
)
def read_credentials() -> Optional[Dict[str, str]]:
"""从 TOOLS.md 读取禅道凭证"""
tools_path = Path(__file__).parent.parent / "TOOLS.md"
if not tools_path.exists():
return None
content = tools_path.read_text(encoding="utf-8")
# 查找禅道配置部分
zentao_section_start = -1
zentao_section_end = -1
lines = content.split("\n")
for i, line in enumerate(lines):
if "## 禅道 API" in line or "## 禅道" in line:
zentao_section_start = i
elif (
zentao_section_start >= 0
and line.strip().startswith("## ")
and zentao_section_start not in [i]
):
zentao_section_end = i
break
if zentao_section_start < 0:
return None
# 提取禅道配置部分
if zentao_section_end < 0:
zentao_section = "\n".join(lines[zentao_section_start:])
else:
zentao_section = "\n".join(lines[zentao_section_start:zentao_section_end])
endpoint = None
username = None
password = None
for line in zentao_section.split("\n"):
line = line.strip()
if "API 地址" in line and ":" in line:
endpoint = line.split(":")[-1].strip().strip("*").strip()
elif "用户名" in line and ":" in line:
username = line.split(":")[-1].strip().strip("*").strip()
elif "密码" in line and ":" in line:
password = line.split(":")[-1].strip().strip("*").strip()
if endpoint and username and password:
return {"endpoint": endpoint, "username": username, "password": password}
return None
FILE:TOOLS.md
## 禅道 API
- **API 地址:**
- **用户名:**
- **密码:**
Fetch data from social, video, and news websites using OpenCLI by reusing Chrome login sessions without API keys.
---
name: opencli
description: Use OpenCLI to fetch data from websites like Twitter, Reddit, Bilibili, Zhihu, Xiaohongshu, YouTube, etc. Triggers: opencli, social media, twitter, reddit, bilibili, zhihu, xiaohongshu, youtube, weibo, hackernews, fetch website data.
license: MIT
version: 1.0.0
config:
dependencies:
- opencli (npm install -g @jackwener/opencli)
- Chrome with Browser Bridge extension
---
# OpenCLI Skill
通过 OpenCLI 从各种网站获取数据,无需 API 密钥,复用 Chrome 登录状态。
## 触发词
- `opencli` - 使用 OpenCLI 命令
- 社交媒体: `twitter`, `reddit`, `weibo`, `zhihu`, `xiaohongshu`, `jike`
- 视频平台: `bilibili`, `youtube`
- 资讯平台: `hackernews`, `bbc`, `reuters`, `linux-do`
- 其他: `v2ex`, `xueqiu`, `weread`, `stackoverflow`
## 前置要求
1. **安装 OpenCLI**: `npm install -g @jackwener/opencli`
2. **安装 Chrome 扩展**: Browser Bridge
3. **Chrome 已登录目标网站**
## 通用选项
```bash
opencli <site> <command> [options]
# 通用选项
--limit <n> # 限制返回数量
-f, --format # 输出格式: table, json, yaml, md, csv (默认 table)
-v, --verbose # 调试输出
```
## 命令完整列表
### antigravity (9 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `dump` | Dump the DOM to help AI understand the UI | - |
| `extract-code` | Extract multi-line code blocks from the current Antigravity conversation | - |
| `model` | Switch the active LLM model in Antigravity | `name` |
| `new` | Start a new conversation / clear context in Antigravity | - |
| `read` | Read the latest chat messages from Antigravity AI | `last` |
| `send` | Send a message to Antigravity AI via the internal Lexical editor | `message` |
| `serve` | - | - |
| `status` | Check Antigravity CDP connection and get current page state | - |
| `watch` | Stream new chat messages from Antigravity in real-time | - |
### apple-podcasts (5 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `episodes` | List recent episodes of an Apple Podcast (use ID from search) | `id`, `limit` |
| `search` | Search Apple Podcasts | `keyword`, `limit` |
| `top` | Top podcasts chart on Apple Podcasts | `limit`, `country` |
### barchart (4 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `flow` | Barchart unusual options activity / options flow | `type`, `limit` |
| `greeks` | Barchart options greeks overview (IV, delta, gamma, theta, vega) | `symbol`, `expiration`, `limit` |
| `options` | Barchart options chain with greeks, IV, volume, and open interest | `symbol`, `type`, `limit` |
| `quote` | Barchart stock quote with price, volume, and key metrics | `symbol` |
### bbc (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `news` | BBC News headlines (RSS) | `limit` |
### bilibili (12 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `download` | 下载B站视频(需要 yt-dlp) | `bvid`, `output`, `quality` |
| `dynamic` | Get Bilibili user dynamic feed | `limit` |
| `favorite` | 我的默认收藏夹 | `limit`, `page` |
| `feed` | 关注的人的动态时间线 | `limit`, `type` |
| `following` | 获取 Bilibili 用户的关注列表 | `uid`, `page`, `limit` |
| `history` | 我的观看历史 | `limit` |
| `hot` | B站热门视频 | `limit` (default: 20) |
| `me` | My Bilibili profile info | - |
| `ranking` | Get Bilibili video ranking board | `limit` |
| `search` | Search Bilibili videos or users | `keyword`, `type`, `page`, `limit` |
| `subtitle` | 获取 Bilibili 视频的字幕 | `bvid`, `lang` |
| `user-videos` | 查看指定用户的投稿视频 | `uid`, `limit`, `order`, `page` |
### boss (6 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `chatlist` | BOSS直聘查看聊天列表(招聘端) | `page`, `limit`, `job_id` |
| `chatmsg` | BOSS直聘查看与候选人的聊天消息 | `uid`, `page` |
| `detail` | BOSS直聘查看职位详情 | `security_id` |
| `resume` | BOSS直聘查看候选人简历(招聘端) | `uid` |
| `search` | BOSS直聘搜索职位 | `query`, `city`, `experience`, `degree`, `salary`, `industry`, `page`, `limit` |
| `send` | BOSS直聘发送聊天消息 | `uid`, `text` |
### chaoxing (2 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `assignments` | 学习通作业列表 | `course`, `status`, `limit` |
| `exams` | 学习通考试列表 | `course`, `status`, `limit` |
### chatgpt (5 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `ask` | Send a prompt and wait for the AI response (send + wait + read) | `text`, `timeout` |
| `new` | Open a new chat in ChatGPT Desktop App | - |
| `read` | Copy the most recent ChatGPT Desktop App response to clipboard and read it | - |
| `send` | Send a message to the active ChatGPT Desktop App window | `text` |
| `status` | Check if ChatGPT Desktop App is running natively on macOS | - |
### chatwise (9 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `ask` | Send a prompt and wait for the AI response | `text`, `timeout` |
| `export` | Export the current ChatWise conversation to a Markdown file | `output` |
| `history` | List conversation history in ChatWise sidebar | - |
| `model` | Get or switch the active AI model in ChatWise | `model_name` |
| `new` | Start a new conversation in ChatWise | - |
| `read` | Read the current ChatWise conversation history | - |
| `screenshot` | Capture a snapshot of the current ChatWise window | `output` |
| `send` | Send a message to the active ChatWise conversation | `text` |
| `status` | Check active CDP connection to ChatWise Desktop | - |
### codex (11 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `ask` | Send a prompt and wait for the AI response | `text`, `timeout` |
| `dump` | Dump the DOM and Accessibility tree of Codex for reverse-engineering | - |
| `export` | Export the current Codex conversation to a Markdown file | `output` |
| `extract-diff` | Extract visual code review diff patches from Codex | - |
| `history` | List recent conversation threads in Codex | - |
| `model` | Get or switch the currently active AI model in Codex Desktop | `model_name` |
| `new` | Start a new Codex conversation thread / isolated workspace | - |
| `read` | Read the contents of the current Codex conversation thread | - |
| `screenshot` | Capture a snapshot of the current Codex window | `output` |
| `send` | Send text/commands to the Codex AI composer | `text` |
| `status` | Check active CDP connection to OpenAI Codex App | - |
### coupang (2 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `add-to-cart` | Add a Coupang product to cart using logged-in browser session | `productId`, `url` |
| `search` | Search Coupang products with logged-in browser session | `query`, `page`, `limit`, `filter` |
### ctrip (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `search` | 携程旅行搜索 | `query`, `limit` |
### cursor (11 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `ask` | Send a prompt and wait for the AI response | `text`, `timeout` |
| `composer` | Send a prompt directly into Cursor Composer (Cmd+I shortcut) | `text` |
| `dump` | Dump the DOM and Accessibility tree of Cursor for reverse-engineering | - |
| `export` | Export the current Cursor conversation | `output` |
| `extract-code` | Extract multi-line code blocks from the current Cursor conversation | - |
| `history` | List recent chat sessions from the Cursor sidebar | - |
| `model` | Get or switch the currently active AI model in Cursor | `model_name` |
| `new` | Start a new Cursor chat or Composer session | - |
| `read` | Read the current Cursor chat/composer conversation history | - |
| `screenshot` | Capture a snapshot of the current Cursor window | `output` |
| `send` | Send a prompt directly into Cursor Composer/Chat | `text` |
| `status` | Check active CDP connection to Cursor AI Editor | - |
### discord-app (7 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `channels` | List channels in the current Discord server | - |
| `members` | List online members in the current Discord channel | - |
| `read` | Read recent messages from the active Discord channel | `count` |
| `search` | Search messages in the current Discord server/channel (Cmd+F) | `query` |
| `send` | Send a message in the active Discord channel | `text` |
| `servers` | List all Discord servers (guilds) in the sidebar | - |
| `status` | Check active CDP connection to Discord Desktop | - |
### feishu (5 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `new` | Create a new message or document in Feishu | - |
| `read` | Read the current chat content by selecting all and copying | - |
| `search` | Open Feishu global search and type a query (Cmd+K) | `query` |
| `send` | Send a message in the active Feishu (Lark) conversation | `text` |
| `status` | Check if Feishu (Lark) Desktop is running on macOS | - |
### grok (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `ask` | Send a message to Grok and get response | `prompt`, `timeout`, `new` |
### hackernews (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `top` | Hacker News top stories | `limit` (default: 20) |
### hf (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `top` | Top upvoted Hugging Face papers | - |
### jike (11 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `comment` | 评论即刻帖子 | `id`, `text` |
| `create` | 发布即刻动态 | `text` |
| `feed` | 即刻首页动态流 | `limit` |
| `like` | 点赞即刻帖子 | `id` |
| `notifications` | 即刻通知 | `limit` |
| `post` | 即刻帖子详情及评论 | `id` |
| `repost` | 转发即刻帖子 | `id`, `text` |
| `search` | 搜索即刻帖子 | `keyword`, `limit` |
| `topic` | 即刻话题/圈子帖子 | `id`, `limit` |
| `user` | 即刻用户动态 | `username`, `limit` |
### jimeng (2 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `generate` | 即梦AI 文生图 — 输入 prompt 生成图片 | `prompt`, `model`, `wait` |
| `history` | 即梦AI 查看最近生成的作品 | `limit` |
### linkedin (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `search` | Search LinkedIn jobs | `query`, `location`, `limit`, `start`, `details`, `company`, `experience_level`, `job_type`, `date_posted`, `remote` |
### linux-do (6 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `categories` | linux.do 分类列表 | `limit` |
| `category` | linux.do 分类内话题 | `slug`, `id`, `limit` |
| `hot` | linux.do 热门话题 | `limit`, `period` |
| `latest` | linux.do 最新话题 | `limit` |
| `search` | 搜索 linux.do | `keyword`, `limit` |
| `topic` | linux.do 帖子详情和回复 | `id` |
### neteasemusic (10 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `like` | Like/unlike the currently playing song | - |
| `lyrics` | Get the lyrics of the currently playing song | - |
| `next` | Skip to the next song | - |
| `play` | Toggle play/pause for the current song | - |
| `playing` | Get the currently playing song info | - |
| `playlist` | Show the current playback queue / playlist | - |
| `prev` | Go back to the previous song | - |
| `search` | Search for songs, artists, albums, or playlists | `query` |
| `status` | Check CDP connection to NeteaseMusic Desktop | - |
| `volume` | Get or set the volume level (0-100) | `level` |
### notion (8 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `export` | Export the current Notion page as Markdown | `output` |
| `favorites` | List pages from the Notion Favorites section in the sidebar | - |
| `new` | Create a new page in Notion | `title` |
| `read` | Read the content of the currently open Notion page | - |
| `search` | Search pages and databases in Notion via Quick Find (Cmd+P) | `query` |
| `sidebar` | List pages and databases from the Notion sidebar | - |
| `status` | Check active CDP connection to Notion Desktop | - |
| `write` | Append text content to the currently open Notion page | `text` |
### reddit (13 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `comment` | Post a comment on a Reddit post | `post_id`, `text` |
| `frontpage` | Reddit Frontpage / r/all | `limit` |
| `hot` | Reddit 热门帖子 | `subreddit`, `limit` |
| `popular` | Reddit Popular posts (/r/popular) | `limit` |
| `read` | Read a Reddit post and its comments | `post_id`, `sort`, `limit`, `depth`, `replies`, `max_length` |
| `save` | Save or unsave a Reddit post | `post_id`, `undo` |
| `saved` | Browse your saved Reddit posts | `limit` |
| `search` | Search Reddit Posts | `query`, `subreddit`, `sort`, `time`, `limit` |
| `subreddit` | Get posts from a specific Subreddit | `name`, `sort`, `time`, `limit` |
| `subscribe` | Subscribe or unsubscribe to a subreddit | `subreddit`, `undo` |
| `upvote` | Upvote or downvote a Reddit post | `post_id`, `direction` |
| `upvoted` | Browse your upvoted Reddit posts | `limit` |
| `user-comments` | View a Reddit user's comment history | `username`, `limit` |
| `user-posts` | View a Reddit user's submitted posts | `username`, `limit` |
| `user` | View a Reddit user profile | `username` |
### reuters (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `search` | Reuters 路透社新闻搜索 | `query`, `limit` |
### smzdm (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `search` | 什么值得买搜索好价 | `keyword`, `limit` |
### stackoverflow (4 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `bounties` | Active bounties on Stack Overflow | `limit` |
| `hot` | Hot Stack Overflow questions | `limit` |
| `search` | Search Stack Overflow questions | `query`, `limit` |
| `unanswered` | Top voted unanswered questions on Stack Overflow | `limit` |
### twitter (19 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `accept` | Auto-accept DM requests containing specific keywords | `keyword`, `max` |
| `article` | Fetch a Twitter Article (long-form content) and export as Markdown | `tweet_id` |
| `bookmark` | Bookmark a tweet | `url` |
| `bookmarks` | Fetch Twitter/X bookmarks | `limit` |
| `delete` | Delete a specific tweet by URL | `url` |
| `download` | 下载 Twitter/X 媒体(图片和视频) | `username`, `tweet-url`, `limit`, `output` |
| `follow` | Follow a Twitter user | `username` |
| `followers` | Get accounts following a Twitter/X user | `user`, `limit` |
| `following` | Get accounts a Twitter/X user is following | `user`, `limit` |
| `like` | Like a specific tweet | `url` |
| `notifications` | Get Twitter/X notifications | `limit` |
| `post` | Post a new tweet/thread | `text` |
| `profile` | Fetch a Twitter user profile (bio, stats, etc.) | `username` |
| `reply-dm` | Send a message to recent DM conversations | `text`, `max`, `skip-replied` |
| `reply` | Reply to a specific tweet | `url`, `text` |
| `search` | Search Twitter/X for tweets | `query`, `limit` |
| `thread` | Get a tweet thread (original + all replies) | `tweet_id`, `limit` |
| `timeline` | Fetch Twitter Home Timeline | `limit` |
| `trending` | Twitter/X trending topics | `limit` |
| `unbookmark` | Remove a tweet from bookmarks | `url` |
| `unfollow` | Unfollow a Twitter user | `username` |
### v2ex (6 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `daily` | V2EX 每日签到并领取铜币 | - |
| `hot` | V2EX 热门话题 | `limit` |
| `latest` | V2EX 最新话题 | `limit` |
| `me` | V2EX 获取个人资料 (余额/未读提醒) | - |
| `notifications` | V2EX 获取提醒 (回复/由于) | `limit` |
| `topic` | V2EX 主题详情和回复 | `id` |
### wechat (6 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `chats` | Open the WeChat chats panel (conversation list) | - |
| `contacts` | Open the WeChat contacts panel | - |
| `read` | Read the current chat content by selecting all and copying | - |
| `search` | Open WeChat search and type a query (find contacts or messages) | `query` |
| `send` | Send a message in the active WeChat conversation via clipboard paste | `text` |
| `status` | Check if WeChat Desktop is running on macOS | - |
### weibo (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `hot` | 微博热搜 | `limit` |
### weread (8 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `book` | View book details on WeRead | `bookId` |
| `highlights` | List your highlights (underlines) in a book | `bookId`, `limit` |
| `notebooks` | List books that have highlights or notes | - |
| `notes` | List your notes (thoughts) on a book | `bookId`, `limit` |
| `ranking` | WeRead book rankings by category | `category`, `limit` |
| `search` | Search books on WeRead | `keyword`, `limit` |
| `shelf` | List books on your WeRead bookshelf | `limit` |
### xiaohongshu (15 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `creator-note-detail` | 小红书单篇笔记详情页数据 | `note_id` |
| `creator-notes-summary` | 小红书最近笔记批量摘要 | `limit` |
| `creator-notes` | 小红书创作者笔记列表 + 每篇数据 | `limit` |
| `creator-profile` | 小红书创作者账号信息 (粉丝/关注/获赞/成长等级) | - |
| `creator-stats` | 小红书创作者数据总览 (观看/点赞/收藏/评论/分享/涨粉,含每日趋势) | `period` |
| `download` | 下载小红书笔记中的图片和视频 | `note_id`, `output` |
| `feed` | 小红书首页推荐 Feed | `limit` |
| `notifications` | 小红书通知 (mentions/likes/connections) | `type`, `limit` |
| `search` | 搜索小红书笔记 | `keyword`, `limit` |
| `user` | Get public notes from a Xiaohongshu user profile | `id`, `limit` |
### xiaoyuzhou (5 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `episode` | View details of a Xiaoyuzhou podcast episode | `id` |
| `podcast-episodes` | List recent episodes of a Xiaoyuzhou podcast (up to 15, SSR limit) | `id`, `limit` |
| `podcast` | View a Xiaoyuzhou podcast profile | `id` |
### xueqiu (6 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `feed` | 获取雪球首页时间线(关注用户的动态) | `page`, `limit` |
| `hot-stock` | 获取雪球热门股票榜 | `limit`, `type` |
| `hot` | 获取雪球热门动态 | `limit` |
| `search` | 搜索雪球股票(代码或名称) | `query`, `limit` |
| `stock` | 获取雪球股票实时行情 | `symbol` |
| `watchlist` | 获取雪球自选股列表 | `category`, `limit` |
### yahoo-finance (1 command)
| 命令 | 说明 | 参数 |
|------|------|------|
| `quote` | Yahoo Finance 股票行情 | `symbol` |
### youtube (5 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `search` | Search YouTube videos | `query`, `limit` |
| `transcript` | Get YouTube video transcript/subtitles | - |
| `video` | Get YouTube video metadata (title, views, description, etc.) | `url` |
### zhihu (4 commands)
| 命令 | 说明 | 参数 |
|------|------|------|
| `download` | 导出知乎文章为 Markdown 格式 | `url`, `output`, `download-images` |
| `hot` | 知乎热榜 | `limit` |
| `question` | 知乎问题详情和回答 | `id`, `limit` |
| `search` | 知乎搜索 | `keyword`, `limit` |
---
## 输出格式
| 格式 | 说明 | 使用场景 |
|------|------|----------|
| `table` | 表格格式(默认) | 人类阅读 |
| `json` | JSON 格式 | 程序处理、数据提取 |
| `yaml` | YAML 格式 | 配置文件、数据序列化 |
| `md` | Markdown 格式 | 文档生成 |
| `csv` | CSV 格式 | 数据分析、Excel 导入 |
## 诊断命令
```bash
# 检查 Browser Bridge 连接状态
opencli doctor
# 实时测试浏览器连接
opencli doctor --live
# 交互式设置
opencli setup
# 列出所有可用命令
opencli list
```
## 注意事项
1. **登录状态**: 浏览器命令复用 Chrome 登录状态,确保已在 Chrome 中登录目标网站
2. **Chrome 扩展**: 必须安装 Browser Bridge 扩展
3. **命令模式**:
- `[public]` - 公开 API,无需登录
- `[cookie]` - 需要 Chrome 登录状态
- `[ui]` - UI 自动化,需要应用在前台运行
4. **输出解析**: 使用 `-f json` 格式便于程序解析
5. **调试**: 使用 `-v` 参数查看详细日志通过 PinchTab HTTP API 控制无头或有头 Chrome 浏览器,用于网页自动化、爬虫、表单填充、导航、截图和数据提取
---
name: pinchtab
description: 通过 PinchTab HTTP API 控制无头或有头 Chrome 浏览器,用于网页自动化、爬虫、表单填充、导航、截图和数据提取
metadata:
short-description: 浏览器自动化 via PinchTab HTTP API
---
# PinchTab Skill
快速、轻量级的 AI 代理浏览器控制工具,通过 HTTP + 可访问性树实现。
## 安全说明
PinchTab 完全在本地运行,不联系外部服务、不发送遥测数据。但它控制真实的 Chrome 实例——如果指向包含已保存登录信息的配置文件,代理可以访问认证网站。
**最佳实践:**
- 始终使用专用的空配置文件
- 暴露 API 时设置 `BRIDGE_TOKEN`
- 不要将你的日常 Chrome 配置文件指向 PinchTab
## 快速开始
### 1. 启动 PinchTab
```bash
# 无头模式(默认)- 无可见窗口
pinchtab &
# 有头模式 - 可见 Chrome 窗口,便于调试
BRIDGE_HEADLESS=false pinchtab &
# 带认证令牌
BRIDGE_TOKEN="your-secret-token" pinchtab &
# 自定义端口
BRIDGE_PORT=8080 pinchtab &
```
默认:**端口 9867**,无需认证(本地)。设置 `BRIDGE_TOKEN` 用于远程访问。
### 2. 代理工作流(30 秒模式)
```bash
# 1. 启动 PinchTab(持续运行,本地 :9867)
pinchtab &
# 2. 在代理中遵循此循环:
# a) 导航到 URL
# b) 快照页面(获取 refs 如 e0, e5, e12)
# c) 对 ref 执行操作(点击 e5,输入 e12 "搜索文本")
# d) 再次快照查看结果
# e) 重复步骤 c-d 直到完成
```
**就这么简单。** Refs 是稳定的——每次操作前不需要重新快照,只在页面显著变化时快照。
## 核心工作流
典型的代理循环:
1. **导航** 到 URL
2. **快照** 可访问性树(获取 refs)
3. **执行** 操作(点击、输入、按键)
4. **再次快照** 查看结果
### CLI 示例
```bash
# 导航
pinchtab nav https://example.com
# 获取交互式元素(紧凑格式)
pinchtab snap -i -c
# 点击元素
pinchtab click e5
# 输入文本
pinchtab type e12 hello world
# 按键
pinchtab press Enter
# 提取文本(~1K tokens)
pinchtab text
# 截图
pinchtab ss -o page.jpg
# 执行 JavaScript
pinchtab eval "document.title"
# 导出 PDF
pinchtab pdf --tab TAB_ID -o page.pdf
```
## HTTP API 示例
### 导航
```bash
curl -X POST http://localhost:9867/navigate \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
```
### 获取快照
```bash
# 完整快照
curl http://localhost:9867/snapshot
# 仅交互式元素(按钮、链接、输入)
curl "http://localhost:9867/snapshot?filter=interactive"
# 紧凑格式(节省 56-64% tokens)
curl "http://localhost:9867/snapshot?format=compact"
# 仅变化部分(多步骤工作流)
curl "http://localhost:9867/snapshot?diff=true"
```
### 执行操作
```bash
# 点击
curl -X POST http://localhost:9867/action \
-H "Content-Type: application/json" \
-d '{"kind": "click", "ref": "e5"}'
# 输入
curl -X POST http://localhost:9867/action \
-H "Content-Type: application/json" \
-d '{"kind": "type", "ref": "e12", "text": "hello"}'
# 按键
curl -X POST http://localhost:9867/action \
-H "Content-Type: application/json" \
-d '{"kind": "press", "key": "Enter"}'
```
### 提取文本
```bash
# 可读文本(~800 tokens)
curl http://localhost:9867/text
# 原始 HTML
curl "http://localhost:9867/text?mode=raw"
```
### 截图
```bash
curl -X POST http://localhost:9867/screenshot \
-H "Content-Type: application/json" \
-d '{"format": "jpeg", "quality": 80}' \
--output page.jpg
```
### 多标签页管理
```bash
# 创建新标签页
curl -X POST http://localhost:9867/tabs \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}'
# 切换标签页
curl -X POST http://localhost:9867/tabs/switch \
-H "Content-Type: application/json" \
-d '{"tabId": "TAB_123"}'
# 关闭标签页
curl -X DELETE http://localhost:9867/tabs/TAB_123
```
## 快照示例
调用 `/snapshot` 后,获得页面的可访问性树 JSON:
```json
{
"refs": [
{"id": "e0", "role": "link", "text": "Sign In", "selector": "a[href='/login']"},
{"id": "e1", "role": "textbox", "label": "Email", "selector": "input[name='email']"},
{"id": "e2", "role": "button", "text": "Submit", "selector": "button[type='submit']"}
],
"text": "... 页面的可读文本版本 ...",
"title": "Login Page"
}
```
然后对 refs 执行操作:`click e0`,`type e1 "[email protected]"`,`press e2 Enter`。
## Token 成本指南
| 方法 | 典型 tokens | 使用场景 |
|---|---|---|
| `/text` | ~800 | 阅读页面内容 |
| `/snapshot?filter=interactive` | ~3,600 | 查找要点击的按钮/链接 |
| `/snapshot?diff=true` | 变化量 | 多步骤工作流(仅变化) |
| `/snapshot?format=compact` | 减少 56-64% | 每行一个节点,最佳效率 |
| `/snapshot` | ~10,500 | 完整页面理解 |
| `/screenshot` | ~2K (vision) | 视觉验证 |
| `/tabs/{id}/pdf` | 0 (二进制) | 导出 PDF(无 token 成本) |
**策略**:从 `?filter=interactive&format=compact` 开始。后续快照使用 `?diff=true`。仅需要可读内容时使用 `/text`。仅在需要时使用完整 `/snapshot`。
## 代理优化
**2026 年 2 月验证**:测试发现关键模式,实现可靠、节省 token 的爬虫。
### 3 秒模式
导航后等待 3 秒再快照:
```bash
curl -X POST http://localhost:9867/navigate \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com"}' && \
sleep 3 && \
curl http://localhost:9867/snapshot | jq
```
**Token 节省**:93% 减少(3,842 → 272 tokens)。
## 提示
- **多标签页时始终显式传递 `tabId`**
- Refs 在快照和操作之间稳定——点击前无需重新快照
- 导航或页面重大变化后,获取新快照获取新鲜 refs
- PinchTab 持久化会话——标签页在重启后存活(用 `BRIDGE_NO_RESTORE=true` 禁用)
- Chrome 配置文件持久化——cookies/登录信息在运行间保留
- 阅读密集型任务使用 `BRIDGE_BLOCK_IMAGES=true` 或 `"blockImages": true`
- **导航后等待 3+ 秒再快照**——Chrome 需要时间渲染 2000+ 可访问性树节点
## 环境变量
```bash
# 绑定地址(默认 127.0.0.1)
BRIDGE_BIND=127.0.0.1
# 认证令牌(默认无)
BRIDGE_TOKEN="your-secret-token"
# 端口(默认 9867)
BRIDGE_PORT=9867
# 无头模式(默认 true)
BRIDGE_HEADLESS=false
# 配置文件路径
BRIDGE_PROFILE=~/.pinchtab/automation-profile
# 阻止图片(节省带宽)
BRIDGE_BLOCK_IMAGES=true
# 禁用会话恢复
BRIDGE_NO_RESTORE=true
```
## 完整文档
- [API 参考](references/api.md) - 完整 HTTP API
- [配置文件](references/profiles.md) - 配置文件管理
- [环境变量](references/env.md) - 所有配置选项
FILE:TRUST.md
# PinchTab 安全模型
## 本地运行
PinchTab 完全在本地运行:
- 不联系外部服务
- 不发送遥测数据
- 不外泄数据
## 风险
PinchTab 控制真实的 Chrome 实例,存在以下风险:
1. **配置文件访问** - 如果指向包含已保存登录信息的配置文件,代理可以访问认证网站
2. **API 暴露** - 如果暴露到公网 without 认证,任何人都可以控制你的浏览器
3. **恶意网站** - 代理可能访问恶意网站,导致 XSS 或其他攻击
## 最佳实践
### 1. 使用专用配置文件
```bash
# 创建新的空配置文件
BRIDGE_PROFILE=~/.pinchtab/automation-profile pinchtab &
```
**不要**使用你的日常 Chrome 配置文件。
### 2. 设置认证令牌
```bash
# 暴露 API 时始终设置令牌
BRIDGE_TOKEN="your-strong-secret-token" pinchtab &
```
### 3. 绑定到本地
```bash
# 默认绑定到 127.0.0.1(仅本地访问)
BRIDGE_BIND=127.0.0.1 pinchtab &
```
**不要**暴露到 `0.0.0.0` 除非必要。
### 4. 防火墙规则
如果必须暴露到网络:
```bash
# 仅允许特定 IP
ufw allow from 192.168.1.100 to any port 9867
```
### 5. 阻止图片
节省带宽并减少攻击面:
```bash
BRIDGE_BLOCK_IMAGES=true pinchtab &
```
## 检查清单
- [ ] 使用专用空配置文件
- [ ] 设置 `BRIDGE_TOKEN`
- [ ] 绑定到 `127.0.0.1`
- [ ] 不使用日常 Chrome 配置文件
- [ ] 定期清理配置文件数据
- [ ] 监控 API 访问日志
## 事件响应
如果怀疑安全事件:
1. 停止 PinchTab:`pkill pinchtab`
2. 删除配置文件:`rm -rf ~/.pinchtab/automation-profile`
3. 更改所有可能泄露的密码
4. 检查浏览器扩展和保存的密码
FILE:references/api.md
# PinchTab API 参考
完整 HTTP API 文档。
## 基础 URL
```
http://localhost:9867
```
## 认证
如果设置了 `BRIDGE_TOKEN`,所有请求需要:
```
Authorization: Bearer YOUR_TOKEN
```
## 端点
### POST /navigate
导航到 URL。
**请求:**
```json
{
"url": "https://example.com",
"blockImages": false,
"stealth": true
}
```
**响应:**
```json
{
"tabId": "TAB_123",
"success": true
}
```
### GET /snapshot
获取页面可访问性树快照。
**参数:**
- `filter` - `interactive` 仅交互式元素
- `format` - `compact` 紧凑格式
- `diff` - `true` 仅变化
- `tabId` - 指定标签页
**响应:**
```json
{
"refs": [...],
"text": "...",
"title": "..."
}
```
### POST /action
执行操作。
**请求:**
```json
{
"kind": "click",
"ref": "e5",
"tabId": "TAB_123"
}
```
**操作类型:**
- `click` - 点击
- `type` - 输入文本
- `press` - 按键
- `focus` - 聚焦
- `hover` - 悬停
- `scroll` - 滚动
### GET /text
提取页面文本。
**参数:**
- `mode` - `readable` (默认) 或 `raw`
- `tabId` - 指定标签页
### POST /screenshot
截图。
**请求:**
```json
{
"format": "jpeg",
"quality": 80,
"fullPage": true
}
```
### POST /tabs
创建新标签页。
**请求:**
```json
{
"url": "https://example.com"
}
```
### POST /tabs/switch
切换标签页。
**请求:**
```json
{
"tabId": "TAB_123"
}
```
### DELETE /tabs/{id}
关闭标签页。
### POST /eval
执行 JavaScript。
**请求:**
```json
{
"script": "document.title",
"tabId": "TAB_123"
}
```
### POST /tabs/{id}/pdf
导出 PDF。
**请求:**
```json
{
"landscape": false,
"printBackground": true,
"headerTemplate": "<div>Header</div>",
"footerTemplate": "<div>Footer</div>"
}
```
FILE:references/profiles.md
# 配置文件管理
配置文件存储浏览器状态(cookies、历史、本地存储)。
## 创建配置文件
```bash
# 使用新配置文件启动
BRIDGE_PROFILE=~/.pinchtab/work-profile pinchtab &
```
## 配置文件位置
- **macOS/Linux**: `~/.pinchtab/<profile-name>`
- **Windows**: `%USERPROFILE%\.pinchtab\<profile-name>`
## 多配置文件
```bash
# 实例 1 - 工作配置文件
BRIDGE_PROFILE=~/.pinchtab/work BRIDGE_PORT=9867 pinchtab &
# 实例 2 - 个人配置文件
BRIDGE_PROFILE=~/.pinchtab/personal BRIDGE_PORT=9868 pinchtab &
```
## 配置文件隔离
每个配置文件完全隔离:
- Cookies
- 本地存储
- 会话存储
- 浏览器历史
- 保存的密码(如果启用)
## 清理配置文件
```bash
# 删除配置文件
rm -rf ~/.pinchtab/work-profile
```
## 最佳实践
1. **自动化专用** - 为自动化任务创建空配置文件
2. **定期清理** - 定期删除并重建配置文件
3. **不要共享** - 每个用户/任务使用独立配置文件
FILE:references/env.md
# 环境变量参考
所有 PinchTab 配置环境变量。
## 网络
| 变量 | 默认 | 描述 |
|---|---|---|
| `BRIDGE_BIND` | `127.0.0.1` | 绑定地址 |
| `BRIDGE_PORT` | `9867` | 监听端口 |
| `BRIDGE_TOKEN` | 无 | API 认证令牌 |
## 浏览器
| 变量 | 默认 | 描述 |
|---|---|---|
| `BRIDGE_HEADLESS` | `true` | 无头模式 |
| `BRIDGE_PROFILE` | 默认配置文件 | 配置文件路径 |
| `BRIDGE_CHROME_PATH` | 自动检测 | Chrome 可执行文件路径 |
| `BRIDGE_BLOCK_IMAGES` | `false` | 阻止图片加载 |
## 会话
| 变量 | 默认 | 描述 |
|---|---|---|
| `BRIDGE_NO_RESTORE` | `false` | 禁用会话恢复 |
| `BRIDGE_NO_SANDBOX` | `false` | 禁用 Chrome 沙箱 |
## 日志
| 变量 | 默认 | 描述 |
|---|---|---|
| `BRIDGE_LOG_LEVEL` | `info` | 日志级别 (debug, info, warn, error) |
| `BRIDGE_LOG_FILE` | 无 | 日志文件路径 |
## 示例
```bash
# 完整配置
BRIDGE_BIND=127.0.0.1 \
BRIDGE_PORT=9867 \
BRIDGE_TOKEN="my-secret" \
BRIDGE_HEADLESS=true \
BRIDGE_PROFILE=~/.pinchtab/auto \
BRIDGE_BLOCK_IMAGES=true \
BRIDGE_LOG_LEVEL=debug \
pinchtab &
```