左帮右臂 P2 编码任务清单
版本: V1.0
日期: 2026-06-24
对应需求: spec-p2.md
对应设计: design-p2.md
范围: P2 编码任务 T33-T45,共 13 个任务
总工时: 约 16.5 天(单人全栈)/ 约 6 天(3 条并行轨道)
1. 任务依赖关系总览
P2 任务依赖图(→ 表示依赖):
T33 ──────────────────────────────────────── (协作链可视化,独立)
T34 ──→ T35 ──→ (配额中间件集成) (配额链路)
T34 ──→ T36 ──→ T45 (配额管理链路)
T37 ──→ T38 (文章管理链路)
T39 ──────────────────────────────────────── (BOM循环可视化,独立)
T40 ──→ T41 (ASR降级链路)
T42 ──→ T43 (WebSocket网页端链路)
T42 ──→ T44 (WebSocket小程序链路)
并行轨道规划:
| 轨道 | 任务序列 | 预估工时 |
|------|---------|---------|
| 轨道 A(协作+可视化) | T33 → T39 | 3.5 天 |
| 轨道 B(配额+文章) | T34 → T35+T36 → T38+T45 | 6 天 |
| 轨道 C(ASR+WebSocket) | T42+T40 → T43+T44 → T41 | 6 天 |
2. 任务详细清单
T33. 协作链可视化组件 — CollaborationChainGraph.vue
- 优先级: P2
- 预估工时: 2 天
- 依赖: T24(协作调度器)、T25(协作链 API)
- 可并行: 是(与 T34/T37/T39/T40/T42 无依赖)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| src/components/digital-staff/CollaborationChainGraph.vue | 新增 | 协作链流程图组件 |
| src/views/DigitalStaff.vue | 修改 | 集成协作链图到任务看板 |
编码步骤
- [ ] T33.1 创建
src/components/digital-staff/CollaborationChainGraph.vue组件骨架 - 定义 Props:
chain: Array<{ taskId, assignedTo, status, title, result }>,currentTaskId: string - 定义 Emits:
node-click(nodeData) - 定义内部状态:
hoveredNodeId: ref,autoRefreshTimer: ref
- [ ] T33.2 实现 SVG 水平流程图布局算法
layoutChain(chain, currentTaskId) - 节点尺寸: 圆角矩形 180×60
- 水平间距: 40px
- 计算每个节点的 x/y 坐标
- 标记
isCurrent和statusClass
- [ ] T33.3 实现节点状态渲染与样式
completed→ 绿色 ✅ (.node-completed)running→ 蓝色+脉冲动画 🔄 (.node-running)pending→ 灰色 ⏳ (.node-pending)failed→ 红色 ❌ (.node-failed)- 节点显示: 员工名称 + 任务状态 + 耗时
- [ ] T33.4 实现连线渲染(带箭头的 SVG path)
- 节点间使用贝塞尔曲线连接
- 箭头指向下一个节点
- 连线颜色跟随源节点状态
- [ ] T33.5 实现交互功能
- 点击节点 →
emit('node-click', nodeData)→ 显示任务详情面板 - 鼠标悬停 →
hoveredNodeId更新 → 显示简要信息 tooltip - tooltip 内容: 任务描述、执行结果、耗时
- [ ] T33.6 实现自动刷新机制
- 当 chain 中有
running状态节点时,每 5 秒轮询GET /api/digital-staff/collaboration/chain/:taskId - 更新 chain 数据,流程图自动重渲染
- 所有节点完成后停止轮询
- 组件卸载时清除定时器
- [ ] T33.7 实现异常场景处理
- 协作链数据不完整(缺少
collaboration_chain字段)→ 显示单节点视图 + "该任务无协作链信息"标注 - API 超时(>5秒)→ 显示骨架屏 + 后台重试一次 + "加载失败,请重试"提示
- [ ] T33.8 修改
src/views/DigitalStaff.vue集成协作链图 - 在任务看板区域添加 CollaborationChainGraph 组件
- 从
GET /api/digital-staff/collaboration/chain/:taskId获取链路数据 - 实现
showTaskDetail(nodeData)方法展示任务详情面板
- [ ] T33.9 前端构建与验证
Stop-Process -Name "node"停止旧进程npm run build构建前端- 在数字员工页面触发协作链,确认流程图正确渲染
- 确认节点状态颜色和动画正确
- 点击节点确认显示任务详情
- 协作链执行中确认自动刷新
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| 协作链流程图渲染 | 10 节点以内渲染 <1秒 |
| 节点状态颜色 | completed=绿, running=蓝+脉冲, pending=灰, failed=红 |
| 点击节点交互 | 弹出任务详情面板 |
| 自动刷新 | 执行中每 5 秒更新,完成后停止 |
| 数据不完整 | 显示单节点+提示信息 |
T34. 租户配额后端服务 — tenant-quota-service.js
- 优先级: P2
- 预估工时: 1.5 天
- 依赖: T09(租户中间件)、T15(数据库表)
- 可并行: 是(与 T33/T37/T39/T40/T42 无依赖)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| server/services/tenant-quota-service.js | 新增 | 租户配额后端服务 |
| server/db-adapter.js | 修改 | 新增 tenant_quotas 建表 |
编码步骤
- [ ] T34.1 创建
server/services/tenant-quota-service.js服务骨架 - 定义
TenantQuotaService类,单例模式 module.exports = new TenantQuotaService()直接导出实例- 依赖:
db-adapter(SQLite/MySQL 双后端) - 定义默认配额常量:
const DEFAULT_QUOTAS = {
maxParts: 10000,
maxBoms: 1000,
maxUsers: 50,
maxStaffTasks: 5000
}
- [ ] T34.2 实现
ensureTable()— 建表 CREATE TABLE IF NOT EXISTS tenant_quotas(字段见 design-p2.md 3.2.1)- 创建索引
idx_tenant_quotas_enterprise - 在服务初始化时调用
- [ ] T34.3 实现
checkQuota(enterpriseId, resourceType)— 配额检查 - 查询
tenant_quotas获取配额上限和当前数量 - 无记录 → 使用
DEFAULT_QUOTAS默认值 - 计算使用率
usagePercent = current / max * 100 - 返回
{ allowed: boolean, current: number, max: number, warning: string|null, usagePercent: number } - allowed 判定:
current < max - warning 判定:
usagePercent >= 80→"${resourceType}数量已达配额80%,请关注"
- [ ] T34.4 实现
incrementUsage(enterpriseId, resourceType, delta = 1)— 使用量递增 UPDATE tenant_quotas SET current_{resourceType} = current_{resourceType} + delta WHERE enterprise_id = ?- 若行不存在 →
INSERT默认配额行 + increment - 使用 camelCase 命名:
incrementUsage
- [ ] T34.5 实现
syncQuotaUsage(enterpriseId)— 单租户同步 - 统计实际 Part/BOM/User/StaffTask 数量(查询各业务表)
UPDATE tenant_quotas SET currentParts=..., currentBoms=..., currentUsers=..., currentStaffTasks=...- 若行不存在 →
INSERT默认配额行 + 实际数量 - 日志:
[Quota] 租户 ${enterpriseId} 配额同步完成: Parts=${n}, BOMs=${n}, Users=${n}, Tasks=${n}
- [ ] T34.6 实现
syncAllQuotas()— 全量同步 - 查询所有租户列表
- 遍历执行
syncQuotaUsage - 启动时调用一次
- 每日凌晨定时调用(使用
setInterval模拟 cron)
- [ ] T34.7 实现
getQuota(enterpriseId)— 获取配额信息 - 查询
tenant_quotas返回完整配额信息 - 无记录 → 返回默认配额 + 当前使用量全为 0
- [ ] T34.8 实现
updateQuota(enterpriseId, fields)— 修改配额上限 - 验证 fields 中的值 > 0
UPDATE tenant_quotas SET maxParts=..., maxBoms=..., ... WHERE enterprise_id = ?- 若行不存在 →
INSERT新行 - 记录审计日志:
{ action: 'quota_updated', enterprise_id, changes: fields }
- [ ] T34.9 实现
getAllQuotas()— 管理员查看所有租户配额 SELECT * FROM tenant_quotas ORDER BY enterprise_id- 返回配额列表
- [ ] T34.10 修改
server/db-adapter.js新增建表语句 - 在
createDatabase()中新增tenant_quotas建表 SQL - 在
createDatabase()中新增索引创建 SQL
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| checkQuota 正常 | 返回 { allowed: true, current: N, max: N, warning: null } |
| checkQuota 超限 | 返回 { allowed: false, current: 10000, max: 10000, warning: "..." } |
| checkQuota 80%警告 | 返回 { allowed: true, warning: "Part数量已达配额80%..." } |
| incrementUsage | 调用后 current 值 +1 |
| syncQuotaUsage | 与实际数据一致 |
| 无配额记录 | 使用默认配额,不阻断 |
T35. 租户配额检查中间件集成
- 优先级: P2
- 预估工时: 1 天
- 依赖: T34(配额服务需先就绪)
- 可并行: 否(依赖 T34),但可与 T36 并行
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| server/middleware/tenant-middleware.js | 修改 | 新增 quotaGuard(resourceType) |
| server.js | 修改 | 在创建类路由中增加配额检查 |
编码步骤
- [ ] T35.1 在
server/middleware/tenant-middleware.js中新增quotaGuard(resourceType)方法 - 从
req.tenantContext.enterpriseId获取租户 ID - 从
req.tenantContext.role获取用户角色 - 调用
tenantQuotaService.checkQuota(enterpriseId, resourceType) - 若
allowed === false且非管理员 → 403 + 配额超限提示
res.writeHead(403, { 'Content-Type': 'application/json; charset=utf-8' })
res.end(JSON.stringify({ success: false, error: `已达到${resourceType}配额上限(${result.max}),请联系管理员升级` }))
- 若
warning !== null→ 在响应头中附加X-Quota-Warning - 管理员角色跳过阻断(仅附加
X-Quota-Exceeded: true警告头) - 注入
req.quotaResult = result - 调用
next()继续处理
- [ ] T35.2 在
tenant-middleware.js中导出quotaGuard - 确保
module.exports包含quotaGuard
- [ ] T35.3 修改
server.js— Part 创建路由增加配额检查 - 在 Part 创建处理前调用
quotaGuard('parts')(req, res, () => { / 原有创建逻辑 / }) - 在 Part 创建成功后调用
tenantQuotaService.incrementUsage(enterpriseId, 'parts')
- [ ] T35.4 修改
server.js— BOM 创建路由增加配额检查 quotaGuard('boms')+incrementUsage('boms')
- [ ] T35.5 修改
server.js— 用户创建路由增加配额检查 quotaGuard('users')+incrementUsage('users')
- [ ] T35.6 修改
server.js— 数字员工任务创建路由增加配额检查 quotaGuard('staffTasks')+incrementUsage('staffTasks')
- [ ] T35.7 实现配额超限审计日志
- 在
quotaGuard中,当allowed === false时调用审计日志服务 logAudit({ action: 'quota_exceeded', enterprise_id: enterpriseId, resource_type: resourceType, current: result.current, max: result.max })
- [ ] T35.8 在
server.js中引入配额服务 const tenantQuotaService = require('./server/services/tenant-quota-service')const { quotaGuard } = require('./server/middleware/tenant-middleware')
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| 配额超限阻断 | 租户达到上限后创建返回 403 |
| 80%警告 | 达到 80% 后响应头包含 X-Quota-Warning |
| 管理员跳过 | 管理员超限后创建成功,响应头含 X-Quota-Exceeded |
| 审计日志 | 配额超限事件记录到审计日志 |
| 创建后计数 | 创建成功后 current 值 +1 |
T36. 租户配额管理 API
- 优先级: P2
- 预估工时: 0.5 天
- 依赖: T34(配额服务需先就绪)
- 可并行: 可与 T35 并行
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| server/routes/admin-quota.js | 新增 | 配额管理 API 路由 |
| server.js | 修改 | 注册路由 |
编码步骤
- [ ] T36.1 创建
server/routes/admin-quota.js路由文件 - 导出
handleAdminQuotaRoute(req, res, pathname, query, bodyStr) module.exports = { handleAdminQuotaRoute }
- [ ] T36.2 实现
GET /api/admin/quotas— 所有租户配额列表 - 验证管理员角色:
req.userRole === 'admin',否则返回 403 - 调用
tenantQuotaService.getAllQuotas() - 返回
{ success: true, data: { quotas: [...] } }
- [ ] T36.3 实现
GET /api/admin/quotas/:enterpriseId— 指定租户配额 - 验证管理员角色
- 从 pathname 解析 enterpriseId
- 调用
tenantQuotaService.getQuota(enterpriseId) - 返回
{ success: true, data: { enterpriseId, maxParts, currentParts, ... } }
- [ ] T36.4 实现
PUT /api/admin/quotas/:enterpriseId— 修改配额上限 - 验证管理员角色
- 使用
collectBody(req)读取请求体 - 解析 body:
{ maxParts?, maxBoms?, maxUsers?, maxStaffTasks? } - 调用
tenantQuotaService.updateQuota(enterpriseId, fields) - 记录审计日志
- 返回
{ success: true }
- [ ] T36.5 实现
POST /api/admin/quotas/init— 批量初始化默认配额 - 验证管理员角色
- 使用
collectBody(req)读取请求体 - 调用
tenantQuotaService.initDefaultQuotas() - 返回
{ success: true, data: { initialized: N } }
- [ ] T36.6 实现
POST /api/admin/quotas/:enterpriseId/sync— 手动同步配额 - 验证管理员角色
- 使用
collectBody(req)读取请求体 - 调用
tenantQuotaService.syncQuotaUsage(enterpriseId) - 返回
{ success: true, data: { synced: true } }
- [ ] T36.7 修改
server.js注册路由 const adminQuotaRoutes = require('./server/routes/admin-quota')- 在
handleRequest中:
if (pathname.startsWith('/api/admin/quotas')) {
return adminQuotaRoutes.handleAdminQuotaRoute(req, res, pathname, query, bodyStr)
}
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| 获取配额列表 | GET /api/admin/quotas 返回所有租户配额 |
| 修改配额上限 | PUT /api/admin/quotas/:id 修改后立即生效 |
| 非管理员访问 | 返回 403 Forbidden |
| 批量初始化 | 为无配额记录的租户创建默认配额 |
| 手动同步 | 同步后 current 值与实际数据一致 |
T37. 已发布文章后端 — published-articles 服务与 API
- 优先级: P2
- 预估工时: 1.5 天
- 依赖: T11(微信环境变量统一)、T31(发布重试)
- 可并行: 是(与 T33/T34/T39/T40/T42 无依赖)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| server/services/published-article-service.js | 新增 | 已发布文章服务 |
| server/services/wechat-publish.js | 修改 | 发布成功后写入记录 |
| server/routes/content-api.js | 修改 | 新增已发布文章 API |
| server/db-adapter.js | 修改 | 新增 published_articles 建表 |
编码步骤
- [ ] T37.1 创建
server/services/published-article-service.js服务骨架 - 定义
PublishedArticleService类,单例模式 module.exports = new PublishedArticleService()直接导出实例- 依赖:
db-adapter
- [ ] T37.2 实现
ensureTable()— 建表 CREATE TABLE IF NOT EXISTS published_articles(字段见 design-p2.md 3.2.2)- 创建索引
idx_published_articles_enterprise和idx_published_articles_status
- [ ] T37.3 实现
recordPublish(data)— 发布成功后记录 - 参数:
{ articleId, publishId, mediaId, title, publishTime, publishUrl, status, enterpriseId } INSERT INTO published_articles (article_id, publish_id, media_id, title, publish_time, publish_url, status, enterprise_id) VALUES (...)- 日志:
[PublishedArticle] 记录发布: ${title}, publishId=${publishId}
- [ ] T37.4 实现
getPublishedArticles(filters)— 分页查询 - 参数:
{ page, pageSize, enterpriseId, status } SELECT * FROM published_articles WHERE enterprise_id = ? AND status = ? LIMIT ? OFFSET ?- 返回
{ items: [...], total, page, pageSize }
- [ ] T37.5 实现
getPublishedArticle(id)— 单条记录 SELECT * FROM published_articles WHERE id = ?- 返回完整发布记录
- [ ] T37.6 实现
updatePublishStatus(id, status, extra)— 更新发布状态 UPDATE published_articles SET status = ?, retry_count = retry_count + 1, updated_at = ? WHERE id = ?- extra 可包含 error 信息等
- 日志:
[PublishedArticle] 状态更新: id=${id}, status=${status}
- [ ] T37.7 修改
server/services/wechat-publish.js— 发布成功后写入记录 - 在
publishArticle()函数末尾,发布成功后:
try {
const publishedArticleService = require('./published-article-service')
await publishedArticleService.recordPublish({
articleId: options.articleId || '',
publishId: publishResult.publishId,
mediaId: draft.mediaId,
title,
publishTime: new Date().toISOString(),
publishUrl: '',
status: 'published',
enterpriseId: options.enterpriseId || 'default'
})
} catch (e) {
console.error('[WeChat] 发布记录保存失败:', e.message)
}
- 发布失败后:
try {
const publishedArticleService = require('./published-article-service')
await publishedArticleService.updatePublishStatus(options.articleId, 'failed', { error: publishResult.error })
} catch (e) {}
- [ ] T37.8 修改
server/routes/content-api.js— 新增已发布文章 API GET /api/content/published-articles— 已发布文章列表- 解析 query 参数: page, pageSize, enterpriseId, status
- 调用
publishedArticleService.getPublishedArticles(filters) GET /api/content/published-articles/:id— 单条发布记录- 从 pathname 解析 id
- 调用
publishedArticleService.getPublishedArticle(id)
- [ ] T37.9 修改
server/db-adapter.js新增建表语句 - 在
createDatabase()中新增published_articles建表 SQL - 在
createDatabase()中新增索引创建 SQL
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| 发布成功记录 | published_articles 表有新记录 |
| 发布失败记录 | 状态标记为 failed |
| 文章列表查询 | GET /api/content/published-articles 返回分页列表 |
| 单条记录查询 | GET /api/content/published-articles/:id 返回详情 |
| 记录保存失败 | 文章已发布但记录缺失,日志记录错误 |
T38. 已发布文章前端管理界面
- 优先级: P2
- 预估工时: 1 天
- 依赖: T37(已发布文章 API 需先就绪)
- 可并行: 否(依赖 T37)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| src/views/ContentManager.vue | 修改 | 增加"已发布"标签页 |
| src/services/api.js | 修改 | 新增已发布文章 API 调用 |
编码步骤
- [ ] T38.1 修改
src/views/ContentManager.vue— 增加"已发布"标签页 - 在现有标签页(生成 | 草稿 | 设置)后新增"已发布"标签页
- 使用 Vue 3 Composition API 风格
- [ ] T38.2 实现已发布文章列表 UI
- 表格列: 标题、发布时间、发布状态、操作
- 状态标记: 🟢已发布(published) / 🟡发布中(publishing) / 🔴发布失败(failed)
- 空状态提示: "暂无已发布文章"
- [ ] T38.3 实现操作按钮
- "查看链接" →
window.open(publishUrl, '_blank')新窗口打开微信文章 - "重新发布" → 仅对
failed状态显示,调用发布 API
- [ ] T38.4 实现分页和搜索功能
- 分页组件: 上一页/下一页/页码跳转
- 搜索: 按标题关键词搜索
- 筛选: 按发布状态筛选
- [ ] T38.5 修改
src/services/api.js— 新增已发布文章 API 调用 getPublishedArticles(params)—GET /api/content/published-articlesgetPublishedArticle(id)—GET /api/content/published-articles/:id
- [ ] T38.6 添加浏览器 console 详细日志
- 列表加载:
console.log('[ContentManager] 已发布文章加载:', data) - 操作日志:
console.log('[ContentManager] 查看链接:', publishUrl)
- [ ] T38.7 前端构建与验证
Stop-Process -Name "node"停止旧进程npm run build构建前端- 打开内容管理页面,切换到"已发布"标签页
- 确认文章列表正确显示
- 点击"查看链接"确认新窗口打开
- 发布失败的文章确认显示"重新发布"按钮
验证方法
| 验证项 | 预期结果 |
|---|---|
| 已发布标签页 | 切换后显示文章列表 |
| 状态标记 | published=🟢, publishing=🟡, failed=🔴 |
| 查看链接 | 新窗口打开微信文章 |
| 重新发布 | 仅 failed 状态显示按钮 |
| 分页搜索 | 功能正常 |
T39. BOM 循环依赖可视化增强
- 优先级: P2
- 预估工时: 1.5 天
- 依赖: T22(BomTreeGraph)、T07(BOM 导入)
- 可并行: 是(与 T33/T34/T37/T40/T42 无依赖)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| src/components/bom/BomTreeGraph.vue | 修改 | 增加循环依赖高亮 |
| server/services/bom-import-service.js | 修改 | 返回循环路径数据 |
| src/views/BomAssistant.vue | 修改 | 传递 cyclePaths 到 BomTreeGraph |
编码步骤
- [ ] T39.1 修改
BomTreeGraph.vue— 新增 Props - 新增 prop
cyclePaths: Array— 循环路径数组> [[nodeId1, nodeId2, ...], ...] - 默认值:
[]
- [ ] T39.2 修改
BomTreeGraph.vue— 新增 Computed cycleNodeIds: computed(() => new Set(cyclePaths.value.flat()))— 从 cyclePaths 提取所有循环节点 IDcycleEdgeIds: computed(() => { / 从 cyclePaths 提取循环路径的边 ID 集合 / })— 循环边集合
- [ ] T39.3 修改
BomTreeGraph.vue— 修改flattenTree()方法 - 节点增加
status: 'cycle'标记(当id in cycleNodeIds) - 循环节点使用特殊 CSS 类
.node-cycle
- [ ] T39.4 修改
BomTreeGraph.vue— 修改边渲染 - 循环路径的边增加
class: 'edge-cycle'(红色加粗) - 多循环场景颜色区分:
const CYCLE_COLORS = ['#f44336', '#ff9800', '#9c27b0'] // 红/橙/紫
function getCycleColor(cycleIndex) {
return CYCLE_COLORS[cycleIndex % CYCLE_COLORS.length]
}
- [ ] T39.5 新增 CSS 样式
.node-cycle .node-rect: 红色填充 + 红色边框 + 脉冲动画.edge-cycle: 红色加粗线条@keyframes pulse: 透明度脉冲动画- 循环节点旁显示 "⚠️ 循环依赖" 标签
- [ ] T39.6 新增循环节点点击交互
- 点击循环节点 → 弹出提示 "检测到循环依赖:A → B → C → A"
- 提供"查看完整路径"和"忽略"选项
- 循环路径过长(>10节点)→ 截断显示 + "...等 N 个节点形成循环"
- [ ] T39.7 修改
server/services/bom-import-service.js— 返回循环路径数据 - 修改
_detectCycle为_detectCycleWithPaths,返回循环路径数组而非布尔值 - DFS 算法检测循环并记录完整路径(见 design-p2.md 4.4)
- 修改
buildBomTree()返回值: 增加cyclePaths字段
if (cyclePaths.length > 0) {
return { error: '检测到循环依赖', items: [], cyclePaths }
}
- [ ] T39.8 修改
src/views/BomAssistant.vue— 传递 cyclePaths - 从 BOM 导入结果中提取
cyclePaths - 导入含循环依赖的 BOM 时,BomTreeGraph 预览中高亮循环路径
- 提示 "请修正循环依赖后重新导入"
- [ ] T39.9 前端构建与验证
Stop-Process -Name "node"停止旧进程npm run build构建前端- 导入包含循环依赖的 BOM,确认循环节点标红
- 确认循环路径的边使用红色加粗线条
- 点击循环节点确认显示完整循环路径
- 多个独立循环确认使用不同颜色区分
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| 循环节点高亮 | 节点标红 + 脉冲动画 + ⚠️标签 |
| 循环边高亮 | 红色加粗线条 |
| 点击循环节点 | 弹出循环路径信息 |
| 多循环颜色区分 | 红/橙/紫三种颜色 |
| 导入阻断 | 含循环依赖的 BOM 拒绝导入 |
| 长路径截断 | >10 节点截断显示 |
T40. 阿里云 ASR 后端实现
- 优先级: P2
- 预估工时: 1.5 天
- 依赖: T01(VoiceInput 需先就绪)
- 可并行: 是(与 T33/T34/T37/T39/T42 无依赖)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| server/services/asr-service.js | 修改 | 增加阿里云后端 + 降级链 + 健康检查 |
| config.yaml | 修改 | 新增 asr.providers + asr.aliyun 配置节 |
编码步骤
- [ ] T40.1 修改
config.yaml— 新增 ASR 配置节 - 在
asr节点下新增providers数组和aliyun配置:
asr:
provider: iflytek
timeout: 15000
providers:
- name: iflytek
priority: 1
enabled: true
- name: aliyun
priority: 2
enabled: true
- name: echo
priority: 3
enabled: true
aliyun:
access_key_id: ""
access_key_secret: ""
app_key: ""
- [ ] T40.2 在
asr-service.js中新增recognizeAliyun(audioBuffer, format, sampleRate)方法 - 阿里云智能语音 REST API 调用
- API:
https://nls-gateway-cn-shanghai.aliyuncs.com/stream/v1/asr - 认证: AccessKeyId + AccessKeySecret 签名
- 参数: appKey, format(pcm/wav), sampleRate(16000)
- 环境变量覆盖:
ALIYUN_ASR_ACCESS_KEY_ID/ALIYUN_ASR_ACCESS_KEY_SECRET/ALIYUN_ASR_APP_KEY - 返回识别文本
- 日志:
[ASR] 阿里云识别结果: ${text}
- [ ] T40.3 修改
asr-service.js的recognize()方法 — 实现降级链 - 从 config.yaml 读取
asr.providers配置 - 按
priority排序,过滤enabled !== false - 遍历 providers,按顺序尝试:
iflytek→recognizeIflytek()aliyun→recognizeAliyun()echo→recognizeEcho()- 成功 → 返回
{ text, provider } - 失败 → 记录日志 + 尝试下一个
- 全部失败 → 抛出错误 "语音识别服务暂时不可用,请稍后重试"
- 保持
/api/asr/recognize接口格式不变,响应增加provider字段
- [ ] T40.4 新增
checkProviderHealth(providerName)方法 — 健康检查 - 缓存健康状态:
healthCache = new Map(),5 分钟有效期 - iflytek: 验证配置完整性 (
app_id,api_key,api_secret) - aliyun: 验证配置完整性 (
access_key_id,access_key_secret,app_key) - echo: 永远可用
- 请求时优先使用最近一次健康检查通过的后端
- [ ] T40.5 新增降级统计
degradeStats degradeStats = { iflytek: { success: 0, fail: 0 }, aliyun: { success: 0, fail: 0 }, echo: { count: 0 } }- 每次识别成功/失败时更新统计
- [ ] T40.6 处理阿里云 ASR 配置缺失场景
- 当
config.yaml中未配置aliyun.access_key_id等时 - 跳过阿里云后端,直接降级到 Echo 模式
- 日志:
[ASR] 阿里云配置缺失,跳过
- [ ] T40.7 添加浏览器 console 详细日志(PREFERENCE_2)
- 降级切换日志:
[ASR] ${provider.name} 识别失败,切换到下一个: ${error.message} - 识别成功日志:
[ASR] 识别成功, provider=${provider.name}, text=${text.substring(0, 50)}
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| 讯飞可用 | 正常识别,provider='iflytek' |
| 讯飞不可用 | 自动切换阿里云,provider='aliyun' |
| 阿里云不可用 | 降级到 Echo,provider='echo' |
| 配置缺失 | 跳过阿里云,直接 Echo |
| 全部不可用 | 返回错误提示 |
| 健康检查 | 5 分钟缓存,优先使用健康后端 |
| 接口兼容 | /api/asr/recognize 格式不变,增加 provider 字段 |
T41. ASR 降级链路测试与监控
- 优先级: P2
- 预估工时: 0.5 天
- 依赖: T40(阿里云 ASR 后端需先就绪)
- 可并行: 否(依赖 T40)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| server/services/asr-service.js | 修改 | 增加降级统计 API + 日志汇总 |
| server.js | 修改 | 注册 ASR 统计 API |
编码步骤
- [ ] T41.1 在
asr-service.js中新增getStats()方法 - 返回降级统计数据:
{
iflytek: { success: N, fail: N },
aliyun: { success: N, fail: N },
echo: { count: N }
}
- [ ] T41.2 新增
GET /api/asr/statsAPI - 调用
asrService.getStats() - 返回
{ success: true, data: { ...stats } } - 在
server.js中注册路由
- [ ] T41.3 新增统计汇总日志
- 每 100 次识别输出一次统计摘要:
console.log(`[ASR] 统计汇总: iflytek(${stats.iflytek.success}/${stats.iflytek.fail}), aliyun(${stats.aliyun.success}/${stats.aliyun.fail}), echo(${stats.echo.count})`)
- [ ] T41.4 添加浏览器 console 详细日志
- 每次降级切换时输出详细日志
- 健康检查结果日志
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| 降级统计正确 | 调用 ASR 接口后统计数据更新 |
| 统计 API | GET /api/asr/stats 返回正确数据 |
| 汇总日志 | 每 100 次输出统计摘要 |
| 浏览器日志 | console 显示 ASR 降级详细日志 |
T42. WebSocket 服务端实现
- 优先级: P2
- 预估工时: 2 天
- 依赖: T17(通知同步服务需先就绪)
- 可并行: 是(与 T33/T34/T37/T39/T40 无依赖)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| server/services/websocket-service.js | 新增 | WebSocket 服务端 |
| server.js | 修改 | 集成 WebSocket 升级 + 通知推送 |
编码步骤
- [ ] T42.1 安装
ws依赖 npm install ws- 如 jsonwebtoken 未安装:
npm install jsonwebtoken
- [ ] T42.2 创建
server/services/websocket-service.js服务骨架 - 定义
WebSocketService类,单例模式 module.exports = new WebSocketService()直接导出实例- 依赖:
ws,jsonwebtoken - 核心数据结构:
connections: Map— 用户连接映射> tenantConnections: Map— 租户连接映射> messageBuffer: Map— 离线消息缓冲>
- [ ] T42.3 实现
init(httpServer)— 初始化 WebSocket 服务 - 创建
WebSocket.Server({ noServer: true }) - 监听
httpServer的upgrade事件 - 匹配
/ws路径 - 验证 JWT(从
req.url的 query 参数获取 token) - JWT 无效 → 拒绝升级,返回 4001 错误码
- JWT 有效 →
wss.handleUpgrade(req, socket, head, ws)
- [ ] T42.4 实现
handleConnection(ws, req)— 连接管理 - 从 JWT 解析
userId和enterpriseId - 检查连接数限制: 全局 <1000, 单用户 <5
- 超限 → 关闭连接,返回 503 "服务繁忙"
- 添加到
connections和tenantConnections映射 - 监听
ws.on('message')→ 处理 pong 等客户端消息 - 监听
ws.on('close')→ 调用handleDisconnect(ws) - 日志:
[WS] 用户 ${userId} 连接, 当前在线: ${totalConnections}
- [ ] T42.5 实现
broadcastToUser(userId, message)— 用户级推送 - 查找
connections.get(userId)的所有 WebSocket - 逐个
ws.send(JSON.stringify(message)) - 消息格式:
{ type, data, timestamp, messageId } - 发送失败 → 从连接映射移除该 ws
- [ ] T42.6 实现
broadcastToTenant(enterpriseId, message)— 租户级推送 - 查找
tenantConnections.get(enterpriseId)的所有用户 - 逐用户调用
broadcastToUser - 日志:
[WS] 租户 ${enterpriseId} 广播, 在线用户: ${userCount}
- [ ] T42.7 实现
handleDisconnect(ws)— 断连处理 - 从
connections和tenantConnections映射中移除 - 将未送达消息暂存到
messageBuffer - 日志:
[WS] 用户 ${userId} 断开连接
- [ ] T42.8 实现消息补发机制
- 客户端重连时发送
lastMessageId参数 - 服务端从
notifications表查询该 ID 之后的消息 - 逐条补发
- 日志:
[WS] 用户 ${userId} 补发 ${count} 条消息
- [ ] T42.9 实现心跳保活
- 服务端每 30 秒发送
ping消息 - 客户端 10 秒内未响应
pong→ 关闭连接 - 使用
ws.ping()+ws.pong()原生机制
- [ ] T42.10 实现
getStats()— 连接统计 - 返回:
{ totalConnections, uniqueUsers, tenantStats: { enterpriseId: userCount } }
- [ ] T42.11 修改
server.js— 集成 WebSocket 服务 - 在 HTTP 服务器创建后:
const websocketService = require('./server/services/websocket-service')
websocketService.init(server)
- 在通知推送逻辑中增加:
websocketService.broadcastToUser(userId, {
type: 'notification',
data: message,
timestamp: Date.now(),
messageId: generateMessageId()
})
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| WebSocket 连接 | ws://host/ws?token=xxx 连接成功 |
| JWT 验证 | 无效 token 返回 4001 关闭连接 |
| 消息推送 | 通知发送后 WebSocket 客户端收到消息 |
| 消息补发 | 重连后收到断连期间的消息 |
| 心跳保活 | 30 秒 ping,10 秒无 pong 关闭 |
| 连接数限制 | 全局 >1000 返回 503,单用户 >5 拒绝 |
| 推送延迟 | <200ms |
T43. WebSocket 前端集成
- 优先级: P2
- 预估工时: 1.5 天
- 依赖: T42(WebSocket 服务端需先就绪)
- 可并行: 否(依赖 T42),但可与 T44 并行
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| src/composables/useWebSocket.js | 新增 | WebSocket 前端 composable |
| src/stores/app.js | 修改 | 使用 WebSocket 接收通知 |
| src/App.vue | 修改 | 初始化 WebSocket 连接 |
编码步骤
- [ ] T43.1 创建
src/composables/useWebSocket.jscomposable - 使用 Vue 3 Composition API 风格
- 状态:
ws: refconnected: ref(false) usePolling: ref(false) retryCount: ref(0) messageHandlers: Array([]) lastMessageId: ref('')
- [ ] T43.2 实现
connect(token)方法 - 获取 WebSocket URL:
ws://${window.location.host}/ws?token=${token} ws = new WebSocket(url)ws.onopen→connected = true,usePolling = false,retryCount = 0ws.onmessage→ 解析 JSON → 调用messageHandlersws.onclose→connected = false→ 2 秒后重连(最多 5 次,指数退避)ws.onerror→ 标记usePolling = true- console.log 详细日志:
[WS] 连接成功/[WS] 连接失败/[WS] 重连中(${retryCount}/5)
- [ ] T43.3 实现
disconnect()方法 ws.close()- 清除重连定时器
connected = false
- [ ] T43.4 实现
onMessage(handler)方法 messageHandlers.push(handler)- 返回取消注册函数:
() => { messageHandlers.splice(index, 1) }
- [ ] T43.5 实现
send(data)方法 ws.send(JSON.stringify(data))- 连接未建立时缓存消息
- [ ] T43.6 实现自动重连逻辑
- 断连后等待 2 秒重试
- 最多重试 5 次
- 指数退避: 2s → 4s → 8s → 16s → 32s
- 重连时携带
lastMessageId参数 - 重连成功后补发缓存消息
- [ ] T43.7 实现轮询降级逻辑
- 当
usePolling = true时,每 5 秒调用GET /api/notifications轮询 - 轮询结果通过
messageHandlers分发 - WebSocket 重连成功后切换回实时模式:
usePolling = false - console.log:
[WS] 降级为轮询模式/[WS] 恢复实时模式
- [ ] T43.8 修改
src/stores/app.js— 集成 WebSocket - 在 store 初始化时调用
useWebSocket.connect(token) - WebSocket 消息到达时更新 store 状态
- 新通知到达时更新通知列表
- [ ] T43.9 修改
src/App.vue— 初始化 WebSocket 连接 - 在
onMounted中:
const { connect, disconnect, onMessage } = useWebSocket()
const token = localStorage.getItem('token')
if (token) connect(token)
- 在
onUnmounted中:disconnect() - 注册消息处理器:
onMessage(handleWsMessage)
- [ ] T43.10 添加浏览器 console 详细日志(PREFERENCE_2)
- 连接状态变化:
[WS] 连接成功/[WS] 断开连接/[WS] 重连成功 - 消息接收:
[WS] 收到消息: type=${msg.type} - 降级切换:
[WS] 降级为轮询模式/[WS] 恢复实时模式
- [ ] T43.11 前端构建与验证
Stop-Process -Name "node"停止旧进程npm run build构建前端- 登录后确认 WebSocket 连接建立
- 收到通知后确认 store 状态实时更新
- 断网后确认自动重连
- WebSocket 不可用时确认降级为轮询
- 浏览器 console 显示 WebSocket 详细日志
验证方法
| 验证项 | 预期结果 |
|--------|---------|
| 连接建立 | 登录后 WebSocket 连接成功 |
| 实时通知 | 收到通知后 store 状态即时更新 |
| 自动重连 | 断网后 2 秒重连,最多 5 次 |
| 轮询降级 | WebSocket 不可用时 5 秒轮询 |
| 恢复实时 | 重连成功后切换回 WebSocket |
| Console 日志 | 显示连接/断连/重连/消息日志 |
T44. 小程序 WebSocket 集成
- 优先级: P2
- 预估工时: 1 天
- 依赖: T42(WebSocket 服务端需先就绪)、T04(小程序登录)
- 可并行: 可与 T43 并行
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| bossagents-miniapp/src/utils/websocket.js | 新增 | 小程序 WebSocket 工具 |
| bossagents-miniapp/src/store/index.js | 修改 | 集成 WebSocket |
编码步骤
- [ ] T44.1 创建
bossagents-miniapp/src/utils/websocket.js - 使用
uni.connectSocket()建立连接 - 状态:
connected: false,retryCount: 0,usePolling: false
- [ ] T44.2 实现
connect(token)方法 uni.connectSocket({ url: 'ws://${host}/ws?token=${token}' })uni.onSocketOpen→connected = true,usePolling = falseuni.onSocketMessage→ 解析 JSON → 调用回调uni.onSocketError→ 触发重连uni.onSocketClose→ 触发重连
- [ ] T44.3 实现自动重连
- 2 秒后重试,最多 5 次
- 指数退避: 2s → 4s → 8s → 16s → 32s
- [ ] T44.4 实现降级逻辑
- WebSocket 连接失败时切换到 5 秒轮询
- 轮询调用
GET /api/notifications - 重连成功后切换回 WebSocket
- [ ] T44.5 实现
onMessage(callback)方法 - 注册消息处理回调
- [ ] T44.6 修改
bossagents-miniapp/src/store/index.js— 集成 WebSocket - 在
useNotificationStore中集成 WebSocket - WebSocket 消息到达时更新通知列表
- 新通知到达时显示
uni.showToast提示
验证方法
| 验证项 | 预期结果 |
|---|---|
| 小程序连接 | 登录后 WebSocket 连接成功 |
| 实时通知 | 通知列表即时更新 |
| 自动重连 | 断网后自动重连 |
| 轮询降级 | WebSocket 不可用时 5 秒轮询 |
| Toast 提示 | 新通知到达时显示提示 |
T45. 租户配额管理前端界面
- 优先级: P2
- 预估工时: 1.5 天
- 依赖: T36(配额管理 API 需先就绪)
- 可并行: 否(依赖 T36)
涉及文件
| 文件路径 | 操作 | 说明 |
|---|---|---|
| src/views/AdminQuotaManager.vue | 新增 | 配额管理前端界面 |
| src/router/index.js | 修改 | 新增配额管理路由 |
| src/services/api.js | 修改 | 新增配额管理 API 调用 |
编码步骤
- [ ] T45.1 创建
src/views/AdminQuotaManager.vue页面骨架 - 使用 Vue 3 Composition API 风格
- 顶部: 租户选择下拉框 + "批量初始化"按钮
- 主体: 配额使用情况表格
- [ ] T45.2 实现配额使用情况表格
- 列: 租户名称 | Part(当前/上限/占比) | BOM(当前/上限/占比) | 用户(当前/上限/占比) | 月任务(当前/上限/占比) | 操作
- 占比计算:
current / max * 100 - 占比 >80% → 单元格标黄 (background: #fff3e0)
- 占比 >100% → 单元格标红 (background: #fce4ec)
- 进度条可视化: 每个资源类型显示进度条
- [ ] T45.3 实现编辑配额弹窗
- 表单字段: maxParts、maxBoms、maxUsers、maxStaffTasks
- 输入验证: 值必须 >0
- 保存时调用
PUT /api/admin/quotas/:enterpriseId - 新配额 < 当前使用量 → 弹出警告 "当前使用量(N)已超过新配额(N),已有数据不受影响但无法新增"
- 保存成功后刷新表格
- [ ] T45.4 实现批量初始化功能
- 点击"批量初始化" → 确认弹窗 "将为所有无配额记录的租户创建默认配额"
- 调用
POST /api/admin/quotas/init - 显示初始化结果: "已为 N 个租户初始化默认配额"
- [ ] T45.5 实现手动同步功能
- 每行操作列增加"同步"按钮
- 调用
POST /api/admin/quotas/:enterpriseId/sync - 同步成功后刷新该行数据
- [ ] T45.6 修改
src/services/api.js— 新增配额管理 API 调用 getQuotas()—GET /api/admin/quotasgetQuota(enterpriseId)—GET /api/admin/quotas/:enterpriseIdupdateQuota(enterpriseId, data)—PUT /api/admin/quotas/:enterpriseIdinitQuotas()—POST /api/admin/quotas/initsyncQuota(enterpriseId)—POST /api/admin/quotas/:enterpriseId/sync
- [ ] T45.7 修改
src/router/index.js— 新增配额管理路由 - 新增
/admin/quotas路由 - 需 admin 角色守卫: 非管理员访问返回 403
- 页面标题: "配额管理"
- [ ] T45.8 实现非管理员访问拦截
- 路由守卫检查用户角色
- 非管理员 → 重定向到首页 + 提示 "无权访问"
- [ ] T45.9 添加浏览器 console 详细日志
- 配额加载:
console.log('[AdminQuota] 配额列表加载:', data) - 操作日志:
console.log('[AdminQuota] 修改配额:', enterpriseId, data)
- [ ] T45.10 前端构建与验证
Stop-Process -Name "node"停止旧进程npm run build构建前端- 管理员打开配额管理页面,确认显示所有租户配额
- 修改配额上限后确认保存成功
- 占比超过 80% 的指标确认标黄
- 非管理员访问确认返回 403
- 批量初始化和手动同步功能正常
验证方法
| 验证项 | 预期结果 |
|---|---|
| 配额列表展示 | 显示所有租户配额及使用情况 |
| 占比标色 | >80%标黄, >100%标红 |
| 编辑配额 | 修改后立即生效 |
| 新配额低于使用量 | 弹出警告 |
| 批量初始化 | 为无配额租户创建默认配额 |
| 手动同步 | 同步后数据一致 |
| 非管理员拦截 | 返回 403 |
3. 推荐执行顺序
3.1 三轨并行执行计划
第一周(P2 核心,3 条并行轨道)
| 天数 | 轨道 A(协作+可视化) | 轨道 B(配额+文章) | 轨道 C(ASR+WebSocket) |
|---|---|---|---|
| D1-D2 | T33 协作链可视化 | T34 租户配额后端 | T42 WebSocket 服务端 |
| D2-D3 | T39 BOM 循环依赖可视化 | T37 已发布文章后端 | T40 阿里云 ASR 后端 |
| D3-D4 | — | T35 配额检查中间件 + T36 配额 API | T43 WebSocket 前端 + T44 小程序 |
| D4-D5 | — | T38 文章前端 + T45 配额前端 | T41 ASR 降级监控 |
关键里程碑
| 里程碑 | 完成标志 | 预计时间 |
|---|---|---|
| M9: 协作可视化可用 | T33 完成,协作链流程图可渲染 | P2 D2 |
| M10: 配额管控上线 | T34-T36+T45 完成,配额检查+管理界面可用 | P2 D5 |
| M11: 文章管理闭环 | T37-T38 完成,已发布文章可查询管理 | P2 D4 |
| M12: BOM 诊断增强 | T39 完成,循环依赖可视化高亮 | P2 D3 |
| M13: ASR 三后端就绪 | T40-T41 完成,讯飞→阿里云→Echo 降级链 | P2 D5 |
| M14: 实时推送上线 | T42-T44 完成,三端 WebSocket 实时同步 | P2 D4 |
3.2 任务依赖与并行矩阵
可并行任务组:
组1 (D1-D2, 无依赖):
T33 + T34 + T42
组2 (D2-D3, 依赖组1):
T39 + T37 + T40
组3 (D3-D4, 依赖组2):
T35+T36 + T43+T44
组4 (D4-D5, 依赖组3):
T38+T45 + T41
4. 全局约束与注意事项
4.1 编码约束
| 约束项 | 说明 |
|--------|------|
| 包管理 | 只用 npm install,不用 pnpm |
| POST 路由 | server.js 中 POST 路由需要 collectBody(req) |
| 模块导出 | module.exports = ClassName 直接导出(服务类用单例: module.exports = new ClassName()) |
| 前端构建 | 修改前端代码后需要 npm run build |
| 构建前停止 | 构建前必须先 Stop-Process -Name "node" |
| 命名规范 | JavaScript 变量和函数使用 camelCase |
| 配置驱动 | 使用 JSON 定义对象模型、YAML 定义规则,声明式配置风格 |
| 三端统一 | 网页端+飞书端+小程序端底层统一实现 |
4.2 server.js 修改汇总
// 1. 新增 require (T35/T36/T42)
const tenantQuotaService = require('./server/services/tenant-quota-service')
const { quotaGuard } = require('./server/middleware/tenant-middleware')
const adminQuotaRoutes = require('./server/routes/admin-quota')
const websocketService = require('./server/services/websocket-service')
// 2. WebSocket 初始化 (T42) — 在 server 创建后
websocketService.init(server)
// 3. 配额检查中间件集成 (T35) — 在创建类路由中
// Part 创建: quotaGuard('parts')(req, res, () => { /* 原有逻辑 */ })
// BOM 创建: quotaGuard('boms')
// 用户创建: quotaGuard('users')
// 数字员工任务创建: quotaGuard('staffTasks')
// 4. 配额管理路由注册 (T36)
if (pathname.startsWith('/api/admin/quotas')) {
return adminQuotaRoutes.handleAdminQuotaRoute(req, res, pathname, query, bodyStr)
}
// 5. ASR 统计路由注册 (T41)
if (pathname === '/api/asr/stats' && req.method === 'GET') {
// 返回降级统计
}
// 6. 通知推送集成 WebSocket (T42)
websocketService.broadcastToUser(userId, { type: 'notification', data: message, timestamp: Date.now() })
4.3 db-adapter.js 修改汇总
// 在 createDatabase() 中新增:
// tenant_quotas (T34)
db.exec(`CREATE TABLE IF NOT EXISTS tenant_quotas (...)`)
db.exec(`CREATE INDEX IF NOT EXISTS idx_tenant_quotas_enterprise ON tenant_quotas(enterprise_id)`)
// published_articles (T37)
db.exec(`CREATE TABLE IF NOT EXISTS published_articles (...)`)
db.exec(`CREATE INDEX IF NOT EXISTS idx_published_articles_enterprise ON published_articles(enterprise_id)`)
db.exec(`CREATE INDEX IF NOT EXISTS idx_published_articles_status ON published_articles(status)`)
4.4 依赖安装汇总
# T42: WebSocket 服务端
npm install ws
# T42: JWT 验证(如未安装)
npm install jsonwebtoken
5. 新增文件清单
| 文件路径 | 任务 | 说明 |
|---------|------|------|
| src/components/digital-staff/CollaborationChainGraph.vue | T33 | 协作链流程图组件 |
| server/services/tenant-quota-service.js | T34 | 租户配额后端服务 |
| server/routes/admin-quota.js | T36 | 配额管理 API 路由 |
| server/services/published-article-service.js | T37 | 已发布文章服务 |
| src/views/AdminQuotaManager.vue | T45 | 配额管理前端界面 |
| server/services/websocket-service.js | T42 | WebSocket 服务端 |
| src/composables/useWebSocket.js | T43 | WebSocket 前端 composable |
| bossagents-miniapp/src/utils/websocket.js | T44 | 小程序 WebSocket 工具 |
修改文件清单
| 文件路径 | 任务 | 修改内容 |
|---|---|---|
| server/middleware/tenant-middleware.js | T35 | 新增 quotaGuard(resourceType) |
| server.js | T35/T36/T41/T42 | 配额检查路由集成 + WebSocket 初始化 + ASR 统计路由 |
| server/db-adapter.js | T34/T37 | 新增 tenant_quotas + published_articles 建表 |
| server/services/wechat-publish.js | T37 | 发布成功后调用 recordPublish() |
| server/routes/content-api.js | T37 | 新增已发布文章 API |
| src/views/ContentManager.vue | T38 | 增加"已发布"标签页 |
| src/services/api.js | T38/T45 | 新增已发布文章 + 配额管理 API 调用 |
| src/components/bom/BomTreeGraph.vue | T39 | 新增 cyclePaths prop + 循环高亮 CSS |
| server/services/bom-import-service.js | T39 | _detectCycle 返回循环路径 |
| src/views/BomAssistant.vue | T39 | 传递 cyclePaths 到 BomTreeGraph |
| server/services/asr-service.js | T40/T41 | 增加阿里云后端 + 降级链 + 健康检查 + 统计 |
| config.yaml | T40 | 新增 asr.providers + asr.aliyun 配置节 |
| src/views/DigitalStaff.vue | T33 | 集成 CollaborationChainGraph |
| src/router/index.js | T45 | 新增 /admin/quotas 路由 |
| src/stores/app.js | T43 | 使用 WebSocket 接收通知 |
| src/App.vue | T43 | 初始化 WebSocket 连接 |
| bossagents-miniapp/src/store/index.js | T44 | 集成 WebSocket |
6. 任务统计
| 编号 | 任务名称 | 优先级 | 预估工时 | 依赖 | 可并行 |
|------|---------|--------|---------|------|--------|
| T33 | 协作链可视化组件 | P2 | 2天 | T24+T25 | 是 |
| T34 | 租户配额后端服务 | P2 | 1.5天 | T09+T15 | 是 |
| T35 | 租户配额检查中间件集成 | P2 | 1天 | T34 | 与T36并行 |
| T36 | 租户配额管理 API | P2 | 0.5天 | T34 | 与T35并行 |
| T37 | 已发布文章后端 | P2 | 1.5天 | T11+T31 | 是 |
| T38 | 已发布文章前端界面 | P2 | 1天 | T37 | 否 |
| T39 | BOM 循环依赖可视化 | P2 | 1.5天 | T22+T07 | 是 |
| T40 | 阿里云 ASR 后端实现 | P2 | 1.5天 | T01 | 是 |
| T41 | ASR 降级链路测试与监控 | P2 | 0.5天 | T40 | 否 |
| T42 | WebSocket 服务端实现 | P2 | 2天 | T17 | 是 |
| T43 | WebSocket 前端集成 | P2 | 1.5天 | T42 | 与T44并行 |
| T44 | 小程序 WebSocket 集成 | P2 | 1天 | T42+T04 | 与T43并行 |
| T45 | 租户配额管理前端界面 | P2 | 1.5天 | T36 | 否 |
P2 总工时: 约 16.5 天(单人全栈)
并行执行: 约 5 天(3 条并行轨道)
文档状态: 已完成
文件路径: C:\bossagents\docs\tasks-p2.md
BossAgents