feat: 成长路径支持多岗位关联 + 增强拖拽功能
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
前端: - 岗位选择改为多选模式 - 增强拖拽视觉反馈(高亮、动画提示) - 列表显示多个岗位标签 后端: - 添加 position_ids 字段支持多岗位 - 兼容旧版 position_id 单选数据 - 返回 position_names 数组
This commit is contained in:
@@ -226,7 +226,10 @@ class GrowthPath(BaseModel, SoftDeleteMixin):
|
||||
|
||||
# 岗位关联
|
||||
position_id: Mapped[Optional[int]] = mapped_column(
|
||||
Integer, nullable=True, comment="关联岗位ID"
|
||||
Integer, nullable=True, comment="关联岗位ID(兼容旧版,优先使用position_ids)"
|
||||
)
|
||||
position_ids: Mapped[Optional[List[int]]] = mapped_column(
|
||||
JSON, nullable=True, comment="关联岗位ID列表(支持多选)"
|
||||
)
|
||||
|
||||
# 路径配置(保留用于兼容,新版使用 nodes 关联表)
|
||||
|
||||
@@ -56,7 +56,8 @@ class GrowthPathCreate(BaseModel):
|
||||
name: str = Field(..., description="路径名称")
|
||||
description: Optional[str] = Field(None, description="路径描述")
|
||||
target_role: Optional[str] = Field(None, description="目标角色")
|
||||
position_id: Optional[int] = Field(None, description="关联岗位ID")
|
||||
position_id: Optional[int] = Field(None, description="关联岗位ID(兼容旧版)")
|
||||
position_ids: Optional[List[int]] = Field(None, description="关联岗位ID列表(支持多选)")
|
||||
stages: Optional[List[StageConfig]] = Field(None, description="阶段配置")
|
||||
estimated_duration_days: Optional[int] = Field(None, description="预计完成天数")
|
||||
is_active: bool = Field(True, description="是否启用")
|
||||
@@ -70,6 +71,7 @@ class GrowthPathUpdate(BaseModel):
|
||||
description: Optional[str] = None
|
||||
target_role: Optional[str] = None
|
||||
position_id: Optional[int] = None
|
||||
position_ids: Optional[List[int]] = None
|
||||
stages: Optional[List[StageConfig]] = None
|
||||
estimated_duration_days: Optional[int] = None
|
||||
is_active: Optional[bool] = None
|
||||
|
||||
@@ -58,12 +58,21 @@ class GrowthPathService:
|
||||
if existing.scalar_one_or_none():
|
||||
raise ValueError(f"成长路径名称 '{data.name}' 已存在")
|
||||
|
||||
# 处理岗位关联:优先使用 position_ids,兼容 position_id
|
||||
position_ids = data.position_ids
|
||||
position_id = data.position_id
|
||||
if position_ids is None and position_id is not None:
|
||||
position_ids = [position_id]
|
||||
elif position_ids and not position_id:
|
||||
position_id = position_ids[0] if position_ids else None
|
||||
|
||||
# 创建成长路径
|
||||
growth_path = GrowthPath(
|
||||
name=data.name,
|
||||
description=data.description,
|
||||
target_role=data.target_role,
|
||||
position_id=data.position_id,
|
||||
position_id=position_id,
|
||||
position_ids=position_ids,
|
||||
stages=[s.model_dump() for s in data.stages] if data.stages else None,
|
||||
estimated_duration_days=data.estimated_duration_days,
|
||||
is_active=data.is_active,
|
||||
@@ -110,6 +119,12 @@ class GrowthPathService:
|
||||
if 'stages' in update_data and update_data['stages']:
|
||||
update_data['stages'] = [s.model_dump() if hasattr(s, 'model_dump') else s for s in update_data['stages']]
|
||||
|
||||
# 处理 position_ids 和 position_id 的兼容
|
||||
if 'position_ids' in update_data and update_data['position_ids']:
|
||||
update_data['position_id'] = update_data['position_ids'][0]
|
||||
elif 'position_id' in update_data and update_data['position_id'] and 'position_ids' not in update_data:
|
||||
update_data['position_ids'] = [update_data['position_id']]
|
||||
|
||||
for key, value in update_data.items():
|
||||
setattr(growth_path, key, value)
|
||||
|
||||
@@ -173,12 +188,20 @@ class GrowthPathService:
|
||||
if not growth_path:
|
||||
return None
|
||||
|
||||
# 获取岗位名称
|
||||
position_name = None
|
||||
if growth_path.position_id:
|
||||
position = await db.get(Position, growth_path.position_id)
|
||||
# 获取岗位名称(支持多岗位)
|
||||
position_ids = growth_path.position_ids or []
|
||||
# 兼容旧数据
|
||||
if not position_ids and growth_path.position_id:
|
||||
position_ids = [growth_path.position_id]
|
||||
|
||||
position_names = []
|
||||
for pid in position_ids:
|
||||
position = await db.get(Position, pid)
|
||||
if position:
|
||||
position_name = position.name
|
||||
position_names.append(position.name)
|
||||
|
||||
# 兼容旧版 position_name(取第一个)
|
||||
position_name = position_names[0] if position_names else None
|
||||
|
||||
# 获取课程名称
|
||||
nodes_data = []
|
||||
@@ -208,7 +231,9 @@ class GrowthPathService:
|
||||
"description": growth_path.description,
|
||||
"target_role": growth_path.target_role,
|
||||
"position_id": growth_path.position_id,
|
||||
"position_ids": position_ids,
|
||||
"position_name": position_name,
|
||||
"position_names": position_names,
|
||||
"stages": growth_path.stages,
|
||||
"estimated_duration_days": growth_path.estimated_duration_days,
|
||||
"is_active": growth_path.is_active,
|
||||
@@ -250,12 +275,18 @@ class GrowthPathService:
|
||||
|
||||
items = []
|
||||
for path in paths:
|
||||
# 获取岗位名称
|
||||
position_name = None
|
||||
if path.position_id:
|
||||
position = await db.get(Position, path.position_id)
|
||||
# 获取岗位名称(支持多岗位)
|
||||
position_ids = path.position_ids or []
|
||||
if not position_ids and path.position_id:
|
||||
position_ids = [path.position_id]
|
||||
|
||||
position_names = []
|
||||
for pid in position_ids:
|
||||
position = await db.get(Position, pid)
|
||||
if position:
|
||||
position_name = position.name
|
||||
position_names.append(position.name)
|
||||
|
||||
position_name = position_names[0] if position_names else None
|
||||
|
||||
# 获取节点数量
|
||||
node_count_result = await db.execute(
|
||||
@@ -273,7 +304,9 @@ class GrowthPathService:
|
||||
"name": path.name,
|
||||
"description": path.description,
|
||||
"position_id": path.position_id,
|
||||
"position_ids": position_ids,
|
||||
"position_name": position_name,
|
||||
"position_names": position_names,
|
||||
"is_active": path.is_active,
|
||||
"node_count": node_count,
|
||||
"estimated_duration_days": path.estimated_duration_days,
|
||||
|
||||
Reference in New Issue
Block a user