【项目中心】工作台与项目管理
工作台、项目列表和项目设置属于项目中心,由 yudao-module-pms 后端模块的 pm.workbench、pm.project 包实现,前端实现在 @/views/pms/pm/workbench 和 @/views/pms/pm/project 目录。
项目是 PMS 的业务数据边界。迭代、工作项、评论、动态和工时都归属于一个项目;项目成员级别决定当前用户能读、能写还是能管理,项目状态决定项目是否还能被编辑。
- 工作台:集中查看当前用户负责的工作项和迭代,并按项目、状态、优先级、迭代和截止日期筛选。
- 项目列表:按全部项目、我负责的和我参与的查看项目,支持星标、个人分组、项目设置、归档和回收站。
- 项目设置:维护项目基本资料、项目成员、项目公告和工作项协作配置。
- 项目模板:维护通用项目和敏捷开发项目的默认事项类型、状态和看板列配置。
本文涉及表如下图所示:
# 1. 工作台
工作台,由 PmsWorkbenchController 提供接口(/pms/pm/workbench)。工作台没有独立的数据表,只按当前用户查询负责的未归档工作项和未完成迭代;行内编辑最终调用工作项接口,详见 《【项目中心】工作项与协作》。
# 1.1 管理后台
对应 [PMS 项目管理 -> 项目中心 -> 工作台] 菜单,对应 yudao-ui-admin-vue3 项目的 @/views/pms/pm/workbench 目录。
# 查询与页签
页面顶部为查询条件,下面按「全部事项、需求、任务、缺陷、迭代」切换列表。各页签数量按当前筛选条件重新统计,「全部事项」只汇总工作项,不包含独立迭代。
查询条件支持项目、标题或编号、状态、优先级、迭代和截止日期。其中未选择状态时默认排除已完成工作项,迭代选项依赖项目,只有先选择项目才会加载。

# 列表与行内编辑
工作项表格展示编号、标题、优先级、状态、处理人、创建人、所属项目、截止日期和创建日期。拥有项目写权限时,点击优先级、状态、处理人或截止日期可以直接行内编辑;只读成员只显示文本,不会出现可编辑控件。

点击工作项标题打开工作项详情抽屉,可以在工作台直接查看和维护描述、评论、动态、子工作项和工时;点击迭代标题则进入迭代详情。抽屉与项目详情页打开的是同一个组件,详见 《【项目中心】工作项与协作》。

# 2. 项目
项目,由 PmsProjectController 提供接口(/pms/pm/project)。项目成员、公告、个人分组关系和收藏关系分别保存到后文的子表,不在主表中冗余保存。
# 2.1 表结构
省略 creator/create_time/updater/update_time/deleted/tenant_id 等通用字段
CREATE TABLE `pms_project` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`name` varchar(50) NOT NULL COMMENT '项目名称',
`description` text DEFAULT NULL COMMENT '项目描述',
`icon` varchar(255) DEFAULT NULL COMMENT '项目图标',
`type` int NOT NULL COMMENT '项目类型',
`level` int NOT NULL COMMENT '项目优先级',
`open_status` bit(1) NOT NULL DEFAULT b'1' COMMENT '是否公开',
`sort` int DEFAULT NULL COMMENT '排序',
`start_time` datetime DEFAULT NULL COMMENT '开始时间',
`end_time` datetime DEFAULT NULL COMMENT '截止时间',
`access_time` datetime DEFAULT NULL COMMENT '最近访问时间',
`archive_time` datetime DEFAULT NULL COMMENT '归档时间',
`recycle_time` datetime DEFAULT NULL COMMENT '移入回收站时间',
`status` int NOT NULL DEFAULT 1 COMMENT '项目状态',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='PMS 项目';
① 枚举 type 项目类型(PmsProjectTypeEnum):1 通用项目、2 敏捷开发项目。通用项目只提供项目概况、任务和甘特图;敏捷开发项目额外提供待规划、迭代、需求、缺陷和工时。项目类型创建后不可修改。
② 枚举 level 项目优先级(PmsProjectLevelEnum):最高、较高、普通、较低、最低。优先级只用于展示,不改变项目成员级别。
③ open_status = 0 表示私有项目,只有项目成员或超级管理员可以查看;open_status = 1 表示公开项目,所有登录用户可以查看,但只有项目成员可以编辑。公开不等于可以维护项目。
④ start_time、end_time 保存项目周期,必须同时填写或同时为空,且开始时间早于截止时间。access_time 在打开项目详情时更新,用于按最近访问时间排序;archive_time、recycle_time 记录对应生命周期操作时间,恢复时由 Service 清空。
⑤ 枚举 status 项目状态(PmsProjectStatusEnum)。详见 §2.2 状态流转。
⑥ createProject 在同一事务中创建项目、写入项目成员,并按项目类型调用 PmsWorkItemStatusService 的 initProjectWorkItemStatuses 初始化工作项状态和看板列。创建人使用 OWNER 级别,表单中的其他初始成员使用 WRITE 级别。
该表包含四个子表:
pms_project_favorite(项目收藏):在项目列表点击星标时维护,属于当前用户维度,详见 §3.1 项目收藏表。pms_project_group_relation(个人分组关系):在项目列表移动分组时维护,属于当前用户维度,详见 §3.3 项目分组关系表。pms_project_member(项目成员):在项目设置的「成员」页签中维护,详见 §4.1 项目成员表。pms_project_announcement(项目公告):在项目设置的「项目公告」页签中维护,详见 §4.2 项目公告表。
# 2.2 状态流转
项目生命周期由 PmsProjectServiceImpl 控制。状态字段为 status:
| 状态值 | 枚举 | 说明 | 可执行操作 |
|---|---|---|---|
1 | NORMAL | 进行中 | 查看、编辑、成员维护、公告、协作配置、迭代与工作项、归档、移入回收站 |
2 | ARCHIVED | 已归档 | 查看、恢复 |
3 | RECYCLED | 回收站 | 查看列表、恢复;项目拥有者可彻底删除 |
状态流转说明
创建项目 ──→ 进行中(1) ──归档──→ 已归档(2)
↑ │ │
│ └──移入回收站──→ 回收站(3) ──彻底删除(终态)
└───────── 恢复 ───────┘
- 创建(
createProject):Service 强制写入进行中,创建请求不能自行传入状态。 - 归档 / 移入回收站(
archiveProject/recycleProject):项目管理员操作进行中项目,分别写入archive_time、recycle_time,并清除该项目的所有个人分组关系和星标关系。 - 恢复(
restoreProject):项目管理员恢复已归档或回收站项目,状态回到进行中并清空生命周期时间。恢复不会自动恢复历史星标和分组关系。 - 彻底删除(
deleteProject):只允许项目拥有者或超级管理员删除回收站项目。Service 在同一事务中删除工时、工作项、迭代、成员、个人分组关系、收藏、公告和项目主表记录,该操作不可恢复。 - 归档和回收站没有独立表,状态和时间都保存在
pms_project;归档后所有迭代和工作项的编辑入口自动隐藏。
# 2.3 管理后台
对应 [PMS 项目管理 -> 项目中心 -> 我的项目] 菜单,对应 yudao-ui-admin-vue3 项目的 @/views/pms/pm/project/list 目录。页面由 ProjectForm.vue、ProjectGroupList.vue 和 ProjectGroupForm.vue 组成。
# 列表
列表提供「全部项目」「我参与的」「我负责的」三个页签,分别对应路由参数 tabs=all、tabs=participate 和 tabs=owner,默认进入「我参与的」。列表支持按项目名称搜索,以及按最近访问时间或创建时间排序。
项目范围由 Service 根据成员级别和公开状态计算:
| 页签 | 查询范围 |
|---|---|
| 全部项目 | 当前用户参与的项目,并包含公开项目;超级管理员可以查看全部公开和私有项目 |
| 我参与的 | 当前用户参与的项目,可以再按个人分组筛选 |
| 我负责的 | 当前用户级别为 OWNER 或 ADMIN 的项目 |
点击项目名称进入 /pms/pm/project/detail/:id,点击【项目设置】进入 /pms/pm/project/config/:id。两个隐藏路由都通过 activeMenu: '/pms/pm/project/list' 保持左侧「我的项目」高亮。

# 星标项目
页面顶部的「星标项目」只展示当前用户参与且处于进行中的项目。每张卡片展示项目图标、名称、描述、完成进度和近 14 日完成趋势;点击卡片进入项目详情,右上角星形按钮调用收藏接口。
# 新增
点击【新建项目】打开 ProjectForm.vue,填写项目类型、项目名称、项目封面、开始时间、截止时间、项目描述、可见范围和初始成员。
选择「私有」时可以选择初始成员,创建人会自动加入并成为项目拥有者;选择「公开」时不要求填写成员,但后续仍只有成员可以编辑。

# 修改
项目管理员在更多操作中点击【项目设置】,或在项目设置的「基本信息」页点击【编辑项目】,复用同一个 ProjectForm.vue 回显资料。保存时后端只更新基本资料,不修改项目类型、创建人、成员关系和项目状态。
# 归档项目
对应 [PMS 项目管理 -> 项目中心 -> 归档项目] 菜单,对应 @/views/pms/pm/project/archive 目录。页面复用项目分页接口并传入 status=2,展示项目名称、归档时间和【恢复项目】;恢复后项目重新回到进行中。

# 项目回收站
对应 [PMS 项目管理 -> 项目中心 -> 项目回收站] 菜单,对应 @/views/pms/pm/project/recycle 目录。页面复用项目分页接口并传入 status=3,支持按项目名称搜索,展示项目名称、删除时间、【恢复项目】和【彻底删除】。
彻底删除前会二次确认,并要求项目拥有者级别。

# 3. 项目收藏与个人分组
项目收藏,由 PmsProjectFavoriteController 提供接口(/pms/pm/project-favorite);个人分组及项目分组关系,由 PmsProjectGroupController 提供接口(/pms/pm/project-group)。
两者都只改变当前用户的项目入口,不改变项目本身的可见范围,也不影响其他项目成员看到的列表。
# 3.1 项目收藏表
CREATE TABLE `pms_project_favorite` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '收藏编号',
`project_id` bigint NOT NULL COMMENT '项目编号',
`user_id` bigint NOT NULL COMMENT '收藏人用户编号',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='PMS 项目收藏';
① project_id 关联 pms_project 表的 id 字段,user_id 关联 system_users 表的 id 字段。一条记录表示一个用户收藏了一个项目,同一项目可以被多个成员分别收藏。
② 收藏前 Service 会校验当前用户是项目成员,公开项目的普通访问者不能直接收藏。
③ createProjectFavorite 和 deleteProjectFavorite 都按「项目 + 当前用户」查询,重复收藏或重复取消保持幂等。
# 3.2 项目分组表
CREATE TABLE `pms_project_group` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`user_id` bigint NOT NULL COMMENT '后台用户编号',
`name` varchar(100) NOT NULL COMMENT '分组名称',
`type` tinyint NOT NULL DEFAULT 3 COMMENT '分组类型',
`sort` int NOT NULL DEFAULT 0 COMMENT '显示顺序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='PMS 项目个人分组';
① user_id 关联 system_users 表的 id 字段。分组是当前用户维度的,每个用户独立维护自己的分组。
② 枚举 type 分组类型(PmsProjectGroupTypeEnum):
| 值 | 枚举 | 说明 | 能否编辑 / 删除 | 能否作为移动目标 |
|---|---|---|---|---|
1 | ALL | 全部项目 | — | —(只是查询范围) |
2 | UNGROUPED | 未分组 | — | ✓(用于清除分组关系) |
3 | CUSTOM | 自定义分组 | ✓ | ✓ |
③ getGroupList 首次查询时,会为当前用户补齐「全部项目」和「未分组」两个系统分组。自定义分组名称在当前用户维度必须唯一。
# 3.3 项目分组关系表
CREATE TABLE `pms_project_group_relation` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`user_id` bigint NOT NULL COMMENT '后台用户编号',
`group_id` bigint NOT NULL COMMENT '分组编号',
`project_id` bigint NOT NULL COMMENT '项目编号',
`sort` int NOT NULL DEFAULT 0 COMMENT '显示顺序',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='PMS 项目个人分组关系';
① group_id 关联 pms_project_group 表的 id 字段,project_id 关联 pms_project 表的 id 字段,user_id 表示该关系所属用户。
② 分组关系不授予项目访问权限,移动前仍会校验当前用户是项目成员。
③ 移动到「未分组」或不传 groupId 时删除已有关系;移动到自定义分组时新增或更新关系。
# 3.4 管理后台
对应 [PMS 项目管理 -> 项目中心 -> 我的项目] 页面中的星标开关和【管理分组】操作,对应 @/views/pms/pm/project/list 目录下的 ProjectGroupList.vue 和 ProjectGroupForm.vue。
# 星标
在星标卡片或项目列表中点击星形开关,调用 createProjectFavorite 收藏、deleteProjectFavorite 取消收藏。项目归档或移入回收站时,Service 会同步清除该项目的所有收藏关系。
# 管理分组
点击【管理分组】打开 ProjectGroupList.vue 弹窗,列表展示分组名称、分组类型和项目数量。拖拽后点击【保存排序】调用 updateProjectGroupSort;自定义分组可以编辑名称和删除,系统分组只读。删除自定义分组时会同时删除其分组关系,项目自动回到「未分组」。

# 移动项目
项目列表的【移动分组】下拉菜单调用 moveProject。目标分组列表会过滤「全部项目」,选择「未分组」等同于移出当前自定义分组。该操作只修改当前用户的 pms_project_group_relation,不修改项目本身。
# 4. 项目设置
项目设置由项目管理员在项目列表或项目详情的【项目设置】入口打开,隐藏路由为 /pms/pm/project/config/:id。项目成员,由 PmsProjectMemberController 提供接口(/pms/pm/project-member);项目公告,由 PmsProjectAnnouncementController 提供接口(/pms/pm/project-announcement)。
# 4.1 项目成员表
pms_project_member 是项目私有访问、管理权限和编辑权限的依据。
CREATE TABLE `pms_project_member` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
`project_id` bigint NOT NULL COMMENT '项目编号',
`user_id` bigint NOT NULL COMMENT '后台用户编号',
`level` tinyint NOT NULL COMMENT '成员权限级别',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='PMS 项目成员';
① project_id 关联 pms_project 表的 id 字段,user_id 关联 system_users 表的 id 字段。项目创建时,当前用户自动插入为项目拥有者,表单中的其他初始成员按编辑级别插入。
② 枚举 level 成员权限级别(PmsProjectMemberLevelEnum):
| 值 | 枚举 | 说明 | 读取项目 | 编辑业务数据 | 管理项目及成员 |
|---|---|---|---|---|---|
1 | OWNER | 项目拥有者 | ✓ | ✓ | ✓ |
2 | ADMIN | 项目管理员 | ✓ | ✓ | ✓ |
3 | WRITE | 编辑 | ✓ | ✓ | — |
4 | READ | 只读 | ✓ | — | — |
③ 后端不会只依赖前端按钮隐藏:查询项目数据时校验项目读权限,维护迭代和工作项时校验项目写权限,修改项目资料和成员时校验项目管理员权限。菜单、按钮和接口的功能权限仍由 System 模块统一分配,项目成员级别不替代菜单授权。
④ 创建人不能被移除,也不能把其他成员提升为 OWNER;项目拥有者不能主动退出项目。超级管理员绕过项目成员级别校验,但仍需要通过菜单和接口功能权限。
# 4.2 项目公告表
pms_project_announcement 保存项目公告及附件。项目概况只展示最新公告,完整列表在项目设置的「项目公告」页签中查看。
CREATE TABLE `pms_project_announcement` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '公告编号',
`project_id` bigint NOT NULL COMMENT '项目编号',
`content` text NOT NULL COMMENT '公告内容',
`file_urls` varchar(5000) DEFAULT NULL COMMENT '附件地址列表',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='PMS 项目公告';
① project_id 关联 pms_project 表的 id 字段。file_urls 通过 MyBatis 的 JacksonTypeHandler 保存为 JSON 数组,前端使用 UploadFile 组件维护附件。
② 公告内容必填。发布、编辑和删除都要求项目写成员(拥有者、管理员或编辑)权限;查看列表和详情只要求项目读权限。
# 4.3 管理后台
对应 yudao-ui-admin-vue3 项目的 @/views/pms/pm/project/config 目录,页签包含「基本信息」「成员」「项目公告」「协作配置」。
# 基本信息
ProjectBasicInfo.vue 展示项目名称、类型、周期、可见范围和描述。项目管理员在项目进行中时可以点击【编辑项目】复用 ProjectForm.vue;归档项目只读,不能修改项目资料。
页面下方提供【归档】和【移入回收站】操作,具体规则见 §2.2 状态流转。

# 成员
ProjectMemberList.vue 展示成员头像、昵称、项目级别和创建人标识。项目管理员点击【新增成员】或【修改】打开 ProjectMemberForm.vue,使用 System 模块的 UserSelectV2.vue 选择一个或多个后台账号,并分配项目管理员、编辑或只读级别。
保存时后端按本次完整成员列表进行差量新增、修改和移除,并再次校验用户存在。非拥有者的直接成员可以在项目列表中点击【退出项目】,调用 exitProject;项目拥有者不能退出。

# 项目公告
ProjectAnnouncementList.vue 展示公告内容、附件、发布人和发布时间。点击【发布公告】或【编辑】打开 ProjectAnnouncementForm.vue,填写公告内容并使用 UploadFile 上传附件。

# 协作配置
ProjectCollaborationConfig.vue 根据项目类型展示可配置的事项类型:通用项目只有任务,敏捷开发项目包含需求、任务和缺陷。点击【状态设置】打开 WorkItemStatusList.vue,维护状态名称、语义状态、初始状态和看板列。
状态和看板数据属于工作项协作范围,详见 《【项目中心】工作项与协作》。

# 5. 项目模板
项目模板,由 PmsProjectTemplateController 提供接口(/pms/pm/project-template),用于维护项目类型对应的默认协作配置。模板不与某个项目建立外键关系。
# 5.1 表结构
CREATE TABLE `pms_project_template` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '模板编号',
`name` varchar(100) NOT NULL COMMENT '模板名称',
`description` varchar(500) DEFAULT NULL COMMENT '模板描述',
`project_type` int NOT NULL COMMENT '项目类型',
`status` tinyint NOT NULL DEFAULT 0 COMMENT '模板状态',
`sort` int NOT NULL DEFAULT 0 COMMENT '显示顺序',
`item_types` varchar(5000) NOT NULL COMMENT '启用的工作项类型列表',
`statuses` varchar(10000) NOT NULL COMMENT '工作项状态模板列表',
`boards` varchar(10000) NOT NULL COMMENT '看板列模板列表',
PRIMARY KEY (`id`)
) ENGINE=InnoDB COMMENT='PMS 项目模板';
① project_type 使用枚举 PmsProjectTypeEnum;status 使用通用状态:0 开启、1 停用;sort 决定模板列表显示顺序。Service 校验同一项目类型下模板名称不能重复。
② item_types、statuses 和 boards 使用 JacksonTypeHandler 保存 JSON。保存时后端校验:事项类型不能重复或无效;每种事项类型必须且只能有一个初始状态;状态编码和看板编码不能重复;每个状态必须且只能归属一个同类型看板列。
item_types / statuses / boards JSON 字段结构
{
"itemTypes": [2, 3, 4],
"statuses": [
{
"code": "pending",
"name": "待处理",
"workItemType": 3,
"statusType": 1,
"defaultStatus": true,
"sort": 0,
"boardCode": "todo"
}
],
"boards": [
{
"code": "todo",
"name": "待办",
"workItemType": 3,
"sort": 0,
"statusCodes": ["pending"]
}
]
}
① itemTypes 保存启用的工作项类型编号数组,取值同枚举 PmsWorkItemTypeEnum:2 需求、3 任务、4 缺陷。
② statuses 的 code 是模板内的稳定编码,statusType 是语义状态(1 未开始、2 进行中、3 已完成),defaultStatus 标识该类型的初始状态,boardCode 指向所属看板列。
③ boards 的 statusCodes 反向保存该看板列包含的状态编码,与 statuses 的 boardCode 互为映射。两者必须一致,否则保存时被校验拦截。
③ 当前 createProject 按项目类型调用 initProjectWorkItemStatuses 初始化系统默认状态和看板,并未读取 pms_project_template。因此本表当前是独立的模板维护能力,新建项目不会自动套用自定义模板。
# 5.2 管理后台
对应 [PMS 项目管理 -> 项目中心 -> 项目模板] 菜单,对应 yudao-ui-admin-vue3 项目的 @/views/pms/pm/project/template 目录。
# 列表
支持按模板名称、项目类型和状态筛选,展示模板名称、描述、项目类型、状态、排序和创建时间。

# 新增与修改
点击【新增】或【编辑】打开 ProjectTemplateForm.vue,填写模板名称、描述、项目类型、状态和排序,再维护事项类型、工作项状态和看板列三组配置。保存时后端重新校验模板名称、初始状态和状态与看板列的映射关系。

# 删除
点击【删除】并二次确认后,模板不再出现在模板列表中。如果只需暂时隐藏,应将状态修改为停用,以便后续恢复。