""" 科室类型BSC维度权重配置服务 根据详细设计文档中的考核维度权重总览: | 科室类型 | 财务维度 | 顾客维度 | 内部流程 | 学习成长 | 合计 | |----------|----------|----------|----------|----------|------| | 手术临床科室 | 60% | 15% | 20% | 5% | 100% | | 非手术有病房科室 | 60% | 15% | 20% | 5% | 100% | | 非手术无病房科室 | 60% | 15% | 20% | 5% | 100% | | 医技科室 | 40% | 25% | 30% | 5% | 100% | | 医疗辅助/行政科室 | 40% | 25% | 30% | 5% | 100% | | 护理单元 | 20% | 15% | 50% | 15% | 100% | | 药学部门 | 30% | 15% | 55% | - | 100% | """ from typing import Optional, List, Dict, Any from sqlalchemy import select, func from sqlalchemy.ext.asyncio import AsyncSession from app.models.models import DeptType, DeptTypeDimensionWeight # 默认权重配置(根据详细设计文档) DEFAULT_WEIGHTS = { DeptType.CLINICAL_SURGICAL: { "financial": 0.60, "customer": 0.15, "internal_process": 0.20, "learning_growth": 0.05, "description": "手术临床科室:外科、骨科、泌尿外科、心胸外科、神经外科等" }, DeptType.CLINICAL_NONSURGICAL_WARD: { "financial": 0.60, "customer": 0.15, "internal_process": 0.20, "learning_growth": 0.05, "description": "非手术有病房科室:内科、神经内科、呼吸内科、消化内科等" }, DeptType.CLINICAL_NONSURGICAL_NOWARD: { "financial": 0.60, "customer": 0.15, "internal_process": 0.20, "learning_growth": 0.05, "description": "非手术无病房科室:门诊科室、急诊科等" }, DeptType.MEDICAL_TECH: { "financial": 0.40, "customer": 0.25, "internal_process": 0.30, "learning_growth": 0.05, "description": "医技科室:放射科、检验科、超声科、病理科、功能检查科等" }, DeptType.MEDICAL_AUXILIARY: { "financial": 0.40, "customer": 0.25, "internal_process": 0.30, "learning_growth": 0.05, "description": "医疗辅助/行政科室:设备科、信息科、总务科、财务科、人事科、医务科等" }, DeptType.NURSING: { "financial": 0.20, "customer": 0.15, "internal_process": 0.50, "learning_growth": 0.15, "description": "护理单元:各病区护理单元" }, DeptType.ADMIN: { "financial": 0.40, "customer": 0.25, "internal_process": 0.30, "learning_growth": 0.05, "description": "行政科室" }, DeptType.FINANCE: { "financial": 0.40, "customer": 0.25, "internal_process": 0.30, "learning_growth": 0.05, "description": "财务科室" }, DeptType.LOGISTICS: { "financial": 0.40, "customer": 0.25, "internal_process": 0.30, "learning_growth": 0.05, "description": "后勤保障科室" }, } class DimensionWeightService: """科室类型BSC维度权重配置服务""" @staticmethod async def get_by_dept_type(db: AsyncSession, dept_type: DeptType) -> Optional[DeptTypeDimensionWeight]: """根据科室类型获取权重配置""" result = await db.execute( select(DeptTypeDimensionWeight) .where(DeptTypeDimensionWeight.dept_type == dept_type) .where(DeptTypeDimensionWeight.is_active == True) ) return result.scalar_one_or_none() @staticmethod async def get_all(db: AsyncSession, active_only: bool = True) -> List[DeptTypeDimensionWeight]: """获取所有权重配置""" query = select(DeptTypeDimensionWeight) if active_only: query = query.where(DeptTypeDimensionWeight.is_active == True) query = query.order_by(DeptTypeDimensionWeight.dept_type) result = await db.execute(query) return result.scalars().all() @staticmethod async def create_or_update( db: AsyncSession, dept_type: DeptType, financial_weight: float, customer_weight: float, internal_process_weight: float, learning_growth_weight: float, description: Optional[str] = None ) -> DeptTypeDimensionWeight: """创建或更新权重配置""" # 验证权重总和为1 total = financial_weight + customer_weight + internal_process_weight + learning_growth_weight if abs(total - 1.0) > 0.01: raise ValueError(f"权重总和必须为100%,当前总和为{total * 100}%") # 查找现有配置 existing = await DimensionWeightService.get_by_dept_type(db, dept_type) if existing: # 更新现有配置 existing.financial_weight = financial_weight existing.customer_weight = customer_weight existing.internal_process_weight = internal_process_weight existing.learning_growth_weight = learning_growth_weight if description: existing.description = description await db.flush() await db.refresh(existing) return existing else: # 创建新配置 config = DeptTypeDimensionWeight( dept_type=dept_type, financial_weight=financial_weight, customer_weight=customer_weight, internal_process_weight=internal_process_weight, learning_growth_weight=learning_growth_weight, description=description ) db.add(config) await db.flush() await db.refresh(config) return config @staticmethod async def init_default_weights(db: AsyncSession) -> List[DeptTypeDimensionWeight]: """初始化默认权重配置(根据详细设计文档)""" configs = [] for dept_type, weights in DEFAULT_WEIGHTS.items(): config = await DimensionWeightService.create_or_update( db, dept_type=dept_type, financial_weight=weights["financial"], customer_weight=weights["customer"], internal_process_weight=weights["internal_process"], learning_growth_weight=weights["learning_growth"], description=weights.get("description") ) configs.append(config) return configs @staticmethod def get_dimension_weights(dept_type: DeptType) -> Dict[str, float]: """ 获取科室类型的维度权重(用于计算) 优先使用数据库配置,如果没有则使用默认配置 """ default = DEFAULT_WEIGHTS.get(dept_type, { "financial": 0.40, "customer": 0.25, "internal_process": 0.30, "learning_growth": 0.05, }) return { "financial": default["financial"], "customer": default["customer"], "internal_process": default["internal_process"], "learning_growth": default["learning_growth"], } @staticmethod async def calculate_dimension_weighted_score( db: AsyncSession, dept_type: DeptType, financial_score: float, customer_score: float, internal_process_score: float, learning_growth_score: float ) -> Dict[str, Any]: """ 根据科室类型计算维度加权得分 Args: db: 数据库会话 dept_type: 科室类型 financial_score: 财务维度得分 customer_score: 客户维度得分 internal_process_score: 内部流程维度得分 learning_growth_score: 学习成长维度得分 Returns: 包含各维度加权得分和总分的字典 """ # 获取权重配置 config = await DimensionWeightService.get_by_dept_type(db, dept_type) if config: weights = { "financial": float(config.financial_weight), "customer": float(config.customer_weight), "internal_process": float(config.internal_process_weight), "learning_growth": float(config.learning_growth_weight), } else: weights = DimensionWeightService.get_dimension_weights(dept_type) # 计算各维度加权得分 weighted_scores = { "financial": financial_score * weights["financial"], "customer": customer_score * weights["customer"], "internal_process": internal_process_score * weights["internal_process"], "learning_growth": learning_growth_score * weights["learning_growth"], } # 计算总分 total_score = sum(weighted_scores.values()) return { "weights": weights, "weighted_scores": weighted_scores, "total_score": round(total_score, 2), "raw_scores": { "financial": financial_score, "customer": customer_score, "internal_process": internal_process_score, "learning_growth": learning_growth_score, } } @staticmethod async def delete(db: AsyncSession, config_id: int) -> bool: """删除权重配置(软删除)""" result = await db.execute( select(DeptTypeDimensionWeight).where(DeptTypeDimensionWeight.id == config_id) ) config = result.scalar_one_or_none() if not config: return False config.is_active = False await db.flush() return True