diff --git a/doc/plans/2026-02-06-ccdi_purchase_transaction.md b/doc/plans/2026-02-06-ccdi_purchase_transaction.md index d70d9fc..ecc40f7 100644 --- a/doc/plans/2026-02-06-ccdi_purchase_transaction.md +++ b/doc/plans/2026-02-06-ccdi_purchase_transaction.md @@ -13,19 +13,14 @@ --- -## 实施进度 +## 前置条件 -✅ **已完成** (2026-02-06): -- Task 1-14: 后端核心功能开发 -- 导入失败记录VO优化 - -🔄 **待完成**: -- Task 15-21: 前端开发、测试、文档 - ---- - -## 数据库表结构 +### 参考文档 +- 员工招聘信息模块: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/**/CcdiStaffRecruitment*` +- 员工异步导入实现: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiEmployeeImportServiceImpl.java` +- 数据库表定义: `doc/docs/ccdi_purchase_transaction.csv` +### 数据库表结构 ```sql CREATE TABLE `ccdi_purchase_transaction` ( `purchase_id` VARCHAR(32) NOT NULL COMMENT '采购事项ID', @@ -64,173 +59,1152 @@ CREATE TABLE `ccdi_purchase_transaction` ( `update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', `created_by` VARCHAR(50) NOT NULL COMMENT '创建人', `updated_by` VARCHAR(50) DEFAULT NULL COMMENT '更新人', - PRIMARY KEY (`purchase_id`), - KEY `idx_applicant_id` (`applicant_id`), - KEY `idx_apply_date` (`apply_date`), - KEY `idx_supplier_uscc` (`supplier_uscc`), - KEY `idx_category_method` (`purchase_category`, `purchase_method`) + PRIMARY KEY (`purchase_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工采购交易信息表'; ``` --- -## 已完成的任务 (Task 1-14) +## Task 1: 创建数据库表 -### Task 1: 创建数据库表 ✅ -- Commit: d83732f (修复后的提交) -- 包含4个业务索引优化查询性能 +**Files:** +- Modify: 执行SQL创建表 -### Task 2: 创建实体类 ✅ -- 文件: `CcdiPurchaseTransaction.java` -- Commit: 913e5e5 +**Step 1: 连接数据库并创建表** -### Task 3-7: 创建DTO、VO、Excel类 ✅ -- QueryDTO, AddDTO, EditDTO (修复工号验证) -- VO类 -- Excel类 -- Commits: f80a58f, ad369e7→ac3b9cd, c1de614→ac3b9cd, 39032eb, 1d09c88 +使用MCP连接MySQL数据库: +```bash +# 使用 mcp__mysql__connect_db 连接到数据库 +# 然后执行上面的CREATE TABLE语句 +``` -### Task 8-9: 创建Mapper ✅ -- Mapper接口 -- Mapper XML映射 -- Commits: b0bd66d, d9f1b52 +**Step 2: 验证表创建** -### Task 10-11: 创建Service接口 ✅ -- Service接口 -- 异步导入Service接口 -- Commits: 584581e, 1799017 +```sql +SHOW CREATE TABLE ccdi_purchase_transaction; +``` -### Task 12-13: 创建Service实现 ✅ -- Service实现类 (修复Redis初始化) -- 异步导入Service实现类 -- Commits: a2764fd→9df2b5a, a4c21b8 +Expected: 表结构正确创建 -### Task 14: 创建Controller ✅ -- 10个REST API接口 -- Commit: 4ba0803 +**Step 3: Commit** -### 额外: 优化导入失败记录VO ✅ -- 创建专门的 `PurchaseTransactionImportFailureVO` -- 更新异步导入Service使用新VO -- Commits: 1aa0d15, 4a560bd +```bash +git add sql/ +git commit -m "feat: 添加员工采购交易信息表" +``` --- -## 待执行任务 (Task 15-21) +## Task 2: 创建实体类 -### Task 15: 创建前端API文件 -**文件:** `ruoyi-ui/src/api/ccdiPurchaseTransaction.js` +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/CcdiPurchaseTransaction.java` -**内容:** 定义10个API方法 -- listTransaction - 分页查询 -- getTransaction - 查询详情 -- addTransaction - 新增 -- updateTransaction - 修改 -- delTransaction - 删除 -- exportTransaction - 导出 -- importTemplate - 下载模板 -- importData - 导入 -- getImportStatus - 查询导入状态 -- getImportFailures - 查询失败记录 +**Step 1: 创建实体类** -### Task 16: 创建前端页面组件 -**文件:** `ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue` +```java +package com.ruoyi.ccdi.domain; -**功能:** -- 查询表单(项目名称、标的物名称、申请人、日期范围) -- 列表表格(13个主要字段 + 操作列) -- 新增/编辑对话框 -- **导入对话框(异步轮询)** -- 删除确认 +import com.baomidou.mybatisplus.annotation.FieldFill; +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import lombok.Data; -**关键实现:** -```javascript -// 异步导入轮询逻辑 -async handleImport(file, updateSupport) { - const res = await importData(file, updateSupport) - const taskId = res.data.taskId +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; - // 每2秒轮询状态 - const timer = setInterval(async () => { - const status = await getImportStatus(taskId) - if (status.data.status === 'SUCCESS' || status.data.status === 'PARTIAL_SUCCESS') { - clearInterval(timer) - if (status.data.status === 'PARTIAL_SUCCESS') { - // 显示失败记录 - this.fetchFailures(taskId) - } - this.$message.success(status.data.message) - } - }, 2000) +/** + * 员工采购交易信息对象 ccdi_purchase_transaction + * + * @author ruoyi + * @date 2026-02-06 + */ +@Data +public class CcdiPurchaseTransaction implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** 采购事项ID */ + @TableId(type = IdType.INPUT) + private String purchaseId; + + /** 采购类别 */ + private String purchaseCategory; + + /** 项目名称 */ + private String projectName; + + /** 标的物名称 */ + private String subjectName; + + /** 标的物描述 */ + private String subjectDesc; + + /** 采购数量 */ + private BigDecimal purchaseQty; + + /** 预算金额 */ + private BigDecimal budgetAmount; + + /** 中标金额 */ + private BigDecimal bidAmount; + + /** 实际采购金额 */ + private BigDecimal actualAmount; + + /** 合同金额 */ + private BigDecimal contractAmount; + + /** 结算金额 */ + private BigDecimal settlementAmount; + + /** 采购方式 */ + private String purchaseMethod; + + /** 中标供应商名称 */ + private String supplierName; + + /** 供应商联系人 */ + private String contactPerson; + + /** 供应商联系电话 */ + private String contactPhone; + + /** 供应商统一信用代码 */ + private String supplierUscc; + + /** 供应商银行账户 */ + private String supplierBankAccount; + + /** 采购申请日期 */ + private LocalDate applyDate; + + /** 采购计划批准日期 */ + private LocalDate planApproveDate; + + /** 采购公告发布日期 */ + private LocalDate announceDate; + + /** 开标日期 */ + private LocalDate bidOpenDate; + + /** 合同签订日期 */ + private LocalDate contractSignDate; + + /** 预计交货日期 */ + private LocalDate expectedDeliveryDate; + + /** 实际交货日期 */ + private LocalDate actualDeliveryDate; + + /** 验收日期 */ + private LocalDate acceptanceDate; + + /** 结算日期 */ + private LocalDate settlementDate; + + /** 申请人工号 */ + private String applicantId; + + /** 申请人姓名 */ + private String applicantName; + + /** 申请部门 */ + private String applyDepartment; + + /** 采购负责人工号 */ + private String purchaseLeaderId; + + /** 采购负责人姓名 */ + private String purchaseLeaderName; + + /** 采购部门 */ + private String purchaseDepartment; + + /** 创建时间 */ + @TableField(fill = FieldFill.INSERT) + private LocalDateTime createTime; + + /** 更新时间 */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private LocalDateTime updateTime; + + /** 创建人 */ + @TableField(fill = FieldFill.INSERT) + private String createdBy; + + /** 更新人 */ + @TableField(fill = FieldFill.INSERT_UPDATE) + private String updatedBy; } ``` -### Task 17: 配置菜单和权限 -**文件:** `sql/ccdi_purchase_transaction_menu.sql` +**Step 2: 验证编译** -**内容:** -- 主菜单:采购交易管理 -- 6个按钮权限:查询、新增、修改、删除、导出、导入 +```bash +cd ruoyi-ccdi +mvn compile -pl . -am +``` -### Task 18: 生成测试脚本(跳过) -**文件:** `test/test_purchase_transaction_api.ps1` +Expected: 编译成功,无错误 -**内容:** PowerShell测试脚本 -- 登录 (admin/admin123) -- 测试所有API接口 -- 包含异步导入流程测试 +**Step 3: Commit** -### Task 19: 创建测试说明 -**文件:** `doc/test-data/purchase_transaction/README.md` - -**内容:** 测试运行说明 - -### Task 20: 生成API文档 -**文件:** `doc/api/ccdi_purchase_transaction_api.md` - -**内容:** 接口文档 -- 接口列表 -- 请求参数 -- 响应格式 -- 示例 - -### Task 21: 最终验证清单 -**文件:** `doc/plans/2026-02-06-ccdi_purchase_transaction-verification.md` - -**内容:** -- 功能测试清单 -- 代码审查清单 -- 性能测试建议 -- 部署前检查项 +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/CcdiPurchaseTransaction.java +git commit -m "feat: 添加采购交易信息实体类" +``` --- -## 技术要点 +## Task 3: 创建查询DTO -### 必填字段 -purchaseId, purchaseCategory, subjectName, purchaseQty, budgetAmount, purchaseMethod, applyDate, applicantId, applicantName, applyDepartment +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiPurchaseTransactionQueryDTO.java` -### 异步导入 -- 使用 @Async + @Transactional + Redis -- taskId追踪导入进度 -- 每2秒轮询状态 -- 失败记录存储7天 +**Step 1: 创建查询DTO** -### 更新策略 -- 先批量删除旧记录 -- 再批量插入新记录 -- 每批500条记录 +```java +package com.ruoyi.ccdi.domain.dto; -### 数据验证 -- Jakarta Validation注解 -- 工号格式:7位数字 -- 金额非负验证 +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.time.LocalDate; + +/** + * 采购交易信息查询DTO + * + * @author ruoyi + * @date 2026-02-06 + */ +@Data +@Schema(description = "采购交易信息查询条件") +public class CcdiPurchaseTransactionQueryDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** 项目名称 */ + @Schema(description = "项目名称") + private String projectName; + + /** 标的物名称 */ + @Schema(description = "标的物名称") + private String subjectName; + + /** 申请人姓名 */ + @Schema(description = "申请人姓名") + private String applicantName; + + /** 申请人工号 */ + @Schema(description = "申请人工号") + private String applicantId; + + /** 申请日期-开始 */ + @Schema(description = "申请日期-开始") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate applyDateStart; + + /** 申请日期-结束 */ + @Schema(description = "申请日期-结束") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate applyDateEnd; +} +``` + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiPurchaseTransactionQueryDTO.java +git commit -m "feat: 添加采购交易查询DTO" +``` --- +## Task 4: 创建新增DTO + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiPurchaseTransactionAddDTO.java` + +**Step 1: 创建新增DTO(包含验证注解)** + +```java +package com.ruoyi.ccdi.domain.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.*; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDate; + +/** + * 采购交易信息新增DTO + * + * @author ruoyi + * @date 2026-02-06 + */ +@Data +@Schema(description = "采购交易信息新增") +public class CcdiPurchaseTransactionAddDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "采购事项ID") + @NotBlank(message = "采购事项ID不能为空") + @Size(max = 32, message = "采购事项ID长度不能超过32个字符") + private String purchaseId; + + @Schema(description = "采购类别") + @NotBlank(message = "采购类别不能为空") + @Size(max = 50, message = "采购类别长度不能超过50个字符") + private String purchaseCategory; + + @Schema(description = "项目名称") + @Size(max = 200, message = "项目名称长度不能超过200个字符") + private String projectName; + + @Schema(description = "标的物名称") + @NotBlank(message = "标的物名称不能为空") + @Size(max = 200, message = "标的物名称长度不能超过200个字符") + private String subjectName; + + @Schema(description = "标的物描述") + private String subjectDesc; + + @Schema(description = "采购数量") + @NotNull(message = "采购数量不能为空") + @DecimalMin(value = "0.0001", message = "采购数量必须大于0") + private BigDecimal purchaseQty; + + @Schema(description = "预算金额") + @NotNull(message = "预算金额不能为空") + @DecimalMin(value = "0.01", message = "预算金额必须大于0") + private BigDecimal budgetAmount; + + @Schema(description = "中标金额") + @DecimalMin(value = "0", message = "中标金额不能为负数") + private BigDecimal bidAmount; + + @Schema(description = "实际采购金额") + @DecimalMin(value = "0", message = "实际采购金额不能为负数") + private BigDecimal actualAmount; + + @Schema(description = "合同金额") + @DecimalMin(value = "0", message = "合同金额不能为负数") + private BigDecimal contractAmount; + + @Schema(description = "结算金额") + @DecimalMin(value = "0", message = "结算金额不能为负数") + private BigDecimal settlementAmount; + + @Schema(description = "采购方式") + @NotBlank(message = "采购方式不能为空") + @Size(max = 50, message = "采购方式长度不能超过50个字符") + private String purchaseMethod; + + @Schema(description = "中标供应商名称") + @Size(max = 200, message = "中标供应商名称长度不能超过200个字符") + private String supplierName; + + @Schema(description = "供应商联系人") + @Size(max = 50, message = "供应商联系人长度不能超过50个字符") + private String contactPerson; + + @Schema(description = "供应商联系电话") + @Size(max = 20, message = "供应商联系电话长度不能超过20个字符") + private String contactPhone; + + @Schema(description = "供应商统一信用代码") + @Size(max = 18, message = "供应商统一信用代码长度不能超过18个字符") + private String supplierUscc; + + @Schema(description = "供应商银行账户") + @Size(max = 50, message = "供应商银行账户长度不能超过50个字符") + private String supplierBankAccount; + + @Schema(description = "采购申请日期") + @NotNull(message = "采购申请日期不能为空") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate applyDate; + + @Schema(description = "采购计划批准日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate planApproveDate; + + @Schema(description = "采购公告发布日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate announceDate; + + @Schema(description = "开标日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate bidOpenDate; + + @Schema(description = "合同签订日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate contractSignDate; + + @Schema(description = "预计交货日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate expectedDeliveryDate; + + @Schema(description = "实际交货日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate actualDeliveryDate; + + @Schema(description = "验收日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate acceptanceDate; + + @Schema(description = "结算日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate settlementDate; + + @Schema(description = "申请人工号") + @NotBlank(message = "申请人工号不能为空") + @Pattern(regexp = "^\\d{7}$", message = "申请人工号必须为7位数字") + private String applicantId; + + @Schema(description = "申请人姓名") + @NotBlank(message = "申请人姓名不能为空") + @Size(max = 50, message = "申请人姓名长度不能超过50个字符") + private String applicantName; + + @Schema(description = "申请部门") + @NotBlank(message = "申请部门不能为空") + @Size(max = 100, message = "申请部门长度不能超过100个字符") + private String applyDepartment; + + @Schema(description = "采购负责人工号") + @Pattern(regexp = "^\\d{7}$", message = "采购负责人工号必须为7位数字") + private String purchaseLeaderId; + + @Schema(description = "采购负责人姓名") + @Size(max = 50, message = "采购负责人姓名长度不能超过50个字符") + private String purchaseLeaderName; + + @Schema(description = "采购部门") + @Size(max = 100, message = "采购部门长度不能超过100个字符") + private String purchaseDepartment; +} +``` + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiPurchaseTransactionAddDTO.java +git commit -m "feat: 添加采购交易新增DTO" +``` + +--- + +## Task 5: 创建编辑DTO + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiPurchaseTransactionEditDTO.java` + +**Step 1: 创建编辑DTO** + +复制AddDTO的内容,修改类名和类注释,所有验证注解保持不变。 + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/dto/CcdiPurchaseTransactionEditDTO.java +git commit -m "feat: 添加采购交易编辑DTO" +``` + +--- + +## Task 6: 创建VO类 + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/vo/CcdiPurchaseTransactionVO.java` + +**Step 1: 创建VO类** + +```java +package com.ruoyi.ccdi.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +/** + * 采购交易信息VO + * + * @author ruoyi + * @date 2026-02-06 + */ +@Data +@Schema(description = "采购交易信息") +public class CcdiPurchaseTransactionVO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "采购事项ID") + private String purchaseId; + + @Schema(description = "采购类别") + private String purchaseCategory; + + @Schema(description = "项目名称") + private String projectName; + + @Schema(description = "标的物名称") + private String subjectName; + + @Schema(description = "标的物描述") + private String subjectDesc; + + @Schema(description = "采购数量") + private BigDecimal purchaseQty; + + @Schema(description = "预算金额") + private BigDecimal budgetAmount; + + @Schema(description = "中标金额") + private BigDecimal bidAmount; + + @Schema(description = "实际采购金额") + private BigDecimal actualAmount; + + @Schema(description = "合同金额") + private BigDecimal contractAmount; + + @Schema(description = "结算金额") + private BigDecimal settlementAmount; + + @Schema(description = "采购方式") + private String purchaseMethod; + + @Schema(description = "中标供应商名称") + private String supplierName; + + @Schema(description = "供应商联系人") + private String contactPerson; + + @Schema(description = "供应商联系电话") + private String contactPhone; + + @Schema(description = "供应商统一信用代码") + private String supplierUscc; + + @Schema(description = "供应商银行账户") + private String supplierBankAccount; + + @Schema(description = "采购申请日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate applyDate; + + @Schema(description = "采购计划批准日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate planApproveDate; + + @Schema(description = "采购公告发布日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate announceDate; + + @Schema(description = "开标日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate bidOpenDate; + + @Schema(description = "合同签订日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate contractSignDate; + + @Schema(description = "预计交货日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate expectedDeliveryDate; + + @Schema(description = "实际交货日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate actualDeliveryDate; + + @Schema(description = "验收日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate acceptanceDate; + + @Schema(description = "结算日期") + @JsonFormat(pattern = "yyyy-MM-dd") + private LocalDate settlementDate; + + @Schema(description = "申请人工号") + private String applicantId; + + @Schema(description = "申请人姓名") + private String applicantName; + + @Schema(description = "申请部门") + private String applyDepartment; + + @Schema(description = "采购负责人工号") + private String purchaseLeaderId; + + @Schema(description = "采购负责人姓名") + private String purchaseLeaderName; + + @Schema(description = "采购部门") + private String purchaseDepartment; + + @Schema(description = "创建时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime createTime; + + @Schema(description = "更新时间") + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private LocalDateTime updateTime; + + @Schema(description = "创建人") + private String createdBy; + + @Schema(description = "更新人") + private String updatedBy; +} +``` + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/vo/CcdiPurchaseTransactionVO.java +git commit -m "feat: 添加采购交易VO类" +``` + +--- + +## Task 7: 创建Excel导入导出类 + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/excel/CcdiPurchaseTransactionExcel.java` + +**Step 1: 创建Excel类** + +参考 `CcdiStaffRecruitmentExcel.java`,为36个字段添加 `@ExcelProperty`、`@ColumnWidth`、`@Required` 注解。必填字段:purchaseId, purchaseCategory, subjectName, purchaseQty, budgetAmount, purchaseMethod, applyDate, applicantId, applicantName, applyDepartment。 + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/domain/excel/CcdiPurchaseTransactionExcel.java +git commit -m "feat: 添加采购交易Excel类" +``` + +--- + +## Task 8: 创建Mapper接口 + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/mapper/CcdiPurchaseTransactionMapper.java` + +**Step 1: 创建Mapper接口** + +```java +package com.ruoyi.ccdi.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.ruoyi.ccdi.domain.CcdiPurchaseTransaction; +import com.ruoyi.ccdi.domain.dto.CcdiPurchaseTransactionQueryDTO; +import com.ruoyi.ccdi.domain.vo.CcdiPurchaseTransactionVO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; + +/** + * 采购交易信息 数据层 + * + * @author ruoyi + * @date 2026-02-06 + */ +public interface CcdiPurchaseTransactionMapper extends BaseMapper { + + /** + * 分页查询采购交易列表 + */ + Page selectTransactionPage(@Param("page") Page page, + @Param("query") CcdiPurchaseTransactionQueryDTO queryDTO); + + /** + * 查询采购交易详情 + */ + CcdiPurchaseTransactionVO selectTransactionById(@Param("purchaseId") String purchaseId); + + /** + * 批量插入 + */ + int insertBatch(@Param("list") List list); + + /** + * 批量更新(先删除再插入) + */ + int insertOrUpdateBatch(@Param("list") List list); +} +``` + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/mapper/CcdiPurchaseTransactionMapper.java +git commit -m "feat: 添加采购交易Mapper接口" +``` + +--- + +## Task 9: 创建Mapper XML文件 + +**Files:** +- Create: `ruoyi-ccdi/src/main/resources/mapper/ccdi/CcdiPurchaseTransactionMapper.xml` + +**Step 1: 创建XML映射文件** + +参考 `CcdiStaffRecruitmentMapper.xml`,编写SQL映射: +- selectTransactionPage: 分页查询,支持项目名称、标的物名称、申请人、日期范围查询 +- selectTransactionById: 根据ID查询详情 +- insertBatch: 批量插入 +- insertOrUpdateBatch: 批量更新(先删除再插入) + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/resources/mapper/ccdi/CcdiPurchaseTransactionMapper.xml +git commit -m "feat: 添加采购交易Mapper XML" +``` + +--- + +## Task 10: 创建Service接口 + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/ICcdiPurchaseTransactionService.java` + +**Step 1: 创建Service接口** + +参考 `ICcdiStaffRecruitmentService.java`,定义以下方法: +- selectTransactionList +- selectTransactionPage +- selectTransactionListForExport +- selectTransactionById +- insertTransaction +- updateTransaction +- deleteTransactionByIds +- importTransaction (返回taskId) + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/ICcdiPurchaseTransactionService.java +git commit -m "feat: 添加采购交易Service接口" +``` + +--- + +## Task 11: 创建异步导入Service接口 + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/ICcdiPurchaseTransactionImportService.java` + +**Step 1: 创建异步导入Service接口** + +参考 `ICcdiEmployeeImportService.java`,定义方法: +- importTransactionAsync +- getImportStatus +- getImportFailures + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/ICcdiPurchaseTransactionImportService.java +git commit -m "feat: 添加采购交易异步导入Service接口" +``` + +--- + +## Task 12: 创建Service实现类 + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiPurchaseTransactionServiceImpl.java` + +**Step 1: 创建Service实现** + +参考 `CcdiStaffRecruitmentServiceImpl.java`,实现所有CRUD方法和importTransaction方法(初始化Redis状态,调用异步服务)。 + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiPurchaseTransactionServiceImpl.java +git commit -m "feat: 添加采购交易Service实现" +``` + +--- + +## Task 13: 创建异步导入Service实现类 + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiPurchaseTransactionImportServiceImpl.java` + +**Step 1: 创建异步导入实现** + +参考 `CcdiEmployeeImportServiceImpl.java`,实现: +- @Async + @Transactional 注解 +- importTransactionAsync方法(接收userName参数) +- 数据分类(新记录/更新记录/失败记录) +- 批量插入和更新 +- Redis状态管理 +- 数据验证逻辑 + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiPurchaseTransactionImportServiceImpl.java +git commit -m "feat: 添加采购交易异步导入Service实现" +``` + +--- + +## Task 14: 创建Controller控制器 + +**Files:** +- Create: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/controller/CcdiPurchaseTransactionController.java` + +**Step 1: 创建Controller** + +参考 `CcdiStaffRecruitmentController.java` 和 `CcdiEmployeeController.java`,实现接口: +- GET /list - 分页查询 +- GET /{purchaseId} - 查询详情 +- POST / - 新增 +- PUT / - 修改 +- DELETE /{purchaseIds} - 删除 +- POST /export - 导出 +- POST /importTemplate - 下载模板 +- POST /importData - 异步导入 +- GET /importStatus/{taskId} - 查询导入状态 +- GET /importFailures/{taskId} - 查询失败记录 + +添加完整的Swagger注解。 + +**Step 2: Commit** + +```bash +git add ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/controller/CcdiPurchaseTransactionController.java +git commit -m "feat: 添加采购交易Controller" +``` + +--- + +## Task 15: 创建前端API文件 + +**Files:** +- Create: `ruoyi-ui/src/api/ccdiPurchaseTransaction.js` + +**Step 1: 创建API定义** + +```javascript +import request from '@/utils/request' + +// 查询采购交易列表 +export function listTransaction(query) { + return request({ + url: '/ccdi/purchaseTransaction/list', + method: 'get', + params: query + }) +} + +// 查询采购交易详情 +export function getTransaction(purchaseId) { + return request({ + url: '/ccdi/purchaseTransaction/' + purchaseId, + method: 'get' + }) +} + +// 新增采购交易 +export function addTransaction(data) { + return request({ + url: '/ccdi/purchaseTransaction', + method: 'post', + data: data + }) +} + +// 修改采购交易 +export function updateTransaction(data) { + return request({ + url: '/ccdi/purchaseTransaction', + method: 'put', + data: data + }) +} + +// 删除采购交易 +export function delTransaction(purchaseIds) { + return request({ + url: '/ccdi/purchaseTransaction/' + purchaseIds, + method: 'delete' + }) +} + +// 导出采购交易 +export function exportTransaction(query) { + return request({ + url: '/ccdi/purchaseTransaction/export', + method: 'post', + params: query + }) +} + +// 下载导入模板 +export function importTemplate() { + return request({ + url: '/ccdi/purchaseTransaction/importTemplate', + method: 'post' + }) +} + +// 导入采购交易 +export function importData(file, updateSupport) { + const formData = new FormData() + formData.append('file', file) + formData.append('updateSupport', updateSupport) + return request({ + url: '/ccdi/purchaseTransaction/importData', + method: 'post', + data: formData + }) +} + +// 查询导入状态 +export function getImportStatus(taskId) { + return request({ + url: '/ccdi/purchaseTransaction/importStatus/' + taskId, + method: 'get' + }) +} + +// 查询导入失败记录 +export function getImportFailures(taskId, pageNum, pageSize) { + return request({ + url: '/ccdi/purchaseTransaction/importFailures/' + taskId, + method: 'get', + params: { pageNum, pageSize } + }) +} +``` + +**Step 2: Commit** + +```bash +git add ruoyi-ui/src/api/ccdiPurchaseTransaction.js +git commit -m "feat: 添加采购交易前端API" +``` + +--- + +## Task 16: 创建前端页面组件 + +**Files:** +- Create: `ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue` + +**Step 1: 创建页面组件** + +参考 `ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue`,实现: +- 查询表单(项目名称、标的物名称、申请人、日期范围) +- 列表表格(13个字段 + 操作列) +- 新增/编辑对话框 +- 导入对话框(支持异步导入状态轮询) +- 删除确认 + +**Step 2: Commit** + +```bash +git add ruoyi-ui/src/views/ccdiPurchaseTransaction/index.vue +git commit -m "feat: 添加采购交易管理页面" +``` + +--- + +## Task 17: 配置菜单和权限 + +**Files:** +- Modify: 数据库菜单表 + +**Step 1: 添加菜单数据** + +执行SQL: +```sql +-- 添加采购交易管理菜单 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark) +VALUES +('采购交易管理', (SELECT menu_id FROM sys_menu WHERE menu_name='CCDI管理' AND parent_id=0), 5, 'purchaseTransaction', 'ccdiPurchaseTransaction/index', 1, 0, 'C', '0', '0', 'ccdi:purchaseTransaction:list', 'shopping', 'admin', NOW(), '', NULL, '采购交易信息管理菜单'); + +-- 获取刚插入的菜单ID +SET @menu_id = LAST_INSERT_ID(); + +-- 添加按钮权限 +INSERT INTO sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, remark) VALUES +('采购交易查询', @menu_id, 1, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:query', '#', 'admin', NOW(), ''), +('采购交易新增', @menu_id, 2, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:add', '#', 'admin', NOW(), ''), +('采购交易修改', @menu_id, 3, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:edit', '#', 'admin', NOW(), ''), +('采购交易删除', @menu_id, 4, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:remove', '#', 'admin', NOW(), ''), +('采购交易导出', @menu_id, 5, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:export', '#', 'admin', NOW(), ''), +('采购交易导入', @menu_id, 6, '', '', 1, 0, 'F', '0', '0', 'ccdi:purchaseTransaction:import', '#', 'admin', NOW(), ''); +``` + +**Step 2: Commit** + +```bash +git add sql/ +git commit -m "feat: 配置采购交易管理菜单和权限" +``` + +--- + +## Task 18: 生成测试脚本 + +**Files:** +- Create: `test/test_purchase_transaction_api.ps1` + +**Step 1: 创建测试脚本** + +参考 `test/test_employee_api.ps1`,编写完整的测试脚本: +- 登录获取token +- 测试分页查询 +- 测试新增 +- 测试查询详情 +- 测试修改 +- 测试删除 +- 测试导入 +- 测试导出 + +**Step 2: Commit** + +```bash +git add test/test_purchase_transaction_api.ps1 +git commit -m "test: 添加采购交易API测试脚本" +``` + +--- + +## Task 19: 运行测试并生成报告 + +**Step 1: 运行测试脚本** + +```powershell +cd test +./test_purchase_transaction_api.ps1 > test_report_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt +``` + +**Step 2: 验证所有接口正常** + +Expected: 所有测试用例通过 + +**Step 3: 保存测试报告** + +将测试报告保存到 `doc/test-data/purchase_transaction/` 目录。 + +**Step 4: Commit** + +```bash +git add doc/test-data/purchase_transaction/ +git commit -m "test: 添加采购交易测试报告" +``` + +--- + +## Task 20: 生成API文档 + +**Files:** +- Create: `doc/api/ccdi_purchase_transaction_api.md` + +**Step 1: 导出Swagger API文档** + +访问 http://localhost:8080/swagger-ui/index.html,导出采购交易管理的API文档。 + +**Step 2: 整理为Markdown格式** + +整理所有接口的请求参数、响应格式、示例。 + +**Step 3: Commit** + +```bash +git add doc/api/ccdi_purchase_transaction_api.md +git commit -m "docs: 添加采购交易API文档" +``` + +--- + +## Task 21: 最终验证和清理 + +**Step 1: 完整功能测试** + +1. 启动后端服务 +2. 启动前端服务 +3. 登录系统 +4. 导航到采购交易管理菜单 +5. 测试所有功能: + - 列表查询 + - 新增记录 + - 编辑记录 + - 删除记录 + - 批量删除 + - 导入功能(含异步状态轮询) + - 导出功能 + +**Step 2: 代码审查** + +检查: +- 所有DTO验证注解完整 +- 所有Swagger注解完整 +- 异常处理完善 +- 日志记录完整 +- 审计字段正确填充 + +**Step 3: 性能测试** + +测试批量导入1000条数据的性能。 + +**Step 4: 最终Commit** + +```bash +git add . +git commit -m "feat: 完成采购交易信息管理功能开发" +``` + +--- + +## 实施注意事项 + +1. **必填字段**: purchaseId, purchaseCategory, subjectName, purchaseQty, budgetAmount, purchaseMethod, applyDate, applicantId, applicantName, applyDepartment +2. **异步导入**: 使用@Async + @Transactional + Redis +3. **批量操作**: 每批500条记录 +4. **更新策略**: 先批量删除,再批量插入 +5. **数据验证**: Jakarta Validation + 自定义业务验证 +6. **审计字段**: 使用@TableField(fill = FieldFill.INSERT/INSERT_UPDATE) +7. **错误处理**: 只返回失败记录,不返回成功记录 +8. **导入轮询**: 每2秒轮询一次状态 + ## 参考文件 -- 员工招聘模块: `CcdiStaffRecruitment*` -- 员工异步导入: `CcdiEmployeeImportServiceImpl.java` +- 员工招聘信息模块: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/**/CcdiStaffRecruitment*` +- 员工异步导入: `ruoyi-ccdi/src/main/java/com/ruoyi/ccdi/service/impl/CcdiEmployeeImportServiceImpl.java` - 前端页面: `ruoyi-ui/src/views/ccdiStaffRecruitment/index.vue` - 测试脚本: `test/test_employee_api.ps1`