diff --git a/doc/plans/2026-02-26-create-project-design.md b/doc/plans/2026-02-26-create-project-design.md new file mode 100644 index 0000000..b597bb2 --- /dev/null +++ b/doc/plans/2026-02-26-create-project-design.md @@ -0,0 +1,902 @@ +# 创建项目功能设计文档 + +**文档版本:** v1.0 +**创建日期:** 2026-02-26 +**设计人员:** Claude Code + +--- + +## 1. 概述 + +### 1.1 功能描述 + +新增"创建项目"功能,允许用户在首页点击"新建项目"按钮后,通过弹窗表单创建新的纪检初核项目。 + +### 1.2 核心需求 + +- 弹窗包含3个字段:项目名称、项目描述、配置方式 +- 配置方式为单选按钮:全局默认模型参数配置 / 自定义项目规则参数配置 +- 项目列表展示项目名称和描述(上下排列)、状态、目标人数、预警人数、创建人、创建时间 +- 预警人数为各级别风险人数之和,悬停显示详细分布 + +--- + +## 2. 数据库设计 + +### 2.1 表结构 + +**表名:** `ccdi_project` + +**字段列表:** + +| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 | +|--------|------|------|------|--------|------| +| project_id | BIGINT | - | 是 | 自增 | 项目ID(主键) | +| project_name | VARCHAR | 100 | 是 | - | 项目名称 | +| project_desc | VARCHAR | 500 | 否 | NULL | 项目描述 | +| config_type | VARCHAR | 20 | 是 | 'default' | 配置方式:default-全局默认,custom-自定义 | +| project_status | CHAR | 1 | 是 | '0' | 项目状态:0-进行中,1-已完成,2-已归档 | +| target_count | INT | - | 是 | 0 | 目标人数 | +| high_risk_count | INT | - | 是 | 0 | 高风险人数 | +| medium_risk_count | INT | - | 是 | 0 | 中风险人数 | +| low_risk_count | INT | - | 是 | 0 | 低风险人数 | +| create_by | VARCHAR | 64 | 否 | '' | 创建者 | +| create_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 创建时间 | +| update_by | VARCHAR | 64 | 否 | '' | 更新者 | +| update_time | DATETIME | - | 否 | CURRENT_TIMESTAMP | 更新时间 | +| remark | VARCHAR | 500 | 否 | NULL | 备注 | + +**索引设计:** +- 主键索引:`PRIMARY KEY (project_id)` +- 项目名称索引:`INDEX idx_project_name (project_name)` +- 项目状态索引:`INDEX idx_project_status (project_status)` +- 创建时间索引:`INDEX idx_create_time (create_time)` + +### 2.2 SQL 脚本 + +```sql +-- 创建项目表 +CREATE TABLE `ccdi_project` ( + `project_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '项目ID', + `project_name` VARCHAR(100) NOT NULL COMMENT '项目名称', + `project_desc` VARCHAR(500) DEFAULT NULL COMMENT '项目描述', + `config_type` VARCHAR(20) NOT NULL DEFAULT 'default' COMMENT '配置方式:default-全局默认,custom-自定义', + `project_status` CHAR(1) NOT NULL DEFAULT '0' COMMENT '项目状态:0-进行中,1-已完成,2-已归档', + `target_count` INT NOT NULL DEFAULT 0 COMMENT '目标人数', + `high_risk_count` INT NOT NULL DEFAULT 0 COMMENT '高风险人数', + `medium_risk_count` INT NOT NULL DEFAULT 0 COMMENT '中风险人数', + `low_risk_count` INT NOT NULL DEFAULT 0 COMMENT '低风险人数', + `create_by` VARCHAR(64) DEFAULT '' COMMENT '创建者', + `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `update_by` VARCHAR(64) DEFAULT '' COMMENT '更新者', + `update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `remark` VARCHAR(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`project_id`), + INDEX `idx_project_name` (`project_name`), + INDEX `idx_project_status` (`project_status`), + INDEX `idx_create_time` (`create_time`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='纪检初核项目表'; + +-- 插入项目状态字典 +INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) +VALUES ('项目状态', 'ccdi_project_status', '0', 'admin', NOW(), '纪检初核项目状态'); + +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time) +VALUES +(1, '进行中', '0', 'ccdi_project_status', '', 'primary', 'Y', '0', 'admin', NOW()), +(2, '已完成', '1', 'ccdi_project_status', '', 'success', 'N', '0', 'admin', NOW()), +(3, '已归档', '2', 'ccdi_project_status', '', 'info', 'N', '0', 'admin', NOW()); + +-- 插入配置方式字典 +INSERT INTO sys_dict_type (dict_name, dict_type, status, create_by, create_time, remark) +VALUES ('配置方式', 'ccdi_config_type', '0', 'admin', NOW(), '项目配置方式'); + +INSERT INTO sys_dict_data (dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time) +VALUES +(1, '全局默认模型参数配置', 'default', 'ccdi_config_type', '', 'primary', 'Y', '0', 'admin', NOW()), +(2, '自定义项目规则参数配置', 'custom', 'ccdi_config_type', '', 'warning', 'N', '0', 'admin', NOW()); + +-- 插入菜单权限 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, status, perms, icon, create_by, create_time) +VALUES ('纪检初核管理', 0, 1, 'ccdi', NULL, 'M', '0', '0', '', 'monitor', 'admin', NOW()); + +SET @parent_id = LAST_INSERT_ID(); + +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, menu_type, visible, status, perms, icon, create_by, create_time) +VALUES ('项目管理', @parent_id, 1, 'project', 'ccdiProject/index', 'C', '0', '0', 'ccdi:project:list', 'project', 'admin', NOW()); + +SET @menu_id = LAST_INSERT_ID(); + +INSERT INTO sys_menu (menu_name, parent_id, order_num, menu_type, visible, status, perms, create_by, create_time) +VALUES +('创建项目', @menu_id, 1, 'F', '0', '0', 'ccdi:project:add', 'admin', NOW()), +('编辑项目', @menu_id, 2, 'F', '0', '0', 'ccdi:project:edit', 'admin', NOW()), +('删除项目', @menu_id, 3, 'F', '0', '0', 'ccdi:project:remove', 'admin', NOW()), +('查询项目', @menu_id, 4, 'F', '0', '0', 'ccdi:project:query', 'admin', NOW()); + +-- 为管理员角色分配权限 +INSERT INTO sys_role_menu (role_id, menu_id) +SELECT 1, menu_id FROM sys_menu WHERE perms LIKE 'ccdi:project:%' OR perms = 'ccdi:project:list'; +``` + +--- + +## 3. 后端架构设计 + +### 3.1 实体类 + +**类名:** `CcdiProject` +**位置:** `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/` + +```java +@Data +public class CcdiProject { + /** 项目ID */ + private Long projectId; + + /** 项目名称 */ + private String projectName; + + /** 项目描述 */ + private String projectDesc; + + /** 配置方式:default-全局默认,custom-自定义 */ + private String configType; + + /** 项目状态:0-进行中,1-已完成,2-已归档 */ + private String projectStatus; + + /** 目标人数 */ + private Integer targetCount; + + /** 高风险人数 */ + private Integer highRiskCount; + + /** 中风险人数 */ + private Integer mediumRiskCount; + + /** 低风险人数 */ + private Integer lowRiskCount; + + /** 创建者 */ + private String createBy; + + /** 创建时间 */ + private Date createTime; + + /** 更新者 */ + private String updateBy; + + /** 更新时间 */ + private Date updateTime; + + /** 备注 */ + private String remark; +} +``` + +### 3.2 DTO 设计 + +**类名:** `CcdiProjectSaveDTO` +**位置:** `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/` + +```java +@Data +public class CcdiProjectSaveDTO { + /** 项目名称(必填) */ + @NotBlank(message = "项目名称不能为空") + @Length(max = 100, message = "项目名称长度不能超过100个字符") + private String projectName; + + /** 项目描述(可选) */ + @Length(max = 500, message = "项目描述长度不能超过500个字符") + private String projectDesc; + + /** 配置方式(必填):default-全局默认,custom-自定义 */ + @NotBlank(message = "配置方式不能为空") + private String configType; +} +``` + +### 3.3 VO 设计 + +**类名:** `CcdiProjectVO` +**位置:** `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/` + +```java +@Data +public class CcdiProjectVO { + /** 项目ID */ + private Long projectId; + + /** 项目名称 */ + private String projectName; + + /** 项目描述 */ + private String projectDesc; + + /** 配置方式 */ + private String configType; + + /** 项目状态 */ + private String projectStatus; + + /** 目标人数 */ + private Integer targetCount; + + /** 高风险人数 */ + private Integer highRiskCount; + + /** 中风险人数 */ + private Integer mediumRiskCount; + + /** 低风险人数 */ + private Integer lowRiskCount; + + /** 创建时间 */ + private Date createTime; + + /** 创建者 */ + private String createBy; +} +``` + +### 3.4 Controller 接口 + +**类名:** `CcdiProjectController` +**位置:** `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/controller/` + +**接口列表:** + +| 接口路径 | 方法 | 说明 | 权限标识 | +|---------|------|------|---------| +| `/ccdi/project` | POST | 创建项目 | `ccdi:project:add` | +| `/ccdi/project` | PUT | 更新项目 | `ccdi:project:edit` | +| `/ccdi/project/{projectId}` | DELETE | 删除项目 | `ccdi:project:remove` | +| `/ccdi/project/{projectId}` | GET | 查询项目详情 | `ccdi:project:query` | +| `/ccdi/project/list` | GET | 查询项目列表(分页) | `ccdi:project:list` | + +**示例代码:** + +```java +@RestController +@RequestMapping("/ccdi/project") +@Api(tags = "纪检初核项目管理") +public class CcdiProjectController extends BaseController { + + @Resource + private ICcdiProjectService projectService; + + @PostMapping + @ApiOperation("创建项目") + @PreAuthorize("@ss.hasPermi('ccdi:project:add')") + public AjaxResult createProject(@Validated @RequestBody CcdiProjectSaveDTO dto) { + CcdiProjectVO vo = projectService.createProject(dto); + return AjaxResult.success("项目创建成功", vo); + } + + @GetMapping("/list") + @ApiOperation("查询项目列表") + @PreAuthorize("@ss.hasPermi('ccdi:project:list')") + public TableDataInfo listProject(CcdiProjectQueryDTO queryDTO) { + PageDomain pageDomain = TableSupport.buildPageRequest(); + Page page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize()); + Page result = projectService.selectProjectPage(page, queryDTO); + return getDataTable(result.getRecords(), result.getTotal()); + } +} +``` + +### 3.5 Service 层 + +**接口名:** `ICcdiProjectService` +**实现类名:** `CcdiProjectServiceImpl` +**位置:** `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/` + +```java +public interface ICcdiProjectService { + /** + * 创建项目 + * @param dto 项目保存DTO + * @return 项目VO + */ + CcdiProjectVO createProject(CcdiProjectSaveDTO dto); + + /** + * 更新项目 + * @param dto 项目更新DTO + * @return 项目VO + */ + CcdiProjectVO updateProject(CcdiProjectSaveDTO dto); + + /** + * 删除项目 + * @param projectId 项目ID + * @return 是否成功 + */ + boolean deleteProject(Long projectId); + + /** + * 查询项目详情 + * @param projectId 项目ID + * @return 项目VO + */ + CcdiProjectVO getProjectById(Long projectId); + + /** + * 分页查询项目列表 + * @param page 分页对象 + * @param queryDTO 查询条件 + * @return 分页结果 + */ + Page selectProjectPage(Page page, CcdiProjectQueryDTO queryDTO); +} +``` + +**实现类示例:** + +```java +@Service +public class CcdiProjectServiceImpl implements ICcdiProjectService { + + @Resource + private CcdiProjectMapper projectMapper; + + @Override + public CcdiProjectVO createProject(CcdiProjectSaveDTO dto) { + CcdiProject project = new CcdiProject(); + BeanUtils.copyProperties(dto, project); + + // 设置默认值 + project.setProjectStatus("0"); // 进行中 + project.setTargetCount(0); + project.setHighRiskCount(0); + project.setMediumRiskCount(0); + project.setLowRiskCount(0); + + projectMapper.insert(project); + + CcdiProjectVO vo = new CcdiProjectVO(); + BeanUtils.copyProperties(project, vo); + return vo; + } +} +``` + +### 3.6 Mapper 层 + +**接口名:** `CcdiProjectMapper` +**位置:** `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/` + +```java +public interface CcdiProjectMapper extends BaseMapper { + /** + * 分页查询项目列表 + * @param page 分页对象 + * @param queryDTO 查询条件 + * @return 分页结果 + */ + Page selectProjectPage(Page page, @Param("queryDTO") CcdiProjectQueryDTO queryDTO); +} +``` + +**XML 文件:** `CcdiProjectMapper.xml` +**位置:** `ruoyi-info-collection/src/main/resources/mapper/info/collection/` + +```xml + + + + + + + + + + + + + + + + + + + + + +``` + +--- + +## 4. 前端架构设计 + +### 4.1 组件修改 + +**组件名称:** `AddProjectDialog.vue` +**位置:** `ruoyi-ui/src/views/ccdiProject/components/` + +**修改内容:** + +1. **简化表单字段**:只保留项目名称、项目描述、配置方式3个字段 +2. **移除字段**:目标人员、开始日期、结束日期、目标人数、高级设置 +3. **默认值**:配置方式默认为 `'default'` + +**关键代码:** + +```vue + + + + + +``` + +### 4.2 项目列表表格 + +**组件名称:** `ProjectTable.vue` +**位置:** `ruoyi-ui/src/views/ccdiProject/components/` + +**关键特性:** + +1. **项目名称和描述上下排列**:同一单元格内,项目名称加粗深色,项目描述常规浅色 +2. **预警人数悬停提示**:显示高、中、低风险人数详细分布 +3. **预警人数样式**:根据风险级别自动调整颜色 + +**表格列配置:** + +| 列名 | 宽度 | 对齐方式 | 说明 | +|------|------|---------|------| +| 项目名称 | 最小300px | 左对齐 | 包含项目名称(上)+项目描述(下),自适应 | +| 项目状态 | 100px | 居中对齐 | 固定宽度 | +| 目标人数 | 100px | 居中对齐 | 固定宽度 | +| 预警人数 | 120px | 居中对齐 | 悬停显示详细风险分布 | +| 创建人 | 120px | 居中对齐 | 固定宽度 | +| 创建时间 | 160px | 居中对齐 | 格式化显示 | +| 操作 | 280px | 居中对齐 | 固定在右侧 | + +**关键代码:** + +```vue + + + + + + + + + +``` + +**样式代码:** + +```scss +.project-info-cell { + padding: 8px 0; + line-height: 1.5; + + .project-name { + font-size: 14px; + font-weight: 600; + color: #303133; + margin-bottom: 4px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + .project-desc { + font-size: 12px; + color: #909399; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } +} + +.text-danger { + color: #f56c6c; +} + +.text-warning { + color: #e6a23c; +} + +.text-info { + color: #909399; +} + +.text-bold { + font-weight: bold; +} +``` + +**预警人数样式规则:** + +- 高风险 > 0:红色加粗 +- 中风险 > 0:橙色加粗 +- 低风险 > 0:灰色 +- 无预警:普通黑色 + +### 4.3 API 接口 + +**文件名:** `ccdiProject.js` +**位置:** `ruoyi-ui/src/api/` + +```javascript +import request from '@/utils/request' + +// 创建初核项目 +export function createProject(data) { + return request({ + url: '/ccdi/project', + method: 'post', + data: data + }) +} + +// 查询初核项目列表(分页) +export function listProject(query) { + return request({ + url: '/ccdi/project/list', + method: 'get', + params: query + }) +} + +// 查询初核项目详细 +export function getProject(projectId) { + return request({ + url: '/ccdi/project/' + projectId, + method: 'get' + }) +} + +// 修改初核项目 +export function updateProject(data) { + return request({ + url: '/ccdi/project', + method: 'put', + data: data + }) +} + +// 删除初核项目 +export function delProject(projectId) { + return request({ + url: '/ccdi/project/' + projectId, + method: 'delete' + }) +} +``` + +--- + +## 5. 实施计划 + +### 5.1 实施步骤 + +#### 阶段一:数据库与后端开发(预计 2.5 小时) + +1. **创建数据库表**(15 分钟) + - 执行 `ccdi_project` 表创建脚本 + - 插入字典数据和菜单数据 + +2. **后端开发**(2 小时) + - 创建实体类 `CcdiProject` + - 创建 DTO `CcdiProjectSaveDTO` + - 创建 VO `CcdiProjectVO` + - 创建 Mapper 接口和 XML + - 创建 Service 接口和实现类 + - 创建 Controller 接口 + - 添加 Swagger 注解 + +3. **后端测试**(30 分钟) + - 使用 Swagger 测试创建项目接口 + - 使用 Swagger 测试查询项目列表接口 + - 验证数据字典显示 + +#### 阶段二:前端开发(预计 2.5 小时) + +4. **前端组件开发**(1.5 小时) + - 修改 `AddProjectDialog.vue` 组件 + - 修改 `ProjectTable.vue` 组件 + - 更新 API 接口文件 `ccdiProject.js` + - 修改父组件调用逻辑 + +5. **前端联调**(1 小时) + - 测试创建项目功能 + - 测试项目列表显示 + - 测试预警人数悬停提示 + - 测试字典数据展示 + +--- + +## 6. 注意事项 + +### 6.1 数据完整性 + +- 创建项目时,`project_status` 默认为 `'0'`(进行中) +- 创建项目时,风险计数字段默认为 `0` +- `config_type` 默认为 `'default'` +- 项目名称和描述不能为空 + +### 6.2 权限控制 + +- 创建项目需要 `ccdi:project:add` 权限 +- 编辑项目需要 `ccdi:project:edit` 权限 +- 删除项目需要 `ccdi:project:remove` 权限 +- 查询项目需要 `ccdi:project:list` 权限 + +### 6.3 前端验证 + +- 项目名称:必填,2-100字符 +- 项目描述:可选,最多500字符 +- 配置方式:必填,只能选择 `default` 或 `custom` + +### 6.4 后端验证 + +- 使用 `@Validated` 注解进行参数校验 +- 项目名称长度校验 +- 配置方式枚举值校验 + +### 6.5 性能优化 + +- 项目列表分页查询 +- 项目名称和状态字段添加索引 +- 字典数据使用缓存 + +### 6.6 用户体验 + +- 提交按钮显示 loading 状态 +- 创建成功后自动刷新列表 +- 预警人数悬停提示详细信息 +- 项目名称和描述上下排列,层次分明 + +--- + +## 7. 测试清单 + +### 7.1 后端测试 + +- [ ] 创建项目成功(必填字段) +- [ ] 创建项目失败(缺少必填字段) +- [ ] 创建项目失败(字段长度超限) +- [ ] 查询项目列表(分页) +- [ ] 查询项目详情 +- [ ] 更新项目 +- [ ] 删除项目 +- [ ] 字典数据正确返回 +- [ ] 权限验证正确 + +### 7.2 前端测试 + +- [ ] 弹窗显示正确(3个字段) +- [ ] 表单验证正常(必填项) +- [ ] 表单验证正常(长度限制) +- [ ] 项目名称和描述上下排列 +- [ ] 项目名称样式正确(加粗深色) +- [ ] 项目描述样式正确(常规浅色) +- [ ] 项目状态标签正确显示 +- [ ] 预警人数计算正确(高+中+低) +- [ ] 预警人数悬停提示显示 +- [ ] 预警人数颜色根据风险级别变化 +- [ ] 创建人正确显示 +- [ ] 创建时间格式化正确 +- [ ] 操作按钮权限控制 +- [ ] 提交按钮 loading 状态 +- [ ] 创建成功后列表刷新 + +--- + +## 8. 附录 + +### 8.1 参考文档 + +- 若依框架官方文档 +- Element UI 组件库文档 +- MyBatis Plus 官方文档 + +### 8.2 相关文件 + +- 数据库脚本:`sql/ccdi_project.sql` +- 设计截图:`doc/创建项目功能/ScreenShot_2026-02-26_153149_900.png` +- 设计截图:`doc/创建项目功能/ScreenShot_2026-02-26_162233_965.png` + +--- + +**文档结束** diff --git a/doc/创建项目功能/ScreenShot_2026-02-26_153149_900.png b/doc/创建项目功能/ScreenShot_2026-02-26_153149_900.png new file mode 100644 index 0000000..d34f68b Binary files /dev/null and b/doc/创建项目功能/ScreenShot_2026-02-26_153149_900.png differ diff --git a/doc/创建项目功能/task.md b/doc/创建项目功能/task.md new file mode 100644 index 0000000..e69de29