From cd37ea46614ba28cbb14d4d9733f8065f35642c2 Mon Sep 17 00:00:00 2001 From: chezhiqi Date: Wed, 23 Sep 2026 16:34:56 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9A=E5=BC=80=EF=BC=9A=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E5=8F=A3=E5=BE=84=E6=8C=89=E9=A1=B9=E7=9B=AE=E7=8A=B6=E6=80=81?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=20+=20=E5=91=A8=E6=AC=A1=E6=8C=89=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E8=87=AA=E5=8A=A8=E5=88=9B=E5=BB=BA=EF=BC=88=E5=90=88?= =?UTF-8?q?=E5=B9=B6=20main=20V=200.1.1=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 合并 origin/main「V 0.1.1」(bcb3feb):fast-forward,带来登录/权限(RBAC)、users/roles 表等 验收统计改为:先按「项目状态 = 已验收」过滤(状态一改,统计立即同步),季度归属再按「验收时间」accept_date,验收时间为空时算本季度;工作看板同口径同步 周期按时间自动创建:/api/periods 每次补齐「今天所在的这一周」,本周期默认落在本周(已自动生成 9月第4周) --- .workbuddy/memory/2026-09-20.md | 8 +++++++- .workbuddy/memory/2026-09-23.md | 26 ++++++++++++++++++++++++++ .workbuddy/memory/MEMORY.md | 5 +++++ app/routers/board.py | 6 ++++++ data/board.db | Bin 409600 -> 409600 bytes web/app.js | 15 +++++++++------ 6 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 .workbuddy/memory/2026-09-23.md diff --git a/.workbuddy/memory/2026-09-20.md b/.workbuddy/memory/2026-09-20.md index a3a50e4..eb18451 100644 --- a/.workbuddy/memory/2026-09-20.md +++ b/.workbuddy/memory/2026-09-20.md @@ -93,4 +93,10 @@ 3. **表头排序**:`下单时间`(sign_date) / `订单金额`(amount, 数值) / `更新时间`(update_date) 三个表头可点击排序,`state.customSort = {key, dir}`;点不同列默认「降序」,再点同列切换升/降;表头显示 ▲/▼,卡片副标题显示当前排序。 4. **新增「推动验收计划」筛选**:工具栏加 `#cAcceptPlan`(`state.customAcceptPlan`),选项取数据中实际出现过的值(Q3/Q4/27年/-- 等);导出也带 `accept_plan` 参数(后端 `export_custom` 新增 `accept_plan`)。 - `state` 新增 `customAcceptPlan` / `customSort`,均加入 `UI_FIELDS` 持久化。 -- 后端 `export.py` 改动 → 重启 uvicorn(PID 23436);`node --check` / `ast.parse` 通过。实测导出 `accept_plan=Q3` 生效。**本轮未 push**。 +- 后端 `export.py` 改动 → 重启 uvicorn(PID 23436);`node --check` / `ast.parse` 通过。实测导出 `accept_plan=Q3` 生效。 + +## 第二次推送 develop-chezhiqi +- 提交 **07e1b0a**「定开项目:改名(华智下单/进行中)+ 表格排序与筛选 + 列序/按钮调整」(6 files changed, 106 insertions, 78 deletions):`web/app.js`、`app/models.py`、`app/routers/export.py`、`scripts/import_custom_ledger.py`、`data/board.db`、`.workbuddy/memory/2026-09-20.md`。 +- 已 push 到 `origin/develop-chezhiqi`(`a77cd7b..07e1b0a`),本地与远端一致。 +- **注意**:首次 `git push` 那次返回空输出、实际未推成功(`status -sb` 显示 ahead 1),重试后成功;以后 push 后要用 `git status -sb` / `git log origin/` 复核。 +- 仍未提交:`data/board.db.bak-*` 本地备份(7 个,保持 untracked)。 diff --git a/.workbuddy/memory/2026-09-23.md b/.workbuddy/memory/2026-09-23.md new file mode 100644 index 0000000..3c7ad47 --- /dev/null +++ b/.workbuddy/memory/2026-09-23.md @@ -0,0 +1,26 @@ +# 2026-09-23 + +## 合并 main(V 0.1.1)到 develop-chezhiqi + +- `git fetch`:**origin/main 从 e9854eb 前进到 `bcb3feb`「V 0.1.1」**(其祖先已包含 a77cd7b / 07e1b0a,即 develop-chezhiqi 的全部提交)。 +- `develop-chezhiqi` 是 `origin/main` 的**祖先** → 直接 **fast-forward 合并**:`git merge origin/main`。分支现指向 `bcb3feb`,**领先 origin/develop-chezhiqi 1 个提交(未 push)**。 +- 合并前已备份数据库:`data/board.db.bak-before-merge-main-`。 +- **main 带来的新内容**:登录与权限 —— `app/security.py`、`app/routers/auth.py`、`app/routers/rbac.py`;`users` / `roles` / `user_sessions` 表;`app/config.py`(新增 `ADMIN_PASSWORD`);`app/main.py`(启动时 `security.ensure_seed`);models/schemas 扩展(+83 行等);`web/**`(登录页、按角色显示菜单);`run.sh`、`README.md`、`data/board.db`。 +- **我之前的改动全部保留**:`web/app.js` 里 项目总览 / 推动验收计划 / 进行中 / 华智下单 / 年度任务 / 新增项目 / data-sort 均在;DB 迁移也在 —— origin:华智下单 84 / 存量项目 27 / 汇智直签 10 / 提前交付 2;status:进行中 10(原交付中);`update_date` 空 111 / 有值 12;共 **123** 条。 +- **无需新依赖**:`security.py` 仅用 hashlib / hmac / json / secrets 等标准库。 +- 已启动服务:uvicorn(PID 30036),`/health` ok。 +- **现在需要登录**(重要):未登录访问 `/api/custom/*` 返回 **401**。默认管理员 **admin / admin123**(`app/config.py` 里 `ADMIN_PASSWORD` 默认值,可用 `.env` 覆盖),实测登录成功(角色「管理员」,menus 全 rw);另有 `user`(部门成员,部分菜单只读)。 +- 未提交:`.workbuddy/memory/2026-09-20.md`(本地日志改动)。未跟踪:`data/board.db.bak-*`(本地备份)。 +- 注意:**本地 `main` 分支仍是旧的 e9854eb**(我未改动它);本次合并用的是 `origin/main`。 + +## 修复定开 3 个问题 + +1. **统计不随项目状态变更**(排查结论): + - 不是刷新/缓存问题 —— 实测 PATCH 改状态后 GET 立刻反映;前端 `afterWrite() → refresh() → renderCustom()` 会重新取数,`/api/custom/projects` 也没有缓存头。 + - 真因是**统计口径**:验收只认「验收时间」`accept_date`,改「项目状态」不会移动任何数字。 + - **改口径**:验收**先按「项目状态 = 已验收」过滤**(状态一改统计立即同步),**季度归属再按「验收时间」**`accept_date`,**验收时间为空时算「本季度」**。工作看板里同口径的「本季度/本年验收」(`web/app.js` 约 1186 行)也同步改了。 + - 影响数字:本年验收 65 → **68**、本季度验收 22 → **25**、本季金额 → 101.54 万(多出的 3 条是「状态=已验收但没有验收时间」的项目)。实测:把某项目改成已验收 → 本季 25→26、本年 68→69。 +2. **「本周」= 9月第4周、默认展示本周**:`periods` 表原来只到「9月第3周」,`/api/periods` 的 `today_id` 为 `null`,前端只能退回最后一个周期(第3周)。 +3. **周次按时间自动创建**:`app/routers/board.py` 的 `list_periods` 里加了一句 —— `_week_period(db, *constants.week_of_date(date.today()))`(复用 `focus._week_period`),每次取周期列表时自动补上「今天所在的这一周」。实测首次请求即生成 **9月第4周(id 53,2026-09-21 ~ 09-27)**,`today_id = 53`,无需手动新建。 + +- 重启 uvicorn(PID 26184);`node --check` / `ast.parse` / `/health` 均通过。本轮改动**未提交**。 diff --git a/.workbuddy/memory/MEMORY.md b/.workbuddy/memory/MEMORY.md index af5e442..4a9ac6f 100644 --- a/.workbuddy/memory/MEMORY.md +++ b/.workbuddy/memory/MEMORY.md @@ -45,6 +45,11 @@ 导入「市场责任人」等销售侧人名**不走花名册校验**,不要往 `staff` 里塞。 +## 登录与权限(2026-09-23 合并 main V 0.1.1 起) + +- 全站需**登录**:未登录访问 `/api/*` 返回 **401**。默认管理员 **admin / admin123**(`app/config.py` 的 `ADMIN_PASSWORD` 默认值,可用 `.env` 覆盖);另有 `user`(部门成员)。 +- 权限模型:`roles.menus` 是 JSON(board/custom/focus/intake/projects/rbac/settings/staff,值 `rw` / `ro`);内置角色 管理员 / 部门成员 / 只读访客。代码:`app/security.py`(hashlib+hmac 手写,无新依赖)、`app/routers/auth.py`、`app/routers/rbac.py`;表 `users` / `roles` / `user_sessions`。 + ## 术语(2026-09-16 起) 模块③ 的正式称呼是 **「定开项目」**(旧称「定制交付」),界面统一用「定开」:定开项目 / 定开项目明细 / 定开合同额 / 定开记录 / 定开动态 / 定开待计收。`categories` 表里也有一行分类叫「定开项目」。 diff --git a/app/routers/board.py b/app/routers/board.py index 9501d67..2b9b683 100644 --- a/app/routers/board.py +++ b/app/routers/board.py @@ -63,6 +63,12 @@ def resolve_period_ids( @router.get("/periods") def list_periods(db: Session = Depends(get_db)): from ..models import CustomUpdate + from .focus import _week_period + + # 周期按时间自动创建:确保「今天所在的这一周」一定存在,不再需要手动新建第几周。 + # (_week_period 已用于「每周重点工作」,没有则补一条,口径与 week_of_date 一致) + _week_period(db, *constants.week_of_date(date.today())) + db.commit() weeks = db.query(Period).order_by(Period.sort_key).all() uc = dict( diff --git a/data/board.db b/data/board.db index 7224015a5cb75f3ae4ec9dd6e511dcbcdd26ce50..506bb10556d1fde5e8dea2468776223be82b6931 100644 GIT binary patch delta 2079 zcmb7^{cjU>9LK-c-u29s7r`GWpH4X&xHdu~VSg&iqK zT^eOaO8fJTa?^L^i(&zH=5f$<}8PSUD^r zzp0+d3sGeA<1;mtb!tr(S&>CRqEM14U zSFt=v2oynaHo{?}@?G*yhP3lM?cfP{Fpg}Jw?~l8^6zHEQo2$zquo*qhGpnmq)Pd* zA89ebCEu97I96@_TKRPlVKv*Phns5w2`rkt538EW_O#Sgnc5VbM!MJK*;$hWJ0Yk| zadKG%sgPeuBh{$#(e3wNUVQD7Hd?-6hszC1#R`@|&g%EA18HEh1nU*-2y%Yfyc{x$6a;~mFaL{dS#^^lIg-1mgRNE^jcd%u%?y48 zJB~4U6bGg&rl?6%a-xJoucC2vhkDUTu@vbwx?JPC$lXG4G}7s7YwSx%wjrsf%OSF( zQfnjMeyGC}jtuwvq}Z-dytl}uT;M6vK?+PxA&I4s6%>INXwjUb3^)=@d}xU6X_uO9 zLgRR-Yci1_lcQoL6zyziiMsd}e`~rm-Ag1}iZHB`CG0%I(R_YPE0}^pGc+sWISj)$ zhhxp%2RlYxjf24fIy8Qe>GMnsH;hrfp?)cus_%F8B@c;B{=Jh$7{*Dkc7{;HNfv!g zK_NJX6tNt}FC}8$^u$1Ktb8bJe3&X14O-tr)Db*2@Iz&Hr-W?701E=pT@p2m*H*L zUGph?0l#6EuvxRqd<_fZ)oS*4Vv|p3d!dI2erdLTZG`_f!RBoJeX=-N97a6*z(b@8 h%ho?cJWSd8l{tqVIOvkx7Zi=`J`+Qgg{O1@=s(GvD2(8_Hsv%uNCyLZlyik4x`kDTdhttiWFIakANnq(21 zL0|YI5qeAd(8yE>QdYc~5Ydka`k;t@RgmGfq(AjHkeX1`j|UFt@Nf=?6OZS|i$CVVL#kT(Ewn> z0eA&2(q!fUtZ}H=8o*HvK(U;thoM%1!*}2donRE@O2JwwOQn)vwTk8V?I>J^TgTug z2msiFN5)_gy&mAn1z19^k3rut6K7q<2lPT4Id4A|@ z=JD;!*g*R7WUBws-1ODVg>zYuzS_qW6@zX}Jwpca>IiC3Le0;d`9YKMDf!%qY&33+ zAtyc+MF;Vg6jb2tUmypS3t%JGb)hwSlPP^OnIbp7Ci>?d4y7-~)7S11Z5NtgnKBT= z;w&^QH|Wgk!QO_JYRj&gCZole>f`E)|A;6nW{XutP=-$U@uw(SO98w&hP?kg6@93t z7#zbtPNPEn{T*b9_B5JI@IpnUt)fzrO0x@*L;=72g^K { const t = String(s || "").trim().toUpperCase(); return /^Q[1-4]$/.test(t) ? t : ""; }; - const accQuarter = customAll.filter((p) => qOf(p.accept_date) === "Q" + qNo); + // 先按「项目状态=已验收」过滤(状态一改统计立即同步);季度归属再按「验收时间」,为空时算本季度 + const accRows = customAll.filter((p) => String(p.project_status || "").trim() === "已验收"); + const accQuarter = accRows.filter((p) => { const q = qOf(p.accept_date); return !q || q === "Q" + qNo; }); const accQuarterAmount = accQuarter.reduce((a, p) => a + Number(p.amount || 0), 0); - const accYearCount = customAll.filter((p) => qOf(p.accept_date)).length; + const accYearCount = accRows.length; state.weekly = data; state.customAll = customAll; // 右栏「高风险项目」用全量台账 state.focusRows = focusRows; @@ -1937,11 +1939,12 @@ const signedQuarter = placed.filter((p) => inQuarter(p.sign_date)); const signedYear = placed.filter((p) => inYear(p.sign_date)); - // 验收:以「验收时间」(accept_date,季度文本 Q1~Q4) 为准;本季度 = 当前季度 + // 验收:以「项目状态 = 已验收」为准(状态一改,统计立即同步); + // 季度归属看「验收时间」(accept_date,季度文本 Q1~Q4);验收时间为空时按「本季度」计。 const qOf = (s) => { const t = String(s || "").trim().toUpperCase(); return /^Q[1-4]$/.test(t) ? t : ""; }; const thisQ = "Q" + Q; - const accRows = allRows.filter((p) => qOf(p.accept_date)); // 有「验收时间」即视为已验收 - const accQuarter = accRows.filter((p) => qOf(p.accept_date) === thisQ); + const accRows = allRows.filter((p) => String(p.project_status || "").trim() === "已验收"); + const accQuarter = accRows.filter((p) => { const q = qOf(p.accept_date); return !q || q === thisQ; }); const accYear = accRows; const stat = (label, count, amount, color) =>