266 lines
9.8 KiB
Python
266 lines
9.8 KiB
Python
"""
|
|
科室类型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
|