From eff9b6222456764d36ddf916437aee2546a98079 Mon Sep 17 00:00:00 2001 From: yueli Date: Wed, 9 Sep 2026 11:19:15 +0800 Subject: [PATCH] =?UTF-8?q?fix(borrow,outbound):=20=E6=99=AE=E9=80=9A?= =?UTF-8?q?=E7=94=A8=E6=88=B7=E8=AE=B0=E5=BD=95=E5=8F=AA=E7=9C=8B=E6=9C=AC?= =?UTF-8?q?=E4=BA=BA=E2=80=94=E2=80=94=E6=8C=89=E9=A2=86=E7=94=A8=E4=BA=BA?= =?UTF-8?q?/=E5=80=9F=E7=94=A8=E4=BA=BA=E5=A7=93=E5=90=8D(=E4=B8=8D?= =?UTF-8?q?=E5=90=AB=E8=B4=A6=E5=8F=B7=E5=89=8D=E7=BC=80)=E5=8C=B9?= =?UTF-8?q?=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 出库记录/借还记录:非管理者视角时按 领用人(consumer_name)/借用人(borrower_name) 过滤 - 匹配取登录名 username.split(/)[0] 的姓名;兼容库里存“姓名/xiaolongxia”全名(姓名+/前缀) - 修复:管理员替员工创建、领用人=员工 的单,员工登录可见 --- inventory-backend/app/api/v1/outbound.py | 16 +++++++++++++++- inventory-backend/app/api/v1/transactions.py | 15 ++++++++++++++- .../app/services/outbound_service.py | 17 ++++++++++++++++- .../app/services/trans_service.py | 18 +++++++++++++++++- 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/inventory-backend/app/api/v1/outbound.py b/inventory-backend/app/api/v1/outbound.py index f82f47c..ee5565c 100644 --- a/inventory-backend/app/api/v1/outbound.py +++ b/inventory-backend/app/api/v1/outbound.py @@ -175,8 +175,22 @@ def get_outbound_list(): search_type = request.args.get('search_type', 'all') company = request.args.get('company', '') + # ★ 数据权限:普通用户只看“领用人=本人姓名(不含账号前缀)”的出库记录;管理者看全部 + consumer_name = None + if not is_privileged_viewer(): + _identity = get_jwt_identity() + if _identity: + from app.models.system import SysUser + _u = SysUser.query.get(int(_identity)) + # username 形如 “中文名/xiaolongxia” → 取“/”前的领用人姓名 + _uname = _u.username if _u else '' + consumer_name = _uname.split('/')[0].strip() if _uname else None + # ★ [修改] 调用分组查询服务,支持搜索类型 - result = OutboundService.get_grouped_list(page, limit, keyword, search_type=search_type, company=company) + result = OutboundService.get_grouped_list( + page, limit, keyword, search_type=search_type, + company=company, consumer_name=consumer_name + ) # 字段级脱敏 user_permissions = get_current_user_permissions() diff --git a/inventory-backend/app/api/v1/transactions.py b/inventory-backend/app/api/v1/transactions.py index d41df29..c0e8e3c 100644 --- a/inventory-backend/app/api/v1/transactions.py +++ b/inventory-backend/app/api/v1/transactions.py @@ -163,7 +163,20 @@ def get_records(): keyword = request.args.get('keyword', '') search_type = request.args.get('search_type', 'all') - res = TransService.get_records(page=page, limit=10, status=status, keyword=keyword, search_type=search_type) + # ★ 数据权限:普通用户只看“借用人=本人姓名(不含账号前缀)”的借还记录;管理者看全部 + borrower_name = None + if not is_privileged_viewer(): + _identity = get_jwt_identity() + if _identity: + from app.models.system import SysUser + _u = SysUser.query.get(int(_identity)) + _uname = _u.username if _u else '' + borrower_name = _uname.split('/')[0].strip() if _uname else None + + res = TransService.get_records( + page=page, limit=10, status=status, keyword=keyword, + search_type=search_type, borrower_name=borrower_name + ) # ★ service 层异常时:code==500 的字典(带 traceback),需要直通到前端,便于排查 if isinstance(res, dict) and res.get('code') == 500: diff --git a/inventory-backend/app/services/outbound_service.py b/inventory-backend/app/services/outbound_service.py index 1818116..93839e7 100644 --- a/inventory-backend/app/services/outbound_service.py +++ b/inventory-backend/app/services/outbound_service.py @@ -327,7 +327,7 @@ class OutboundService: raise e @staticmethod - def get_grouped_list(page=1, per_page=10, keyword=None, search_type='all', start_date=None, end_date=None, company=None): + def get_grouped_list(page=1, per_page=10, keyword=None, search_type='all', start_date=None, end_date=None, company=None, consumer_name=None): """ 查询出库记录(按出库单号分组),包含详细物品信息 支持跨表搜索:单号、领用人、SKU、物料名称、规格型号 @@ -543,6 +543,21 @@ class OutboundService: if company_limit is not None: stmt = stmt.filter(TransOutbound.outbound_no.in_(comp_all)) + # ★ 数据权限:普通用户只看“领用人=本人姓名(不含账号前缀)”的出库记录; + # 同时兼容库里存成“姓名/xiaolongxia”全名的记录(姓名 + '/' 前缀也命中) + if consumer_name: + from sqlalchemy import or_ + _own_out_nos = ( + db.session.query(TransOutbound.outbound_no) + .filter(or_( + TransOutbound.consumer_name == consumer_name, + TransOutbound.consumer_name.like(f"{consumer_name}/%") + )) + .distinct() + .subquery() + ) + stmt = stmt.filter(TransOutbound.outbound_no.in_(_own_out_nos)) + stmt = stmt.order_by(desc('max_time')) # 使用 distinct 确保跨表查询不重复 diff --git a/inventory-backend/app/services/trans_service.py b/inventory-backend/app/services/trans_service.py index 215572d..6b5afee 100644 --- a/inventory-backend/app/services/trans_service.py +++ b/inventory-backend/app/services/trans_service.py @@ -410,7 +410,7 @@ class TransService: raise e @staticmethod - def get_records(page=1, limit=10, status='all', keyword=None, search_type='all'): + def get_records(page=1, limit=10, status='all', keyword=None, search_type='all', borrower_name=None): """ 获取借还记录列表(按单号 borrow_no 维度分页,避免明细撑爆 pageSize) @@ -648,6 +648,22 @@ class TransService: # ==================================================================== borrow_no_q = db.session.query(order_subq.c.borrow_no) + # ★ 数据权限:普通用户只看“借用人=本人姓名(不含账号前缀)”的借还记录; + # 兼容库里存成“姓名/xiaolongxia”全名(姓名 + '/' 前缀)的情况 + if borrower_name: + own_borrow_nos_subq = ( + db.session.query(TransBorrow.borrow_no) + .filter(or_( + TransBorrow.borrower_name == borrower_name, + TransBorrow.borrower_name.like(f"{borrower_name}/%") + )) + .distinct() + .subquery() + ) + borrow_no_q = borrow_no_q.filter( + order_subq.c.borrow_no.in_(own_borrow_nos_subq) + ) + # 关键词过滤 if keyword_borrow_nos_subq is not None: borrow_no_q = borrow_no_q.filter(