Commit Graph

43 Commits

Author SHA1 Message Date
fd506775c1 fix: send_email_async 主线程预取 config 传入 daemon 线程,修复异步邮件因丢失 Flask context 导致 MAIL_ENABLED=false 2026-07-17 14:27:39 +08:00
08b7674610 fix: 后端数量字段纳入RBAC — StockBuy/Semi/Product 的 in_quantity/stock_quantity/available_quantity 从 None 改为显式权限码 2026-07-17 13:45:23 +08:00
3c0954598c perf: 综合安全加固 — RBAC严格映射+异步邮件+字段权限白名单+前端对齐+导入模板
本次提交包含本会话所有修改的最终统一提交

## 权限系统重构
- permission_service.py: 添加入库/采购操作元素 + ensure_default_permissions
- field_permissions.py: 严格1-to-1 Default Deny 字段映射(StockBuy/Semi/Product/MaterialBase)
- decorators.py: _expand_operation_perms 双向粒度桥接 + prevent_double_submit
- deploy_production.sql: 修复 sys_element 别名码(qty_inbound→in_quantity)

## 采购模块
- purchase.py: 权限驱动可见性 + inbound_purchase独立权限 + 价格字段过滤
- purchase_service.py: 异步邮件 + 三阶段批量模糊匹配防N+1
- purchase/index.vue: canApprove严格操作权限 + upload重复修复

## 导出/入
- base_service.py: export_excel 流式写入防OOM + get_latest_specs 优化
- import_service.py + import_api.py: Excel批量导入(模板+预览+执行)
- ImportDialog.vue: 三步骤导入弹窗

## 异步邮件
- email_service.py: send_email_async (守护线程)
- inventory_task.py: send_email→send_email_async

## 前端对齐
- product/semi/buy.vue: 列对齐in_quantity/stock_quantity/available_quantity + localStorage缓存V2
- buyOdoo.vue: 排序修复 + 导入按钮 + 移除点击展开加载
- BomManage.vue: 懒加载分组 + 导入按钮
- list.vue: 导入按钮
- Selection.vue + borrow/apply: BOM匹配修复 + 导入按钮
- outbound/create.vue: 出库类型必选
- AppMain.vue: 移除transition白屏修复
- material_base.ts, outbound.ts, bom.ts, stock.ts: 新增API函数
2026-07-17 13:07:12 +08:00
347f20497c feat: Redis幂等锁 + 关键端点防重复提交
## decorators.py
- 新增 @prevent_double_submit(lock_timeout=5) 装饰器
  Redis key: idem:{user_id}:{path}:{MD5(body)}
  锁存在→409, 不存在→setex→执行业务→delete
  Redis不可用时fail-open降级放行

## purchase.py
- POST /purchase (创建): +@prevent_double_submit
- PATCH /purchase/<id>/approve (审批): +@prevent_double_submit

## outbound.py
- POST /outbound (出库): +@prevent_double_submit

## transactions.py
- POST /borrow/dispatch (借库扣减): +@prevent_double_submit
2026-07-16 13:08:37 +08:00
e313f575bf perf: 系统级异步邮件 — 消除SMTP阻塞导致的10-15秒UI冻结
## email_service.py
- 新增 send_email_async(): threading.Thread(daemon=True) 包装 send_email()
  无需 Flask app_context (send_email仅用os.getenv+smtplib)
- 6处 send_email→send_email_async 替换

## inventory_task.py
- 库存预警 send_email→send_email_async (2处)
2026-07-16 11:26:12 +08:00
0b75740ae0 feat: 权限系统重构 — 操作权限双向展开 + 启动时自动补全默认权限
## permission_service.py
- init_all_menus: menu_defs 新增 inbound_purchase(采购申请) 菜单项
- init_all_menus: 创建 inbound_purchase:operation 操作元素
- 新增 ensure_default_permissions(): 启动时从 sys_user 提取活跃角色,
  对空权限角色自动补全默认菜单(按角色类型分级)
- 自动迁移: 已有 inbound_buy 权限的角色 → 自动获得 inbound_purchase
- SUPERVISOR 启动时自动获得 inbound_purchase 菜单权限

## decorators.py
- _expand_operation_perms 改为双向桥接:
  正向(inbound_buy:operation←inbound_buy:write)→通过
  反向(inbound_buy←inbound_buy:operation)→通过(可编辑隐含可读)
- 新增详细诊断日志,记录展开路径和失败原因

## __init__.py
- 启动时调用 PermissionService.ensure_default_permissions()
2026-07-16 11:25:41 +08:00
e1417d740a feat: 全模块公司隔离 + crossDomain权限码动态跨域控制
- get_current_company_filter: 新增_has_cross_domain_permission, 权限码替代硬编码
- 补全11个Service的get_current_company_filter调用(semi/product/service/outbound/bom/trans/scrap/summary)
- base/search修复: search_material此前无隔离, 已补全
- get_current_company_filter兜底: JWT缺company_name时返回__NO_COMPANY__防止放行
- permission.py: _get_operator_company补全返回值, 修复权限页保存逻辑
- 新增crossDomain迁移脚本, element_type=element挂system_mgmt下
2026-07-15 11:11:40 +08:00
9cae1cc44c feat: 跨域访问从硬编码改为权限码crossDomain动态控制, 新增SQL迁移脚本 2026-07-15 09:22:58 +08:00
4f5965db02 feat: JWT多租户数据权限隔离 & 主管系统管理权限 & 含税单价补齐
## 多租户公司数据隔离
- 新增 get_current_company_filter() 工具函数 (decorators.py)
  SUPER_ADMIN: 可传company_name参数过滤或传ALL看全量
  其他角色: 强制隔离到JWT中的company_name
- 重构 base_service.py / buy_service.py: 用集中式函数替换内联公司过滤
- SysRolePermission 表新增 company_name 字段,支持同角色不同公司权限
- get_user_permissions() 新增 company_name 参数,查公司定制+全局模板权限
- permission.py API 新增 @permission_required 拦截 + 公司过滤
- 19个API/service文件传递 company_name 到权限查询

## 主管系统管理权限
- delete_user() 允许SUPERVISOR删除同公司用户 (原仅SUPER_ADMIN)
- get_all_users() 新增 company_name 参数过滤
- 用户列表/权限分配 API 应用 get_current_company_filter()
- 前端 UserCreate.vue: 超管可见公司下拉框,主管隐藏部门字段

## 前端多租户适配
- material/list.vue / buy.vue: 公司下拉框仅超管可见,默认ALL
- UserCreate.vue: 新增搜索栏公司筛选,部门字段按角色显隐
- auth.ts: getUserList() 支持 params 参数

## Bug修复: 含税单价字段补齐
- buy.vue: 表格列/高级筛选/排序/权限映射新增 post_tax_unit_price
- buy_service.py: allowed_fields/sort_field_map 新增 post_tax_unit_price
2026-07-13 15:12:22 +08:00
DXC
5c0c1632c3 fix(审批邮件): items_json序列化Bug修复 + 邮件方法出库/借库物理隔离 2026-06-12 15:04:57 +08:00
dxc
7d828d3ebf 版本变更V3.35将图像的处理统一更换到新表当中 2026-05-26 12:01:58 +08:00
dxc
fb5b8d873b 版本变更V3.35将图像的处理统一更换到新表当中 2026-05-26 11:28:26 +08:00
DXC
1da4b454cd feat: 新增物料/入库单实时 CLIP 向量提取(新建+更新),修复 I/O 延迟和路径解析静默失败 2026-05-25 10:04:32 +08:00
DXC
c273f5a9d9 feat: 以图搜图功能升级(跨表UNION检索 + 拍照识图入口 + 批量向量初始化脚本) 2026-05-21 15:43:45 +08:00
DXC
1a7c06f197 feat: 添加以图搜图功能(CLIP ONNX + pgvector)+ Dify会话修复 + 版本升至V3.30 2026-05-21 14:09:57 +08:00
DXC
3cb31c2b67 fix: 修复 JWT 幽灵令牌漏洞,新增 Dify 权限过滤服务 2026-05-18 16:16:50 +08:00
DXC
3dae206828 feat(outbound): 完善出库审批邮件通知逻辑,支持申请人与审批人同时收到邮件(带物料明细),审批通过后申请人和库管均收到带物料明细的通知 2026-05-12 13:42:15 +08:00
dxc
259f3a7e0d 4.29扫码获取库位小工具接口 2026-04-29 15:40:43 +08:00
DXC
8276597a67 fix(email): 审批通知逻辑重构 - 通过时同时通知库管和申请人,驳回仅通知申请人;精简 DEBUG 日志 2026-04-29 09:10:34 +08:00
DXC
ccbce82c2e fix(email): 审批通过后库管通知增加明细+DEBUG日志,修复MAIL_DEFAULT_SENDER格式问题 2026-04-28 16:46:12 +08:00
dxc
183b93012e 4.28 2026-04-28 16:07:11 +08:00
DXC
1205d9c7e8 feat(audit): 优化审计日志的人性化展示 2026-04-22 10:44:13 +08:00
DXC
4b794b9bcc feat(audit): 添加全局无侵入审计日志拦截器 2026-04-22 10:41:15 +08:00
DXC
f8f5b05d7d refactor(audit): 废弃装饰器+分离架构,改为监听器单体直写入库 2026-04-20 16:04:01 +08:00
DXC
7e72c12f30 fix(audit): 修复 decorators.py 中缺失 has_request_context 导入导致的致命 NameError 2026-04-20 15:10:12 +08:00
DXC
decb7f5e1f debug(audit): 添加X光调试-追踪断点 2026-04-20 15:01:20 +08:00
DXC
1c8def7e6f refactor(audit): 分离架构-监听器计算装饰器入库 2026-04-20 14:41:40 +08:00
DXC
381d1fa675 feat(audit): 平滑升级-监听器+装饰器共存,装饰器自动检测并跳过已处理日志 2026-04-20 13:15:25 +08:00
DXC
a52ced0375 fix(backend): resolve DetachedInstanceError in audit_log, add pessimistic locks for stock adjustments, and eliminate N+1 queries with eager loading 2026-04-02 18:44:12 +08:00
DXC
46dd8f1c3a fix(auth,audit): ensure display_name persists in token refresh and add fallback in audit log 2026-03-25 11:16:13 +08:00
DXC
032479fe38 fix: capture and persist target object names for delete, outbound, and borrow operations in audit logs 2026-03-20 15:47:13 +08:00
DXC
4223a95f10 feat: generate permission sql for stocktake modules and implement single-device login restriction 2026-03-20 09:11:54 +08:00
DXC
ac97c6066b feat: 升级审计装饰器,支持自动抓取并记录 API 请求体作为变更明细 2026-03-10 17:36:02 +08:00
DXC
be6575344a feat: 新增企业级操作审计日志闭环模块(包含底层模型、记录装饰器与前端看板) 2026-03-10 12:15:26 +08:00
dxc
c1e4acc1d8 fix: standardize role case handling in permission logic
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-27 17:07:45 +08:00
dxc
a0993767fe fix: make SUPER_ADMIN role checks case-insensitive across app
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-27 17:04:22 +08:00
dxc
11fafde5e3 fix: remove temporary role whitelist and add permission denial logging
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-27 10:29:15 +08:00
dxc
1f9a363545 chore: add debug logs and temp whitelist to permission decorator
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-27 10:27:44 +08:00
dxc
b3e1ac6245 feat: implement permission checking and field-level data masking
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-27 10:20:09 +08:00
dxc
73ee163352 feat: add MaterialBase permission control with field-level filtering
Co-authored-by: aider (openai/DeepSeek-V3.2-Thinking) <aider@aider.chat>
2026-02-27 10:16:43 +08:00
dxc
1c3f116c50 修改登录,添加超级管理员权限 2026-02-25 11:02:06 +08:00
dxc
13590b1fac 超级管理员登录设置 2026-02-04 13:30:07 +08:00
dxc
ee9f4aed3e 修正git管理关系 2026-01-26 13:47:53 +08:00