docs: 添加前后端分离的实施计划文档
This commit is contained in:
943
doc/plans/2026-02-26-create-project-backend-implementation.md
Normal file
943
doc/plans/2026-02-26-create-project-backend-implementation.md
Normal file
@@ -0,0 +1,943 @@
|
||||
# 创建项目功能 - 后端实施计划
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**目标:** 实现创建项目功能的后端接口,包括数据库表、实体类、DTO/VO、Mapper、Service、Controller
|
||||
|
||||
**架构:** 基于若依框架 + MyBatis Plus,采用分层架构(Controller -> Service -> Mapper)
|
||||
|
||||
**技术栈:** Spring Boot 3.5.8, MyBatis Plus 3.5.10, MySQL 8.2.0, SpringDoc OpenAPI 2.8.14
|
||||
|
||||
---
|
||||
|
||||
## 前置条件
|
||||
|
||||
- MySQL 数据库已启动
|
||||
- 后端项目已启动
|
||||
- 已有 admin 账号和测试权限
|
||||
- 数据库连接配置正确
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 创建数据库表和字典数据
|
||||
|
||||
**文件:**
|
||||
- Create: `sql/ccdi_project.sql`
|
||||
|
||||
**Step 1: 创建 SQL 脚本文件**
|
||||
|
||||
创建文件 `sql/ccdi_project.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';
|
||||
```
|
||||
|
||||
**Step 2: 执行 SQL 脚本**
|
||||
|
||||
运行命令连接数据库并执行脚本:
|
||||
|
||||
```bash
|
||||
mysql -h<host> -u<user> -p<password> ccdi < sql/ccdi_project.sql
|
||||
```
|
||||
|
||||
预期输出:无错误,表创建成功
|
||||
|
||||
**Step 3: 验证数据库表**
|
||||
|
||||
连接数据库验证表是否创建成功:
|
||||
|
||||
```bash
|
||||
mysql -h<host> -u<user> -p<password> -e "USE ccdi; SHOW TABLES LIKE 'ccdi_project'; DESC ccdi_project;"
|
||||
```
|
||||
|
||||
预期输出:显示 `ccdi_project` 表及其字段结构
|
||||
|
||||
**Step 4: 验证字典数据**
|
||||
|
||||
验证字典数据是否插入成功:
|
||||
|
||||
```bash
|
||||
mysql -h<host> -u<user> -p<password> -e "USE ccdi; SELECT * FROM sys_dict_type WHERE dict_type IN ('ccdi_project_status', 'ccdi_config_type'); SELECT * FROM sys_dict_data WHERE dict_type IN ('ccdi_project_status', 'ccdi_config_type');"
|
||||
```
|
||||
|
||||
预期输出:显示新插入的字典类型和数据
|
||||
|
||||
**Step 5: 提交代码**
|
||||
|
||||
```bash
|
||||
git add sql/ccdi_project.sql
|
||||
git commit -m "feat: 添加项目表和字典数据SQL脚本"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: 创建实体类 CcdiProject
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiProject.java`
|
||||
|
||||
**Step 1: 创建实体类**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiProject.java`:
|
||||
|
||||
```java
|
||||
package com.ruoyi.info.collection.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 纪检初核项目实体类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
@TableName("ccdi_project")
|
||||
public class CcdiProject {
|
||||
/** 项目ID */
|
||||
@TableId(type = IdType.AUTO)
|
||||
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;
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 3: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/CcdiProject.java
|
||||
git commit -m "feat: 添加项目实体类"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 创建 DTO - CcdiProjectSaveDTO
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiProjectSaveDTO.java`
|
||||
|
||||
**Step 1: 创建 DTO 目录(如果不存在)**
|
||||
|
||||
```bash
|
||||
mkdir -p ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto
|
||||
```
|
||||
|
||||
**Step 2: 创建 DTO 类**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiProjectSaveDTO.java`:
|
||||
|
||||
```java
|
||||
package com.ruoyi.info.collection.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import org.hibernate.validator.constraints.Length;
|
||||
|
||||
/**
|
||||
* 项目保存DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiProjectSaveDTO.java
|
||||
git commit -m "feat: 添加项目保存DTO"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 创建 VO - CcdiProjectVO
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiProjectVO.java`
|
||||
|
||||
**Step 1: 创建 VO 目录(如果不存在)**
|
||||
|
||||
```bash
|
||||
mkdir -p ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo
|
||||
```
|
||||
|
||||
**Step 2: 创建 VO 类**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiProjectVO.java`:
|
||||
|
||||
```java
|
||||
package com.ruoyi.info.collection.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 项目VO
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/vo/CcdiProjectVO.java
|
||||
git commit -m "feat: 添加项目VO"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 创建查询 DTO - CcdiProjectQueryDTO
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiProjectQueryDTO.java`
|
||||
|
||||
**Step 1: 创建查询 DTO 类**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiProjectQueryDTO.java`:
|
||||
|
||||
```java
|
||||
package com.ruoyi.info.collection.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 项目查询DTO
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Data
|
||||
public class CcdiProjectQueryDTO {
|
||||
/** 项目名称 */
|
||||
private String projectName;
|
||||
|
||||
/** 项目状态 */
|
||||
private String projectStatus;
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 3: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/domain/dto/CcdiProjectQueryDTO.java
|
||||
git commit -m "feat: 添加项目查询DTO"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 创建 Mapper 接口
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiProjectMapper.java`
|
||||
|
||||
**Step 1: 创建 Mapper 接口**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiProjectMapper.java`:
|
||||
|
||||
```java
|
||||
package com.ruoyi.info.collection.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.info.collection.domain.CcdiProject;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiProjectQueryDTO;
|
||||
import com.ruoyi.info.collection.domain.vo.CcdiProjectVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
/**
|
||||
* 项目Mapper接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Mapper
|
||||
public interface CcdiProjectMapper extends BaseMapper<CcdiProject> {
|
||||
/**
|
||||
* 分页查询项目列表
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param queryDTO 查询条件
|
||||
* @return 分页结果
|
||||
*/
|
||||
Page<CcdiProjectVO> selectProjectPage(Page<CcdiProjectVO> page, @Param("queryDTO") CcdiProjectQueryDTO queryDTO);
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 3: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/mapper/CcdiProjectMapper.java
|
||||
git commit -m "feat: 添加项目Mapper接口"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 创建 Mapper XML 文件
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/resources/mapper/info/collection/CcdiProjectMapper.xml`
|
||||
|
||||
**Step 1: 创建 Mapper 目录(如果不存在)**
|
||||
|
||||
```bash
|
||||
mkdir -p ruoyi-info-collection/src/main/resources/mapper/info/collection
|
||||
```
|
||||
|
||||
**Step 2: 创建 XML 文件**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/resources/mapper/info/collection/CcdiProjectMapper.xml`:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.ruoyi.info.collection.mapper.CcdiProjectMapper">
|
||||
|
||||
<resultMap id="ProjectVOResultMap" type="com.ruoyi.info.collection.domain.vo.CcdiProjectVO">
|
||||
<id property="projectId" column="project_id"/>
|
||||
<result property="projectName" column="project_name"/>
|
||||
<result property="projectDesc" column="project_desc"/>
|
||||
<result property="configType" column="config_type"/>
|
||||
<result property="projectStatus" column="project_status"/>
|
||||
<result property="targetCount" column="target_count"/>
|
||||
<result property="highRiskCount" column="high_risk_count"/>
|
||||
<result property="mediumRiskCount" column="medium_risk_count"/>
|
||||
<result property="lowRiskCount" column="low_risk_count"/>
|
||||
<result property="createTime" column="create_time"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
</resultMap>
|
||||
|
||||
<!-- 分页查询项目列表 -->
|
||||
<select id="selectProjectPage" resultMap="ProjectVOResultMap">
|
||||
SELECT
|
||||
project_id, project_name, project_desc, config_type,
|
||||
project_status, target_count, high_risk_count,
|
||||
medium_risk_count, low_risk_count, create_time, create_by
|
||||
FROM ccdi_project
|
||||
<where>
|
||||
<if test="queryDTO.projectName != null and queryDTO.projectName != ''">
|
||||
AND project_name LIKE CONCAT('%', #{queryDTO.projectName}, '%')
|
||||
</if>
|
||||
<if test="queryDTO.projectStatus != null and queryDTO.projectStatus != ''">
|
||||
AND project_status = #{queryDTO.projectStatus}
|
||||
</if>
|
||||
</where>
|
||||
ORDER BY create_time DESC
|
||||
</select>
|
||||
</mapper>
|
||||
```
|
||||
|
||||
**Step 3: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/resources/mapper/info/collection/CcdiProjectMapper.xml
|
||||
git commit -m "feat: 添加项目Mapper XML配置"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 8: 创建 Service 接口
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiProjectService.java`
|
||||
|
||||
**Step 1: 创建 Service 接口**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiProjectService.java`:
|
||||
|
||||
```java
|
||||
package com.ruoyi.info.collection.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiProjectQueryDTO;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiProjectSaveDTO;
|
||||
import com.ruoyi.info.collection.domain.vo.CcdiProjectVO;
|
||||
|
||||
/**
|
||||
* 项目Service接口
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
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<CcdiProjectVO> selectProjectPage(Page<CcdiProjectVO> page, CcdiProjectQueryDTO queryDTO);
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 3: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/ICcdiProjectService.java
|
||||
git commit -m "feat: 添加项目Service接口"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 9: 创建 Service 实现类
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiProjectServiceImpl.java`
|
||||
|
||||
**Step 1: 创建 Service 实现目录(如果不存在)**
|
||||
|
||||
```bash
|
||||
mkdir -p ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl
|
||||
```
|
||||
|
||||
**Step 2: 创建 Service 实现类**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiProjectServiceImpl.java`:
|
||||
|
||||
```java
|
||||
package com.ruoyi.info.collection.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.info.collection.domain.CcdiProject;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiProjectQueryDTO;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiProjectSaveDTO;
|
||||
import com.ruoyi.info.collection.domain.vo.CcdiProjectVO;
|
||||
import com.ruoyi.info.collection.mapper.CcdiProjectMapper;
|
||||
import com.ruoyi.info.collection.service.ICcdiProjectService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* 项目Service实现类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcdiProjectVO updateProject(CcdiProjectSaveDTO dto) {
|
||||
// TODO: 实现更新逻辑
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteProject(Long projectId) {
|
||||
return projectMapper.deleteById(projectId) > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcdiProjectVO getProjectById(Long projectId) {
|
||||
CcdiProject project = projectMapper.selectById(projectId);
|
||||
if (project == null) {
|
||||
return null;
|
||||
}
|
||||
CcdiProjectVO vo = new CcdiProjectVO();
|
||||
BeanUtils.copyProperties(project, vo);
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<CcdiProjectVO> selectProjectPage(Page<CcdiProjectVO> page, CcdiProjectQueryDTO queryDTO) {
|
||||
return projectMapper.selectProjectPage(page, queryDTO);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/service/impl/CcdiProjectServiceImpl.java
|
||||
git commit -m "feat: 添加项目Service实现类"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 10: 创建 Controller
|
||||
|
||||
**文件:**
|
||||
- Create: `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiProjectController.java`
|
||||
|
||||
**Step 1: 创建 Controller 类**
|
||||
|
||||
创建文件 `ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiProjectController.java`:
|
||||
|
||||
```java
|
||||
package com.ruoyi.info.collection.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.PageDomain;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiProjectQueryDTO;
|
||||
import com.ruoyi.info.collection.domain.dto.CcdiProjectSaveDTO;
|
||||
import com.ruoyi.info.collection.domain.vo.CcdiProjectVO;
|
||||
import com.ruoyi.info.collection.service.ICcdiProjectService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
/**
|
||||
* 纪检初核项目管理Controller
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ccdi/project")
|
||||
@Tag(name = "纪检初核项目管理")
|
||||
public class CcdiProjectController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private ICcdiProjectService projectService;
|
||||
|
||||
/**
|
||||
* 创建项目
|
||||
*/
|
||||
@PostMapping
|
||||
@Operation(summary = "创建项目")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:add')")
|
||||
public AjaxResult createProject(@Validated @RequestBody CcdiProjectSaveDTO dto) {
|
||||
CcdiProjectVO vo = projectService.createProject(dto);
|
||||
return AjaxResult.success("项目创建成功", vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新项目
|
||||
*/
|
||||
@PutMapping
|
||||
@Operation(summary = "更新项目")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||
public AjaxResult updateProject(@Validated @RequestBody CcdiProjectSaveDTO dto) {
|
||||
CcdiProjectVO vo = projectService.updateProject(dto);
|
||||
return AjaxResult.success("项目更新成功", vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除项目
|
||||
*/
|
||||
@DeleteMapping("/{projectId}")
|
||||
@Operation(summary = "删除项目")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:remove')")
|
||||
public AjaxResult deleteProject(@PathVariable Long projectId) {
|
||||
boolean success = projectService.deleteProject(projectId);
|
||||
return success ? AjaxResult.success("项目删除成功") : AjaxResult.error("项目删除失败");
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询项目详情
|
||||
*/
|
||||
@GetMapping("/{projectId}")
|
||||
@Operation(summary = "查询项目详情")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getProject(@PathVariable Long projectId) {
|
||||
CcdiProjectVO vo = projectService.getProjectById(projectId);
|
||||
return AjaxResult.success(vo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询项目列表(分页)
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "查询项目列表")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:list')")
|
||||
public TableDataInfo listProject(CcdiProjectQueryDTO queryDTO) {
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiProjectVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiProjectVO> result = projectService.selectProjectPage(page, queryDTO);
|
||||
return getDataTable(result.getRecords(), result.getTotal());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Step 2: 验证编译**
|
||||
|
||||
```bash
|
||||
cd ruoyi-info-collection && mvn clean compile
|
||||
```
|
||||
|
||||
预期输出:BUILD SUCCESS
|
||||
|
||||
**Step 3: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-info-collection/src/main/java/com/ruoyi/info/collection/controller/CcdiProjectController.java
|
||||
git commit -m "feat: 添加项目Controller"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 11: 启动后端并测试接口
|
||||
|
||||
**Step 1: 启动后端服务**
|
||||
|
||||
```bash
|
||||
cd ruoyi-admin && mvn spring-boot:run
|
||||
```
|
||||
|
||||
预期输出:Spring Boot 启动成功日志,端口 8080
|
||||
|
||||
**Step 2: 获取测试 Token**
|
||||
|
||||
使用测试接口获取 Token:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/login/test?username=admin&password=admin123"
|
||||
```
|
||||
|
||||
预期输出:返回包含 token 的 JSON 响应
|
||||
|
||||
**Step 3: 测试创建项目接口**
|
||||
|
||||
使用 Token 测试创建项目接口:
|
||||
|
||||
```bash
|
||||
curl -X POST "http://localhost:8080/ccdi/project" \
|
||||
-H "Authorization: Bearer <token>" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"projectName": "测试项目1",
|
||||
"projectDesc": "这是测试项目描述",
|
||||
"configType": "default"
|
||||
}'
|
||||
```
|
||||
|
||||
预期输出:返回成功响应,包含项目 ID 和创建的项目信息
|
||||
|
||||
**Step 4: 测试查询项目列表接口**
|
||||
|
||||
```bash
|
||||
curl -X GET "http://localhost:8080/ccdi/project/list?pageNum=1&pageSize=10" \
|
||||
-H "Authorization: Bearer <token>"
|
||||
```
|
||||
|
||||
预期输出:返回分页数据,包含刚才创建的项目
|
||||
|
||||
**Step 5: 使用 Swagger 测试**
|
||||
|
||||
访问 Swagger UI 进行接口测试:
|
||||
|
||||
```bash
|
||||
# 浏览器打开
|
||||
http://localhost:8080/swagger-ui/index.html
|
||||
```
|
||||
|
||||
预期结果:在 Swagger UI 中可以看到项目管理的所有接口,并进行测试
|
||||
|
||||
---
|
||||
|
||||
## Task 12: 提交最终代码
|
||||
|
||||
**Step 1: 检查所有文件**
|
||||
|
||||
```bash
|
||||
git status
|
||||
```
|
||||
|
||||
预期输出:所有后端文件已提交
|
||||
|
||||
**Step 2: 推送到远程仓库**
|
||||
|
||||
```bash
|
||||
git push origin dev
|
||||
```
|
||||
|
||||
预期输出:推送成功
|
||||
|
||||
---
|
||||
|
||||
## 完成检查清单
|
||||
|
||||
- [ ] 数据库表 `ccdi_project` 创建成功
|
||||
- [ ] 字典数据 `ccdi_project_status` 和 `ccdi_config_type` 插入成功
|
||||
- [ ] 菜单权限配置成功
|
||||
- [ ] 实体类 `CcdiProject` 创建并编译通过
|
||||
- [ ] DTO `CcdiProjectSaveDTO` 创建并编译通过
|
||||
- [ ] VO `CcdiProjectVO` 创建并编译通过
|
||||
- [ ] Mapper 接口和 XML 创建并编译通过
|
||||
- [ ] Service 接口和实现类创建并编译通过
|
||||
- [ ] Controller 创建并编译通过
|
||||
- [ ] 后端服务启动成功
|
||||
- [ ] 创建项目接口测试通过
|
||||
- [ ] 查询项目列表接口测试通过
|
||||
- [ ] Swagger 文档显示正确
|
||||
- [ ] 所有代码已提交到 git
|
||||
|
||||
---
|
||||
|
||||
**后端实施计划完成!**
|
||||
881
doc/plans/2026-02-26-create-project-frontend-implementation.md
Normal file
881
doc/plans/2026-02-26-create-project-frontend-implementation.md
Normal file
@@ -0,0 +1,881 @@
|
||||
# 创建项目功能 - 前端实施计划
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**目标:** 实现创建项目功能的前端界面,包括弹窗表单、项目列表展示、API调用
|
||||
|
||||
**架构:** 基于 Vue 2.6.12 + Element UI 2.15.14,采用组件化开发
|
||||
|
||||
**技术栈:** Vue.js 2.6.12, Element UI 2.15.14, Axios 0.28.1
|
||||
|
||||
---
|
||||
|
||||
## 前置条件
|
||||
|
||||
- 后端接口已部署并测试通过
|
||||
- 前端项目依赖已安装
|
||||
- 已有测试账号(admin/admin123)
|
||||
- 后端服务运行在 http://localhost:8080
|
||||
|
||||
---
|
||||
|
||||
## Task 1: 更新 API 接口文件
|
||||
|
||||
**文件:**
|
||||
- Modify: `ruoyi-ui/src/api/ccdiProject.js`
|
||||
|
||||
**Step 1: 备份原文件**
|
||||
|
||||
```bash
|
||||
cp ruoyi-ui/src/api/ccdiProject.js ruoyi-ui/src/api/ccdiProject.js.bak
|
||||
```
|
||||
|
||||
**Step 2: 修改 API 文件**
|
||||
|
||||
将 `ruoyi-ui/src/api/ccdiProject.js` 修改为以下内容:
|
||||
|
||||
```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'
|
||||
})
|
||||
}
|
||||
|
||||
// Mock数据:获取项目列表(保留用于测试)
|
||||
export function getMockProjectList() {
|
||||
return Promise.resolve({
|
||||
code: 200,
|
||||
total: 3,
|
||||
rows: [
|
||||
{
|
||||
projectId: 1,
|
||||
projectName: '2024年Q1初核',
|
||||
projectDesc: '2024年第一季度纪检初核排查工作',
|
||||
createTime: '2024-01-01',
|
||||
projectStatus: '0',
|
||||
configType: 'default',
|
||||
targetCount: 500,
|
||||
highRiskCount: 5,
|
||||
mediumRiskCount: 10,
|
||||
lowRiskCount: 0
|
||||
},
|
||||
{
|
||||
projectId: 2,
|
||||
projectName: '2023年Q4初核',
|
||||
projectDesc: '2023年第四季度纪检初核排查工作',
|
||||
createTime: '2023-10-01',
|
||||
projectStatus: '1',
|
||||
configType: 'custom',
|
||||
targetCount: 480,
|
||||
highRiskCount: 8,
|
||||
mediumRiskCount: 15,
|
||||
lowRiskCount: 0
|
||||
},
|
||||
{
|
||||
projectId: 3,
|
||||
projectName: '2023年Q3初核',
|
||||
projectDesc: '2023年第三季度纪检初核排查工作',
|
||||
createTime: '2023-07-01',
|
||||
projectStatus: '2',
|
||||
configType: 'default',
|
||||
targetCount: 450,
|
||||
highRiskCount: 0,
|
||||
mediumRiskCount: 18,
|
||||
lowRiskCount: 5
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 验证语法**
|
||||
|
||||
```bash
|
||||
cd ruoyi-ui && npm run lint -- --fix src/api/ccdiProject.js
|
||||
```
|
||||
|
||||
预期输出:无 ESLint 错误
|
||||
|
||||
**Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/api/ccdiProject.js
|
||||
git commit -m "feat: 更新项目API接口,添加创建项目接口"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: 修改 AddProjectDialog 组件
|
||||
|
||||
**文件:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiProject/components/AddProjectDialog.vue`
|
||||
|
||||
**Step 1: 备份原文件**
|
||||
|
||||
```bash
|
||||
cp ruoyi-ui/src/views/ccdiProject/components/AddProjectDialog.vue ruoyi-ui/src/views/ccdiProject/components/AddProjectDialog.vue.bak
|
||||
```
|
||||
|
||||
**Step 2: 重写组件**
|
||||
|
||||
将 `ruoyi-ui/src/views/ccdiProject/components/AddProjectDialog.vue` 重写为以下内容:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<el-dialog
|
||||
:visible.sync="dialogVisible"
|
||||
:title="title"
|
||||
width="600px"
|
||||
:close-on-click-modal="false"
|
||||
:close-on-press-escape="false"
|
||||
@close="handleClose"
|
||||
>
|
||||
<el-form
|
||||
ref="projectForm"
|
||||
:model="formData"
|
||||
:rules="rules"
|
||||
label-width="100px"
|
||||
label-position="right"
|
||||
>
|
||||
<!-- 项目名称 -->
|
||||
<el-form-item label="项目名称" prop="projectName">
|
||||
<el-input
|
||||
v-model="formData.projectName"
|
||||
placeholder="请输入项目名称"
|
||||
maxlength="100"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 项目描述 -->
|
||||
<el-form-item label="项目描述" prop="projectDesc">
|
||||
<el-input
|
||||
v-model="formData.projectDesc"
|
||||
type="textarea"
|
||||
:rows="4"
|
||||
placeholder="请输入项目描述"
|
||||
maxlength="500"
|
||||
show-word-limit
|
||||
/>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 配置方式 -->
|
||||
<el-form-item label="配置方式" prop="configType">
|
||||
<el-radio-group v-model="formData.configType">
|
||||
<el-radio label="default">全局默认模型参数配置</el-radio>
|
||||
<el-radio label="custom">自定义项目规则参数配置</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="handleClose">取 消</el-button>
|
||||
<el-button type="primary" :loading="submitting" @click="handleSubmit">
|
||||
创建项目
|
||||
</el-button>
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { createProject } from '@/api/ccdiProject'
|
||||
|
||||
export default {
|
||||
name: 'AddProjectDialog',
|
||||
props: {
|
||||
visible: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
default: '新建项目'
|
||||
},
|
||||
form: {
|
||||
type: Object,
|
||||
default: () => ({})
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
submitting: false,
|
||||
formData: {
|
||||
projectName: '',
|
||||
projectDesc: '',
|
||||
configType: 'default'
|
||||
},
|
||||
rules: {
|
||||
projectName: [
|
||||
{ required: true, message: '请输入项目名称', trigger: 'blur' },
|
||||
{ min: 2, max: 100, message: '长度在 2 到 100 个字符', trigger: 'blur' }
|
||||
],
|
||||
configType: [
|
||||
{ required: true, message: '请选择配置方式', trigger: 'change' }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
dialogVisible: {
|
||||
get() {
|
||||
return this.visible
|
||||
},
|
||||
set(val) {
|
||||
if (!val) {
|
||||
this.handleClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
form: {
|
||||
handler(newVal) {
|
||||
if (newVal && Object.keys(newVal).length > 0) {
|
||||
this.formData = { ...this.formData, ...newVal }
|
||||
}
|
||||
},
|
||||
immediate: true,
|
||||
deep: true
|
||||
},
|
||||
visible(val) {
|
||||
if (val) {
|
||||
this.$nextTick(() => {
|
||||
if (this.$refs.projectForm) {
|
||||
this.$refs.projectForm.clearValidate()
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
/** 提交表单 */
|
||||
handleSubmit() {
|
||||
this.$refs.projectForm.validate(valid => {
|
||||
if (valid) {
|
||||
this.submitting = true
|
||||
createProject(this.formData).then(response => {
|
||||
this.$message.success('项目创建成功')
|
||||
this.submitting = false
|
||||
this.$emit('submit', response.data)
|
||||
this.handleClose()
|
||||
}).catch(() => {
|
||||
this.submitting = false
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
/** 关闭对话框 */
|
||||
handleClose() {
|
||||
this.$emit('close')
|
||||
this.$refs.projectForm.resetFields()
|
||||
this.formData = {
|
||||
projectName: '',
|
||||
projectDesc: '',
|
||||
configType: 'default'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.dialog-footer {
|
||||
text-align: right;
|
||||
|
||||
.el-button + .el-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.el-radio-group) {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
|
||||
.el-radio {
|
||||
line-height: 32px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
**Step 3: 验证语法**
|
||||
|
||||
```bash
|
||||
cd ruoyi-ui && npm run lint -- --fix src/views/ccdiProject/components/AddProjectDialog.vue
|
||||
```
|
||||
|
||||
预期输出:无 ESLint 错误
|
||||
|
||||
**Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiProject/components/AddProjectDialog.vue
|
||||
git commit -m "feat: 简化项目创建弹窗,只保留3个核心字段"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: 修改 ProjectTable 组件
|
||||
|
||||
**文件:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiProject/components/ProjectTable.vue`
|
||||
|
||||
**Step 1: 备份原文件**
|
||||
|
||||
```bash
|
||||
cp ruoyi-ui/src/views/ccdiProject/components/ProjectTable.vue ruoyi-ui/src/views/ccdiProject/components/ProjectTable.vue.bak
|
||||
```
|
||||
|
||||
**Step 2: 重写组件**
|
||||
|
||||
将 `ruoyi-ui/src/views/ccdiProject/components/ProjectTable.vue` 重写为以下内容:
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="project-table-container">
|
||||
<el-table
|
||||
:data="dataList"
|
||||
:loading="loading"
|
||||
border
|
||||
style="width: 100%"
|
||||
>
|
||||
<!-- 项目名称(含描述) -->
|
||||
<el-table-column
|
||||
label="项目名称"
|
||||
min-width="300"
|
||||
align="left"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<div class="project-info-cell">
|
||||
<div class="project-name">{{ scope.row.projectName }}</div>
|
||||
<div class="project-desc">{{ scope.row.projectDesc || '暂无描述' }}</div>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 项目状态 -->
|
||||
<el-table-column
|
||||
prop="projectStatus"
|
||||
label="项目状态"
|
||||
width="100"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<el-tag :type="getStatusType(scope.row.projectStatus)">
|
||||
<dict-tag :options="dict.type.ccdi_project_status" :value="scope.row.projectStatus"/>
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 目标人数 -->
|
||||
<el-table-column
|
||||
prop="targetCount"
|
||||
label="目标人数"
|
||||
width="100"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<!-- 预警人数(带悬停详情) -->
|
||||
<el-table-column
|
||||
label="预警人数"
|
||||
width="120"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<el-tooltip placement="top" effect="light">
|
||||
<div slot="content">
|
||||
<div style="padding: 8px;">
|
||||
<div style="margin-bottom: 8px; font-weight: bold; color: #303133;">
|
||||
风险人数统计
|
||||
</div>
|
||||
<div style="margin-bottom: 6px;">
|
||||
<span style="color: #f56c6c;">● 高风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.highRiskCount }} 人</span>
|
||||
</div>
|
||||
<div style="margin-bottom: 6px;">
|
||||
<span style="color: #e6a23c;">● 中风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.mediumRiskCount }} 人</span>
|
||||
</div>
|
||||
<div>
|
||||
<span style="color: #909399;">● 低风险:</span>
|
||||
<span style="font-weight: bold;">{{ scope.row.lowRiskCount }} 人</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="warning-count-wrapper">
|
||||
<span :class="getWarningClass(scope.row)" style="cursor: pointer;">
|
||||
{{ scope.row.highRiskCount + scope.row.mediumRiskCount + scope.row.lowRiskCount }}
|
||||
</span>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 创建人 -->
|
||||
<el-table-column
|
||||
prop="createBy"
|
||||
label="创建人"
|
||||
width="120"
|
||||
align="center"
|
||||
/>
|
||||
|
||||
<!-- 创建时间 -->
|
||||
<el-table-column
|
||||
prop="createTime"
|
||||
label="创建时间"
|
||||
width="160"
|
||||
align="center"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<span>{{ parseTime(scope.row.createTime) }}</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
|
||||
<!-- 操作列 -->
|
||||
<el-table-column
|
||||
label="操作"
|
||||
width="200"
|
||||
align="center"
|
||||
fixed="right"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-view"
|
||||
@click="handleDetail(scope.row)"
|
||||
>详情</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-edit"
|
||||
@click="handleEdit(scope.row)"
|
||||
>编辑</el-button>
|
||||
<el-button
|
||||
size="mini"
|
||||
type="text"
|
||||
icon="el-icon-delete"
|
||||
@click="handleDelete(scope.row)"
|
||||
>删除</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
|
||||
<!-- 分页 -->
|
||||
<el-pagination
|
||||
v-show="total > 0"
|
||||
:current-page="pageParams.pageNum"
|
||||
:page-size="pageParams.pageSize"
|
||||
:page-sizes="[10, 20, 30, 50]"
|
||||
:total="total"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
@size-change="handleSizeChange"
|
||||
@current-change="handleCurrentChange"
|
||||
style="margin-top: 16px; text-align: right;"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'ProjectTable',
|
||||
dicts: ['ccdi_project_status', 'ccdi_config_type'],
|
||||
props: {
|
||||
dataList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
total: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
pageParams: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getStatusType(status) {
|
||||
const statusMap = {
|
||||
'0': 'primary', // 进行中
|
||||
'1': 'success', // 已完成
|
||||
'2': 'info' // 已归档
|
||||
}
|
||||
return statusMap[status] || 'info'
|
||||
},
|
||||
|
||||
getWarningClass(row) {
|
||||
const total = row.highRiskCount + row.mediumRiskCount + row.lowRiskCount
|
||||
if (row.highRiskCount > 0) {
|
||||
return 'text-danger text-bold'
|
||||
} else if (row.mediumRiskCount > 0) {
|
||||
return 'text-warning text-bold'
|
||||
} else if (total > 0) {
|
||||
return 'text-info'
|
||||
}
|
||||
return ''
|
||||
},
|
||||
|
||||
handleDetail(row) {
|
||||
this.$emit('detail', row)
|
||||
},
|
||||
|
||||
handleEdit(row) {
|
||||
this.$emit('edit', row)
|
||||
},
|
||||
|
||||
handleDelete(row) {
|
||||
this.$emit('delete', row)
|
||||
},
|
||||
|
||||
handleSizeChange(val) {
|
||||
this.$emit('pagination', { pageNum: this.pageParams.pageNum, pageSize: val })
|
||||
},
|
||||
|
||||
handleCurrentChange(val) {
|
||||
this.$emit('pagination', { pageNum: val, pageSize: this.pageParams.pageSize })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.project-table-container {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-count-wrapper {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.text-danger {
|
||||
color: #f56c6c;
|
||||
}
|
||||
|
||||
.text-warning {
|
||||
color: #e6a23c;
|
||||
}
|
||||
|
||||
.text-info {
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.text-bold {
|
||||
font-weight: bold;
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
**Step 3: 验证语法**
|
||||
|
||||
```bash
|
||||
cd ruoyi-ui && npm run lint -- --fix src/views/ccdiProject/components/ProjectTable.vue
|
||||
```
|
||||
|
||||
预期输出:无 ESLint 错误
|
||||
|
||||
**Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiProject/components/ProjectTable.vue
|
||||
git commit -m "feat: 优化项目列表表格,添加预警人数悬停提示"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: 修改父组件 index.vue
|
||||
|
||||
**文件:**
|
||||
- Modify: `ruoyi-ui/src/views/ccdiProject/index.vue`
|
||||
|
||||
**Step 1: 备份原文件**
|
||||
|
||||
```bash
|
||||
cp ruoyi-ui/src/views/ccdiProject/index.vue ruoyi-ui/src/views/ccdiProject/index.vue.bak
|
||||
```
|
||||
|
||||
**Step 2: 修改父组件**
|
||||
|
||||
将 `ruoyi-ui/src/views/ccdiProject/index.vue` 的 `getList` 和 `handleSubmitProject` 方法修改为:
|
||||
|
||||
```javascript
|
||||
/** 查询项目列表 */
|
||||
getList() {
|
||||
this.loading = true
|
||||
// 使用真实API
|
||||
listProject(this.queryParams).then(response => {
|
||||
this.projectList = response.rows
|
||||
this.total = response.total
|
||||
this.loading = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
|
||||
/** 提交项目表单 */
|
||||
handleSubmitProject(data) {
|
||||
// 不需要再次调用API,因为AddProjectDialog已经处理了
|
||||
this.addDialogVisible = false
|
||||
this.getList() // 刷新列表
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3: 验证语法**
|
||||
|
||||
```bash
|
||||
cd ruoyi-ui && npm run lint -- --fix src/views/ccdiProject/index.vue
|
||||
```
|
||||
|
||||
预期输出:无 ESLint 错误
|
||||
|
||||
**Step 4: 提交代码**
|
||||
|
||||
```bash
|
||||
git add ruoyi-ui/src/views/ccdiProject/index.vue
|
||||
git commit -m "feat: 修改父组件,切换为真实API调用"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: 启动前端并测试
|
||||
|
||||
**Step 1: 启动前端开发服务器**
|
||||
|
||||
```bash
|
||||
cd ruoyi-ui && npm run dev
|
||||
```
|
||||
|
||||
预期输出:前端服务启动成功,访问地址 http://localhost:80
|
||||
|
||||
**Step 2: 测试登录**
|
||||
|
||||
浏览器访问 http://localhost:80,使用测试账号登录:
|
||||
- 用户名:admin
|
||||
- 密码:admin123
|
||||
|
||||
预期结果:登录成功,进入首页
|
||||
|
||||
**Step 3: 测试项目列表**
|
||||
|
||||
导航到"纪检初核管理 > 项目管理"菜单:
|
||||
|
||||
预期结果:
|
||||
- 项目列表正常显示
|
||||
- 项目名称和描述上下排列
|
||||
- 项目状态标签显示正确
|
||||
- 预警人数悬停提示显示风险详情
|
||||
|
||||
**Step 4: 测试创建项目**
|
||||
|
||||
点击"新建项目"按钮:
|
||||
|
||||
预期结果:
|
||||
- 弹窗正常打开
|
||||
- 显示3个字段(项目名称、项目描述、配置方式)
|
||||
- 配置方式默认选中"全局默认模型参数配置"
|
||||
|
||||
填写表单:
|
||||
- 项目名称:测试项目001
|
||||
- 项目描述:这是测试项目的描述
|
||||
- 配置方式:选择"自定义项目规则参数配置"
|
||||
|
||||
点击"创建项目"按钮:
|
||||
|
||||
预期结果:
|
||||
- 按钮显示 loading 状态
|
||||
- 创建成功,提示"项目创建成功"
|
||||
- 弹窗关闭
|
||||
- 项目列表自动刷新,显示新创建的项目
|
||||
|
||||
**Step 5: 测试预警人数悬停**
|
||||
|
||||
在项目列表中,将鼠标悬停在预警人数上:
|
||||
|
||||
预期结果:
|
||||
- 显示风险人数统计提示框
|
||||
- 显示高风险、中风险、低风险人数
|
||||
- 预警人数颜色根据风险级别变化
|
||||
|
||||
**Step 6: 测试表单验证**
|
||||
|
||||
不填写项目名称,直接点击"创建项目":
|
||||
|
||||
预期结果:
|
||||
- 提示"请输入项目名称"
|
||||
- 表单不提交
|
||||
|
||||
**Step 7: 测试取消按钮**
|
||||
|
||||
点击"新建项目",然后点击"取消":
|
||||
|
||||
预期结果:
|
||||
- 弹窗关闭
|
||||
- 表单数据清空
|
||||
|
||||
---
|
||||
|
||||
## Task 6: 跨浏览器测试
|
||||
|
||||
**Step 1: Chrome 测试**
|
||||
|
||||
在 Chrome 浏览器中重复 Task 5 的所有测试:
|
||||
|
||||
预期结果:所有功能正常
|
||||
|
||||
**Step 2: Edge 测试**
|
||||
|
||||
在 Edge 浏览器中重复 Task 5 的所有测试:
|
||||
|
||||
预期结果:所有功能正常
|
||||
|
||||
**Step 3: Firefox 测试(可选)**
|
||||
|
||||
在 Firefox 浏览器中重复 Task 5 的所有测试:
|
||||
|
||||
预期结果:所有功能正常
|
||||
|
||||
---
|
||||
|
||||
## Task 7: 响应式测试
|
||||
|
||||
**Step 1: 测试不同分辨率**
|
||||
|
||||
调整浏览器窗口大小,测试以下分辨率:
|
||||
|
||||
- 1920x1080(桌面)
|
||||
- 1366x768(笔记本)
|
||||
- 768x1024(平板)
|
||||
|
||||
预期结果:
|
||||
- 表格自适应宽度
|
||||
- 弹窗居中显示
|
||||
- 所有功能正常使用
|
||||
|
||||
**Step 2: 测试表格横向滚动**
|
||||
|
||||
缩小浏览器窗口,使表格宽度小于内容宽度:
|
||||
|
||||
预期结果:
|
||||
- 表格出现横向滚动条
|
||||
- 操作列固定在右侧
|
||||
- 可以横向滚动查看所有列
|
||||
|
||||
---
|
||||
|
||||
## Task 8: 提交最终代码
|
||||
|
||||
**Step 1: 检查所有文件**
|
||||
|
||||
```bash
|
||||
git status
|
||||
```
|
||||
|
||||
预期输出:所有前端文件已提交
|
||||
|
||||
**Step 2: 推送到远程仓库**
|
||||
|
||||
```bash
|
||||
git push origin dev
|
||||
```
|
||||
|
||||
预期输出:推送成功
|
||||
|
||||
---
|
||||
|
||||
## 完成检查清单
|
||||
|
||||
- [ ] API 接口文件更新完成
|
||||
- [ ] AddProjectDialog 组件简化完成(3个字段)
|
||||
- [ ] ProjectTable 组件优化完成(上下排列、预警悬停)
|
||||
- [ ] 父组件切换为真实API
|
||||
- [ ] 前端服务启动成功
|
||||
- [ ] 登录功能正常
|
||||
- [ ] 项目列表显示正常
|
||||
- [ ] 项目名称和描述上下排列正确
|
||||
- [ ] 项目状态标签显示正确
|
||||
- [ ] 预警人数悬停提示显示正常
|
||||
- [ ] 预警人数颜色根据风险级别变化
|
||||
- [ ] 创建项目弹窗打开正常
|
||||
- [ ] 配置方式默认值正确
|
||||
- [ ] 创建项目功能正常
|
||||
- [ ] 创建成功后列表刷新
|
||||
- [ ] 表单验证正常
|
||||
- [ ] 取消按钮功能正常
|
||||
- [ ] 跨浏览器测试通过
|
||||
- [ ] 响应式测试通过
|
||||
- [ ] 所有代码已提交到 git
|
||||
|
||||
---
|
||||
|
||||
**前端实施计划完成!**
|
||||
BIN
doc/创建项目功能/ScreenShot_2026-02-26_162233_965.png
Normal file
BIN
doc/创建项目功能/ScreenShot_2026-02-26_162233_965.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 64 KiB |
Reference in New Issue
Block a user