Commit Graph
18 Commits
Author SHA1 Message Date
shishengliang 6ea1b3d5dd revert: restore v1.1.14 (37a9f303)
ci/woodpecker/push/woodpecker Pipeline failed
2026-09-16 09:29:30 +08:00
dsh-agent 5196db5df7 refactor(stage12): 调度域拆出 repository,跨域数据源改为显式注入
改动
- 新增 scheduling/repository.ts:通知/干预与建议列表的全部 SQL(13 条)。
- notify.ts / suggestions.ts 改为 register*(app, deps) 可注入,保留默认导出与 create*Router 工厂。
- suggestions.ts 的两处跨域依赖(里程车辆信息、OneOS 里程)改为依赖注入:
  既让本域可独立测试,也让"建议依赖里程数据"在类型上可见,而不是藏在 import 里。
- 跨域引用修正:mapRegion 原本从 '../vehicles/routes.js' 引入(为一个纯函数把整个
  车辆路由拖进依赖图),改为直接从 '../vehicles/model.js' 引入。

契约测试(新增 10 个用例)
- 逐条锁定 SQL 与参数顺序:干预登记的三步(查重 → INSERT → 回读)、409 阻断、
  批量循环、历史列表的状态过滤与 limit 上限(500/默认 200)、状态更新的 UPDATE 形状、
  400/404 分支、活跃映射与近 7 天计数、建议列表五条基础查询的内容与顺序。
- 架构守护升级:不再只看 routes.ts,而是要求该域**除 repository.ts 外的任何非测试文件
  都不得含 SQL**;匹配用"语句形状"正则(如 update <table> set)而非裸关键字,
  避免把 UpdateNotification 或日志 "update error" 误判。已验证 6/6 个 repository 被识别、
  其余文件零误判。

等价性验证
- 把 notify.ts / suggestions.ts 改造前的实现从 git 取出,与改造后跑同一批请求
  (9 个场景,含建议列表整条链路 8 次查询),对比落库 SQL、参数、HTTP 状态与响应体:
  完全一致。
- 期间修正了两处**验证工具自身**的缺陷(旧文件误引用新 notify;跨域默认实现的调用
  被记到另一侧),修正后结论可信。

lint / test(191) / build 全绿,可达性 0 未引用文件。
2026-09-11 10:44:52 +08:00
dsh-agent 795fb207cb refactor(stage9): 后端业务域目录形状统一
- 每个域现在都是 src/server/routes/<domain>/ 目录:
  vehicles/routes.ts(原 routes/vehicles.ts)、vehicle-heatmap/{routes,model}.ts、
  hydrogen-heatmap/{routes,model}.ts、ele/routes.ts、feedback/routes.ts。
- 命名约定:index.ts 是聚合器(挂子路由),routes.ts 是叶子路由。mileage/energy/
  scheduling 保持 index.ts 聚合,其余统一为 routes.ts。
- 纯移动与改名,未改动任何 SQL、参数顺序、路由挂载前缀或处理器逻辑。
  import 改写由一次性 codemod 完成;vehicles/repository.test.ts 读取的源码路径同步更新。
- docs/ARCHITECTURE.md 补充"后端业务域形状"表,并如实标注 ele / feedback 尚未拆出
  repository(这两个域缺 SQL 指纹测试,建议先补测试再拆)。

lint / test(139) / build 全绿,可达性 0 未引用文件。
2026-09-11 10:30:54 +08:00
dsh-agent b28ca49491 refactor(stage7): 后端目录分层、架构守护测试与文档
后端目录
- db/:mysql / hydrogen / heatmap 连接与氢能只读 SQL 守卫收拢到一处。
- middleware/:auth(JWT → 注入 user)与 read-only 归位。
- 相关测试随文件移动(middleware/read-only.test.ts、db/hydrogen-read-only.test.ts)。
  import 改写由一次性 codemod 完成,未改变任何逻辑。

架构守护
- 新增 src/architecture.test.ts,断言 6 条分层铁律:
  server 不依赖 modules、前端不依赖 server、shared 为叶子层、
  无 vendor 引用、model.ts 不依赖 react、@ts-nocheck 仅限已登记的原型快照。
  豁免清单只减不增。

测试基建
- npm test 的 glob 同时匹配 .test.ts 与 .test.tsx(此前 .tsx 测试会被静默漏掉)。

文档
- 新增根 README.md:入口、快速开始、命令、目录、部署注意事项
  (JWT_SECRET 必须注入且 >=32 字符,否则拒绝启动)。
- 新增 docs/ARCHITECTURE.md:依赖方向、6 条硬规则、业务域形状、
  中间件顺序、新增模块步骤,以及"已知未尽事项"的诚实清单。

lint / test(134) / build 全绿。
2026-09-11 10:20:47 +08:00
kkfluous 3f29bed5fa feat: integrate OneOS mileage APIs and release v1.1.10
ci/woodpecker/push/woodpecker Pipeline was successful
2026-07-23 12:19:11 +08:00
kkfluous 91202bdf71 fix asset module database migration
ci/woodpecker/manual/woodpecker Pipeline was successful
2026-06-17 11:53:39 +08:00
kkfluousandClaude Opus 4.7 200172f0af feat(scheduling): role-based access + align list count with qualifiedCount
ci/woodpecker/push/woodpecker Pipeline was successful
- Gate 智能调度 module on BI-SCHEDULE-OPT role (or full-access roles)
  via shared canAccessScheduling helper, replacing hardcoded userId allowlist
- Thread roles[] through JWT payload → middleware → frontend nav
- Add router guard that 403s non-authorized users on /api/scheduling/*
- Emit replace_qualified suggestion for every qualified vehicle so list
  count matches the 已完成考核目标 card; recalc qualifiedCount /
  hopelessCount post-permission-filter for card↔list consistency

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 15:42:21 +08:00
kkfluousandClaude Opus 4.7 ba1e0e9f16 feat(scheduling): add 近期已干预 summary card (last 7 days)
Restore 替换建议 card and add a new emerald 近期已干预 card. Clicking
opens the history modal pre-filtered to the last 7 days (excluding
cancelled) via a toggle chip users can switch off.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-17 09:25:59 +08:00
kkfluousandClaude Opus 4.7 1d9f4cb43d feat(scheduling): history view, execute/cancel lifecycle, CSV export, 7d trend
- Add 调度记录 modal: lists notifications by status, supports 标记已执行 (with
  after-mileage + notes) and 取消 for open records
- Add CSV export of filtered suggestions (UTF-8 BOM for Excel); top candidate
  per row picked by same-region > can-qualify preference
- Compute customer 7-day average alongside 30-day baseline in a single query;
  show trend indicator (up/down/flat) next to 客户日均 in list and detail card

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-16 23:47:31 +08:00
kkfluousandClaude Opus 4.7 3ef0d4edfa feat(scheduling): persist notifications, batch notify flow, dedup protection
- Add tab_scheduling_notifications table with bootstrap via ensureSchedulingTables()
- Notify endpoint rewritten: dedup by (suggestion_id, candidate_plate), history list, PATCH /:id for execute/cancel lifecycle
- Batch notify endpoint returns success/skipped/failed counts
- Suggestions response now carries notificationId + notificationStatus per candidate (joined from active-notification map)
- UI: select mode with checkboxes, floating action bar, confirmation modal listing each swap; already-notified items are dimmed and skipped
- Detail view badges show sent/executed state, preventing duplicate notify

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-16 23:43:21 +08:00
kkfluousandClaude Opus 4.6 aa9a29fed8 fix(scheduling): use each candidate's own daysLeft for prediction
ci/woodpecker/push/woodpecker Pipeline was successful
Different assessment targets have different end dates. Previously all
candidates used the current vehicle's daysLeft, causing wrong predictions.

Now each inventory vehicle computes its own daysLeft from its assessment
target's current_year_assessment_end_date. predictedAfterSwap uses the
candidate's own daysLeft instead of the current vehicle's.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 22:58:47 +08:00
kkfluousandClaude Opus 4.6 d0984a430b refactor(scheduling): improve reason text, fix classification, polish detail view
ci/woodpecker/push/woodpecker Pipeline was successful
- Classification: qualified requires actual completionRate >= 100% (not just predicted)
- Reason text: structured two-column layout (客户日均 | 考核周期剩余)
- Conclusion line in red bold (预估无法达标,需替换 / 已达标,建议换上未达标车辆)
- Remove verbose subtitle from candidate section
- Remove redundant middle line (预估考核期里程 vs 考核里程)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 22:32:50 +08:00
kkfluousandClaude Opus 4.6 694e9a207a feat(scheduling): enable department/personal permission filtering
ci/woodpecker/push/woodpecker Pipeline was successful
- Disable BYPASS_AUTH (was true, now false) — backend enforces JWT auth
- Scheduling suggestions filtered by department/manager permissions:
  - full: see all suggestions
  - department: see only own department's vehicles
  - personal: see only own managed vehicles
- Candidate vehicles (inventory) remain fully visible to all
- Summary recalculated after permission filtering
- Consistent with mileage module permission model

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 22:04:52 +08:00
kkfluousandClaude Opus 4.6 9398688829 feat(scheduling): add department/manager filters, refine color palette
- Add department and manager fields to backend types and suggestions API
- Add department/manager to advanced filter panel
- Refine card colors: orange (换下) / blue (换走) / dark slate (全部)
- Selected card uses solid bg color, inactive uses gradient
- Batch pills use dark slate, confirm button uses dark slate
- Background changed to #F0F4F8 for subtle cool tone

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 21:28:04 +08:00
kkfluousandClaude Opus 4.6 ec3b079311 fix(scheduling): only suggest replacements for rented/operated vehicles
Filter enriched vehicles to only include rent_status = '租赁' or '自营'.
Inventory candidates already filtered by truck_rent_status = 0 (在库).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 20:52:16 +08:00
kkfluousandClaude Opus 4.6 033af15814 fix(scheduling): include soft-deleted trucks and infer type from target name
411 of 451 assessment vehicles had is_deleted=1 in tab_truck, causing type
classification to fall back to "其他" and miss all inventory matches. Fix:
- Remove is_deleted=0 filter from truck type query (assessment vehicles need type info regardless)
- Add inferTypeFromTargetName() fallback deriving type from target name when truck record is missing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 20:47:00 +08:00
kkfluousandClaude Opus 4.6 253cc2f2c0 fix(scheduling): fix vehicle type classification and algorithm candidate matching
- classifyVehicleType now parses dic_type.dic_name (e.g. "4.5吨冷链车") instead of raw model code
- Remove overly strict completionRate >= 0.8 filter for hopeless candidates
- Use vehicle's yearTarget as fallback when inventory has no assessment target
- Filter out suggestions with no candidates (not actionable)
- estimatedGain counts rescue_hopeless suggestions as potential gains

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 20:31:44 +08:00
kkfluousandClaude Opus 4.6 4169e04a9c feat(scheduling): add suggestions route with data aggregation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-16 20:23:56 +08:00