# inventory-backend/app/api/v1/inbound/service.py from flask import request, jsonify, current_app from flask_jwt_extended import jwt_required from . import inbound_bp from app.services.inbound.service_service import ServiceService from app.utils.decorators import role_required, permission_required import traceback # ============================================================================== # 辅助函数:获取当前用户的完整权限列表(基于角色查询) # ============================================================================== def get_current_user_permissions(): """ 返回当前用户拥有的所有权限码列表(包括菜单和元素) 此函数根据角色查询数据库得到权限。 """ from flask_jwt_extended import get_jwt from app.services.auth_service import AuthService claims = get_jwt() user_role = claims.get('role') if not user_role: return [] # 超级管理员返回所有字段权限 (忽略大小写) if user_role.upper() == 'SUPER_ADMIN': return ['inbound_service:*'] perm_dict = AuthService.get_user_permissions(user_role) # 合并菜单和元素权限 perms = perm_dict.get('menus', []) + perm_dict.get('elements', []) return perms def filter_item_by_permissions(item_dict, user_permissions): """ 根据用户权限过滤 item 字典,无权限的字段值置为 None """ # 字段名到权限码的映射(与前端 permissionMap 保持一致) field_to_perm = { 'id': 'inbound_service:id', 'base_id': 'inbound_service:base_id', 'sku': 'inbound_service:sku', 'material_name': 'inbound_service:material_name', 'provider_name': 'inbound_service:provider_name', 'sale_price': 'inbound_service:sale_price', 'description': 'inbound_service:description', 'created_at': 'inbound_service:created_at', 'material_type': 'inbound_service:material_type', 'category': 'inbound_service:category', 'spec_model': 'inbound_service:spec_model', 'unit': 'inbound_service:unit', } if 'inbound_service:*' in user_permissions: return item_dict for field, perm_code in field_to_perm.items(): if field in item_dict and perm_code not in user_permissions: item_dict[field] = None return item_dict @inbound_bp.route('/service/search-base', methods=['GET']) @permission_required('inbound_service') def search_base(): """搜索基础物料""" keyword = request.args.get('keyword', '') try: data = ServiceService.search_base_material(keyword) user_permissions = get_current_user_permissions() filtered_data = [filter_item_by_permissions(item, user_permissions) for item in data] return jsonify({ 'code': 200, 'msg': 'success', 'data': filtered_data }) except Exception as e: current_app.logger.error(f'搜索基础物料失败: {str(e)}') return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500 @inbound_bp.route('/service', methods=['GET']) @permission_required('inbound_service') def get_service_list(): """获取服务权益列表""" page = request.args.get('page', 1, type=int) per_page = request.args.get('per_page', 20, type=int) keyword = request.args.get('keyword', None) start_date = request.args.get('start_date', None) end_date = request.args.get('end_date', None) provider_name = request.args.get('provider_name', None) try: result = ServiceService.get_service_list( page=page, per_page=per_page, keyword=keyword, start_date=start_date, end_date=end_date, provider_name=provider_name ) user_permissions = get_current_user_permissions() if result.get('items'): result['items'] = [filter_item_by_permissions(item, user_permissions) for item in result['items']] return jsonify({ 'code': 200, 'msg': 'success', 'data': result }) except Exception as e: current_app.logger.error(f'获取服务列表失败: {str(e)}') traceback.print_exc() return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500 @inbound_bp.route('/service', methods=['POST']) @permission_required('inbound_service:operation') def create_service(): """创建服务权益""" data = request.get_json() if not data: return jsonify({'code': 400, 'msg': '请求数据为空'}), 400 # 数据清洗:移除用户没有权限的字段 user_permissions = get_current_user_permissions() # 超级管理员不过滤 if 'inbound_service:*' not in user_permissions: # 字段名到权限码的映射(与前端 permissionMap 保持一致) field_to_perm = { 'id': 'inbound_service:id', 'base_id': 'inbound_service:base_id', 'sku': 'inbound_service:sku', 'material_name': 'inbound_service:material_name', 'provider_name': 'inbound_service:provider_name', 'sale_price': 'inbound_service:sale_price', 'description': 'inbound_service:description', 'created_at': 'inbound_service:created_at', 'material_type': 'inbound_service:material_type', 'category': 'inbound_service:category', 'spec_model': 'inbound_service:spec_model', 'unit': 'inbound_service:unit', } # 复制一份,避免遍历时修改字典 for field in list(data.keys()): perm_code = field_to_perm.get(field) if perm_code and perm_code not in user_permissions: data.pop(field, None) # 基础校验 if not data.get('base_id'): return jsonify({'code': 400, 'msg': '请选择基础物料'}), 400 if data.get('sale_price') is None: return jsonify({'code': 400, 'msg': '请输入售价'}), 400 try: service = ServiceService.create_service(data) user_permissions = get_current_user_permissions() filtered_data = filter_item_by_permissions(service.to_dict(), user_permissions) return jsonify({ 'code': 201, 'msg': '创建成功', 'data': filtered_data }), 201 except ValueError as e: return jsonify({'code': 400, 'msg': str(e)}), 400 except Exception as e: current_app.logger.error(f'创建服务权益失败: {str(e)}') traceback.print_exc() return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500 @inbound_bp.route('/service/', methods=['GET']) @permission_required('inbound_service') def get_service(service_id): """获取单个服务权益详情""" try: service = ServiceService.get_service(service_id) user_permissions = get_current_user_permissions() filtered_data = filter_item_by_permissions(service.to_dict(), user_permissions) return jsonify({ 'code': 200, 'msg': 'success', 'data': filtered_data }) except ValueError as e: return jsonify({'code': 404, 'msg': str(e)}), 404 except Exception as e: current_app.logger.error(f'获取服务权益详情失败: {str(e)}') return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500 @inbound_bp.route('/service/', methods=['PUT']) @permission_required('inbound_service:operation') def update_service(service_id): """更新服务权益""" data = request.get_json() if not data: return jsonify({'code': 400, 'msg': '请求数据为空'}), 400 # 数据清洗:移除用户没有权限的字段 user_permissions = get_current_user_permissions() # 超级管理员不过滤 if 'inbound_service:*' not in user_permissions: # 字段名到权限码的映射(与前端 permissionMap 保持一致) field_to_perm = { 'id': 'inbound_service:id', 'base_id': 'inbound_service:base_id', 'sku': 'inbound_service:sku', 'material_name': 'inbound_service:material_name', 'provider_name': 'inbound_service:provider_name', 'sale_price': 'inbound_service:sale_price', 'description': 'inbound_service:description', 'created_at': 'inbound_service:created_at', 'material_type': 'inbound_service:material_type', 'category': 'inbound_service:category', 'spec_model': 'inbound_service:spec_model', 'unit': 'inbound_service:unit', } # 复制一份,避免遍历时修改字典 for field in list(data.keys()): perm_code = field_to_perm.get(field) if perm_code and perm_code not in user_permissions: data.pop(field, None) # 允许更新的字段 allowed_fields = { 'sale_price', 'provider_name', 'description', 'cost_price', 'contract_id', 'contact_person', 'valid_period' } filtered_data = {k: v for k, v in data.items() if k in allowed_fields} if not filtered_data: return jsonify({'code': 400, 'msg': '无有效更新字段'}), 400 try: service = ServiceService.update_service(service_id, filtered_data) user_permissions = get_current_user_permissions() filtered_service = filter_item_by_permissions(service.to_dict(), user_permissions) return jsonify({ 'code': 200, 'msg': '更新成功', 'data': filtered_service }) except ValueError as e: return jsonify({'code': 404, 'msg': str(e)}), 404 except Exception as e: current_app.logger.error(f'更新服务权益失败: {str(e)}') return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500 @inbound_bp.route('/service/', methods=['DELETE']) @permission_required('inbound_service:operation') def delete_service(service_id): """删除服务权益""" try: ServiceService.delete_service(service_id) return jsonify({ 'code': 200, 'msg': '删除成功' }) except ValueError as e: return jsonify({'code': 404, 'msg': str(e)}), 404 except Exception as e: current_app.logger.error(f'删除服务权益失败: {str(e)}') return jsonify({'code': 500, 'msg': '内部服务器错误'}), 500 @inbound_bp.route('/service/suggestions/providers', methods=['GET']) @permission_required('inbound_service') def get_provider_suggestions(): base_id = request.args.get('base_id', type=int) if not base_id: return jsonify({'code': 400, 'msg': 'base_id required'}), 400 data = ServiceService.get_history_providers(base_id) return jsonify({'code': 200, 'msg': 'success', 'data': data}) @inbound_bp.route('/service/suggestions/users', methods=['GET']) @permission_required('inbound_service') def get_user_suggestions(): keyword = request.args.get('keyword', '') data = ServiceService.search_system_users(keyword) return jsonify({'code': 200, 'msg': 'success', 'data': data}) @inbound_bp.route('/service/options', methods=['GET']) @permission_required('inbound_service') def get_options(): try: data = ServiceService.get_filter_options() return jsonify({'code': 200, 'msg': 'success', 'data': data}) except Exception as e: return jsonify({'code': 500, 'msg': str(e)}), 500