15 KiB
2026-09-17
清空「定开项目」模块数据
按用户要求清空 data/board.db 里定开项目模块的全部数据(保留表结构与其余模块)。
- 备份:
data/board.db.bak-before-clear-custom-20260917_105824 - 删除顺序:先子表
custom_updates(28 行)→ 再父表custom_projects(119 行),避免外键孤儿。 - 清空前摘要:119 个定开项目(归档 0),合同额合计约 395.2 万,累计计收 0。
- 清空后校验:两表均 0 行,
custom_updates孤儿记录 0。 - 接口验证:
/api/custom/projects返回[];/api/weekly的custom段 0 条,KPI 中custom_total / custom_amount / custom_new / custom_updated / revenue_delta全部归零。项目管理模块(projects/tasks/updates)未受影响。 ledger_items(定开台账)本来就是 0 行,未动。
导入《定开项目.xlsx》市场台账 + 扩展 custom_projects 字段
用户提供 C:/Users/Administrator/Desktop/定开项目.xlsx(Sheet1,120 行含表头 → 119 条数据,14 列),要求导入定开项目库、按表格调整字段、并加「更新时间」字段便于按周查看变化。经确认采用:新增字段(不重构) + 每行一个更新时间 + 项目状态新增独立字段。
表结构(10 个新字段,靠 schema_patch.ensure_columns 自动 ALTER TABLE)
origin(项目归属) / project_code(项目ID, index) / office(办事处) / industry(行业) / man_days(市场下单人天) / market_owner(市场责任人) / project_status(项目状态) / accept_plan(推动验收计划) / risk_level(风险值) / update_date(更新时间 YYYY-MM-DD, index)
字段映射(表格列 → DB 列)
- 项目归属→origin、项目名称→name、项目ID→project_code、行业→industry、市场下单人天→man_days、市场责任人→market_owner、项目状态→project_status、推动验收计划→accept_plan、风险值→risk_level、备注→remark
- 下单时间→
sign_date(原字段注释就是「签单/下单时间」);办事处→region(归一化)+office(原样);验收时间→accept_date entry_date(入库时间)兜底取下单时间,保证明细列表「按入库时间倒序」有排序键
数据质量(表格里就有的问题,未擅自改)
- 重名 2 行:「甘肃省水利厅图像站建设项目二期」×2,项目ID 不同(HGSE25122401N / HGS025010202N)→ 导入脚本有 ID 时只按 ID 匹配,否则会互相覆盖
- 1 行无项目ID(高新区感知源-钰田(定制开发))、1 行无办事处
- 「验收时间/推动验收计划」是季度文本(Q1..Q4/27年),互补:60+59=119
- 「下单时间」混格式:91 个真日期 + 28 个文本(
2024年3月前、2024/)→ 日期转 YYYY-MM-DD,文本原样存 - 「市场责任人」51 人全部不在花名册(销售侧人员,与
owner交付负责人是两个概念) - 只有「深圳」不在区域词表 → 已在
constants.REGION_ALIAS加深圳/深圳市 → 广东
改动文件
app/models.py:CustomProject 加 10 字段 +to_dict输出app/routers/custom.py:PATCH 白名单加新字段;台账字段有变化时刷新update_date(无变化不刷新,已实测);创建时写update_date;CustomProjectIn补字段app/routers/export.py:导出追加 10 列(末尾追加,保持原 money_cols 索引不变)web/app.js:明细列表 16→25 列(加 项目ID/行业/项目归属/市场责任人/项目状态/风险值/人天/推动验收/更新时间);新增statusPill/riskPill小色块;详情抽屉加「市场台账」区块(只读 + 编辑);KPI 提示加 人天/高风险scripts/import_custom_ledger.py:新建,openpyxl 读取 + 按 ID/名称 upsert + 变更比对,支持--dry-run/--date
验证
- 导入:新增 119 / 更新 0 / 无变化 0;重复导入幂等(0/0/119)
- 分布与源表一致:项目状态 已验收60/待开发31/交付完成17/交付中9/退单2;行业 安平51/政府25/企业22/教育11/交通6/医疗2/行业1/高速1
/api/custom/projects返回 119 条含全部新字段;导出 34 列、合计行人天 5066- PATCH 改 industry → update_date 由 2026-01-01 刷新为今天;提交相同值 → 保持旧日期(变更检测正确),测试后已还原
- 备份:
data/board.db.bak-before-ledger-import-20260917_141759
遗留 / 待确认
- 119 行
stage全是默认signed、progress0、计收/开票/回款为空 —— 新台账不带这些业务字段,模块里依赖它们的旧列(进度%、可确认、已计收、开票、回款)目前是空的 - 页面未做浏览器截图验证(agent-browser 未安装,装 Chromium 要 ~500MB 且规则禁止全局 npm),只做了 JS 语法校验 + 接口/导出功能验证
定开项目明细表改为按 Excel 表头顺序展示
用户要求明细表字段参考导入的 Excel 表头。实际 Excel 表头顺序(14 列)为:项目归属 / 项目名称 / 项目ID / 下单时间 / 办事处 / 行业 / 市场下单人天 / 订单金额 / 市场责任人 / 项目状态 / 验收时间 / 推动验收计划 / 风险值 / 备注。
- 重排
renderCustomList表头+数据行,完全按此顺序;追加「更新时间」(用户此前要求,非 Excel 字段)与「操作」列 → 共 16 列。 - 从主表移除 Excel 没有的旧列:区域、负责人(owner)、入库、交付、阶段、进度%、可确认/已计收/开票/回款 —— 这些仍保留在详情抽屉里。
- 顶部统计行改为:合同额/万、人天、高风险数、已验收数(去掉空的计收/开票/回款)。
- 纯前端改动(
web/app.js),后端无需重启;接口此前已验证返回全部新字段。node--check语法通过。
明细表交互改造:去按钮 / 状态筛选 / 新建表单对齐 Excel / 统计条
用户四项要求:① 明细表去掉「详情」「归档」按钮 ② 新增「项目状态」筛选 ③「新建定开项目」字段参考 Excel 调整 ④ 表格上方加统计(项目数量+金额、本月/本年新增下单、本月/本年验收)。
新增字段 accept_date_real(验收日期,真实日期)
Excel 里「验收时间」是季度文本(Q1..Q4),无法算「本月/本年」,故新增 accept_date_real(String(16), YYYY-MM-DD, index)专门用于验收统计,与 accept_date(季度文本,展示用)并存互补。
- 改动:
models.py(字段 + to_dict)、custom.py(CustomProjectIn / PATCH 白名单 / create 时region可由office归一化推导)、scripts/import_custom_ledger.py(导入时对「已验收」+季度文本的行补当年季度末占位;仅在库中为空时补,不覆盖用户手改的真日期)。 - 一次性回填:已导入的 119 行中 60 条「已验收」补上 2026 季度末(Q1→03-31/Q2→06-30/Q3→09-30/Q4→12-31),不动
update_date。结果:本年验收 60、本月(9月)验收 17。
前端(web/app.js + styles.css)
- 去按钮:
renderCustomList行操作列只留「修改」(data-cedit);名称仍可点开详情(data-copen)。bindCustomList移除data-carch绑定。 - 状态筛选:工具栏加
<select id="cStatus">(全部/已验收/待开发/交付完成/交付中/退单),state 加customStatus,在renderCustomList内对已加载行做客户端筛选。 - 新建表单:
openNewCustomDialog重写为对齐 Excel 的字段(项目归属/项目名称*/项目ID/下单时间/办事处/行业/市场下单人天/订单金额/市场责任人/项目状态/验收时间(季度文本)/推动验收计划/风险值/验收日期/备注/重点项目);提交时把台账字段发给后端,region由后端按 office 归一化(实测 深圳→广东)。更新录入页共用此函数,一并生效。 - 统计条:新增
.stat-row/.stat(styles.css),在renderCustomList表头上方展示 5 个格子:项目数量/合同额、本月新增下单、本年新增下单、本月验收、本年验收(均「个数 · 金额万」)。下单按sign_date、验收按accept_date_real,基于当前筛选后的行计算;card-head 的 period-hint 保留人天/高风险/已验收。
验证
- 语法:node
--check(app.js)、ast.parse(models.py/custom.py/export.py/import_custom_ledger.py/constants.py)全通过。 - 接口:重启后
/api/custom/projects119 条含accept_date_real;POST 新建含全部台账字段 → region 由 office 推导正确(深圳→广东),测试项目已删除;/api/export/custom200。 - 统计口径实测:本年验收 60、本月(2026-09)验收 17、本年新增下单 31、本月新增下单 0。
- 页面未做浏览器截图(agent-browser 未装),刷新浏览器查看即可。
明细表:去掉归档下拉 / 按更新时间排序 / 删除本周更新
用户(附截图:归档状态下拉「在库/已归档/全部」)要求:① 删除该下拉 ② 新增展示并「按更新时间排序」 ③ 可按周删除「本周更新」的数据。
前端(web/app.js)
- 移除明细表 card-head 里的
#cArchived归档状态下拉及bindCustomList里的绑定;state.customArchived保留(恒为 "false",仍只查非归档)。 - 排序:
renderCustomList的view改为按update_date倒序(String(b.update_date).localeCompare(...)),表头副标题改为「按「更新时间」倒序」。 - 删除本周更新:card-head 加
<button id="btnPurgeWeek" class="btn sm danger">删除本周更新</button>;purgeWeek()先GET /custom/weekly-preview拿数量/金额/名单 →confirmDialog({danger:true, requireText:"删除"})二次确认(并要求手动输入「删除」)→POST /custom/purge-week→afterWrite()刷新。 confirmDialog增加可选o.requirePlaceholder(原来输入框 placeholder 硬编码「逐字输入项目名称」,批量删除场景不适用)。
后端(app/routers/custom.py)
- 新增
_sort_by_update()(update_date 倒序,无则回落 entry_date);GET /custom/projects改用之(原来是_sort_by_entry)。 - 新增
_week_range()(当前自然周 周一~周日,基于date.today()的weekday())。 - 新增
GET /custom/weekly-preview(本周有 update_date 的项目数/金额/名单,供确认)。 - 新增
POST /custom/purge-week(删除 update_date 落在本周的项目,db.delete(cp)靠 relationship cascade 连带删 custom_updates),返回{deleted,start,end,names}。 - 路径用
/custom/weekly-preview、/custom/purge-week,避开/custom/projects/{cid}(int 路径参数会被非数字段 422),未放在 projects 前缀下。
验证
- node
--check+ ast OK;服务重启后/healthok。 /api/custom/weekly-preview→ 本周 2026-09-14 ~ 2026-09-20,119 个(因导入把 119 行 update_date 都写成 2026-09-17=今天),合同额约 1130.7 万。/api/custom/projects已按 update_date 倒序返回。- ⚠️ 注意:当前所有行 update_date 都是导入当周,所以「删除本周更新」= 会删掉全部 119 条;已用「显示数量 + 需输入『删除』」做强确认。未实际执行 purge(只验证了 preview)。
定开金额单位:明细表用元、汇总统计用万
用户要求表格列「订单金额/万」去掉「/万」,单位换成正常的个位(元);但汇总统计仍需用「万」。
- 关键事实:
custom_projects.amount在库里本来就是元(实测 sum≈11,307,268、avg≈95,019、max=1,000,000),之前的「/万」只是展示约定——fen()/wan()把元÷10000 显示成万。 - 最终约定(定开金额):明细表格每行 = 元(
money(p.amount),¥+千分位);所有汇总/统计 = 万(fen()/wan())。 - 改动(纯前端
web/app.js,静态服务无需重启):- 定开项目明细表:表头
订单金额/万→订单金额;单元格fen(p.amount)→money(p.amount)(元)。 - 上方统计条、人力资源页「定开合同额/定开待计收」、工作看板 KPI「定开合同额」、
删除本周更新确认框的「合同额合计」——仍用万(fen()/wan()),未改/已改回。
- 定开项目明细表:表头
- 未动:项目管理(交付跟踪)模块的「合同额」仍用 wan/fen+万(另一套
projects数据);导出沿用原始元值。 - 服务
/healthok,浏览器刷新即可见(static 带 no-cache+ETag)。
更新时间 = 下单时间 + 修改表单对齐台账字段
两项需求:(1) 更新时间全部改为项目下单时间;(2) 定开「修改」表单只保留《定开项目.xlsx》14 列表字段,删除交付跟踪类多余字段。
1) update_date = sign_date(全量)
- 备份:
data/board.db.bak-before-updatedate-sign-20260917_000000。 UPDATE custom_projects SET update_date = sign_date(119/119 行;0 个 null sign_date,91 个真日期 + 28 个文本如「2024年3月前」)。- 后端
app/routers/custom.pyPATCH:原本改任何字段就update_date=today,改为update_date = cp.sign_date if cp.sign_date else cp.update_date(跟随下单时间)。已用 API 实测:改 remark 后 update_date 仍为 2024-04-30(=sign_date),不是今天。 scripts/import_custom_ledger.py:新增/更新行的update_date改默认取sign_date(无则回退 args.date);同步改了文档注释。- 副作用:「删除本周更新」现在按 sign_date 周判断,历史台账(2024/2025)不会命中本周 → 之前「会删光 119 条」的危险消失。
2) 修改表单对齐台账(前端 web/app.js)
openCustomDrawer的 edit 模式:section「定开项目信息」只放 Excel 14 列(项目归属/项目名称/项目ID/下单时间/办事处/行业/市场下单人天/订单金额/市场责任人/项目状态/验收时间/推动验收计划/风险值/备注)+ 验收日期 + 只读「更新时间(跟随下单时间)」。- 删除的多余字段:基础信息里的 阶段/开发进度/已计收/确认比例/交付环节/区域/交付负责人/团队成员/客户;收入确认里的 开票金额/已回款 编辑框(收入确认 KPI 只读区仅在 view 模式显示,edit 模式整段不渲染)。edit 模式只渲染 ledgerSec 表单,baseSec/收入确认/周期执行记录/阶段流转 仅 view 模式渲染。
cdSavePATCH payload 精简为上述台账字段(不再传 stage/owner/region/members 等,未传字段不动;set_people对 None 不改成员)。- view 模式补充显示 下单时间、验收时间(之前漏显示)。
- 数据保护:编辑表单的「下单时间」用 text 输入(非 date),因为 28 行 sign_date 是文本(date 控件会清空它们);新建对话框仍用 date。
- 重启 uvicorn 使后端生效(原 PID 40088 → 新进程);
node --check与ast.parse均通过;前端 static 无需重启。