diff --git a/project_progress.md b/project_progress.md index dbdf2d0..e51c82c 100644 --- a/project_progress.md +++ b/project_progress.md @@ -18,7 +18,7 @@ | 文档名称 | 状态 | 完成度 | 质量评级 | 最后更新 | 备注 | |---------|------|--------|----------|----------|------| | `water_biz_system_architecture.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已全面适配OpenGauss,架构图完整 | -| `water_biz_module_design.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已补充业务流程图和完整代码示例 | +| `water_biz_module_design.md` | 🔄 修复中 | 95% | B+级 | 2024-12-19 | 正在修复代码示例重复问题 | | `water_biz_database_design.md` | ✅ 已完成 | 100% | A+级 | 2024-12-19 | 已适配OpenGauss,完整DDL和安全设计 | | `water_biz_interface_design.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已补充详细接口参数、代码示例和安全设计 | | `water_biz_deployment_design.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已补充容器化部署方案和自动化脚本 | diff --git a/water_biz_module_design.md b/water_biz_module_design.md index c9bc51a..17a1f94 100644 --- a/water_biz_module_design.md +++ b/water_biz_module_design.md @@ -26,13 +26,13 @@ - [3.2 抄表开账](#32-抄表开账) - [3.2.1 业务流程图](#321-业务流程图) - [3.2.2 主要功能](#322-主要功能) - - [3.2.3 RuoYi-Vue-Pro代码实现](#323-ruoyi-vue-pro代码实现) - - [3.2.4 前端Vue3代码实现](#324-前端vue3代码实现) + - [3.2.3 核心接口定义](#323-核心接口定义) + - [3.2.4 前端界面设计](#324-前端界面设计) - [3.3 收费管理](#33-收费管理) - [3.3.1 业务流程图](#331-业务流程图) - [3.3.2 主要功能](#332-主要功能) - - [3.3.3 RuoYi-Vue-Pro代码实现](#333-ruoyi-vue-pro代码实现) - - [3.3.4 前端Vue3代码实现](#334-前端vue3代码实现) + - [3.3.3 核心接口定义](#333-核心接口定义) + - [3.3.4 前端界面设计](#334-前端界面设计) - [3.4 账务处理](#34-账务处理) - [3.5 发票管理](#35-发票管理) - [3.6 代收业务](#36-代收业务) @@ -488,527 +488,100 @@ flowchart TD - 特殊抄表:临时抄表需求 - 调整抄表:读数错误修正 -#### 3.2.3 RuoYi-Vue-Pro代码实现 +#### 3.2.3 核心接口定义 -**抄表记录Controller层**: +**抄表管理主要接口**: ```java @RestController @RequestMapping("/admin-api/water/reading") @Tag(name = "管理后台 - 抄表管理") -@Validated public class MeterReadingController { - @Resource - private MeterReadingService readingService; - @PostMapping("/create") @Operation(summary = "创建抄表记录") - @PreAuthorize("@ss.hasPermission('water:reading:create')") - public CommonResult createReading(@Valid @RequestBody MeterReadingSaveReqVO createReqVO) { - return success(readingService.createReading(createReqVO)); - } + public CommonResult createReading(@Valid @RequestBody MeterReadingSaveReqVO createReqVO); @PostMapping("/batch-create") @Operation(summary = "批量创建抄表记录") - @PreAuthorize("@ss.hasPermission('water:reading:create')") - public CommonResult batchCreateReading( - @Valid @RequestBody MeterReadingBatchReqVO batchReqVO) { - return success(readingService.batchCreateReading(batchReqVO)); - } + public CommonResult batchCreateReading(@Valid @RequestBody MeterReadingBatchReqVO batchReqVO); @PostMapping("/review") @Operation(summary = "抄表数据复核") - @PreAuthorize("@ss.hasPermission('water:reading:review')") - public CommonResult reviewReading(@Valid @RequestBody MeterReadingReviewReqVO reviewReqVO) { - readingService.reviewReading(reviewReqVO); - return success(true); - } + public CommonResult reviewReading(@Valid @RequestBody MeterReadingReviewReqVO reviewReqVO); @PostMapping("/generate-bill") @Operation(summary = "生成账单") - @PreAuthorize("@ss.hasPermission('water:reading:bill')") - public CommonResult generateBill(@Valid @RequestBody ReadingBillReqVO reqVO) { - return success(readingService.generateBill(reqVO)); - } + public CommonResult generateBill(@Valid @RequestBody ReadingBillReqVO reqVO); } ``` -**抄表业务Service层**: -```java -@Service -@Validated -@Slf4j -public class MeterReadingServiceImpl implements MeterReadingService { - - @Resource - private MeterReadingMapper readingMapper; - @Resource - private MeterService meterService; - @Resource - private BillService billService; - @Resource - private WaterPriceService priceService; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createReading(MeterReadingSaveReqVO createReqVO) { - // 1. 校验水表存在性 - MeterDO meter = meterService.validateMeterExists(createReqVO.getMeterId()); - - // 2. 校验读数合理性 - validateReadingValue(createReqVO); - - // 3. 创建抄表记录 - MeterReadingDO reading = BeanUtils.toBean(createReqVO, MeterReadingDO.class); - reading.setReadingCode(generateReadingCode()); - reading.setCustomerId(meter.getCustomerId()); - - // 4. 计算用水量 - BigDecimal waterUsage = calculateWaterUsage(meter.getCurrentReading(), - createReqVO.getReadingValue()); - reading.setWaterUsage(waterUsage); - reading.setReadingStatus(READING_STATUS_PENDING); - - readingMapper.insert(reading); - - // 5. 更新水表当前读数 - meterService.updateCurrentReading(createReqVO.getMeterId(), - createReqVO.getReadingValue()); - - // 6. 记录操作日志 - logReadingOperation(reading.getId(), "创建抄表记录", createReqVO.toString()); - - return reading.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public MeterReadingBatchRespVO batchCreateReading(MeterReadingBatchReqVO batchReqVO) { - MeterReadingBatchRespVO result = new MeterReadingBatchRespVO(); - List successList = new ArrayList<>(); - List failureList = new ArrayList<>(); - - for (MeterReadingSaveReqVO item : batchReqVO.getReadingList()) { - try { - Long readingId = createReading(item); - successList.add(buildSuccessDetail(readingId, item)); - } catch (Exception e) { - log.error("批量抄表失败,水表ID:{}", item.getMeterId(), e); - failureList.add(buildFailureDetail(item, e.getMessage())); - } - } - - result.setSuccessCount(successList.size()); - result.setFailureCount(failureList.size()); - result.setSuccessList(successList); - result.setFailureList(failureList); - - return result; - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void reviewReading(MeterReadingReviewReqVO reviewReqVO) { - // 1. 获取抄表记录 - MeterReadingDO reading = validateReadingExists(reviewReqVO.getReadingId()); - - // 2. 校验状态 - if (!READING_STATUS_PENDING.equals(reading.getReadingStatus())) { - throw exception(READING_STATUS_INVALID); - } - - // 3. 处理复核结果 - if (reviewReqVO.getReviewResult()) { - // 复核通过 - reading.setReadingStatus(READING_STATUS_REVIEWED); - reading.setReviewRemark(reviewReqVO.getReviewRemark()); - } else { - // 复核退回 - reading.setReadingStatus(READING_STATUS_REJECTED); - reading.setReviewRemark(reviewReqVO.getReviewRemark()); - } - - reading.setReviewerId(reviewReqVO.getReviewerId()); - reading.setReviewTime(LocalDateTime.now()); - - readingMapper.updateById(reading); - - // 4. 记录操作日志 - logReadingOperation(reading.getId(), "数据复核", - "复核结果:" + reviewReqVO.getReviewResult() + ",备注:" + reviewReqVO.getReviewRemark()); - } - - private void validateReadingValue(MeterReadingSaveReqVO reqVO) { - // 获取上次读数 - MeterReadingDO lastReading = readingMapper.selectLastReadingByMeterId(reqVO.getMeterId()); - - if (lastReading != null) { - BigDecimal lastValue = lastReading.getReadingValue(); - BigDecimal currentValue = reqVO.getReadingValue(); - - // 检查读数倒退 - if (currentValue.compareTo(lastValue) < 0) { - throw exception(READING_VALUE_BACKWARD, lastValue, currentValue); - } - - // 检查用量异常(超过最大用量限制) - BigDecimal usage = currentValue.subtract(lastValue); - if (usage.compareTo(new BigDecimal("1000")) > 0) { - throw exception(READING_USAGE_ABNORMAL, usage); - } - } - } - - private BigDecimal calculateWaterUsage(BigDecimal prevReading, BigDecimal currentReading) { - if (prevReading == null) { - return BigDecimal.ZERO; - } - - BigDecimal usage = currentReading.subtract(prevReading); - return usage.max(BigDecimal.ZERO); // 确保用量不为负数 - } -} +**核心业务逻辑**: +- 抄表数据校验:读数合理性检查、用量异常检测 +- 批量处理机制:支持批量抄表录入和结果反馈 +- 数据复核流程:多级审核机制确保数据质量 +- 账单生成:基于抄表数据自动计算费用并生成账单 + +#### 3.2.4 前端界面设计 + +**抄表管理页面结构**: +```vue + ``` -**Entity实体层**: -```java -@TableName("water_meter_reading") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class MeterReadingDO extends BaseDO { - - @TableId(value = "id", type = IdType.ASSIGN_ID) - private Long id; - - @Schema(description = "抄表记录编号", requiredMode = Schema.RequiredMode.REQUIRED) - private String readingCode; - - @Schema(description = "抄表日期", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDate readingDate; - - @Schema(description = "抄表时间") - private LocalDateTime readingTime; - - @Schema(description = "抄表读数", requiredMode = Schema.RequiredMode.REQUIRED) - private BigDecimal readingValue; - - @Schema(description = "上次读数") - private BigDecimal prevReadingValue; - - @Schema(description = "用水量", requiredMode = Schema.RequiredMode.REQUIRED) - private BigDecimal waterUsage; - - @Schema(description = "抄表类型", requiredMode = Schema.RequiredMode.REQUIRED) - private String readingType; - - @Schema(description = "抄表方式") - private String readingMethod; - - @Schema(description = "抄表员ID") - private String readerId; - - @Schema(description = "抄表员姓名") - private String readerName; - - @Schema(description = "抄表照片URL") - private String photoUrl; - - @Schema(description = "抄表位置") - private String readingLocation; - - @Schema(description = "异常标识") - private Boolean abnormalFlag; - - @Schema(description = "异常原因") - private String abnormalReason; - - @Schema(description = "备注") - private String remark; - - @Schema(description = "抄表状态", requiredMode = Schema.RequiredMode.REQUIRED) - private Integer readingStatus; - - @Schema(description = "复核人ID") - private String reviewerId; - - @Schema(description = "复核时间") - private LocalDateTime reviewTime; - - @Schema(description = "复核备注") - private String reviewRemark; - - @Schema(description = "水表ID", requiredMode = Schema.RequiredMode.REQUIRED) - private Long meterId; - - @Schema(description = "客户ID", requiredMode = Schema.RequiredMode.REQUIRED) - private Long customerId; -} -``` - -#### 3.2.4 前端Vue3代码实现 - -**抄表记录Controller层**: -```java -@RestController -@RequestMapping("/admin-api/water/reading") -@Tag(name = "管理后台 - 抄表管理") -@Validated -public class MeterReadingController { - - @Resource - private MeterReadingService readingService; - - @PostMapping("/create") - @Operation(summary = "创建抄表记录") - @PreAuthorize("@ss.hasPermission('water:reading:create')") - public CommonResult createReading(@Valid @RequestBody MeterReadingSaveReqVO createReqVO) { - return success(readingService.createReading(createReqVO)); - } - - @PostMapping("/batch-create") - @Operation(summary = "批量创建抄表记录") - @PreAuthorize("@ss.hasPermission('water:reading:create')") - public CommonResult batchCreateReading( - @Valid @RequestBody MeterReadingBatchReqVO batchReqVO) { - return success(readingService.batchCreateReading(batchReqVO)); - } - - @PostMapping("/review") - @Operation(summary = "抄表数据复核") - @PreAuthorize("@ss.hasPermission('water:reading:review')") - public CommonResult reviewReading(@Valid @RequestBody MeterReadingReviewReqVO reviewReqVO) { - readingService.reviewReading(reviewReqVO); - return success(true); - } - - @PostMapping("/generate-bill") - @Operation(summary = "生成账单") - @PreAuthorize("@ss.hasPermission('water:reading:bill')") - public CommonResult generateBill(@Valid @RequestBody ReadingBillReqVO reqVO) { - return success(readingService.generateBill(reqVO)); - } -} -``` - -**抄表业务Service层**: -```java -@Service -@Validated -@Slf4j -public class MeterReadingServiceImpl implements MeterReadingService { - - @Resource - private MeterReadingMapper readingMapper; - @Resource - private MeterService meterService; - @Resource - private BillService billService; - @Resource - private WaterPriceService priceService; - - @Override - @Transactional(rollbackFor = Exception.class) - public Long createReading(MeterReadingSaveReqVO createReqVO) { - // 1. 校验水表存在性 - MeterDO meter = meterService.validateMeterExists(createReqVO.getMeterId()); - - // 2. 校验读数合理性 - validateReadingValue(createReqVO); - - // 3. 创建抄表记录 - MeterReadingDO reading = BeanUtils.toBean(createReqVO, MeterReadingDO.class); - reading.setReadingCode(generateReadingCode()); - reading.setCustomerId(meter.getCustomerId()); - - // 4. 计算用水量 - BigDecimal waterUsage = calculateWaterUsage(meter.getCurrentReading(), - createReqVO.getReadingValue()); - reading.setWaterUsage(waterUsage); - reading.setReadingStatus(READING_STATUS_PENDING); - - readingMapper.insert(reading); - - // 5. 更新水表当前读数 - meterService.updateCurrentReading(createReqVO.getMeterId(), - createReqVO.getReadingValue()); - - // 6. 记录操作日志 - logReadingOperation(reading.getId(), "创建抄表记录", createReqVO.toString()); - - return reading.getId(); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public MeterReadingBatchRespVO batchCreateReading(MeterReadingBatchReqVO batchReqVO) { - MeterReadingBatchRespVO result = new MeterReadingBatchRespVO(); - List successList = new ArrayList<>(); - List failureList = new ArrayList<>(); - - for (MeterReadingSaveReqVO item : batchReqVO.getReadingList()) { - try { - Long readingId = createReading(item); - successList.add(buildSuccessDetail(readingId, item)); - } catch (Exception e) { - log.error("批量抄表失败,水表ID:{}", item.getMeterId(), e); - failureList.add(buildFailureDetail(item, e.getMessage())); - } - } - - result.setSuccessCount(successList.size()); - result.setFailureCount(failureList.size()); - result.setSuccessList(successList); - result.setFailureList(failureList); - - return result; - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void reviewReading(MeterReadingReviewReqVO reviewReqVO) { - // 1. 获取抄表记录 - MeterReadingDO reading = validateReadingExists(reviewReqVO.getReadingId()); - - // 2. 校验状态 - if (!READING_STATUS_PENDING.equals(reading.getReadingStatus())) { - throw exception(READING_STATUS_INVALID); - } - - // 3. 处理复核结果 - if (reviewReqVO.getReviewResult()) { - // 复核通过 - reading.setReadingStatus(READING_STATUS_REVIEWED); - reading.setReviewRemark(reviewReqVO.getReviewRemark()); - } else { - // 复核退回 - reading.setReadingStatus(READING_STATUS_REJECTED); - reading.setReviewRemark(reviewReqVO.getReviewRemark()); - } - - reading.setReviewerId(reviewReqVO.getReviewerId()); - reading.setReviewTime(LocalDateTime.now()); - - readingMapper.updateById(reading); - - // 4. 记录操作日志 - logReadingOperation(reading.getId(), "数据复核", - "复核结果:" + reviewReqVO.getReviewResult() + ",备注:" + reviewReqVO.getReviewRemark()); - } - - private void validateReadingValue(MeterReadingSaveReqVO reqVO) { - // 获取上次读数 - MeterReadingDO lastReading = readingMapper.selectLastReadingByMeterId(reqVO.getMeterId()); - - if (lastReading != null) { - BigDecimal lastValue = lastReading.getReadingValue(); - BigDecimal currentValue = reqVO.getReadingValue(); - - // 检查读数倒退 - if (currentValue.compareTo(lastValue) < 0) { - throw exception(READING_VALUE_BACKWARD, lastValue, currentValue); - } - - // 检查用量异常(超过最大用量限制) - BigDecimal usage = currentValue.subtract(lastValue); - if (usage.compareTo(new BigDecimal("1000")) > 0) { - throw exception(READING_USAGE_ABNORMAL, usage); - } - } - } - - private BigDecimal calculateWaterUsage(BigDecimal prevReading, BigDecimal currentReading) { - if (prevReading == null) { - return BigDecimal.ZERO; - } - - BigDecimal usage = currentReading.subtract(prevReading); - return usage.max(BigDecimal.ZERO); // 确保用量不为负数 - } -} -``` - -**Entity实体层**: -```java -@TableName("water_meter_reading") -@Data -@EqualsAndHashCode(callSuper = true) -@ToString(callSuper = true) -@Builder -@NoArgsConstructor -@AllArgsConstructor -public class MeterReadingDO extends BaseDO { - - @TableId(value = "id", type = IdType.ASSIGN_ID) - private Long id; - - @Schema(description = "抄表记录编号", requiredMode = Schema.RequiredMode.REQUIRED) - private String readingCode; - - @Schema(description = "抄表日期", requiredMode = Schema.RequiredMode.REQUIRED) - private LocalDate readingDate; - - @Schema(description = "抄表时间") - private LocalDateTime readingTime; - - @Schema(description = "抄表读数", requiredMode = Schema.RequiredMode.REQUIRED) - private BigDecimal readingValue; - - @Schema(description = "上次读数") - private BigDecimal prevReadingValue; - - @Schema(description = "用水量", requiredMode = Schema.RequiredMode.REQUIRED) - private BigDecimal waterUsage; - - @Schema(description = "抄表类型", requiredMode = Schema.RequiredMode.REQUIRED) - private String readingType; - - @Schema(description = "抄表方式") - private String readingMethod; - - @Schema(description = "抄表员ID") - private String readerId; - - @Schema(description = "抄表员姓名") - private String readerName; - - @Schema(description = "抄表照片URL") - private String photoUrl; - - @Schema(description = "抄表位置") - private String readingLocation; - - @Schema(description = "异常标识") - private Boolean abnormalFlag; - - @Schema(description = "异常原因") - private String abnormalReason; - - @Schema(description = "备注") - private String remark; - - @Schema(description = "抄表状态", requiredMode = Schema.RequiredMode.REQUIRED) - private Integer readingStatus; - - @Schema(description = "复核人ID") - private String reviewerId; - - @Schema(description = "复核时间") - private LocalDateTime reviewTime; - - @Schema(description = "复核备注") - private String reviewRemark; - - @Schema(description = "水表ID", requiredMode = Schema.RequiredMode.REQUIRED) - private Long meterId; - - @Schema(description = "客户ID", requiredMode = Schema.RequiredMode.REQUIRED) - private Long customerId; -} -``` +**前端页面功能特性**: +- 响应式设计:基于Element Plus的现代化UI组件 +- 数据表格:支持分页、排序、筛选等功能 +- 表单验证:前端数据校验和错误提示 +- 批量操作:支持批量抄表录入和批量审核 +- 实时更新:页面数据实时刷新和状态同步 ### 3.3 收费管理 @@ -1088,54 +661,30 @@ flowchart TD - 统计分析:缴费趋势、渠道分析 - 导出功能:缴费记录导出 -#### 3.3.3 RuoYi-Vue-Pro代码实现 +#### 3.3.3 核心接口定义 -**缴费Controller层**: +**缴费管理主要接口**: ```java @RestController @RequestMapping("/admin-api/water/payment") @Tag(name = "管理后台 - 缴费管理") -@Validated public class PaymentController { - @Resource - private PaymentService paymentService; - @PostMapping("/create") @Operation(summary = "创建缴费记录") - @PreAuthorize("@ss.hasPermission('water:payment:create')") - public CommonResult createPayment(@Valid @RequestBody PaymentCreateReqVO createReqVO) { - return success(paymentService.createPayment(createReqVO)); - } + public CommonResult createPayment(@Valid @RequestBody PaymentCreateReqVO createReqVO); @PostMapping("/cash-payment") @Operation(summary = "现金缴费") - @PreAuthorize("@ss.hasPermission('water:payment:cash')") - public CommonResult cashPayment(@Valid @RequestBody CashPaymentReqVO cashReqVO) { - return success(paymentService.processCashPayment(cashReqVO)); - } + public CommonResult cashPayment(@Valid @RequestBody CashPaymentReqVO cashReqVO); @PostMapping("/online-payment") @Operation(summary = "在线支付") - @PreAuthorize("@ss.hasPermission('water:payment:online')") - public CommonResult onlinePayment(@Valid @RequestBody OnlinePaymentReqVO onlineReqVO) { - return success(paymentService.processOnlinePayment(onlineReqVO)); - } + public CommonResult onlinePayment(@Valid @RequestBody OnlinePaymentReqVO onlineReqVO); @PostMapping("/prepaid-payment") @Operation(summary = "预存款缴费") - @PreAuthorize("@ss.hasPermission('water:payment:prepaid')") - public CommonResult prepaidPayment(@Valid @RequestBody PrepaidPaymentReqVO prepaidReqVO) { - return success(paymentService.processPrepaidPayment(prepaidReqVO)); - } - - @PostMapping("/refund") - @Operation(summary = "退费处理") - @PreAuthorize("@ss.hasPermission('water:payment:refund')") - public CommonResult refundPayment(@Valid @RequestBody PaymentRefundReqVO refundReqVO) { - paymentService.refundPayment(refundReqVO); - return success(true); - } + public CommonResult prepaidPayment(@Valid @RequestBody PrepaidPaymentReqVO prepaidReqVO); } ``` @@ -1318,55 +867,49 @@ public class PaymentServiceImpl implements PaymentService { } ``` -#### 3.3.4 前端Vue3代码实现 +#### 3.3.4 前端界面设计 -**缴费Controller层**: -```java -@RestController -@RequestMapping("/admin-api/water/payment") -@Tag(name = "管理后台 - 缴费管理") -@Validated -public class PaymentController { - - @Resource - private PaymentService paymentService; - - @PostMapping("/create") - @Operation(summary = "创建缴费记录") - @PreAuthorize("@ss.hasPermission('water:payment:create')") - public CommonResult createPayment(@Valid @RequestBody PaymentCreateReqVO createReqVO) { - return success(paymentService.createPayment(createReqVO)); - } - - @PostMapping("/cash-payment") - @Operation(summary = "现金缴费") - @PreAuthorize("@ss.hasPermission('water:payment:cash')") - public CommonResult cashPayment(@Valid @RequestBody CashPaymentReqVO cashReqVO) { - return success(paymentService.processCashPayment(cashReqVO)); - } - - @PostMapping("/online-payment") - @Operation(summary = "在线支付") - @PreAuthorize("@ss.hasPermission('water:payment:online')") - public CommonResult onlinePayment(@Valid @RequestBody OnlinePaymentReqVO onlineReqVO) { - return success(paymentService.processOnlinePayment(onlineReqVO)); - } - - @PostMapping("/prepaid-payment") - @Operation(summary = "预存款缴费") - @PreAuthorize("@ss.hasPermission('water:payment:prepaid')") - public CommonResult prepaidPayment(@Valid @RequestBody PrepaidPaymentReqVO prepaidReqVO) { - return success(paymentService.processPrepaidPayment(prepaidReqVO)); - } - - @PostMapping("/refund") - @Operation(summary = "退费处理") - @PreAuthorize("@ss.hasPermission('water:payment:refund')") - public CommonResult refundPayment(@Valid @RequestBody PaymentRefundReqVO refundReqVO) { - paymentService.refundPayment(refundReqVO); - return success(true); - } -} +**缴费管理页面结构**: +```vue + ``` **缴费Service层**: