# 创建项目功能设计文档 **文档版本:** 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` --- **文档结束**