需求分解

This commit is contained in:
wkc
2026-01-27 17:09:32 +08:00
parent 0c00a00df0
commit 79cd4fe755
152 changed files with 14990 additions and 21 deletions

View File

@@ -0,0 +1,612 @@
# Design: 项目管理模块
## 概述
本文档描述项目管理模块的技术设计方案包括系统架构、数据模型、API设计等。
## 系统架构
### 模块划分
遵循若依框架的分层架构,新建 `ruoyi-dpc` 模块与若依框架代码分离Controller 层也放在新建模块中:
```
ruoyi-dpc/ (新建模块)
├── pom.xml # 模块依赖配置
├── src/main/java/com/ruoyi/dpc/
│ ├── controller/
│ │ └── DpcProjectController.java # 项目控制器
│ ├── domain/
│ │ ├── DpcProject.java # 项目实体
│ │ ├── DpcProjectPerson.java # 项目人员关联
│ │ ├── dto/
│ │ │ ├── DpcProjectDTO.java # 项目数据传输对象
│ │ │ ├── DpcProjectQueryDTO.java # 项目查询DTO
│ │ │ └── DpcProjectImportDTO.java # 项目导入DTO
│ │ └── vo/
│ │ ├── DpcProjectVO.java # 项目视图对象
│ │ └── DpcProjectQueryVO.java # 查询视图对象
│ ├── mapper/
│ │ ├── DpcProjectMapper.java
│ │ └── DpcProjectPersonMapper.java
│ └── service/
│ ├── IDpcProjectService.java
│ └── impl/
│ └── DpcProjectServiceImpl.java
└── src/main/resources/mapper/dpc/
├── DpcProjectMapper.xml
└── DpcProjectPersonMapper.xml
ruoyi-ui/src/
├── api/
│ └── dpcProject.js # API请求定义
└── views/
└── dpcProject/
├── index.vue # 项目列表页
├── add-or-edit.vue # 新增/编辑弹窗
└── import-history.vue # 导入历史项目弹窗
```
## 数据模型
### 数据库表设计
#### dpc_project (项目主表)
| 字段名 | 类型 | 说明 | 约束 |
|-------|------|------|-----|
| project_id | BIGINT | 项目ID | PK, AUTO_INCREMENT |
| project_name | VARCHAR(100) | 项目名称 | NOT NULL |
| description | VARCHAR(500) | 项目描述 | |
| status | CHAR(1) | 状态 | NOT NULL, DEFAULT '0' |
| target_count | INT | 目标人数 | NOT NULL, DEFAULT 0 |
| warning_count | INT | 预警人数 | NOT NULL, DEFAULT 0 |
| start_date | DATE | 开始日期 | |
| end_date | DATE | 结束日期 | |
| is_archived | CHAR(1) | 是否归档 | DEFAULT '0' |
| archive_file_path | VARCHAR(255) | 归档文件路径 | |
| create_by | VARCHAR(64) | 创建者 | |
| create_time | DATETIME | 创建时间 | |
| update_by | VARCHAR(64) | 更新者 | |
| update_time | DATETIME | 更新时间 | |
| remark | VARCHAR(500) | 备注 | |
**状态枚举值**
- `0`: 进行中
- `1`: 已完成
- `2`: 已归档
#### dpc_project_person (项目人员关联表)
| 字段名 | 类型 | 说明 | 约束 |
|-------|------|------|-----|
| id | BIGINT | 主键ID | PK, AUTO_INCREMENT |
| project_id | BIGINT | 项目ID | FK -> dpc_project.project_id |
| person_id | BIGINT | 人员ID | FK -> sys_user.user_id |
| person_name | VARCHAR(30) | 人员姓名 | 冗余字段 |
| person_dept_id | BIGINT | 部门ID | 冗余字段 |
**索引**
- `idx_project_id`: (project_id)
- `uk_project_person`: (project_id, person_id) 唯一索引
### 实体类设计
#### DpcProject.java
```java
@Data
@TableName("dpc_project")
public class DpcProject {
/** 项目ID */
@TableId(type = IdType.AUTO)
private Long projectId;
/** 项目名称 */
@NotBlank(message = "项目名称不能为空")
@Size(max = 100, message = "项目名称不能超过100个字符")
private String projectName;
/** 项目描述 */
@Size(max = 500, message = "项目描述不能超过500个字符")
private String description;
/** 状态0进行中 1已完成 2已归档 */
private String status;
/** 目标人数 */
private Integer targetCount;
/** 预警人数 */
private Integer warningCount;
/** 开始日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate;
/** 结束日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date endDate;
/** 是否归档 */
private String isArchived;
/** 归档文件路径 */
private String archiveFilePath;
/** 创建者 */
@TableField(fill = FieldFill.INSERT)
private String createBy;
/** 创建时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/** 更新者 */
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/** 更新时间 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
/** 备注 */
private String remark;
@Transient
private List<Long> personIds; // 关联人员ID列表
}
```
#### 审计字段自动填充配置
```java
/**
* MyBatis Plus 审计字段自动填充处理器
*/
@Component
public class DpcMetaObjectHandler implements MetaObjectHandler {
@Resource
private TokenService tokenService;
@Override
public void insertFill(MetaObject metaObject) {
this.strictInsertFill(metaObject, "createTime", Date.class, new Date());
this.strictInsertFill(metaObject, "createBy", String.class, getUsername());
}
@Override
public void updateFill(MetaObject metaObject) {
this.strictUpdateFill(metaObject, "updateTime", Date.class, new Date());
this.strictUpdateFill(metaObject, "updateBy", String.class, getUsername());
}
/**
* 获取当前登录用户名
*/
private String getUsername() {
try {
LoginUser loginUser = SecurityUtils.getLoginUser();
return loginUser != null ? loginUser.getUsername() : "system";
} catch (Exception e) {
return "system";
}
}
}
```
#### 实体类审计字段注解
```java
@Data
@TableName("dpc_project")
public class DpcProject {
// ... 其他字段
/** 创建者 */
@TableField(fill = FieldFill.INSERT)
private String createBy;
/** 创建时间 */
@TableField(fill = FieldFill.INSERT)
private Date createTime;
/** 更新者 */
@TableField(fill = FieldFill.INSERT_UPDATE)
private String updateBy;
/** 更新时间 */
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
/** 备注 */
private String remark;
}
```
**配置说明**
- `@TableField(fill = FieldFill.INSERT)` - 仅在插入时自动填充
- `@TableField(fill = FieldFill.INSERT_UPDATE)` - 插入和更新时都自动填充
- `MetaObjectHandler` 处理器会自动从 Spring Security 上下文中获取当前登录用户
### DTO 设计
按照全局配置要求,接口传参使用单独的 DTO不与 entity 混用。
#### DpcProjectDTO.java新增/修改项目DTO
```java
@Data
public class DpcProjectDTO {
/** 项目名称 */
@NotBlank(message = "项目名称不能为空")
@Size(max = 100, message = "项目名称不能超过100个字符")
private String projectName;
/** 项目描述 */
@Size(max = 500, message = "项目描述不能超过500个字符")
private String description;
/** 开始日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date startDate;
/** 结束日期 */
@JsonFormat(pattern = "yyyy-MM-dd")
private Date endDate;
/** 关联人员ID列表 */
@NotEmpty(message = "请至少选择一名参与人员")
private List<Long> personIds;
}
```
#### DpcProjectQueryDTO.java查询项目DTO
```java
@Data
public class DpcProjectQueryDTO {
/** 项目名称(模糊搜索) */
private String projectName;
/** 状态 */
private String status;
/** 创建时间范围开始 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTimeStart;
/** 创建时间范围结束 */
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTimeEnd;
}
```
#### DpcProjectImportDTO.java导入历史项目DTO
```java
@Data
public class DpcProjectImportDTO {
/** 历史项目ID */
@NotNull(message = "请选择要导入的历史项目")
private Long historyProjectId;
/** 新项目名称 */
@NotBlank(message = "新项目名称不能为空")
@Size(max = 100, message = "项目名称不能超过100个字符")
private String projectName;
}
```
#### DTO 与 Entity 转换
```java
/**
* DTO 与 Entity 转换工具类
*/
public class DpcProjectConverter {
/**
* DTO 转 Entity新增/修改)
*/
public static DpcProject toEntity(DpcProjectDTO dto) {
if (dto == null) {
return null;
}
DpcProject entity = new DpcProject();
entity.setProjectName(dto.getProjectName());
entity.setDescription(dto.getDescription());
entity.setStartDate(dto.getStartDate());
entity.setEndDate(dto.getEndDate());
return entity;
}
/**
* Entity 转 VO
*/
public static DpcProjectVO toVO(DpcProject entity) {
if (entity == null) {
return null;
}
DpcProjectVO vo = new DpcProjectVO();
BeanUtils.copyProperties(entity, vo);
return vo;
}
/**
* Entity 列表转 VO 列表
*/
public static List<DpcProjectVO> toVOList(List<DpcProject> entityList) {
if (entityList == null || entityList.isEmpty()) {
return new ArrayList<>();
}
return entityList.stream()
.map(DpcProjectConverter::toVO)
.collect(Collectors.toList());
}
}
```
#### Controller 使用 DTO
```java
@RestController
@RequestMapping("/dpc/project")
public class DpcProjectController {
@Resource
private IDpcProjectService projectService;
@PreAuthorize("@ss.hasPermi('dpc:project:add')")
@PostMapping
public AjaxResult add(@Validated @RequestBody DpcProjectDTO dto) {
DpcProject project = DpcProjectConverter.toEntity(dto);
return AjaxResult.success(projectService.insertProject(project));
}
@PreAuthorize("@ss.hasPermi('dpc:project:edit')")
@PutMapping
public AjaxResult edit(@Validated @RequestBody DpcProjectDTO dto) {
DpcProject project = DpcProjectConverter.toEntity(dto);
return AjaxResult.success(projectService.updateProject(project));
}
@PreAuthorize("@ss.hasPermi('dpc:project:list')")
@GetMapping("/list")
public TableDataInfo list(DpcProjectQueryDTO queryDTO) {
DpcProject project = new DpcProject();
// 将查询条件转换到实体
BeanUtils.copyProperties(queryDTO, project);
startPage();
List<DpcProject> list = projectService.selectProjectList(project);
List<DpcProjectVO> voList = DpcProjectConverter.toVOList(list);
return getDataTable(voList);
}
}
```
## API设计
### RESTful API规范
| 方法 | 路径 | 说明 | 权限 |
|-----|------|------|-----|
| GET | /project/list | 查询项目列表 | project:list |
| GET | /project/{id} | 查询项目详情 | project:query |
| POST | /project | 新增项目 | project:add |
| PUT | /project | 修改项目 | project:edit |
| DELETE | /project/{ids} | 删除项目 | project:remove |
| GET | /project/history/{id} | 获取历史项目配置 | project:query |
| POST | /project/import | 导入历史项目 | project:add |
| POST | /project/archive/{id} | 归档项目 | project:archive |
| POST | /project/reanalyze/{id} | 重新分析 | project:reanalyze |
### 请求/响应格式
#### 查询项目列表
**请求**: `GET /project/list?projectName=xxx&status=0&pageNum=1&pageSize=10`
**响应**:
```json
{
"total": 100,
"rows": [
{
"projectId": 1,
"projectName": "2026年Q1初核排查",
"description": "季度常规排查",
"status": "0",
"targetCount": 100,
"warningCount": 5,
"createTime": "2026-01-01 10:00:00"
}
],
"code": 200,
"msg": "查询成功"
}
```
#### 新增项目
**请求**: `POST /project`
```json
{
"projectName": "2026年Q1初核排查",
"description": "季度常规排查",
"startDate": "2026-01-01",
"endDate": "2026-03-31",
"personIds": [1, 2, 3, 4, 5]
}
```
**响应**:
```json
{
"code": 200,
"msg": "新增成功"
}
```
## 业务逻辑设计
### 项目状态流转
```
[新建] → [进行中] → [已完成] → [已归档]
|---- [重新分析]
```
### 核心业务规则
1. **新建项目**
- 项目名称必填
- 至少选择一名人员
- 默认状态为"进行中"
2. **导入历史项目**
- 选择已完成的历史项目
- 复制人员配置
- 生成新项目(状态为"进行中"
3. **归档项目**
- 只能归档"已完成"状态的项目
- 生成PDF归档文件
- 更新项目状态为"已归档"
4. **重新分析**
- 只能对"已完成"项目执行
- 异步执行风险模型
- 更新预警人数
## 前端设计
### 页面组件结构
#### 项目列表页 (index.vue)
```
<template>
<div class="app-container">
<!-- 搜索区域 -->
<el-form :inline="true">
<el-input v-model="queryParams.projectName" placeholder="请输入项目名称" />
<el-button @click="handleQuery">搜索</el-button>
<el-button @click="handleAdd">新建项目</el-button>
<el-button @click="handleImport">导入历史项目</el-button>
</el-form>
<!-- 数据表格 -->
<el-table :data="projectList">
<el-table-column prop="projectName" label="项目名称" />
<el-table-column prop="description" label="项目描述" />
<el-table-column prop="createTime" label="创建时间" />
<el-table-column prop="status" label="状态">
<template #default="scope">
<el-tag v-if="scope.row.status === '0'">进行中</el-tag>
<el-tag v-else-if="scope.row.status === '1'" type="success">已完成</el-tag>
<el-tag v-else type="info">已归档</el-tag>
</template>
</el-table-column>
<el-table-column prop="targetCount" label="目标人数" />
<el-table-column prop="warningCount" label="预警人数" />
<el-table-column label="操作" fixed="right">
<template #default="scope">
<el-button v-if="scope.row.status === '0'" @click="handleEnter(scope.row)">进入项目</el-button>
<el-button v-if="scope.row.status === '1'" @click="handleViewResult(scope.row)">查看结果</el-button>
<el-button v-if="scope.row.status === '1'" @click="handleReanalyze(scope.row)">重新分析</el-button>
<el-button v-if="scope.row.status === '1'" @click="handleArchive(scope.row)">归档</el-button>
</template>
</el-table-column>
</el-table>
</div>
</template>
```
### API封装 (project.js)
```javascript
import request from '@/utils/request'
// 查询项目列表
export function listProject(query) {
return request({
url: '/dpc/project/list',
method: 'get',
params: query
})
}
// 新增项目
export function addProject(data) {
return request({
url: '/dpc/project',
method: 'post',
data: data
})
}
// 归档项目
export function archiveProject(projectId) {
return request({
url: '/dpc/project/archive/' + projectId,
method: 'post'
})
}
// 重新分析
export function reanalyzeProject(projectId) {
return request({
url: '/dpc/project/reanalyze/' + projectId,
method: 'post'
})
}
// 导入历史项目
export function importProject(data) {
return request({
url: '/dpc/project/import',
method: 'post',
data: data
})
}
```
## 技术约束
1. **后端**
- Spring Boot 3.5.8
- 使用 MyBatis Plus 3.5.10 进行数据访问Spring Boot 3 适配版)
- 使用 `@Resource` 注入依赖(替代 `@Autowired`
- 使用 `@Data` 注解简化实体类
- 实体类不继承 BaseEntity基础字段直接定义在实体类中
- 新建 `ruoyi-dpc` 模块,与若依框架代码分离
- Controller 层也要放在新建模块中(不在 `ruoyi-admin` 中)
- 接口传参使用单独的 DTO不与 entity 混用
2. **前端**
- Vue 2.6.12
- 使用 Element UI 2.15.14 组件库
- 遵循现有视图组件风格
- 在添加页面和组件后,注意与数据库中菜单表进行联动修改
3. **数据库**
- MySQL 8.2.0
- 表名使用 `dpc_` 前缀(项目英文名首字母集合)
4. **安全**
- 所有API需要 `@PreAuthorize` 权限注解
- 敏感操作记录操作日志
5. **文档**
- 完成后端代码 controller 层代码生成测试后,在项目文件目录下生成 API 文档
6. **测试**
- 测试方式为生成可执行的测试脚本
- 在测试中启动的进程,在测试完成后立刻结束
- `/login/test` 接口可传入 `username``password` 获取 token测试账号admin/admin123
- swagger-ui 地址:`/swagger-ui/index.html`
7. **审计字段自动填充**
- 配置 MyBatis Plus `MetaObjectHandler` 实现审计字段自动填充
- 插入操作自动填充:`create_by``create_time`
- 更新操作自动填充:`update_by``update_time`
## 待确认事项
1. **PDF生成方案**:需确认使用 iText 或其他方案
2. **异步任务实现**:重新分析是否需要集成若依的定时任务模块
3. **菜单配置**:项目管理在系统菜单中的位置

View File

@@ -0,0 +1,112 @@
# Proposal: 添加项目管理模块
## Change ID
`add-project-management`
## Summary
添加项目管理模块,实现初核项目的创建、查询、状态管理、归档等核心功能。该模块是系统的首页和入口,用于管理所有历史创建的核查项目。
## Motivation
目前系统缺少项目管理的核心功能模块。用户需要:
1. 统一管理所有初核项目
2. 快速查找和定位项目
3. 跟踪项目状态(进行中/已完成)
4. 监控预警人数变化
5. 对已完成项目进行归档管理
## Scope
本提案实现以下功能(不包括快捷入口区):
### 包含的功能
- **1.1 导航与搜索区**
- 项目搜索(模糊搜索项目名称)
- 新建项目(标准表单创建)
- 导入历史项目(复制历史配置快速创建)
- **1.2 项目列表区**
- 项目信息展示(名称、描述、创建日期、状态、目标人数、预警人数)
- 项目状态标识(进行中/已完成)
- 预警人数动态更新
- 查看结果(已完成项目跳转结果页)
- 重新分析(已完成项目重新运行风险模型)
- 归档项目生成PDF导出
- 进入项目(进行中项目跳转工作台)
### 明确排除
- **1.3 快捷入口区**(创建季度初核、创建新员工排查等快捷功能)
## Proposed Design
详见 [design.md](./design.md)
## Alternatives Considered
### 选项1使用若依代码生成器
**优点**
- 快速生成标准CRUD代码
- 符合项目规范
**缺点**
- 需要手动调整业务逻辑
- 缺少复杂的业务规则处理
**决定**:不采用。项目管理模块包含复杂的业务逻辑(状态流转、归档、重新分析等),需要自定义实现。
### 选项2完全自定义开发
**优点**
- 完全控制实现细节
- 灵活应对业务需求变化
**缺点**
- 开发周期较长
- 需要确保代码规范一致
**决定**:采用。参考现有系统模块的代码模式,确保与项目风格一致。
## Impact
### 后端影响
- 新建 `ruoyi-dpc` 模块,与若依框架代码分离(包含 Controller、Service、Mapper、Domain 层)
- 新增表:`dpc_project`(项目主表)、`dpc_project_person`(项目人员关联表)
- 新增权限:`dpc:project:list`, `dpc:project:query`, `dpc:project:add`, `dpc:project:edit`, `dpc:project:remove`, `dpc:project:archive`, `dpc:project:reanalyze`
- Controller层`ruoyi-dpc/src/main/java/com/ruoyi/dpc/controller/DpcProjectController.java`
### 前端影响
- 新增视图:`ruoyi-ui/src/views/dpcProject/`
- 新增API`ruoyi-ui/src/api/dpcProject.js`
- 新增菜单:项目管理(在系统菜单中添加,注意与数据库中菜单表进行联动修改)
### 数据库影响
- 新增表:`dpc_project`(项目主表)
- 新增表:`dpc_project_person`(项目人员关联表)
## Dependencies
- 依赖现有用户系统(`SysUser`)进行人员选择
- 依赖部门系统(`SysDept`)进行部门范围选择
- 依赖文件上传功能项目附件、归档PDF
## Related Changes
## Open Questions
1. **项目人员关联方式**使用多对多关联表还是JSON字段存储人员列表
- 建议:使用 `dpc_project_person` 关联表,便于查询和扩展
2. **归档PDF生成**使用什么工具生成PDF
- 建议:使用 iText 或 Apache POI需要后续确认
3. **重新分析的触发方式**:同步还是异步?
- 建议:异步处理,避免长时间阻塞
## Success Criteria
- [ ] 用户可以创建新项目并填写完整信息
- [ ] 用户可以搜索项目(按名称模糊匹配)
- [ ] 项目列表正确显示状态和预警人数
- [ ] 进行中项目可以进入工作台
- [ ] 已完成项目可以查看结果
- [ ] 已完成项目可以归档并生成PDF
- [ ] 已完成项目可以重新分析
## References
- [模块设计文档](../../doc/modules/01-项目管理模块.md)
- [若依开发文档](https://doc.ruoyi.vip/)

View File

@@ -0,0 +1,214 @@
# Spec: 项目管理能力
## 概述
本规范定义了项目管理模块的核心能力,包括项目的创建、查询、状态管理和归档功能。
---
## ADDED Requirements
### Requirement: 项目列表查询
系统 MUST 允许用户查询所有项目列表,支持按项目名称进行模糊搜索。
#### Scenario: 查询所有项目
**Given** 用户已登录系统并具有项目查看权限
**When** 用户进入项目管理页面
**Then** 系统显示所有项目列表,包括项目名称、描述、创建时间、状态、目标人数、预警人数
#### Scenario: 按名称搜索项目
**Given** 用户在项目管理页面
**When** 用户在搜索框输入"Q1初核"并点击搜索
**Then** 系统显示所有包含"Q1初核"的项目
#### Scenario: 项目状态标识
**Given** 项目列表中有多个不同状态的项目
**When** 用户查看项目列表
**Then** 进行中的项目显示蓝色标签,已完成的项目显示绿色标签,已归档的项目显示灰色标签
#### Scenario: 预警人数动态更新
**Given** 存在状态为"进行中"的项目
**When** 用户刷新项目列表
**Then** 预警人数显示最新的统计值
---
### Requirement: 创建新项目
系统 MUST 允许用户创建新的初核项目,填写项目基本信息并选择参与人员。
#### Scenario: 创建标准项目
**Given** 用户在项目管理页面
**When** 用户点击"新建项目"按钮
**Then** 系统打开新增项目弹窗,包含项目名称、项目描述、时间范围、人员选择字段
#### Scenario: 必填字段验证
**Given** 用户新增项目时未填写项目名称
**When** 用户点击"确定"按钮
**Then** 系统提示"项目名称不能为空"
#### Scenario: 至少选择一名人员
**Given** 用户新增项目时未选择任何人员
**When** 用户点击"确定"按钮
**Then** 系统提示"请至少选择一名参与人员"
#### Scenario: 创建成功
**Given** 用户填写了完整的项目信息
**When** 用户点击"确定"按钮
**Then** 系统创建项目并提示"新增成功",项目列表刷新显示新项目
---
### Requirement: 导入历史项目
系统 MUST 允许用户从已完成的历史项目导入配置,快速创建新项目。
#### Scenario: 查看历史项目列表
**Given** 用户点击"导入历史项目"按钮
**When** 系统打开导入历史项目弹窗
**Then** 系统显示所有已完成状态的历史项目列表
#### Scenario: 选择历史项目
**Given** 用户在导入历史项目弹窗中
**When** 用户选择一个历史项目
**Then** 系统显示该项目的详细信息(人员范围、配置等)
#### Scenario: 复制配置创建新项目
**Given** 用户选择了历史项目并填写了新项目名称
**When** 用户点击"确定"按钮
**Then** 系统创建新项目,复制原项目的人员和配置,状态为"进行中"
---
### Requirement: 项目状态管理
系统 MUST 支持项目状态的流转和管理。
#### Scenario: 进入进行中的项目
**Given** 存在状态为"进行中"的项目
**When** 用户点击"进入项目"按钮
**Then** 系统跳转到该项目的工作台页面
#### Scenario: 查看已完成项目结果
**Given** 存在状态为"已完成"的项目
**When** 用户点击"查看结果"按钮
**Then** 系统跳转到该项目的初核结果总览页面
#### Scenario: 重新分析已完成项目
**Given** 存在状态为"已完成"的项目
**When** 用户点击"重新分析"按钮
**Then** 系统基于原有数据重新运行风险模型,更新预警人数和结果
#### Scenario: 重新分析权限控制
**Given** 用户没有重新分析的权限
**When** 用户查看项目列表
**Then** 不显示"重新分析"按钮
---
### Requirement: 项目归档
系统 MUST 允许用户将已结束的项目归档并生成PDF归档文件。
#### Scenario: 归档已完成项目
**Given** 存在状态为"已完成"的项目
**When** 用户点击"归档"按钮
**Then** 系统生成PDF归档文件更新项目状态为"已归档"
#### Scenario: 归档状态校验
**Given** 存在状态为"进行中"的项目
**When** 用户尝试归档该项目
**Then** 系统提示"只能归档已完成的项目"
#### Scenario: 归档文件下载
**Given** 存在已归档的项目
**When** 用户点击"下载归档"按钮
**Then** 系统下载该项目的PDF归档文件
#### Scenario: 归档项目不显示在默认列表
**Given** 存在已归档的项目
**When** 用户查看项目列表
**Then** 默认不显示已归档的项目
#### Scenario: 查看归档项目
**Given** 用户想查看已归档的项目
**When** 用户勾选"显示已归档"选项
**Then** 系统在列表中显示已归档的项目
---
### Requirement: 项目数据模型
系统 MUST 使用正确的数据结构存储项目信息。
#### Scenario: 项目基础信息存储
**Given** 创建新项目
**When** 系统保存项目数据
**Then** 数据库存储项目ID、项目名称、项目描述、创建时间、状态、目标人数、预警人数
#### Scenario: 项目人员关联存储
**Given** 项目包含多名参与人员
**When** 系统保存项目数据
**Then** 人员在关联表中存储包含项目ID、人员ID、人员姓名冗余
#### Scenario: 状态枚举值
**Given** 项目状态字段
**When** 系统存储项目状态
**Then** 状态值为:'0'进行中、'1'已完成、'2'已归档
---
### Requirement: API接口规范
系统 MUST 提供符合RESTful规范的API接口。
#### Scenario: 查询项目列表API
**Given** 前端需要获取项目列表
**When** 调用 `GET /dpc/project/list?projectName=xxx&pageNum=1&pageSize=10`
**Then** 返回分页数据包含total、rows、code、msg
#### Scenario: 创建项目API
**Given** 前端需要创建新项目
**When** 调用 `POST /dpc/project` 并传递项目数据
**Then** 返回操作结果code为200表示成功
#### Scenario: 归档项目API
**Given** 前端需要归档项目
**When** 调用 `POST /dpc/project/archive/{projectId}`
**Then** 系统执行归档操作并返回结果
#### Scenario: 权限校验
**Given** 用户没有相应的权限
**When** 调用需要权限的API
**Then** 返回403错误提示无权限访问
---
### Requirement: 前端用户体验
系统 MUST 提供友好的用户交互体验。
#### Scenario: 响应式布局
**Given** 用户使用不同分辨率的设备
**When** 用户访问项目管理页面
**Then** 页面布局自适应,所有功能可用
#### Scenario: 操作反馈
**Given** 用户执行操作
**When** 操作成功或失败
**Then** 系统显示明确的成功或错误提示消息
#### Scenario: 加载状态
**Given** 数据加载需要时间
**When** 用户请求数据
**Then** 系统显示loading加载状态
---
## 相关能力
- **用户管理能力**:依赖用户系统获取人员信息
- **部门管理能力**:依赖部门系统进行部门范围选择
- **文件管理能力**依赖文件上传功能处理项目附件和归档PDF
- **项目工作台能力**:进入项目后跳转到工作台(后续实现)
- **初核结果能力**:查看结果跳转到结果页(后续实现)

View File

@@ -0,0 +1,257 @@
# Tasks: 项目管理模块开发
本文档列出了实现项目管理模块的具体开发任务,按优先级和依赖关系排序。
## 阶段1基础架构搭建
### 1.1 创建数据库表
- [ ] 创建 `dpc_project`
- [ ] 创建 `dpc_project_person`
- [ ] 创建索引和外键约束
- [ ] 准备测试数据
**验证**执行SQL脚本表结构创建成功可以使用 `DESC dpc_project;` 查看表结构
### 1.2 创建后端模块结构
- [ ] 创建 `ruoyi-dpc` 新模块
- [ ] 配置模块 `pom.xml` 依赖
- [ ] 在根 `pom.xml` 中添加模块引用
- [ ]`ruoyi-admin``pom.xml` 中添加对 `ruoyi-dpc` 的依赖
- [ ] 配置 Spring 扫描 `com.ruoyi.dpc.controller`
- [ ] 创建包结构:`com.ruoyi.dpc.controller`, `com.ruoyi.dpc.domain`, `com.ruoyi.dpc.mapper`, `com.ruoyi.dpc.service`
**验证**:项目可以正常编译启动
### 1.3 创建实体类和DTO
- [ ] 创建 `DpcProject.java` 实体类(使用 `@Data` 注解,不继承 BaseEntity
- [ ] 创建 `DpcProjectPerson.java` 实体类(使用 `@Data` 注解)
- [ ] 创建 `DpcProjectVO.java` 视图对象
- [ ] 创建 `DpcProjectQueryVO.java` 查询视图对象
- [ ] 创建 `DpcProjectDTO.java` 数据传输对象(新增/修改)
- [ ] 创建 `DpcProjectQueryDTO.java` 查询DTO
- [ ] 创建 `DpcProjectImportDTO.java` 导入DTO
- [ ] 为审计字段添加 `@TableField` 注解配置自动填充
**验证**实体类和DTO编译通过字段注解正确
### 1.4 创建DTO转换工具类
- [ ] 创建 `DpcProjectConverter.java` 工具类
- [ ] 实现 `toEntity(DpcProjectDTO)` 方法
- [ ] 实现 `toVO(DpcProject)` 方法
- [ ] 实现 `toVOList(List<DpcProject>)` 方法
**验证**:转换逻辑正确,覆盖所有字段
### 1.5 配置审计字段自动填充
- [ ] 创建 `DpcMetaObjectHandler.java` 实现 `MetaObjectHandler` 接口
- [ ] 实现 `insertFill` 方法自动填充 `create_by``create_time`
- [ ] 实现 `updateFill` 方法自动填充 `update_by``update_time`
- [ ] 从 Spring Security 上下文获取当前登录用户
- [ ] 将处理器注册为 Spring 组件(`@Component`
**验证**:插入和更新操作时审计字段自动填充
## 阶段2数据访问层开发
### 2.1 创建Mapper接口
- [ ] 创建 `DpcProjectMapper.java`(使用 MyBatis Plus
- [ ] 创建 `DpcProjectPersonMapper.java`(使用 MyBatis Plus
### 2.2 创建Mapper XML
- [ ] 创建 `DpcProjectMapper.xml`
- [ ] 创建 `DpcProjectPersonMapper.xml`
- [ ] 定义基础CRUD SQLMyBatis Plus 自动生成)
- [ ] 定义关联查询SQL项目+人员)
**验证**可以使用MyBatis Log查看SQL执行正确
## 阶段3服务层开发
### 3.1 创建Service接口
- [ ] 创建 `IDpcProjectService.java`
- [ ] 定义方法签名:
- `List<DpcProject> selectProjectList(DpcProject project)`
- `DpcProject selectProjectById(Long projectId)`
- `int insertProject(DpcProject project)`
- `int updateProject(DpcProject project)`
- `int deleteProjectByIds(Long[] projectIds)`
- `boolean checkProjectNameUnique(DpcProject project)`
- `void archiveProject(Long projectId)`
- `void reanalyzeProject(Long projectId)`
### 3.2 实现Service
- [ ] 创建 `DpcProjectServiceImpl.java`
- [ ] 使用 `@Resource` 注入依赖
- [ ] 实现基础CRUD方法
- [ ] 实现项目名称唯一性校验
- [ ] 实现项目归档逻辑状态检查、PDF生成
- [ ] 实现重新分析逻辑(异步任务)
**验证**:单元测试通过,业务逻辑符合需求
## 阶段4控制器层开发
### 4.1 创建Controller
- [ ] 创建 `DpcProjectController.java`(位于 `ruoyi-dpc` 模块的 `com.ruoyi.dpc.controller` 包中)
- [ ] 实现列表查询接口 `GET /dpc/project/list`
- [ ] 实现详情查询接口 `GET /dpc/project/{id}`
- [ ] 实现新增接口 `POST /dpc/project`
- [ ] 实现修改接口 `PUT /dpc/project`
- [ ] 实现删除接口 `DELETE /dpc/project/{ids}`
- [ ] 实现归档接口 `POST /dpc/project/archive/{id}`
- [ ] 实现重新分析接口 `POST /dpc/project/reanalyze/{id}`
- [ ] 实现导入历史项目接口 `POST /dpc/project/import`
### 4.2 添加权限注解
- [ ] 为所有接口添加 `@PreAuthorize` 注解
- [ ] 配置权限字符串:
- `dpc:project:list`
- `dpc:project:query`
- `dpc:project:add`
- `dpc:project:edit`
- `dpc:project:remove`
- `dpc:project:archive`
- `dpc:project:reanalyze`
### 4.3 添加操作日志
- [ ] 为关键操作添加 `@Log` 注解
- [ ] 配置业务类型
**验证**使用Postman测试所有接口返回正确
## 阶段4.5生成API文档
### 4.5.1 生成接口文档
- [ ] 使用 SpringDoc/Knife4j 生成 API 文档
- [ ] 在项目文件目录下导出 API 文档
**验证**API 文档生成成功,包含所有接口
## 阶段5前端API开发
### 5.1 创建API文件
- [ ] 创建 `ruoyi-ui/src/api/dpcProject.js`
- [ ] 封装所有API请求方法
- `listProject(query)`
- `getProject(projectId)`
- `addProject(data)`
- `updateProject(data)`
- `delProject(projectIds)`
- `archiveProject(projectId)`
- `reanalyzeProject(projectId)`
- `importProject(data)`
**验证**API方法可以正常调用
## 阶段6前端页面开发
### 6.1 创建项目列表页
- [ ] 创建 `ruoyi-ui/src/views/dpcProject/index.vue`
- [ ] 实现搜索区域(项目名称输入框、搜索按钮)
- [ ] 实现操作按钮(新建、导入历史项目)
- [ ] 实现数据表格(项目信息展示)
- [ ] 实现状态标签(进行中/已完成/已归档)
- [ ] 实现操作列(进入项目、查看结果、重新分析、归档)
### 6.2 创建新增/编辑弹窗
- [ ] 创建 `ruoyi-ui/src/views/dpcProject/add-or-edit.vue`
- [ ] 实现项目基本信息表单(项目名称、描述、时间范围)
- [ ] 实现人员选择器(多选)
- [ ] 实现表单验证
### 6.3 创建导入历史项目弹窗
- [ ] 创建 `ruoyi-ui/src/views/dpcProject/import-history.vue`
- [ ] 实现历史项目列表(只显示已完成项目)
- [ ] 实现项目详情预览
- [ ] 实现新项目配置
**验证**:页面显示正常,交互流畅
## 阶段7菜单与权限配置
### 7.1 创建系统菜单
- [ ] 在系统管理 > 菜单管理中创建"项目管理"菜单
- [ ] 配置菜单图标和路由(路径:`dpcProject`
- [ ] 创建子菜单/按钮权限
### 7.2 配置角色权限
- [ ] 为管理员角色分配项目管理权限
- [ ] 为其他角色配置适当权限
**验证**:登录后可以看到项目管理菜单
## 阶段8测试与优化
### 8.1 功能测试
- [ ] 测试项目创建流程
- [ ] 测试项目搜索功能
- [ ] 测试项目状态流转
- [ ] 测试项目归档功能
- [ ] 测试重新分析功能
- [ ] 测试导入历史项目功能
### 8.2 边界测试
- [ ] 测试必填字段验证
- [ ] 测试项目名称唯一性
- [ ] 测试状态权限控制
- [ ] 测试数据权限
### 8.3 性能优化
- [ ] 优化SQL查询
- [ ] 添加必要的数据库索引
- [ ] 优化大数据量列表加载
**验证**:所有测试用例通过,无明显性能问题
## 阶段9文档与交付
### 9.1 代码注释
- [ ] 为所有公开方法添加JavaDoc注释
- [ ] 为复杂逻辑添加行内注释
### 9.2 更新系统文档
- [ ] 更新数据库设计文档
- [ ] 更新API接口文档
- [ ] 更新用户操作手册
**验证**:文档完整、准确
## 任务依赖关系
```
阶段1 (基础架构)
阶段2 (数据访问层) → 阶段3 (服务层) → 阶段4 (控制器层) → 阶段4.5 (API文档)
阶段5 (前端API) ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ← ←
阶段6 (前端页面)
阶段7 (菜单权限)
阶段8 (测试优化)
阶段9 (文档交付)
```
## 可并行开发任务
以下任务可以并行开发:
- 阶段2和阶段3后端不同层级
- 阶段5和阶段6的前端页面组件
- 阶段7的菜单配置可以在后端开发完成后进行
## 预计工作量
| 阶段 | 预计工时 |
|-----|---------|
| 阶段1 | 0.5天 |
| 阶段2 | 0.5天 |
| 阶段3 | 1天 |
| 阶段4 | 1天 |
| 阶段5 | 0.5天 |
| 阶段6 | 2天 |
| 阶段7 | 0.5天 |
| 阶段8 | 1天 |
| 阶段9 | 0.5天 |
| **总计** | **7.5天** |