fix(borrow,outbound): 普通用户记录只看本人——按领用人/借用人姓名(不含账号前缀)匹配
- 出库记录/借还记录:非管理者视角时按 领用人(consumer_name)/借用人(borrower_name) 过滤 - 匹配取登录名 username.split(/)[0] 的姓名;兼容库里存“姓名/xiaolongxia”全名(姓名+/前缀) - 修复:管理员替员工创建、领用人=员工 的单,员工登录可见
This commit is contained in:
@ -175,8 +175,22 @@ def get_outbound_list():
|
|||||||
search_type = request.args.get('search_type', 'all')
|
search_type = request.args.get('search_type', 'all')
|
||||||
company = request.args.get('company', '')
|
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()
|
user_permissions = get_current_user_permissions()
|
||||||
|
|||||||
@ -163,7 +163,20 @@ def get_records():
|
|||||||
keyword = request.args.get('keyword', '')
|
keyword = request.args.get('keyword', '')
|
||||||
search_type = request.args.get('search_type', 'all')
|
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),需要直通到前端,便于排查
|
# ★ service 层异常时:code==500 的字典(带 traceback),需要直通到前端,便于排查
|
||||||
if isinstance(res, dict) and res.get('code') == 500:
|
if isinstance(res, dict) and res.get('code') == 500:
|
||||||
|
|||||||
@ -327,7 +327,7 @@ class OutboundService:
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
@staticmethod
|
@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、物料名称、规格型号
|
支持跨表搜索:单号、领用人、SKU、物料名称、规格型号
|
||||||
@ -543,6 +543,21 @@ class OutboundService:
|
|||||||
if company_limit is not None:
|
if company_limit is not None:
|
||||||
stmt = stmt.filter(TransOutbound.outbound_no.in_(comp_all))
|
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'))
|
stmt = stmt.order_by(desc('max_time'))
|
||||||
|
|
||||||
# 使用 distinct 确保跨表查询不重复
|
# 使用 distinct 确保跨表查询不重复
|
||||||
|
|||||||
@ -410,7 +410,7 @@ class TransService:
|
|||||||
raise e
|
raise e
|
||||||
|
|
||||||
@staticmethod
|
@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)
|
获取借还记录列表(按单号 borrow_no 维度分页,避免明细撑爆 pageSize)
|
||||||
|
|
||||||
@ -648,6 +648,22 @@ class TransService:
|
|||||||
# ====================================================================
|
# ====================================================================
|
||||||
borrow_no_q = db.session.query(order_subq.c.borrow_no)
|
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:
|
if keyword_borrow_nos_subq is not None:
|
||||||
borrow_no_q = borrow_no_q.filter(
|
borrow_no_q = borrow_no_q.filter(
|
||||||
|
|||||||
Reference in New Issue
Block a user