feat: 成长路径支持多岗位关联 + 增强拖拽功能
All checks were successful
continuous-integration/drone/push Build is passing

前端:
- 岗位选择改为多选模式
- 增强拖拽视觉反馈(高亮、动画提示)
- 列表显示多个岗位标签

后端:
- 添加 position_ids 字段支持多岗位
- 兼容旧版 position_id 单选数据
- 返回 position_names 数组
This commit is contained in:
yuliang_guo
2026-01-30 16:19:40 +08:00
parent a92bfa2b0f
commit 920c6a64c8
4 changed files with 157 additions and 24 deletions

View File

@@ -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 关联表)

View File

@@ -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

View File

@@ -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,