Site Tools


Hotfix release available: 2026-07-14c "Mort". upgrade now! [57.3] (what's this?)
研发任务管理系统h5:冷启动文件

This is an old revision of the document!


研发任务管理系统 H5 — 冷启动文件

版本: 2.2 | 更新: 2026-09-06 | 用途: 研发任务管理系统(含库房集成)的冷启动/重建/排障手册
⚠️ 功能保全铁律(用户定稿):本系统功能只增不减,改版前先读本文件,改完逐项验证,功能不允许丢失。
⚠️ 测试铁律:测试必须用独立数据/独立进程,严禁污染生产数据(rd_tasks.json/accounts.json/store.db)。

一、系统概述

研发任务管理 + 研发库房管理 一体化系统(钉钉生态): - 任务:任务看板(跟踪任务/临时任务)、筛选(优先级/项目/状态/更新天数/搜索)、人员筛选、新增任务、更新记录(带时分+附件+可删)、子任务(进度联动)、工时统计、日报生成 - 账户体系:管理员(武燕青)全权;普通用户(钉钉人员)只看自己任务、可编辑自己任务;管理员可配置用户权限 - 登录:钉钉统一认证(JSAPI 免登 requestAuthCode / OAuth 授权码 / 工作台 authCode 三通道) - 库房集成:底部导航 3 tab(任务/库房/我的);库房 = 研发库房管理(独立子系统,蓝图挂载) - 线上地址:https://rd.huiflytech.com(Caddy HTTPS)= https://rd.huiflytech.com/rd/(任务)、/store/(库房)

二、部署架构

用户/钉钉 → https://rd.huiflytech.com (Caddy :443/:80 自动 HTTPS)
         → rd-h5.service (systemd, Flask :13544, 统一进程)
              ├─ /rd/*        → 任务前端 + API(rd_h5.py + rd_h5.html)
              ├─ /store/*     → 库房前端 + API(rd_store.py 蓝图 + rd_store.html)
              └─ /api/*       → 任务 API

- systemd 服务:`rd-h5.service`(ExecStart=/home/ubuntu/projects/ctwing-2/venv/bin/python /home/ubuntu/.hermes/scripts/rd_h5.py,端口 13544) - Caddy:`/etc/caddy/Caddyfile`(rd.huiflytech.com → 127.0.0.1:13544;80→443 自动跳转;Let's Encrypt 自动证书) - 数据目录:`/home/ubuntu/docs/`

三、数据文件

文件 内容 说明
——————
`rd_tasks.json` 任务数据(items/updated_at) 主数据;normalize 兼容字段
`accounts.json` 账户体系 roles.admin(武燕青)/roles.user/perms(用户权限)/pwds
`people.json` 人员库 简称→全名(钉钉通讯录);注意:无 roles 字段(admin 判定在 accounts.json)
`ding_org.json` 钉钉通讯录全量 MCP 同步缓存(17 人:姓名/userid/部门);/api/ding/org 优先读此文件
`leave.json` 钉钉请假记录 MCP OA 同步(cron 0210e63abf25 工作日 08:30)
`tags.json` 标签库 任务标签(默认/周报汇报 + 自定义)
`store.db` 库房 SQLite samples/requests/history 表(软删除 deleted 标记)
`.env` 凭证 DINGTALK_CLIENT_ID/SECRET(慧飞任务应用 dingh2ogz…)、DINGTALK_CORP_ID=4901944860、HALO_DB_PASSWORD 等

四、核心功能

1. 任务看板

- 任务类型:跟踪任务([优先级](项目)内容)/ 临时小任务(⏱️ 当天) - 筛选:优先级/项目/状态/未更新天数(工作日)/搜索;人员标签筛选(点击) - 人员标签:显示所有有任务人(从任务提取);“+ 更多”打开钉钉通讯录全量(17 人) - 任务详情:状态/进度/负责人/子任务(进度联动)/更新记录(带时分+附件)/总耗时

2. 账户体系(2026-08-31)

- 管理员:武燕青(全部权限:查看/编辑/删除所有任务、账号管理、生成日报、新增) - 普通用户:只见自己任务(负责人=自己或子任务负责人=自己,简称/全名变体匹配 is_mine)、可编辑/删除自己任务(can_edit/can_delete) - 权限配置:管理员「账号管理」弹窗(view_own_only/edit_own/delete_own/manage_subtask 开关 + 设置口令) - 后端强制校验:can_edit/can_delete 在 update_task/add_note/del_note/del_task/subtask_note 接口执行(403) - ⚠️ isAdmin 判定:统一账户体系(USER_ROLE=admin 或 名字=武燕青);不依赖 people.json roles(空)

3. 钉钉统一认证(3 通道)

- JSAPI 免登(主,钉钉内):UA 检测 DingTalk → 加载 dingtalk.open.js → requestAuthCode({corpId: ding3049357e0fcfed24f5bf40eda33b7ba0}) → code → /api/ding/login(gettoken+getuserinfo)→ 自动登录 - OAuth 授权码(浏览器):/api/ding/oauth/url 生成授权 URL → 回跳 /rd/ding_cb?code → /api/ding/oauth/cb(userAccessToken+users/me)→ 登录 - 工作台 authCode:URL 带 authCode → 直接 dingLogin(失败自动降级 JSAPI) - 登录态:localStorage rd_user(同域任务/库房共享);登录用户自动退出只读模式(exitReadonly)

4. 周报生成(2026-08-31)

- 📊 生成周报按钮(btnWeek,管理员):/api/report/week 生成上一周研发工作周报 - 三部分:①研发项目推进(各项目在管/更新/新增/完成+主要进展总结式)②研发管理推进(任务系统/库房系统运行状态)③研发任务日报(正常推进) - 弹窗显示 + 📋 复制按钮;⚠️ 弹窗打开必须 classList.add('open')(style.display 会导致关闭按钮失效)

5. 钉钉请假同步(2026-08-31)

- leave.json(date/name/type/start/end/status);/api/leave?date= 查询 - 人员筛选时名字后显示当天请假标记;任务行负责人标签后同样显示 - 日报:负责人姓名后直接显示(X 请假);每日 08:30 cron 同步(请假模板 PROC-4DD795D7-E54A-4942-B91A-6743ED78AD42)

6. 任务标签(2026-09-02)

- 标签库 tags.json(预置:默认/周报汇报)+ /api/tags(GET/POST 自定义新增) - 任务详情 🏷️ 区:标签库多选 + 自定义(自动入库);新任务默认 [“默认”] - 任务行/详情标题显示非默认标签(🏷️橙色高亮),“默认”不显示在行上

7. 评审会模块(2026-09-05)

- 独立蓝图 review_api.py + 页面 /review/(底部导航 5 tab:任务/库房/测试/评审会/我的) - 会议:新建/继承(复制全部内容+议题自动续序号)/项目/开始时间/预计时长/结束时间(自动算实际)/会议人员(钉钉多选)/负责人/评审阶段/标签

  1. ★ 评审阶段(2026-09-16 更新,共 8 个):需求分析/可行性评估 → 立项评审 → 方案设计 → 详细设计 → 样机试制 → 测试验证 → 量产导入 → 结项评审
  2. 定义位置:`review.html` 的 `stageSel`(唯一来源,改这里即可)

- ★ 与会人员手写签名(2026-09-16 新增):

  1. 前端:编辑页「与会人员签名」区 → 与会人员一人一张卡片(未签名/已签缩略图)→ 点「✍️ 签名」弹出手写板(canvas 900×360,支持手指触摸与鼠标,可清除重写)
  2. 存储:`meetings.signatures`(TEXT,JSON `{人名: “data:image/png;base64,…”}`);保存接口仅当传入非空才更新(防前端未带字段时清空)
  3. 人员来源:`meetings.members`(分号/逗号分隔)解析
  4. 报告:Web 内嵌 `<img>`;Word/PDF 用 `add_picture` 插入真实签名图(原为“打印后手写签字”的空白表)
  5. 相关函数:`sigLoad/renderSigns/openSign/initPad/clearPad/savePad/clearSign/closeSign`;后端 `_parse_sig/_sig_one/_sig_block/_sig_docx`
  6. ★ 自动记录签名时间(2026-09-16):签名为 `{人名: {“img”: “data:image/png;base64,…”, “time”: “YYYY-MM-DD HH:MM”}}`(兼容旧格式纯 base64 字符串,无时间不报错);前端签名卡片显示 `🕐 时间`;报告 Web/Word/PDF 均在签名下方显示时间
  7. ★ 签名后自动提交:`savePad` 完成后自动调用 `saveMeeting()` 落库(避免忘记点保存导致报告无签名)
  8. 实测:3 人签名(2 新格式含时间 + 1 旧格式)→ Web 报告 3 张签名图 + 时间正确显示 ✅|Word 内嵌 3 张图 + 含时间 ✅|PDF 69KB ✅

- ★ 报告要点表按评审阶段动态列(2026-09-16):

  1. 判定:`_pt_need(s)` = 阶段含「需求分析」;`_pt_cols(s)` 返回列定义
  2. 需求分析/可行性评估阶段 → 精简为 4 列:序号 | 记录内容 | 日期 | 负责人(去掉 状态/优化方案/记录图片/附件)
  3. 其他阶段 → 保持 8 列(序号/记录内容/状态/优化方案/记录图片/附件/日期/负责人)
  4. 生效范围:Web 报告 + `_export_docx` + `_export_pdf`(共 3 处)
  5. 实测:需求分析阶段 Web/Word 表头均为 4 列 ✅;立项评审阶段对照仍为 8 列 ✅
  6. 实测:签名 PNG 落库 ✅|Web 报告含签名图 ✅|Word 内嵌 `word/media/image1.png` + drawing 引用 ✅|PDF 52KB ✅

- 要点记录:序号/时间/记录人员(钉钉)/内容/优化方案/记录负责人(钉钉)/状态(☐未解决☑已解决复选框同行)/拍照+图库双传/附件 - 评审结果三方案:方案评审通过 / 方案局部修改无需再审 / 方案重大问题需二次评审 - 报告:网页版 + Word版 + PDF版(libreoffice 转换);首部公司信息“慧飞数字科技(秦皇岛)有限公司”;要点表状态独立列;末尾签字确认区 - 数据:~/docs/review/review.db(meetings/points 两表)+ attachments/ - ⚠️ 服务运行在 ctwing-2 venv(非 huifei venv),python-docx 须装在该 venv

8. 库房集成(2026-08-31 迁移)

- rd_store.py 改 Blueprint(bp)挂载到 rd_h5 统一进程(13544);rd-store.service 已停(13545 退役) - 库房独立运行兼容:`STORE_DB=/tmp/x.db STORE_PORT=13599 python rd_store.py`(测试隔离) - 底部导航(任务/库房/我的):任务=视图切换;库房=跳 /store/;我的=账户信息 - 库房页登录校验:同域读 localStorage rd_user,未登录显示橙色提示条(不覆盖页面) - 库房 tabbar 用 div(不能用 nav——库房 CSS 有 nav 标签选择器 sticky 会覆盖 fixed)

5. 底部导航(3 tab)

[📋 任务] [📦 库房] [👤 我的]

- 我的:账户信息(姓名/身份/钉钉ID/登录方式/我的任务数/权限)+ 账号管理(管理员)+ 返回首页 + 退出登录 - 普通用户无「切换身份」「账号管理」

五、API 列表

API 方法 说明
—–————
/api/tasks GET 任务列表(?user= 过滤:普通用户只看自己;admin 全量)
/api/tasks POST 新增任务(记录 creator)
/api/tasks/<tid> POST 更新任务(can_edit 校验)
/api/tasks/<tid> DELETE 删除任务(can_delete 校验)
/api/tasks/<tid>/note POST 添加更新记录(can_edit)
/api/tasks/<tid>/note/<idx> DELETE 删除记录(can_edit)
/api/tasks/<tid>/subtask/<idx>/note POST 子任务更新(can_edit)
/api/me GET 当前用户信息(role/perms)
/api/accounts GET/POST 账户列表(管理员)/配置权限(管理员)
/api/login_pwd POST 口令登录(备用)
/api/set_pwd POST 设置口令(管理员)
/api/people GET/POST 人员库
/api/ding/login POST 免登 authCode→身份
/api/ding/org GET 钉钉通讯录(读 ding_org.json)
/api/ding/oauth/url GET OAuth 授权 URL
/api/ding/oauth/cb POST OAuth 授权码→身份
/api/upload POST 附件上传
/api/report/today GET 今日日报(含当日请假区)
/api/report/week GET 上周周报(项目推进/管理推进/日报)
/api/tags GET/POST 标签库(列表/自定义新增)
/api/leave GET 请假记录(?date= 按天过滤)
/api/store/* * 库房 API(samples/requests/approve/destroy/back/back_apply/ledger/history/…)

六、关键规则(用户拍板)

1. 管理员:武燕青——查看/编辑所有任务 + 账号管理;普通用户只见/只编辑自己任务 2. 只读模式:?ro=1(共享链接);登录用户自动退出只读(exitReadonly 恢复标题/按钮) 3. 任务负责人:存简称(张/席),登录用全名——匹配用 name_variants(简称↔全名变体) 4. 普通用户不显示:切换身份、账号管理、口令登录入口(唯一登录=钉钉认证) 5. 日报:生成今日日报(按任务/工时);员工日报汇总 21:30 推送(cron 52967bf00170) 6. 钉钉通讯录:MCP 同步到 ding_org.json(cron 8f32fd550f80 每周一 06:00) 7. owner 一律全名(2026-09-02 定稿,不用简称);前端 shortOf 全名→简称映射兼容分组 8. 列表排序:同优先级内新任务在前(id 降序) 9. 删除/编辑 API 必须传 user(delTask/delNote 带 {user},否则 403) 10. 附件查看:链接加 download 属性(内置浏览器无法预览 docx,直接下载) 11. 子任务新增时间(2026-09-03 用户定稿):= 子任务名首次出现在更新记录(notes)中的日期;无记录才回退 created 字段。⚠️ 曾 bug:保存任务时旧子任务 created 被重设为当天(后端已修:同名同负责人保留旧 created);历史污染数据已按 notes 首现批量修正 12. 项目列表:PROJ_LIST 常量(拓远T1/普惠P1/金穗S1/LoRa网关/P3/P5/流量计/表压/软管泵/施肥阀/施肥机/其他) 13. 复盘 cron 已暂停(b9dbd39c3f34,2026-09-03 用户要求不再定时推送,可手动 run) 14. 测试报告导出(2026-09-06):/api/test/report/<sid>?mode=&fmt=html|docx|pdf(横向 Word 含照片)+ /api/test/report/full?fmt= 整机;前端按钮 📄网页/📝Word/📕PDF 15. 评审会导出(2026-09-06):/api/review/report/<mid>?fmt=html|docx|pdf 16. 底部导航 5 tab 三处同步(rd_h5.html / rd_store.html / test.html / review.html 各自的 tabbar)

七、部署运维

sudo systemctl restart rd-h5.service     # 重启
sudo journalctl -u rd-h5.service -n 50   # 日志
sudo systemctl reload caddy              # Caddy 重载
sudo vi /etc/caddy/Caddyfile             # 域名配置(rd.huiflytech.com → 13544)
git -C /home/ubuntu add -A && git -C /home/ubuntu commit -m "..."   # 版本管理

- 证书:Caddy 自动(Let's Encrypt);阿里云手动证书包可留档备用 - 域名 DNS:rd.huiflytech.com → 82.156.85.124(huiflytech.com 已备案,80/443 不被劫持)

八、排障速查

现象 原因 解决
——————
钉钉打开不自动登录 应用类型/权限 JSAPI 免登需钉钉 JSAPI 安全域名;应用需在钉钉后台配置
免登报“不合法的appKey” 凭证错 .env CLIENT_ID(ding 开头)+ SECRET 匹配
通讯录同步空 应用未开通通讯录权限 钉钉后台开通 qyapi_get_department_list/member;或 MCP 同步 ding_org.json
管理员变“只读” applyPerm 用 people.json roles(空) isAdmin 已改账户体系判定(名字=武燕青)
普通用户看到全部任务 view_own_only 未生效 accounts.json perms;后端 is_mine 过滤
任务匹配不上 owner 简称 vs 全名 name_variants 变体匹配
库房 tabbar 跑中间 nav 标签选择器覆盖 tabbar 用 div 类(不用 nav)
库房内容空白 登录校验覆盖 body 已改提示条(不覆盖)
页面旧版 浏览器缓存 强刷 / 加 ?v= 参数;服务端 no-store

附三:新增任务权限调整 + /api/people 角色来源修复(2026-09-16)

问题:刘瑞红“新建了任务但没显示” → 排查发现数据里根本没有她建的任务。

根因: 1. `accounts.json` 的 `roles.admin` 只有「武燕青」→ 刘瑞红是普通用户 → 前端 `applyPerm()` 执行 `['btnAdd','btnPeople'] 隐藏` → 她看不到「+ 新增任务」按钮,建不了任务 2. ★ 更深一层:`/api/people` 的 `roles` 读的是 people.json(其 `roles.admin` 为空),而后端权限判定用 accounts.json → 前端 ADMINS 永远为空 → 即便把某人加入 accounts.json 的 admin,前端仍按普通用户处理(双侧数据源不一致的隐蔽 bug)

修复: - `accounts.json`:`roles.admin` 增加「刘瑞红」(从 user 列表移除) - 前端 `rd_h5.html`:

  1. `applyPerm()` 不再隐藏 `btnAdd`(新增任务对全员放开);`btnPeople`(人员管理)仍限管理员
  2. `openAdd()` 负责人选择器:非管理员默认预选自己(`_defOwn=[myShort()]`),避免建完因筛选自己而看不到

- 后端 `/api/people`:`roles` 改为 `load_accounts()` 读取(与权限判定统一)

验证:`/api/people` → admin=`['武燕青','刘瑞红']` ✅|`/api/me?user=刘瑞红` → role=admin + perms 全开 ✅|叶小军 → user(edit_own/view_own_only 保持)✅|页面 JS 语法 ✅

⚠️ 教训:权限相关的数据源必须唯一(accounts.json)。前端拿角色的接口(/api/people)与后端判权的函数(is_admin)读同一份文件,否则会出现“加了管理员但前端不认”的隐蔽问题。

附四:新建人显示 + 期望完成时间 + 普通用户硬隔离(2026-09-16)

① 任务显示新建人(`creator` 字段,存全名) - 后端 `add_task` 写入 `creator`(取 `creator`/`user` 参数);`update_task` 仅在库中为空时补写(不覆盖) - 前端:任务卡片(跟踪 + 临时)显示 `👤 新建:XXX`;详情页显示 `👤 新建:XXX(创建日期)`;只读详情同样显示 - 新增任务提交时带 `creator: USER_NAME`

② 期望完成时间(`due_date`,YYYY-MM-DD) - 后端 add/update 支持该字段 - 新增任务表单:跟踪任务增加「期望完成」日期选择(可选) - 详情页:可编辑(`#mDue`),保存随 `saveTask` 提交 - 卡片显示:`🎯 期望完成:2026-09-20`;已逾期(due_date < 今天且未完成)标红并附「(已逾期)」

③ 普通用户可见性(2026-09-16 定稿)

规则演进:① 最初「自己负责 或 自己创建」→ ② 用户一度要求收紧为仅负责人 → ③ 最终定稿:创建人可见自己创建的所有任务,其他用户(既非负责人也非创建人)不可见

- 全局开关 `MY_ONLY`:非管理员登录时置 `true` - `baseFilter()` 首行强制过滤:`if(MY_ONLY && !(isMine(t) || isCreatorOf(t))) return false`(不受人员筛选/搜索影响) - `isCreatorOf(t)`:`t.creator` 与登录人全名/简称双向匹配 - 分组:`XXX 主负责` | `XXX 我创建(他人负责)`(绿色 #26a69a)| `XXX 负责子任务` - 权限:`canEditTask` = `isMine` 或 `isCreatorOf`;后端 `can_edit` 同步 = `is_mine or is_creator` - 后端 `is_creator(task,user)` 用 `name_variants` 做全名/简称匹配 - ★ 后端 `/api/tasks` 同步过滤(根本保证):`if user and not is_admin(user) and perm.view_own_only: items=[it for it in items if is_mine(it,user) or is_creator(it,user)]`

  1. 前端 `MY_ONLY` 是展示层过滤,后端过滤才是根本保障(改前端 JS 也无法拿到他人任务)
  2. 未登录 / 管理员 → 返回全量(只读看板 `?ro=1` 需要)

验证(#99 金穗S1单loraPCB板设计:owners=['张'] creator=武燕青)——后端接口实测:

身份 可见任务数 #99
———
张景茹(负责人) 35 可见 ✅
武燕青(管理员/创建人) 99 可见 ✅
席江锋(其他普通用户) 20 不可见 ✅
叶小军(无任务) 0 不可见(无任务)✅
未登录(只读看板) 99 可见 ✅
⚠️ 测试提醒:API 测试勿传空值字段(如 `name:''`)——update_task 会按字段更新导致清空;本次已发现并恢复 #99 名称。

附四补:分组判定 bug 修复(2026-09-16,用户截图报)

现象:管理员(武燕青)在页面上点选「潘保琰」筛选后,分组 “潘保琰 我创建(他人负责)” 里出现了 #99 金穗S1单loraPCB板设计(该任务实际 creator=武燕青、owners=['张'],与潘保琰无关)。

根因:`render()` 里 `made` 分组用的是 `isCreatorOf(t)` —— 它判定的是 当前登录人是否创建,而不是被筛选人(SELP)。 → 管理员筛他人时,会把管理员自己创建的任务错列到被筛人名下的“我创建(他人负责)”分组。

修复:新增 `isCreatorBy(t, who)`(按指定人员的简称/全名判定),`made` 分组改用 `isCreatorBy(t, SELP)`:

function isCreatorBy(t,who){
  var c=(t.creator||'').trim(); if(!c) return false;
  if(c===who) return true;              // 简称相等
  if(full(who)===c) return true;        // 全名相等
  return nameToShort(c)===who;          // creator 全名 → 简称后比较
}
var made=list.filter(function(t){return liu含SELP为假 && 子任务不含SELP && isCreatorBy(t,SELP)});

验证(node 单测):筛选「潘保琰」→ #99 不进入 made 分组 ✅|筛选「武燕青」→ 进入 ✅(正确)

附五:任务主页分组折叠(2026-09-16)

需求:任务主页每个类别(分组)折叠显示。

实现(`rd_h5.html`): - 新增 `gkey/isCol/toggleGroup/gcolMap` 四个辅助函数

  1. `gkey(title)`:分组名转 key(非字母数字中文→`_`)
  2. `isCol(k)`:默认收起(未记录视为 true=收起)
  3. `toggleGroup(k)`:切换并写 `localStorage.rd_gcol`(`false`=展开,`true`/未记录=收起)后 `render()`

- `render()` 中每个 `.group` 的 `.ghead`:加 ▸(收起)/ ▾(展开)指示 + 点击展开/收起;组内容仅在展开时渲染 - 覆盖:各负责人分组 + ✅ 已完成分组(key `done`)

验证(只读链接 ?ro=1 免登录实测): - 首次加载:7 个组全部 `▸` 收起(刘瑞红2|宋逊文2|席江锋13|张景茹9|武燕青19|潘保琰8|✅已完成45)✅ - 点击“刘瑞红”:变 `▾` + 显示 2 项任务,其余组仍收起 ✅ - `localStorage.rd_gcol = {“刘瑞红”:false}` 状态记忆正确 ✅

九、测试隔离

- 任务:测试账号不写生产 rd_tasks.json(改前备份 git 可回滚) - 库房:`STORE_DB=/tmp/store_test.db STORE_PORT=13599 python rd_store.py` 独立实例,测完删库 - 严禁直接操作生产数据;测试数据即时清理

附:任务负责人被判只读修复(2026-09-15)

现象:张景茹(普通用户)打开自己负责的任务(如 #83),详情页显示“🔒 只读(仅管理员或任务负责人可编辑)”,无法编辑(用户报)。

根因(前端 `rd_h5.html`):

function canEditTask(t){
  return (t.owner||'')===USER_NAME||(t.owners||[]).indexOf(USER_NAME)>=0;  // ❌
}

- `USER_NAME` 是全名(“张景茹”),而任务 `owners` 存的是简称(“张”)→ 永不匹配 → 负责人被判只读 - ⚠️ 后端 `is_mine()` 用的是 `name_variants()`(全名+简称变体)✅ 本就正确 → 纯前端 bug

修复(新增两个函数 + 替换 3 处调用):

function nameToShort(nm){ /* OMAP 反查全名→简称,不依赖 DING_USER */ }
function isMine(t){ /* owners/owner/子任务负责 与 [全名, 简称] 双向匹配 */ }
function canEditTask(t){ ... return isMine(t); }
// 另 2 处"我的任务"统计:TASKS.filter(isMine).length

验证: - node 单元测试 5/5:`owners:['张']` + 登录“张景茹” → true ✅|武燕青任务 → false ✅|子任务负责 → true ✅|无负责人 → false ✅|全名存储兼容 → true ✅ - 后端 `name_variants` 正确;`accounts.json` 中张景茹 `edit_own:true` ✅ - 三模块 200 ✅

经验:任务负责人存简称、登录用全名——任何“是否是我的”判断都必须走 `isMine()/nameToShort()`,禁止直接拿 `USER_NAME` 与 `owners` 比较。

附二:生成日报 500 修复(2026-09-15 晚)

现象:点「📋 生成日报」弹窗卡在“正在生成…”(用户报)。

根因: 1. 后端 500:`rd_h5.py` 日报聚合里,子任务负责人“今日无更新但任务今日完成”时直接 `per[so][“done_today”] += 1`,而 `per` 中该键尚未初始化 → `KeyError: '刘'`(刘瑞红为子任务负责人) 2. 前端卡住:`genReportDo()` 的 fetch 无 `.catch()` → 接口返回 HTML(500) 时 `r.json()` 抛错,弹窗永远停在“正在生成…”

修复: - 后端:`if done_today:` 前补 `per_init(so)` - 前端:`genReportDo()` 增加 `.catch()` → 显示“⚠️ 生成失败:…”+关闭按钮

验证:`/api/report/today` 200(1096 字符,含负责人/工时/星级)|周报接口本就正常(已有 catch)|三模块 200

经验:① 聚合 per[键] 累加前一律先 `per_init` ② 所有 fetch 必须带 `.catch()`(否则失败时 UI 卡死无提示)

研发任务管理系统h5/冷启动文件.1789643442.txt.gz · Last modified: by 172.17.0.1