From 920c6a64c88d9de274495bd35c6fa6e2c3918ab6 Mon Sep 17 00:00:00 2001 From: yuliang_guo Date: Fri, 30 Jan 2026 16:19:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=88=90=E9=95=BF=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E5=A4=9A=E5=B2=97=E4=BD=8D=E5=85=B3=E8=81=94?= =?UTF-8?q?=20+=20=E5=A2=9E=E5=BC=BA=E6=8B=96=E6=8B=BD=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 前端: - 岗位选择改为多选模式 - 增强拖拽视觉反馈(高亮、动画提示) - 列表显示多个岗位标签 后端: - 添加 position_ids 字段支持多岗位 - 兼容旧版 position_id 单选数据 - 返回 position_names 数组 --- backend/app/models/course.py | 5 +- backend/app/schemas/growth_path.py | 4 +- backend/app/services/growth_path_service.py | 55 ++++++-- .../views/manager/growth-path-management.vue | 117 ++++++++++++++++-- 4 files changed, 157 insertions(+), 24 deletions(-) diff --git a/backend/app/models/course.py b/backend/app/models/course.py index ba5fa91..570d0e2 100644 --- a/backend/app/models/course.py +++ b/backend/app/models/course.py @@ -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 关联表) diff --git a/backend/app/schemas/growth_path.py b/backend/app/schemas/growth_path.py index 4fe085f..583ab99 100644 --- a/backend/app/schemas/growth_path.py +++ b/backend/app/schemas/growth_path.py @@ -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 diff --git a/backend/app/services/growth_path_service.py b/backend/app/services/growth_path_service.py index 6bef73c..c9a9415 100644 --- a/backend/app/services/growth_path_service.py +++ b/backend/app/services/growth_path_service.py @@ -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, diff --git a/frontend/src/views/manager/growth-path-management.vue b/frontend/src/views/manager/growth-path-management.vue index 8863ce9..46fbe46 100644 --- a/frontend/src/views/manager/growth-path-management.vue +++ b/frontend/src/views/manager/growth-path-management.vue @@ -53,11 +53,19 @@ - + @@ -149,8 +157,11 @@ @@ -292,7 +303,9 @@