====== 研发任务管理系统 H5 — 冷启动文件 ====== > 版本: 1.0 | 更新: 2026-08-31 | 用途: 研发任务管理系统(含库房集成)的冷启动/重建/排障手册 > ⚠️ **功能保全铁律(用户定稿):本系统功能只增不减,改版前先读本文件,改完逐项验证,功能不允许丢失。** > ⚠️ **测试铁律:测试必须用独立数据/独立进程,严禁污染生产数据(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 优先读此文件 | | `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 迁移) ==== * 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/ | POST | 更新任务(can_edit 校验) | | /api/tasks/ | DELETE | 删除任务(can_delete 校验) | | /api/tasks//note | POST | 添加更新记录(can_edit) | | /api/tasks//note/ | DELETE | 删除记录(can_edit) | | /api/tasks//subtask//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/store/* | * | 库房 API(samples/requests/approve/destroy/back/back_apply/ledger/history/...) | ===== 六、关键规则(用户拍板) ===== - **管理员**:武燕青——查看/编辑所有任务 + 账号管理;普通用户只见/只编辑自己任务 - **只读模式**:?ro=1(共享链接);**登录用户自动退出只读**(exitReadonly 恢复标题/按钮) - **任务负责人**:存简称(张/席),登录用全名——匹配用 name_variants(简称↔全名变体) - **普通用户不显示**:切换身份、账号管理、口令登录入口(唯一登录=钉钉认证) - **日报**:生成今日日报(按任务/工时);员工日报汇总 21:30 推送(cron 52967bf00170) - **钉钉通讯录**:MCP 同步到 ding_org.json(cron 8f32fd550f80 每周一 06:00) ===== 七、部署运维 ===== 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 | ===== 九、测试隔离 ===== * 任务:测试账号不写生产 rd_tasks.json(改前备份 git 可回滚) * 库房:`STORE_DB=/tmp/store_test.db STORE_PORT=13599 python rd_store.py` 独立实例,测完删库 * 严禁直接操作生产数据;测试数据即时清理