|
|
5d5aea1015
|
refactor(outbound): 出库单据与领用物料合并成一张表
这两者本来就是同一件事(这台设备对应 MOM 的哪些出库单、领了哪些料),
却因为粒度不同被拆成两张表、界面上两张卡:用户要面对两个入口两个删除按钮,
还会问「我在那边挂的怎么这边看不见」。更糟的是**单据级那张没有 mom_line_id,
挂上去的料根本报不了废**。
- 新建 product_outbound_materials,统一到**明细级**(只有它带 mom_line_id,
而报废要用它定位)。单据级信息(申请单号/备注/撤回)作为冗余列落在每条明细上。
task_id 改为可空 —— 任务只是溯源信息,不再是组织维度,展示/报废/删除按设备走。
- 接口从 7 个收敛成 3 个(GET/POST/DELETE /products/{id}/outbound-materials,
外加整单删 by-order)。任务级那套连同 TaskResponse.outbound_materials 一起删掉:
保留第二个入口只会让「同一个东西两个地方」重新长出来。
- MOM 回调存档改为按 outbound_no 去 MOM **现查明细**逐行落 —— 不查的话
这台设备「领了什么料」永远是空的,也就报不了废。查不到时退化成单据级存档,
宁可显示「有这张单但看不到明细」,也不要静默丢掉这张单。
- 扫码响应补 outbound_materials(附「谁挂上去的」中文名,服务端解析)。
⚠️ 依赖 task_tree_loader 的 selectinload —— 异步 session 下懒加载会
MissingGreenlet。
- 前端两张卡合并成一张:按出库单号分组、点开看明细,明细行才有报废/删除。
|
2026-09-23 15:18:06 +08:00 |
|
|
|
551819e0e3
|
feat(scrap): Track 侧生产报废 —— 提交、回查、金额
料领到产线后在生产中报废,要在 MOM 里走报废流程并能统计金额。
- mom_scrap_client:Track **唯一**一处主动写 MOM 的通道。读仍走直连只读库
(MOM 查询接口有权限与行级隔离),写必须走接口(跨库直写会绕过 MOM 的
全部业务校验、权限与审批)。
- product_scrap_service:归属校验是关键 —— 可见范围是整台设备、不是「谁领的」,
不能靠隐藏来防,必须在写入前确认这条 mom_line_id 就挂在这台设备上。
申请人直接用当前登录人(Track 的 sub 就是 MOM sys_user.id),
MOM 里显示的就是本人,不需要服务账号也不会串人。
- 幂等:track_ref 由前端在打开弹层时生成一次、重试复用;网络超时后重试
不该在 MOM 里多报一张单。
- 状态与金额**实时回查 MOM**,不在本地存副本:报废没有回调,本地那份立刻
就过期;且金额取决于执行时的实际扫码量(MOM 允许少扫),受理量 ≠ 执行量。
⚠️ 未执行时 total_loss 是 null 不是 0 —— 0 会让人以为「这东西不值钱」。
- MOM_INTERNAL_API_KEY 走环境变量且不给默认值:未配置时报废提交 503,
而不是让一个写接口在生产上默默开着。
|
2026-09-23 15:18:06 +08:00 |
|
|
|
e45c97bd1f
|
feat: 组织隔离(IRIS 单实例)与出料功能基础
本轮之前累积的未提交工作,一并固化:
- 组织隔离:同一份代码部署给不同部门只需改 config 的 ORG_DEPARTMENT 与
MATERIAL_CATEGORY_PREFIX。过滤点在登录/人员列表/物料/MOM 出库单四处,
全部服务端钉死,客户端传什么都放不大。
★ 物料必须用**前缀** LIKE,不能反推成 ILIKE '%IRIS%':MOM 里 LICA 的物料是
`LICA/<中文>`,而本部门分类树里另有 `IRIS/成品/LICA/…`(本就属于本部门),
前缀匹配天然区分得开。
- MOM 出库单只读查询(直连 MOM 库):不走 MOM 现成的 /outbound 接口 ——
那个要 JWT + permission_required,且对非特权账号按 consumer_name 做行级
隔离,服务账号只能拿到自己名下的单。分页必须两段式(先按单号 GROUP BY
分页,再 IN 捞明细),对宽表直接分页会得到明细行数而不是单据数。
- 出料功能:产品 ↔ 出库单存档(product_outbounds)与任务 ↔ 出库明细
(task_outbound_materials),供「这台设备对应 MOM 哪张单」的展示。
⚠️ 快照一律由后端拿 ID 去 MOM 现查,不接受前端传入,否则前端可伪造单据。
|
2026-09-23 15:18:06 +08:00 |
|
|
|
39697ca3ad
|
feat(audit): 每日活动打点表 —— 修正日活「上线/下线时间」口径
【问题】
上线/下线时间此前取自审计记录(写操作)时间,当天只翻看、没做写操作的人
会被整条漏掉;而取登录时间更错(Refresh Token 有效期 7 天,用户不必每天登录,
会出现「登录次数 0 却操作 35 次」的自相矛盾报表)。
【方案 C+:一天一人一行的小状态表】
- 新增 user_daily_seen(user_id, day, first_seen_at, last_seen_at),
迁移 k1l2m3n4o5p6(紧接 j1k2l3m4n5o6)
- 打点挂在 RequestContextMiddleware —— 它是最外层,能覆盖【所有】请求,
含不被审计的普通 GET。挂审计中间件没用:那里只记写操作,正是漏人的原因
- 节流:进程内缓存,同一用户 2 分钟内只落盘一次,把"每请求一次写库"
压到"每人每 2 分钟一次";代价是末次活动时间最多落后 2 分钟
- UPSERT on_conflict_do_update 只刷 last_seen_at,first_seen_at 保持当天首次值
- 打点失败全部吞掉并记日志,绝不影响业务请求
【为什么不复用 audit_logs】
「末次活动」是需要不断 UPDATE 的状态,而审计流水必须只增不改 ——
能改的审计记录等于没有审计价值。写进审计表还会让表随访问量线性膨胀。
【查询合并】
get_daily_usage 改为「活动表 ∪ 审计表」并集:只有活动记录的(只看不操作)
和只有审计记录的(本表上线前的历史数据)都会出现。
上线/下线时间取两者的【最早 / 最晚】而非"活动表优先"——打点有 2 分钟节流、
跨零点或写库失败时可能晚于当天第一次写操作,取 min/max 后结果永不劣于任一来源。
零前端改动、零移动端发版:打点在服务端,PC 与移动端同一套口径、同一张表。
|
2026-09-21 13:05:35 +08:00 |
|
|
|
7635802a42
|
feat(audit): 新增操作审计日志(表/中间件/查询接口)+ 角色常量收敛
背景:系统此前没有操作审计。task_logs 的 task_id 是 NOT NULL 外键,只能挂在
任务上,且全项目仅 4 处写入点 —— 登录、导出、产品增删改、收编完全不留痕。
需求方整理的问题清单里「无审计日志查看页」正源于此:不是没有页面,是没数据。
设计参考 MOM(KCGL) 的 audit_logs / audit_listener,但按 Track 栈做了取舍:
1) 写入时机:MOM 用 SQLAlchemy event listener + 同事务写入,优点是零侵入,
缺点是**业务回滚时审计一起消失**,而失败/被拒的操作(越权尝试、参数错误)
恰恰最需要留痕。Track 改为响应生成后用**独立 session** 写入:
- 业务回滚不影响审计(已验证 422/401 失败操作同样落库)
- 审计写入失败也不影响业务(全包裹 try/except)
- 代价:非原子提交,响应后进程立即被 kill 可能丢一条(已注释说明取舍)
2) 采集方式:中间件自动采集写操作 + 导出/下载/打印这类「读但敏感」的 GET。
路径段推导 module/action/target_id。不做手写埋点,因为手写必然漏 ——
task_logs 只有 4 处写入点就是前车之鉴。
3) 增量价值:新增 request_id 字段,与 core/logging.py 的结构化日志打通,
凭一个 ID 就能从审计记录直接跳到那一次接口日志。MOM 无此字段。
4) 敏感信息:details 经 sanitize_details 递归剔除 password/token/secret 等键;
中间件不读请求体,登录明文密码不会落库(已断言表内无密码痕迹)。
配套改动:
- core/roles.py:角色常量与 is_admin 收敛为单一事实来源。此前同一份
「管理员角色」规则散在 task_service、products.py 内联判断和前端
constants/task.ts 三处,已因此发生过「移动端漏判 SUPERVISOR 误挡主管」。
task_service 改为从 core.roles 导入同名常量,保持既有引用可用。
- core/deps.py:抽出 require_roles/require_admin 可复用依赖,替代内联判断。
- main.py:500 响应显式补 X-Request-ID 头 —— 该响应由 ServerErrorMiddleware
生成,位于 RequestContextMiddleware 外层,中间件没机会写头。
- auth.py:登录校验前把「尝试的账号」写入 request.state,使登录事件
(含失败登录)可归属到人,可用于追踪暴力破解。
验证:本地起 PostgreSQL 17 + 迁移后跑端到端测试,32/32 通过
(TestClient 每个请求新建事件循环,与模块级 asyncpg 连接池冲突会报
"got Future attached to a different loop",故改用 httpx.AsyncClient +
ASGITransport 单循环;生产 uvicorn 单循环无此问题)。
|
2026-09-21 02:23:19 +00:00 |
|
|
|
b9f9b897a1
|
feat: 新增产品生命周期阶段字段lifecycle_phase与售后工序词表
|
2026-09-14 14:49:34 +08:00 |
|
|
|
ad4b55dece
|
feat(工作日): 新增工作小时计算工具 + 节假日表与管理接口
- time_utils 新增 to_beijing(统一naive按UTC转北京时间) + working_duration_hours(排除周末/节假日)
- Holiday 模型 + alembic 迁移建 holidays 表
- GET/POST/DELETE /holidays 节假日管理接口,可随时配置放假日期
|
2026-08-28 15:08:05 +08:00 |
|
|
|
b14773f81b
|
feat: 产品协同留言板 — ProductMessage 模型 + API + 迁移
- 新增 ProductMessage 模型,挂载在 products.id(ON DELETE CASCADE)
- GET/POST /products/{id}/messages 接口
- 注册到 Alembic 自动发现
|
2026-08-10 17:37:01 +08:00 |
|
|
|
bff8787e62
|
feat: OTA热更新 — 版本检测API + App端WGT下载安装 + app_versions表
|
2026-08-07 11:49:59 +08:00 |
|
|
|
b71c5a2d07
|
feat: 双Token认证(Access 2h/Refresh 7d) + 通知系统(转交/驳回自动推送)
|
2026-08-07 11:44:04 +08:00 |
|
|
|
0d323e8181
|
血缘锚定法: task_type字段+迁移+三大接口写入+TreeCanvas基于task_type布局
|
2026-08-06 13:03:25 +08:00 |
|
|
|
22f7bb2f79
|
全栈: Task模型+remark字段 + 前端任务卡片初始说明展示区
|
2026-08-05 15:22:50 +08:00 |
|
|
|
e0c01a562f
|
feat(models): Task/Product 模型扩充 + 4个Alembic迁移
Task 模型:
- 新增 received_at, completed_at, reject_reason, is_rework
- 新增 TaskRecord 模型 (remark + images JSON)
- 状态常量 PENDING/WIP/COMPLETED/REJECTED/ARCHIVED
- 全部时间字段改用北京时间 (get_beijing_time)
Product 模型:
- order_id → 可选; 新增 external_serial, current_location_id
- 新增 material_name/spec_model/category/material_type 快照字段
- 新增 overall_status (备货/生产/测试/维修/在库)
迁移:
- b2c3: HEX计数器Sequence + external_serial + order_id nullable
- c3d4: material快照4列
- d4e5: overall_status
- e5f6: task_records表
|
2026-08-05 14:00:23 +08:00 |
|
|
|
2b967afbf6
|
chore: 更新后端依赖,初始化数据库迁移与 MOM 外部系统连接
|
2026-08-04 17:09:33 +08:00 |
|
|
|
9ec4f8efa7
|
feat(api): 新增核心 API 端点 + 数据库迁移
新增 3 个 API 端点:
- POST /tasks/{id}/receive: 确认接收 (PENDING→WIP)
- POST /tasks/{id}/reject: 品质驳回 + 返工闭环
- POST /tasks/{id}/transfer: 完工裂变转交 (多路分支+入库)
数据库迁移 (a1b2c3d4e5f6):
- tasks 表新增 received_at, completed_at, reject_reason, is_rework
- products 表新增 current_location_id
- 数据迁移: 已有任务状态小写→大写 (pending→PENDING 等)
|
2026-08-04 17:03:43 +08:00 |
|
|
|
17105dc9c2
|
初始提交:项目基础结构
- backend: FastAPI 后端服务 (Python)
- frontend: React + Tauri 前端应用
- docker-compose.yml: 容器编排配置
|
2026-08-04 10:05:59 +08:00 |
|