更新福建水务营收系统项目管理文档,调整模块设计文档的状态为修复中,完成度提升至95%,质量评级调整为B+级。修正模块设计文档中的代码示例,替换为核心接口定义和前端界面设计,确保文档内容符合甲方A级交付标准,提升信息的完整性和一致性。
This commit is contained in:
parent
e8413119b0
commit
da49f93abe
@ -18,7 +18,7 @@
|
|||||||
| 文档名称 | 状态 | 完成度 | 质量评级 | 最后更新 | 备注 |
|
| 文档名称 | 状态 | 完成度 | 质量评级 | 最后更新 | 备注 |
|
||||||
|---------|------|--------|----------|----------|------|
|
|---------|------|--------|----------|----------|------|
|
||||||
| `water_biz_system_architecture.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已全面适配OpenGauss,架构图完整 |
|
| `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_database_design.md` | ✅ 已完成 | 100% | A+级 | 2024-12-19 | 已适配OpenGauss,完整DDL和安全设计 |
|
||||||
| `water_biz_interface_design.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已补充详细接口参数、代码示例和安全设计 |
|
| `water_biz_interface_design.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已补充详细接口参数、代码示例和安全设计 |
|
||||||
| `water_biz_deployment_design.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已补充容器化部署方案和自动化脚本 |
|
| `water_biz_deployment_design.md` | ✅ 已完成 | 100% | A级 | 2024-12-19 | 已补充容器化部署方案和自动化脚本 |
|
||||||
|
|||||||
@ -26,13 +26,13 @@
|
|||||||
- [3.2 抄表开账](#32-抄表开账)
|
- [3.2 抄表开账](#32-抄表开账)
|
||||||
- [3.2.1 业务流程图](#321-业务流程图)
|
- [3.2.1 业务流程图](#321-业务流程图)
|
||||||
- [3.2.2 主要功能](#322-主要功能)
|
- [3.2.2 主要功能](#322-主要功能)
|
||||||
- [3.2.3 RuoYi-Vue-Pro代码实现](#323-ruoyi-vue-pro代码实现)
|
- [3.2.3 核心接口定义](#323-核心接口定义)
|
||||||
- [3.2.4 前端Vue3代码实现](#324-前端vue3代码实现)
|
- [3.2.4 前端界面设计](#324-前端界面设计)
|
||||||
- [3.3 收费管理](#33-收费管理)
|
- [3.3 收费管理](#33-收费管理)
|
||||||
- [3.3.1 业务流程图](#331-业务流程图)
|
- [3.3.1 业务流程图](#331-业务流程图)
|
||||||
- [3.3.2 主要功能](#332-主要功能)
|
- [3.3.2 主要功能](#332-主要功能)
|
||||||
- [3.3.3 RuoYi-Vue-Pro代码实现](#333-ruoyi-vue-pro代码实现)
|
- [3.3.3 核心接口定义](#333-核心接口定义)
|
||||||
- [3.3.4 前端Vue3代码实现](#334-前端vue3代码实现)
|
- [3.3.4 前端界面设计](#334-前端界面设计)
|
||||||
- [3.4 账务处理](#34-账务处理)
|
- [3.4 账务处理](#34-账务处理)
|
||||||
- [3.5 发票管理](#35-发票管理)
|
- [3.5 发票管理](#35-发票管理)
|
||||||
- [3.6 代收业务](#36-代收业务)
|
- [3.6 代收业务](#36-代收业务)
|
||||||
@ -488,527 +488,100 @@ flowchart TD
|
|||||||
- 特殊抄表:临时抄表需求
|
- 特殊抄表:临时抄表需求
|
||||||
- 调整抄表:读数错误修正
|
- 调整抄表:读数错误修正
|
||||||
|
|
||||||
#### 3.2.3 RuoYi-Vue-Pro代码实现
|
#### 3.2.3 核心接口定义
|
||||||
|
|
||||||
**抄表记录Controller层**:
|
**抄表管理主要接口**:
|
||||||
```java
|
```java
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/admin-api/water/reading")
|
@RequestMapping("/admin-api/water/reading")
|
||||||
@Tag(name = "管理后台 - 抄表管理")
|
@Tag(name = "管理后台 - 抄表管理")
|
||||||
@Validated
|
|
||||||
public class MeterReadingController {
|
public class MeterReadingController {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MeterReadingService readingService;
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建抄表记录")
|
@Operation(summary = "创建抄表记录")
|
||||||
@PreAuthorize("@ss.hasPermission('water:reading:create')")
|
public CommonResult<Long> createReading(@Valid @RequestBody MeterReadingSaveReqVO createReqVO);
|
||||||
public CommonResult<Long> createReading(@Valid @RequestBody MeterReadingSaveReqVO createReqVO) {
|
|
||||||
return success(readingService.createReading(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/batch-create")
|
@PostMapping("/batch-create")
|
||||||
@Operation(summary = "批量创建抄表记录")
|
@Operation(summary = "批量创建抄表记录")
|
||||||
@PreAuthorize("@ss.hasPermission('water:reading:create')")
|
public CommonResult<MeterReadingBatchRespVO> batchCreateReading(@Valid @RequestBody MeterReadingBatchReqVO batchReqVO);
|
||||||
public CommonResult<MeterReadingBatchRespVO> batchCreateReading(
|
|
||||||
@Valid @RequestBody MeterReadingBatchReqVO batchReqVO) {
|
|
||||||
return success(readingService.batchCreateReading(batchReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/review")
|
@PostMapping("/review")
|
||||||
@Operation(summary = "抄表数据复核")
|
@Operation(summary = "抄表数据复核")
|
||||||
@PreAuthorize("@ss.hasPermission('water:reading:review')")
|
public CommonResult<Boolean> reviewReading(@Valid @RequestBody MeterReadingReviewReqVO reviewReqVO);
|
||||||
public CommonResult<Boolean> reviewReading(@Valid @RequestBody MeterReadingReviewReqVO reviewReqVO) {
|
|
||||||
readingService.reviewReading(reviewReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/generate-bill")
|
@PostMapping("/generate-bill")
|
||||||
@Operation(summary = "生成账单")
|
@Operation(summary = "生成账单")
|
||||||
@PreAuthorize("@ss.hasPermission('water:reading:bill')")
|
public CommonResult<BillGenerateRespVO> generateBill(@Valid @RequestBody ReadingBillReqVO reqVO);
|
||||||
public CommonResult<BillGenerateRespVO> generateBill(@Valid @RequestBody ReadingBillReqVO reqVO) {
|
|
||||||
return success(readingService.generateBill(reqVO));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
**抄表业务Service层**:
|
**核心业务逻辑**:
|
||||||
```java
|
- 抄表数据校验:读数合理性检查、用量异常检测
|
||||||
@Service
|
- 批量处理机制:支持批量抄表录入和结果反馈
|
||||||
@Validated
|
- 数据复核流程:多级审核机制确保数据质量
|
||||||
@Slf4j
|
- 账单生成:基于抄表数据自动计算费用并生成账单
|
||||||
public class MeterReadingServiceImpl implements MeterReadingService {
|
|
||||||
|
#### 3.2.4 前端界面设计
|
||||||
@Resource
|
|
||||||
private MeterReadingMapper readingMapper;
|
**抄表管理页面结构**:
|
||||||
@Resource
|
```vue
|
||||||
private MeterService meterService;
|
<template>
|
||||||
@Resource
|
<ContentWrap>
|
||||||
private BillService billService;
|
<!-- 查询条件 -->
|
||||||
@Resource
|
<el-form class="search-form" inline>
|
||||||
private WaterPriceService priceService;
|
<el-form-item label="抄表日期">
|
||||||
|
<el-date-picker v-model="queryParams.readingDate" type="daterange" />
|
||||||
@Override
|
</el-form-item>
|
||||||
@Transactional(rollbackFor = Exception.class)
|
<el-form-item label="抄表状态">
|
||||||
public Long createReading(MeterReadingSaveReqVO createReqVO) {
|
<el-select v-model="queryParams.status">
|
||||||
// 1. 校验水表存在性
|
<el-option label="待复核" value="pending" />
|
||||||
MeterDO meter = meterService.validateMeterExists(createReqVO.getMeterId());
|
<el-option label="已通过" value="approved" />
|
||||||
|
</el-select>
|
||||||
// 2. 校验读数合理性
|
</el-form-item>
|
||||||
validateReadingValue(createReqVO);
|
<el-form-item>
|
||||||
|
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||||
// 3. 创建抄表记录
|
<el-button @click="resetQuery">重置</el-button>
|
||||||
MeterReadingDO reading = BeanUtils.toBean(createReqVO, MeterReadingDO.class);
|
</el-form-item>
|
||||||
reading.setReadingCode(generateReadingCode());
|
</el-form>
|
||||||
reading.setCustomerId(meter.getCustomerId());
|
|
||||||
|
<!-- 操作按钮 -->
|
||||||
// 4. 计算用水量
|
<el-row class="mb-10px">
|
||||||
BigDecimal waterUsage = calculateWaterUsage(meter.getCurrentReading(),
|
<el-button type="primary" @click="handleAdd">新增抄表</el-button>
|
||||||
createReqVO.getReadingValue());
|
<el-button type="success" @click="handleBatchAdd">批量抄表</el-button>
|
||||||
reading.setWaterUsage(waterUsage);
|
<el-button type="warning" @click="handleExport">导出数据</el-button>
|
||||||
reading.setReadingStatus(READING_STATUS_PENDING);
|
</el-row>
|
||||||
|
|
||||||
readingMapper.insert(reading);
|
<!-- 数据表格 -->
|
||||||
|
<el-table v-loading="loading" :data="readingList">
|
||||||
// 5. 更新水表当前读数
|
<el-table-column prop="readingCode" label="抄表编号" width="180" />
|
||||||
meterService.updateCurrentReading(createReqVO.getMeterId(),
|
<el-table-column prop="customerName" label="客户名称" />
|
||||||
createReqVO.getReadingValue());
|
<el-table-column prop="meterCode" label="水表编号" />
|
||||||
|
<el-table-column prop="readingValue" label="本次读数" />
|
||||||
// 6. 记录操作日志
|
<el-table-column prop="waterUsage" label="用水量" />
|
||||||
logReadingOperation(reading.getId(), "创建抄表记录", createReqVO.toString());
|
<el-table-column prop="readingDate" label="抄表日期" />
|
||||||
|
<el-table-column prop="status" label="状态">
|
||||||
return reading.getId();
|
<template #default="{ row }">
|
||||||
}
|
<dict-tag :type="DICT_TYPE.READING_STATUS" :value="row.status" />
|
||||||
|
</template>
|
||||||
@Override
|
</el-table-column>
|
||||||
@Transactional(rollbackFor = Exception.class)
|
<el-table-column label="操作" width="200" fixed="right">
|
||||||
public MeterReadingBatchRespVO batchCreateReading(MeterReadingBatchReqVO batchReqVO) {
|
<template #default="{ row }">
|
||||||
MeterReadingBatchRespVO result = new MeterReadingBatchRespVO();
|
<el-button link @click="handleUpdate(row)">编辑</el-button>
|
||||||
List<MeterReadingDetailVO> successList = new ArrayList<>();
|
<el-button link @click="handleReview(row)">复核</el-button>
|
||||||
List<MeterReadingDetailVO> failureList = new ArrayList<>();
|
<el-button link type="danger" @click="handleDelete(row)">删除</el-button>
|
||||||
|
</template>
|
||||||
for (MeterReadingSaveReqVO item : batchReqVO.getReadingList()) {
|
</el-table-column>
|
||||||
try {
|
</el-table>
|
||||||
Long readingId = createReading(item);
|
</ContentWrap>
|
||||||
successList.add(buildSuccessDetail(readingId, item));
|
</template>
|
||||||
} 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
|
- 响应式设计:基于Element Plus的现代化UI组件
|
||||||
@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<Long> createReading(@Valid @RequestBody MeterReadingSaveReqVO createReqVO) {
|
|
||||||
return success(readingService.createReading(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/batch-create")
|
|
||||||
@Operation(summary = "批量创建抄表记录")
|
|
||||||
@PreAuthorize("@ss.hasPermission('water:reading:create')")
|
|
||||||
public CommonResult<MeterReadingBatchRespVO> batchCreateReading(
|
|
||||||
@Valid @RequestBody MeterReadingBatchReqVO batchReqVO) {
|
|
||||||
return success(readingService.batchCreateReading(batchReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/review")
|
|
||||||
@Operation(summary = "抄表数据复核")
|
|
||||||
@PreAuthorize("@ss.hasPermission('water:reading:review')")
|
|
||||||
public CommonResult<Boolean> reviewReading(@Valid @RequestBody MeterReadingReviewReqVO reviewReqVO) {
|
|
||||||
readingService.reviewReading(reviewReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/generate-bill")
|
|
||||||
@Operation(summary = "生成账单")
|
|
||||||
@PreAuthorize("@ss.hasPermission('water:reading:bill')")
|
|
||||||
public CommonResult<BillGenerateRespVO> 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<MeterReadingDetailVO> successList = new ArrayList<>();
|
|
||||||
List<MeterReadingDetailVO> 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;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3.3 收费管理
|
### 3.3 收费管理
|
||||||
|
|
||||||
@ -1088,54 +661,30 @@ flowchart TD
|
|||||||
- 统计分析:缴费趋势、渠道分析
|
- 统计分析:缴费趋势、渠道分析
|
||||||
- 导出功能:缴费记录导出
|
- 导出功能:缴费记录导出
|
||||||
|
|
||||||
#### 3.3.3 RuoYi-Vue-Pro代码实现
|
#### 3.3.3 核心接口定义
|
||||||
|
|
||||||
**缴费Controller层**:
|
**缴费管理主要接口**:
|
||||||
```java
|
```java
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/admin-api/water/payment")
|
@RequestMapping("/admin-api/water/payment")
|
||||||
@Tag(name = "管理后台 - 缴费管理")
|
@Tag(name = "管理后台 - 缴费管理")
|
||||||
@Validated
|
|
||||||
public class PaymentController {
|
public class PaymentController {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private PaymentService paymentService;
|
|
||||||
|
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
@Operation(summary = "创建缴费记录")
|
@Operation(summary = "创建缴费记录")
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:create')")
|
public CommonResult<PaymentRespVO> createPayment(@Valid @RequestBody PaymentCreateReqVO createReqVO);
|
||||||
public CommonResult<PaymentRespVO> createPayment(@Valid @RequestBody PaymentCreateReqVO createReqVO) {
|
|
||||||
return success(paymentService.createPayment(createReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/cash-payment")
|
@PostMapping("/cash-payment")
|
||||||
@Operation(summary = "现金缴费")
|
@Operation(summary = "现金缴费")
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:cash')")
|
public CommonResult<PaymentRespVO> cashPayment(@Valid @RequestBody CashPaymentReqVO cashReqVO);
|
||||||
public CommonResult<PaymentRespVO> cashPayment(@Valid @RequestBody CashPaymentReqVO cashReqVO) {
|
|
||||||
return success(paymentService.processCashPayment(cashReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/online-payment")
|
@PostMapping("/online-payment")
|
||||||
@Operation(summary = "在线支付")
|
@Operation(summary = "在线支付")
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:online')")
|
public CommonResult<OnlinePaymentRespVO> onlinePayment(@Valid @RequestBody OnlinePaymentReqVO onlineReqVO);
|
||||||
public CommonResult<OnlinePaymentRespVO> onlinePayment(@Valid @RequestBody OnlinePaymentReqVO onlineReqVO) {
|
|
||||||
return success(paymentService.processOnlinePayment(onlineReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/prepaid-payment")
|
@PostMapping("/prepaid-payment")
|
||||||
@Operation(summary = "预存款缴费")
|
@Operation(summary = "预存款缴费")
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:prepaid')")
|
public CommonResult<PaymentRespVO> prepaidPayment(@Valid @RequestBody PrepaidPaymentReqVO prepaidReqVO);
|
||||||
public CommonResult<PaymentRespVO> prepaidPayment(@Valid @RequestBody PrepaidPaymentReqVO prepaidReqVO) {
|
|
||||||
return success(paymentService.processPrepaidPayment(prepaidReqVO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/refund")
|
|
||||||
@Operation(summary = "退费处理")
|
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:refund')")
|
|
||||||
public CommonResult<Boolean> refundPayment(@Valid @RequestBody PaymentRefundReqVO refundReqVO) {
|
|
||||||
paymentService.refundPayment(refundReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -1318,55 +867,49 @@ public class PaymentServiceImpl implements PaymentService {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3.3.4 前端Vue3代码实现
|
#### 3.3.4 前端界面设计
|
||||||
|
|
||||||
**缴费Controller层**:
|
**缴费管理页面结构**:
|
||||||
```java
|
```vue
|
||||||
@RestController
|
<template>
|
||||||
@RequestMapping("/admin-api/water/payment")
|
<ContentWrap>
|
||||||
@Tag(name = "管理后台 - 缴费管理")
|
<!-- 客户查询 -->
|
||||||
@Validated
|
<el-form class="search-form" inline>
|
||||||
public class PaymentController {
|
<el-form-item label="客户编号">
|
||||||
|
<el-input v-model="queryParams.customerCode" placeholder="请输入客户编号" />
|
||||||
@Resource
|
</el-form-item>
|
||||||
private PaymentService paymentService;
|
<el-form-item label="客户姓名">
|
||||||
|
<el-input v-model="queryParams.customerName" placeholder="请输入客户姓名" />
|
||||||
@PostMapping("/create")
|
</el-form-item>
|
||||||
@Operation(summary = "创建缴费记录")
|
<el-form-item>
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:create')")
|
<el-button type="primary" @click="handleQuery">查询</el-button>
|
||||||
public CommonResult<PaymentRespVO> createPayment(@Valid @RequestBody PaymentCreateReqVO createReqVO) {
|
<el-button @click="resetQuery">重置</el-button>
|
||||||
return success(paymentService.createPayment(createReqVO));
|
</el-form-item>
|
||||||
}
|
</el-form>
|
||||||
|
|
||||||
@PostMapping("/cash-payment")
|
<!-- 账单信息 -->
|
||||||
@Operation(summary = "现金缴费")
|
<el-table v-loading="loading" :data="billList" @selection-change="handleSelectionChange">
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:cash')")
|
<el-table-column type="selection" width="55" />
|
||||||
public CommonResult<PaymentRespVO> cashPayment(@Valid @RequestBody CashPaymentReqVO cashReqVO) {
|
<el-table-column prop="billCode" label="账单编号" />
|
||||||
return success(paymentService.processCashPayment(cashReqVO));
|
<el-table-column prop="billDate" label="账期" />
|
||||||
}
|
<el-table-column prop="waterUsage" label="用水量" />
|
||||||
|
<el-table-column prop="totalAmount" label="应缴金额" />
|
||||||
@PostMapping("/online-payment")
|
<el-table-column prop="balanceAmount" label="欠费金额" />
|
||||||
@Operation(summary = "在线支付")
|
</el-table>
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:online')")
|
|
||||||
public CommonResult<OnlinePaymentRespVO> onlinePayment(@Valid @RequestBody OnlinePaymentReqVO onlineReqVO) {
|
<!-- 缴费操作 -->
|
||||||
return success(paymentService.processOnlinePayment(onlineReqVO));
|
<el-row class="payment-actions">
|
||||||
}
|
<el-col :span="12">
|
||||||
|
<el-statistic title="选中金额" :value="selectedAmount" prefix="¥" />
|
||||||
@PostMapping("/prepaid-payment")
|
</el-col>
|
||||||
@Operation(summary = "预存款缴费")
|
<el-col :span="12" class="text-right">
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:prepaid')")
|
<el-button type="success" @click="handleCashPayment">现金缴费</el-button>
|
||||||
public CommonResult<PaymentRespVO> prepaidPayment(@Valid @RequestBody PrepaidPaymentReqVO prepaidReqVO) {
|
<el-button type="primary" @click="handleOnlinePayment">在线支付</el-button>
|
||||||
return success(paymentService.processPrepaidPayment(prepaidReqVO));
|
<el-button type="warning" @click="handlePrepaidPayment">预存扣费</el-button>
|
||||||
}
|
</el-col>
|
||||||
|
</el-row>
|
||||||
@PostMapping("/refund")
|
</ContentWrap>
|
||||||
@Operation(summary = "退费处理")
|
</template>
|
||||||
@PreAuthorize("@ss.hasPermission('water:payment:refund')")
|
|
||||||
public CommonResult<Boolean> refundPayment(@Valid @RequestBody PaymentRefundReqVO refundReqVO) {
|
|
||||||
paymentService.refundPayment(refundReqVO);
|
|
||||||
return success(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**缴费Service层**:
|
**缴费Service层**:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user