From 754c46bd590c68d2e9f55b3d45e52e226f0fbeb7 Mon Sep 17 00:00:00 2001 From: yueli Date: Thu, 16 Jul 2026 17:34:24 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=87=87=E8=B4=AD=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E7=BA=A7=E4=BB=B7=E6=A0=BC=E6=9D=83=E9=99=90?= =?UTF-8?q?=20=E2=80=94=20=E5=BA=93=E7=AE=A1=E7=9C=8B=E4=B8=8D=E5=88=B0?= =?UTF-8?q?=E9=87=87=E8=B4=AD=E4=BB=B7=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## permission_service.py - init_all_menus: 新增3个采购权限元素 inbound_purchase:unit_price, :total_price, :tax_rate ## purchase.py - _filter_purchase_prices(): 无价格权限则pop价格字段 - GET /purchase (列表): 应用价格过滤 - GET /purchase/ (详情): 应用价格过滤 - approved-unstocked: 保留价格(入库数据源,前端按inbound_buy权限控制) ## purchase/index.vue - 列表: 单价/总价/税率列 v-if hasPermission - 详情: 单价/总价 v-if hasPermission --- inventory-backend/app/api/v1/purchase.py | 26 ++++++++++++++++ .../app/services/permission_service.py | 30 +++++++++++-------- inventory-web/src/views/purchase/index.vue | 10 +++---- 3 files changed, 48 insertions(+), 18 deletions(-) diff --git a/inventory-backend/app/api/v1/purchase.py b/inventory-backend/app/api/v1/purchase.py index 462d247..fe37823 100644 --- a/inventory-backend/app/api/v1/purchase.py +++ b/inventory-backend/app/api/v1/purchase.py @@ -34,6 +34,25 @@ def _user_has_purchase_perm(): ) +def _filter_purchase_prices(item_dict): + """Fail-Closed: 无价格权限则剥离采购价格字段""" + from app.services.auth_service import AuthService + claims = get_jwt() + role = claims.get('role', '') + if role.upper() in ('SUPER_ADMIN', 'SUPERVISOR'): + return + perm_dict = AuthService.get_user_permissions(role, company_name=claims.get('company_name', '')) + all_perms = perm_dict.get('menus', []) + perm_dict.get('elements', []) + if 'inbound_purchase:unit_price' not in all_perms: + item_dict.pop('unit_price', None) + item_dict.pop('pre_tax_unit_price', None) + item_dict.pop('post_tax_unit_price', None) + if 'inbound_purchase:total_price' not in all_perms: + item_dict.pop('total_price', None) + if 'inbound_purchase:tax_rate' not in all_perms: + item_dict.pop('tax_rate', None) + + # -------------------------------------------------------- # 1. 采购申请列表 # GET /api/v1/purchase @@ -58,6 +77,10 @@ def get_purchase_list(): status=status ) + # ★ 字段级价格过滤 + for item in (result.get('items') or []): + _filter_purchase_prices(item) + return jsonify({'code': 200, 'msg': '获取成功', 'data': result}) except Exception as e: traceback.print_exc() @@ -128,6 +151,7 @@ def get_purchase_detail(purchase_id): if purchase['requester_id'] != user_id and not _user_has_purchase_perm(): return jsonify({'code': 403, 'msg': '无权查看此申请'}), 403 + _filter_purchase_prices(purchase) return jsonify({'code': 200, 'msg': '获取成功', 'data': purchase}), 200 except Exception as e: return jsonify({'code': 500, 'msg': str(e)}), 500 @@ -241,6 +265,8 @@ def get_approved_unstocked_requests(): page=page, per_page=per_page, keyword=keyword ) + # ★ 注意:不在此处过滤价格。此端点用于按单入库, + # 价格数据需随响应传递到入库表单(前端通过 inbound_buy:unit_price 权限控制写入) return jsonify({'code': 200, 'msg': '获取成功', 'data': result}), 200 except Exception as e: traceback.print_exc() diff --git a/inventory-backend/app/services/permission_service.py b/inventory-backend/app/services/permission_service.py index 55b42a0..d446859 100644 --- a/inventory-backend/app/services/permission_service.py +++ b/inventory-backend/app/services/permission_service.py @@ -638,19 +638,23 @@ class PermissionService: db.session.add(new_perm) db.session.commit() - # ★ 采购申请操作权限元素 - purchase_op = SysElement.query.filter_by( - menu_code='inbound_purchase', - code='inbound_purchase:operation' - ).first() - if not purchase_op: - db.session.add(SysElement( - menu_code='inbound_purchase', - name='可编辑', - code='inbound_purchase:operation', - element_type='operation' - )) - print(f"✅ 采购申请操作权限元素已创建") + # ★ 采购申请权限元素 + purchase_elements = [ + ('inbound_purchase:operation', '可编辑', 'operation'), + ('inbound_purchase:unit_price', '采购单价', 'column'), + ('inbound_purchase:total_price', '采购总价', 'column'), + ('inbound_purchase:tax_rate', '税率', 'column'), + ] + for code, name, etype in purchase_elements: + existing = SysElement.query.filter_by( + menu_code='inbound_purchase', code=code + ).first() + if not existing: + db.session.add(SysElement( + menu_code='inbound_purchase', name=name, + code=code, element_type=etype + )) + print(f"✅ 采购申请元素已创建: {code}") print(f"✅ 所有菜单初始化完成") return True diff --git a/inventory-web/src/views/purchase/index.vue b/inventory-web/src/views/purchase/index.vue index f02039d..7b18acc 100644 --- a/inventory-web/src/views/purchase/index.vue +++ b/inventory-web/src/views/purchase/index.vue @@ -24,17 +24,17 @@ - + - + - + @@ -200,8 +200,8 @@ {{ detail.spec_model || '-' }} {{ detail.quantity }} {{ detail.purchase_date }} - {{ detail.unit_price || '-' }} - {{ detail.total_price || '-' }} + {{ detail.unit_price || '-' }} + {{ detail.total_price || '-' }} {{ detail.requester_name }} {{ detail.approver_name || '-' }} {{ detail.approved_at || '-' }}