245 lines
14 KiB
JavaScript
245 lines
14 KiB
JavaScript
const BASE = 'http://localhost:8080/api/v1'
|
|
|
|
async function api(path, options = {}) {
|
|
const res = await fetch(`${BASE}${path}`, options)
|
|
const text = await res.text()
|
|
let json = null
|
|
try { json = JSON.parse(text) } catch { /* empty body */ }
|
|
if (!res.ok) {
|
|
throw new Error(`${options.method || 'GET'} ${path} -> ${res.status} ${text}`)
|
|
}
|
|
return json
|
|
}
|
|
|
|
function auth(token) {
|
|
return { 'content-type': 'application/json', authorization: `Bearer ${token}` }
|
|
}
|
|
|
|
const daysFromNow = (n) => {
|
|
const d = new Date(Date.now() + n * 86400000)
|
|
const pad = (x) => String(x).padStart(2, '0')
|
|
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`
|
|
}
|
|
|
|
const issues = [
|
|
{
|
|
title: '「用户管理」批量导入用户时部门字段校验缺失',
|
|
description: '批量导入 Excel 时,部门字段为空或填写错误也能导入成功,导致用户归属部门错乱,需增加必填与有效性校验。',
|
|
status: 'draft', priority: 'high', phase: '基本设计', subProject: '用户管理子系统',
|
|
category: '功能缺陷', impactLevel: '较高', impactScope: '影响全部用户',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 2, deadline: daysFromNow(10),
|
|
},
|
|
{
|
|
title: '权限控制子系统操作日志字段说明文档缺失',
|
|
description: '操作日志接口返回字段(requestId、clientIp、duration)缺少字段说明,开发对接困难,需补齐接口文档。',
|
|
status: 'draft', priority: 'medium', phase: '详细设计', subProject: '权限控制子系统',
|
|
category: '文档错误', impactLevel: '一般', impactScope: '仅本页面',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 3, deadline: daysFromNow(12),
|
|
},
|
|
{
|
|
title: '用户列表页在高分辨率下表格布局错位',
|
|
description: '2560x1440 分辨率下用户列表表格列宽挤压错位,操作按钮被遮挡,需调整弹性布局。',
|
|
status: 'draft', priority: 'low', phase: '基本设计', subProject: '用户管理子系统',
|
|
category: 'UI/UX问题', impactLevel: '轻微', impactScope: '影响部分模块',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 4, deadline: daysFromNow(14),
|
|
},
|
|
{
|
|
title: '报表导出超时:5万行数据接口响应超过60秒',
|
|
description: '导出 5 万行报表数据时接口耗时超过 60 秒,前端请求超时,需改为异步导出或分批流式输出。',
|
|
status: 'pending', priority: 'urgent', phase: '综合测试 (ST)', subProject: '数据报表子系统',
|
|
category: '性能问题', impactLevel: '严重', impactScope: '影响全部用户',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 2, deadline: daysFromNow(-2),
|
|
},
|
|
{
|
|
title: '越权访问:普通用户可调用管理员角色接口',
|
|
description: '使用普通账号登录后,直接访问 /admin/* 接口返回 200,权限过滤未生效,存在越权风险。',
|
|
status: 'pending', priority: 'urgent', phase: '结合测试 (IT)', subProject: '权限控制子系统',
|
|
category: '安全漏洞', impactLevel: '严重', impactScope: '影响全部用户',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 2, deadline: daysFromNow(-1),
|
|
},
|
|
{
|
|
title: '忘记密码流程未发送重置邮件',
|
|
description: '点击「忘记密码」并提交邮箱后未收到重置邮件,邮件服务异常但无错误提示,用户无法自助找回密码。',
|
|
status: 'pending', priority: 'medium', phase: '单体测试', subProject: '用户管理子系统',
|
|
category: '功能缺陷', impactLevel: '一般', impactScope: '仅本页面',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 3, deadline: daysFromNow(-1),
|
|
},
|
|
{
|
|
title: '角色权限勾选后未实时生效,需刷新页面',
|
|
description: '修改角色权限并保存后,对应账号重新登录仍显示旧菜单,需强制刷新浏览器才能生效。',
|
|
status: 'pending', priority: 'medium', phase: '详细设计', subProject: '权限控制子系统',
|
|
category: '功能缺陷', impactLevel: '一般', impactScope: '影响部分模块',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 2, deadline: daysFromNow(5),
|
|
},
|
|
{
|
|
title: '数据报表子系统接口文档缺少分页参数说明',
|
|
description: '报表查询接口文档未说明 page/pageSize 参数默认值与上限,前端翻页按 20 条处理与后端默认值不一致。',
|
|
status: 'pending', priority: 'low', phase: '基本设计', subProject: '数据报表子系统',
|
|
category: '文档错误', impactLevel: '轻微', impactScope: '仅本页面',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 3, deadline: daysFromNow(7),
|
|
},
|
|
{
|
|
title: '登录接口存在暴力破解风险,无验证码与限流',
|
|
description: '登录接口连续失败无次数限制、无验证码、无 IP 限流,可被脚本暴力破解弱口令账号。',
|
|
status: 'in_progress', priority: 'urgent', phase: '综合测试 (ST)', subProject: '用户管理子系统',
|
|
category: '安全漏洞', impactLevel: '严重', impactScope: '影响全部用户',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 2, deadline: daysFromNow(-3),
|
|
},
|
|
{
|
|
title: '权限复制功能在子菜单继承时丢失父级权限',
|
|
description: '将角色 A 权限复制给角色 B 后,B 的某些子菜单有权限但父级菜单无权限,导致页面 403。',
|
|
status: 'in_progress', priority: 'high', phase: '结合测试 (IT)', subProject: '权限控制子系统',
|
|
category: '功能缺陷', impactLevel: '较高', impactScope: '影响部分模块',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 2, deadline: daysFromNow(2),
|
|
agent: { goal: '分析权限复制子菜单继承丢失父级权限问题并生成对应方案', action: 'reject' },
|
|
},
|
|
{
|
|
title: '报表图表加载慢:首屏渲染耗时 8 秒',
|
|
description: '打开报表图表页首屏渲染需 8 秒,前端一次性拉取全部历史数据,需改为按日期范围按需加载。',
|
|
status: 'in_progress', priority: 'high', phase: '单体测试', subProject: '数据报表子系统',
|
|
category: '性能问题', impactLevel: '较高', impactScope: '影响部分模块',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 3, deadline: daysFromNow(4),
|
|
},
|
|
{
|
|
title: '修改手机号后旧 Token 仍有效,未强制下线',
|
|
description: '用户修改绑定手机号后,旧 Token 依旧有效可继续访问,存在账号被冒用风险,应在敏感信息变更后使旧 Token 失效。',
|
|
status: 'in_progress', priority: 'medium', phase: '详细设计', subProject: '用户管理子系统',
|
|
category: '安全漏洞', impactLevel: '较高', impactScope: '影响全部用户',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 2, deadline: daysFromNow(6),
|
|
agent: { goal: '修改手机号后旧Token失效方案设计,检索知识库相似案例', action: 'approve-pending' },
|
|
},
|
|
{
|
|
title: '用户搜索输入中文时出现乱码',
|
|
description: '用户列表搜索框输入中文关键词后,接口返回数据为空,日志显示查询参数编码异常。',
|
|
status: 'in_progress', priority: 'medium', phase: '单体测试', subProject: '用户管理子系统',
|
|
category: '功能缺陷', impactLevel: '一般', impactScope: '仅本页面',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 2, deadline: daysFromNow(8),
|
|
attachments: [{ name: 'search-garbled-log.txt', content: '2026-08-06 14:32:10 WARN query keyword=[\uFFFD\uFFFD] returns 0 rows' }],
|
|
},
|
|
{
|
|
title: '数据报表缓存未失效,修改后仍显示旧数据',
|
|
description: '修改基础数据后刷新报表,图表仍展示缓存中的旧数据,缓存 key 未包含数据更新时间。',
|
|
status: 'pending_confirm', priority: 'high', phase: '综合测试 (ST)', subProject: '数据报表子系统',
|
|
category: '功能缺陷', impactLevel: '较高', impactScope: '影响部分模块',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 3, deadline: daysFromNow(1),
|
|
},
|
|
{
|
|
title: '用户批量停用后历史操作记录被误删',
|
|
description: '批量停用用户时,误触发历史操作记录清理逻辑,导致该用户历史日志丢失,需与停用流程解耦。',
|
|
status: 'pending_confirm', priority: 'high', phase: '结合测试 (IT)', subProject: '用户管理子系统',
|
|
category: '功能缺陷', impactLevel: '较高', impactScope: '影响部分模块',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 2, deadline: daysFromNow(3),
|
|
},
|
|
{
|
|
title: '权限树勾选父节点时子节点状态不同步',
|
|
description: '权限树中勾选父节点后,部分子节点显示为半选状态,保存后子节点权限丢失,需级联同步。',
|
|
status: 'pending_confirm', priority: 'medium', phase: '单体测试', subProject: '权限控制子系统',
|
|
category: '功能缺陷', impactLevel: '一般', impactScope: '仅本页面',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 2, deadline: daysFromNow(5),
|
|
attachments: [{ name: 'screenshot-permission-tree.png', content: 'PNG 占位:权限树半选状态截图(测试数据)' }],
|
|
},
|
|
{
|
|
title: '综合测试环境 SQL 注入漏洞:动态拼接登录查询',
|
|
description: '登录接口存在动态拼接 SQL,构造恶意用户名可绕过密码校验,已复现并完成修复,待上线验证。',
|
|
status: 'closed', priority: 'urgent', phase: '综合测试 (ST)', subProject: '用户管理子系统',
|
|
category: '安全漏洞', impactLevel: '严重', impactScope: '影响全部用户',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 2, deadline: daysFromNow(-6),
|
|
},
|
|
{
|
|
title: '用户编辑时角色下拉缺少默认选中值',
|
|
description: '编辑已有用户时,角色下拉框未回显当前角色,保存时如未重新选择会误覆盖角色,已改为编辑时预填当前角色。',
|
|
status: 'closed', priority: 'high', phase: '结合测试 (IT)', subProject: '用户管理子系统',
|
|
category: '功能缺陷', impactLevel: '较高', impactScope: '影响部分模块',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 3, deadline: daysFromNow(-4),
|
|
},
|
|
{
|
|
title: '报表页日期筛选在 Chrome 下无法选择',
|
|
description: '报表页日期范围控件在 Chrome 最新版下点击无响应,Safari 正常,需兼容第三方日期组件初始化时机。',
|
|
status: 'closed', priority: 'medium', phase: '单体测试', subProject: '数据报表子系统',
|
|
category: '功能缺陷', impactLevel: '一般', impactScope: '仅本页面',
|
|
assigneeId: 2, reviewerId: 1, departmentId: 4, deadline: daysFromNow(-2),
|
|
attachments: [{ name: 'repro-datepicker-steps.txt', content: '复现:1.打开报表页 2.点击日期框 3.Chrome v126 无弹层' }],
|
|
},
|
|
{
|
|
title: '权限控制子系统部署说明文档版本过旧',
|
|
description: '部署文档仍为 v1.2 旧版,与实际 v2.0 配置(新增 JWT 密钥项)不一致,需同步更新部署手册。',
|
|
status: 'closed', priority: 'low', phase: '详细设计', subProject: '权限控制子系统',
|
|
category: '文档错误', impactLevel: '轻微', impactScope: '仅本页面',
|
|
assigneeId: 3, reviewerId: 1, departmentId: 3, deadline: daysFromNow(-5),
|
|
},
|
|
]
|
|
|
|
const FLOW = {
|
|
draft: [],
|
|
pending: ['pending'],
|
|
in_progress: ['pending', 'in_progress'],
|
|
pending_confirm: ['pending', 'in_progress', 'pending_confirm'],
|
|
closed: ['pending', 'in_progress', 'pending_confirm', 'closed'],
|
|
}
|
|
|
|
async function main() {
|
|
const login = await api('/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'content-type': 'application/json' },
|
|
body: JSON.stringify({ username: 'admin', password: 'Admin@2026' }),
|
|
})
|
|
const token = login.data.accessToken
|
|
console.log('登录成功\n')
|
|
|
|
const created = []
|
|
for (const [i, it] of issues.entries()) {
|
|
const num = String(i + 1).padStart(2, '0')
|
|
const { status, attachments, agent, ...payload } = it
|
|
const res = await api('/issues', {
|
|
method: 'POST',
|
|
headers: auth(token),
|
|
body: JSON.stringify(payload),
|
|
})
|
|
const issue = res.data
|
|
console.log(`[${num}] 创建 ${issue.issueNo} - ${issue.title}`)
|
|
|
|
for (const s of FLOW[status] || []) {
|
|
await api(`/issues/${issue.id}/status`, {
|
|
method: 'PATCH',
|
|
headers: auth(token),
|
|
body: JSON.stringify({ status: s, remark: '测试数据流转' }),
|
|
})
|
|
console.log(` 流转 -> ${s}`)
|
|
}
|
|
|
|
if (attachments && attachments.length) {
|
|
for (const a of attachments) {
|
|
const fd = new FormData()
|
|
fd.append('file', new Blob([a.content], { type: 'text/plain' }), a.name)
|
|
await api(`/issues/${issue.id}/attachments`, { method: 'POST', headers: { authorization: `Bearer ${token}` }, body: fd })
|
|
console.log(` 上传附件 ${a.name}`)
|
|
}
|
|
}
|
|
|
|
if (agent) {
|
|
const exec = await api('/agent/execute', {
|
|
method: 'POST',
|
|
headers: auth(token),
|
|
body: JSON.stringify({ issueId: issue.id, goal: agent.goal }),
|
|
})
|
|
const planId = exec.data.planId
|
|
console.log(` Agent 执行 -> plan#${planId}`)
|
|
if (agent.action === 'approve-pending') {
|
|
console.log(` Agent 审批保持 pending(演示审批中)`)
|
|
} else if (agent.action === 'reject') {
|
|
await api(`/agent/approval/${planId}/reject`, {
|
|
method: 'POST',
|
|
headers: auth(token),
|
|
body: JSON.stringify({ comment: '方案不适用,请人工处理' }),
|
|
})
|
|
console.log(` Agent 已驳回 plan#${planId}`)
|
|
}
|
|
}
|
|
created.push(issue)
|
|
}
|
|
|
|
console.log(`\n完成:共创建 ${created.length} 条测试数据`)
|
|
}
|
|
|
|
main().catch((e) => { console.error('失败:', e.message); process.exit(1) })
|