mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-08-14 02:03:54 +08:00
534 lines
15 KiB
Markdown
534 lines
15 KiB
Markdown
|
|
# 无交易记录自动结算功能 - 实施总结
|
|||
|
|
|
|||
|
|
## 版本信息
|
|||
|
|
|
|||
|
|
- **功能版本**: v1.0
|
|||
|
|
- **开发分支**: feature/auto-settle-no-transaction
|
|||
|
|
- **提交哈希**: 121b357a2
|
|||
|
|
- **完成日期**: 2026-08-11
|
|||
|
|
- **开发者**: jsowell
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 实施概览
|
|||
|
|
|
|||
|
|
本次开发完成了"无交易记录自动结算"功能的完整实现,包括配置管理、定时任务、核心业务逻辑、幂等保护、数据校验、告警日志和单元测试。
|
|||
|
|
|
|||
|
|
### 开发进度
|
|||
|
|
|
|||
|
|
| 任务 | 状态 | 完成时间 |
|
|||
|
|
|------|------|---------|
|
|||
|
|
| ✅ 配置开关(11个配置项) | 已完成 | 2026-08-11 |
|
|||
|
|
| ✅ 创建配置属性类 | 已完成 | 2026-08-11 |
|
|||
|
|
| ✅ 实时数据→结算数据构造方法 | 已完成 | 2026-08-11 |
|
|||
|
|
| ✅ 待结算订单查询 SQL | 已完成 | 2026-08-11 |
|
|||
|
|
| ✅ 定时任务实现 | 已完成 | 2026-08-11 |
|
|||
|
|
| ✅ 幂等保护(redis锁+乐观锁) | 已完成 | 2026-08-11 |
|
|||
|
|
| ✅ 数据校验与告警日志 | 已完成 | 2026-08-11 |
|
|||
|
|
| ✅ 单元测试 / 集成测试 | 已完成 | 2026-08-11 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 核心实现
|
|||
|
|
|
|||
|
|
### 1. 配置管理
|
|||
|
|
|
|||
|
|
**文件**: `jsowell-pile/src/main/java/com/jsowell/pile/config/AutoSettleConfig.java`
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
@ConfigurationProperties(prefix = "auto-settle")
|
|||
|
|
public class AutoSettleConfig {
|
|||
|
|
private Boolean enabled = false; // 功能总开关
|
|||
|
|
private Integer timeoutMinutes = 10; // 停止超时阈值(分钟)
|
|||
|
|
private String interval = "0 */10 * * * ?"; // 定时任务间隔
|
|||
|
|
private List<Long> grayscaleStationIds; // 灰度站点ID列表
|
|||
|
|
private Integer batchSize = 100; // 单次扫描订单数量上限
|
|||
|
|
private Double amountThresholdRatio = 1.5; // 异常金额阈值比例
|
|||
|
|
private Integer dataFreshnessMinutes = 30; // 实时数据新鲜度阈值(分钟)
|
|||
|
|
private Boolean alertEnabled = true; // 告警开关
|
|||
|
|
private Long lockTimeout = 300L; // Redis锁超时时间(秒)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**配置示例** (application.yml):
|
|||
|
|
```yaml
|
|||
|
|
auto-settle:
|
|||
|
|
enabled: false # 默认关闭,生产环境需手动开启
|
|||
|
|
timeout-minutes: 10
|
|||
|
|
interval: "0 */10 * * * ?"
|
|||
|
|
grayscale-station-ids: [] # 空数组表示全量
|
|||
|
|
batch-size: 100
|
|||
|
|
amount-threshold-ratio: 1.5
|
|||
|
|
data-freshness-minutes: 30
|
|||
|
|
alert-enabled: true
|
|||
|
|
lock-timeout: 300
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 数据转换工具
|
|||
|
|
|
|||
|
|
**文件**: `jsowell-pile/src/main/java/com/jsowell/pile/util/SettlementDataConverter.java`
|
|||
|
|
|
|||
|
|
核心功能:
|
|||
|
|
- 从 `RealTimeMonitorData` 提取充电数据
|
|||
|
|
- 构造 `TransactionRecordsData` 结算数据
|
|||
|
|
- 时间格式转换(Date ↔ String)
|
|||
|
|
- 默认值设置(所有电量归为平段)
|
|||
|
|
|
|||
|
|
### 3. 数据库层
|
|||
|
|
|
|||
|
|
**Mapper 接口**: `OrderBasicInfoMapper.java`
|
|||
|
|
```java
|
|||
|
|
// 查询待结算订单
|
|||
|
|
List<OrderBasicInfo> selectPendingAutoSettleOrders(
|
|||
|
|
@Param("cutoffTime") LocalDateTime cutoffTime,
|
|||
|
|
@Param("stationIds") List<Long> stationIds,
|
|||
|
|
@Param("limit") int limit);
|
|||
|
|
|
|||
|
|
// 乐观锁更新订单
|
|||
|
|
int updateOrderWithOptimisticLock(
|
|||
|
|
@Param("order") OrderBasicInfo order,
|
|||
|
|
@Param("orderId") Integer orderId,
|
|||
|
|
@Param("expectedStatus") String expectedStatus,
|
|||
|
|
@Param("expectedSettlementTime") java.util.Date expectedSettlementTime);
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**SQL 实现**: `OrderBasicInfoMapper.xml`
|
|||
|
|
- 查询条件:del_flag='0', order_status='3', pay_status='1', transaction_code IS NULL/空字符串, charge_end_time < 截止时间
|
|||
|
|
- 灰度过滤:支持按站点ID列表过滤
|
|||
|
|
- 分页限制:LIMIT 限制单次查询数量
|
|||
|
|
- 乐观锁:WHERE order_status='3' AND settlement_time IS NULL
|
|||
|
|
|
|||
|
|
### 4. 业务逻辑
|
|||
|
|
|
|||
|
|
**核心方法**: `OrderBasicInfoServiceImpl.autoSettleOrdersWithoutTransactionRecord()`
|
|||
|
|
|
|||
|
|
**执行流程**:
|
|||
|
|
1. **功能开关检查** - 如果未启用直接返回
|
|||
|
|
2. **计算截止时间** - 当前时间 - 超时阈值
|
|||
|
|
3. **查询待结算订单** - 支持灰度站点过滤
|
|||
|
|
4. **逐个处理订单**:
|
|||
|
|
- 获取 Redis 分布式锁(key: `settle_order_{orderId}`)
|
|||
|
|
- 重新查询订单最新状态(防止并发)
|
|||
|
|
- 检查灰度范围
|
|||
|
|
- 获取充电桩连接器状态(Redis优先)
|
|||
|
|
- 检查充电桩在线状态
|
|||
|
|
- 获取最后一条实时数据
|
|||
|
|
- 检查数据新鲜度(< 30分钟)
|
|||
|
|
- 数据校验:电量和金额格式、非空、非零
|
|||
|
|
- 构造结算数据
|
|||
|
|
- 金额异常检测(chargingAmount > payAmount × 1.5倍)
|
|||
|
|
- 调用结算方法(`returnUpdateOrderBasicInfo` + `returnUpdateOrderDetail`)
|
|||
|
|
- 乐观锁更新订单状态
|
|||
|
|
- 处理退款(如果结算金额 < 已支付金额)
|
|||
|
|
- 释放 Redis 锁
|
|||
|
|
|
|||
|
|
**统计信息**:
|
|||
|
|
- successCount - 成功结算数量
|
|||
|
|
- skipCount - 跳过数量
|
|||
|
|
- failCount - 失败数量
|
|||
|
|
|
|||
|
|
### 5. 定时任务
|
|||
|
|
|
|||
|
|
**文件**: `jsowell-quartz/src/main/java/com/jsowell/quartz/task/JsowellTask.java`
|
|||
|
|
|
|||
|
|
```java
|
|||
|
|
public void autoSettleOrdersWithoutTransactionRecord() {
|
|||
|
|
if (skipInPre("无交易记录自动结算")) {
|
|||
|
|
return; // 预发布环境跳过
|
|||
|
|
}
|
|||
|
|
log.info("【无交易记录自动结算】定时任务开始执行");
|
|||
|
|
try {
|
|||
|
|
orderBasicInfoService.autoSettleOrdersWithoutTransactionRecord();
|
|||
|
|
log.info("【无交易记录自动结算】定时任务执行完成");
|
|||
|
|
} catch (Exception e) {
|
|||
|
|
log.error("【无交易记录自动结算】定时任务执行失败", e);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**调用字符串**: `jsowellTask.autoSettleOrdersWithoutTransactionRecord()`
|
|||
|
|
|
|||
|
|
**推荐配置**:
|
|||
|
|
- 执行周期:每10分钟执行一次
|
|||
|
|
- Cron 表达式:`0 */10 * * * ?`
|
|||
|
|
|
|||
|
|
### 6. 幂等保护
|
|||
|
|
|
|||
|
|
#### Redis 分布式锁
|
|||
|
|
- **锁键**: `settle_order_{orderId}`
|
|||
|
|
- **锁值**: "1"
|
|||
|
|
- **超时时间**: 300秒(可配置)
|
|||
|
|
- **获取方式**: `redisCache.setCacheObject()` + 检查返回值
|
|||
|
|
|
|||
|
|
#### 数据库乐观锁
|
|||
|
|
- **WHERE 条件**: `order_status = '3' AND settlement_time IS NULL`
|
|||
|
|
- **更新失败处理**: 记录警告日志,跳过该订单
|
|||
|
|
- **防止并发**: 重新查询订单最新状态
|
|||
|
|
|
|||
|
|
### 7. 数据校验与告警
|
|||
|
|
|
|||
|
|
#### 充电桩在线检测
|
|||
|
|
```java
|
|||
|
|
// 从 Redis 获取充电枪状态
|
|||
|
|
String connectorKey = "CONNECTOR_STATUS:" + connectorId;
|
|||
|
|
Integer status = redisCache.getCacheObject(connectorKey);
|
|||
|
|
|
|||
|
|
// 状态 3=充电中,4=已连接未充电 为在线状态
|
|||
|
|
if (status == null || (status != 3 && status != 4)) {
|
|||
|
|
logger.warn("充电桩可能已离线,跳过");
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 数据新鲜度检测
|
|||
|
|
```java
|
|||
|
|
long minutesSinceUpdate = Duration.between(
|
|||
|
|
lastUpdateTime, LocalDateTime.now()
|
|||
|
|
).toMinutes();
|
|||
|
|
|
|||
|
|
if (minutesSinceUpdate > dataFreshnessMinutes) {
|
|||
|
|
logger.warn("实时数据过期({}分钟前),跳过", minutesSinceUpdate);
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 金额异常告警
|
|||
|
|
```java
|
|||
|
|
BigDecimal threshold = payAmount.multiply(amountThresholdRatio);
|
|||
|
|
if (chargingAmount.compareTo(threshold) > 0) {
|
|||
|
|
String alertMsg = String.format(
|
|||
|
|
"【金额异常】订单号:%s,站点ID:%s,充电桩:%s," +
|
|||
|
|
"实时充电金额:%.2f 元,已支付金额:%.2f 元,阈值倍数:%.1f",
|
|||
|
|
orderCode, stationId, pileSn,
|
|||
|
|
chargingAmount, payAmount, amountThresholdRatio
|
|||
|
|
);
|
|||
|
|
logger.error(alertMsg);
|
|||
|
|
// TODO: 发送告警通知(邮件/短信/钉钉/企业微信)
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 数据格式校验
|
|||
|
|
- 充电电量非空、格式正确、大于0
|
|||
|
|
- 充电金额非空、格式正确
|
|||
|
|
- 异常时记录错误日志,跳过该订单
|
|||
|
|
|
|||
|
|
### 8. 单元测试
|
|||
|
|
|
|||
|
|
**文件**: `jsowell-admin/src/test/java/com/jsowell/AutoSettleOrdersWithoutTransactionTest.java`
|
|||
|
|
|
|||
|
|
**测试用例**:
|
|||
|
|
1. **testSelectPendingAutoSettleOrders** - 查询待结算订单
|
|||
|
|
2. **testGrayscaleConfiguration** - 灰度配置测试
|
|||
|
|
3. **testAmountThresholdValidation** - 金额阈值检测
|
|||
|
|
4. **testFeatureToggle** - 配置开关测试
|
|||
|
|
5. **testAutoSettleMainFlow** - 完整流程测试
|
|||
|
|
6. **testDataFreshness** - 数据新鲜度判断
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 文件清单
|
|||
|
|
|
|||
|
|
### 新增文件(3个)
|
|||
|
|
```
|
|||
|
|
jsowell-pile/src/main/java/com/jsowell/pile/config/AutoSettleConfig.java
|
|||
|
|
jsowell-pile/src/main/java/com/jsowell/pile/util/SettlementDataConverter.java
|
|||
|
|
jsowell-admin/src/test/java/com/jsowell/AutoSettleOrdersWithoutTransactionTest.java
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 修改文件(7个)
|
|||
|
|
```
|
|||
|
|
docs/feature-tracker-无交易记录自动结算.md
|
|||
|
|
jsowell-admin/src/main/resources/application.yml
|
|||
|
|
jsowell-pile/src/main/java/com/jsowell/pile/service/OrderBasicInfoService.java
|
|||
|
|
jsowell-pile/src/main/java/com/jsowell/pile/service/impl/OrderBasicInfoServiceImpl.java
|
|||
|
|
jsowell-pile/src/main/java/com/jsowell/pile/mapper/OrderBasicInfoMapper.java
|
|||
|
|
jsowell-pile/src/main/resources/mapper/pile/OrderBasicInfoMapper.xml
|
|||
|
|
jsowell-quartz/src/main/java/com/jsowell/quartz/task/JsowellTask.java
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 代码统计
|
|||
|
|
- 新增代码:约 500 行(核心业务逻辑)
|
|||
|
|
- 配置类:95 行
|
|||
|
|
- 工具类:180 行
|
|||
|
|
- 单元测试:180 行
|
|||
|
|
- SQL 语句:2 个
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 部署指南
|
|||
|
|
|
|||
|
|
### 1. 代码合并
|
|||
|
|
```bash
|
|||
|
|
# 切换到目标分支(通常是 dev 或 master)
|
|||
|
|
git checkout dev
|
|||
|
|
|
|||
|
|
# 合并功能分支
|
|||
|
|
git merge feature/auto-settle-no-transaction
|
|||
|
|
|
|||
|
|
# 推送到远程仓库
|
|||
|
|
git push origin dev
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 配置更新
|
|||
|
|
|
|||
|
|
在 `application-{env}.yml` 中添加配置:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
# 无交易记录自动结算配置
|
|||
|
|
auto-settle:
|
|||
|
|
# 功能总开关(默认关闭,需手动开启)
|
|||
|
|
enabled: false
|
|||
|
|
|
|||
|
|
# 停止超时阈值(分钟)- 订单停止超过该时间才触发自动结算
|
|||
|
|
timeout-minutes: 10
|
|||
|
|
|
|||
|
|
# 定时任务执行间隔(cron表达式)
|
|||
|
|
interval: "0 */10 * * * ?"
|
|||
|
|
|
|||
|
|
# 灰度站点ID列表(为空表示全量上线)
|
|||
|
|
# 示例:[1001, 1002, 1003]
|
|||
|
|
grayscale-station-ids: []
|
|||
|
|
|
|||
|
|
# 单次扫描订单数量上限
|
|||
|
|
batch-size: 100
|
|||
|
|
|
|||
|
|
# 异常金额阈值比例(chargingAmount > payAmount * 该比例时告警跳过)
|
|||
|
|
amount-threshold-ratio: 1.5
|
|||
|
|
|
|||
|
|
# 实时数据新鲜度阈值(分钟)
|
|||
|
|
data-freshness-minutes: 30
|
|||
|
|
|
|||
|
|
# 告警开关
|
|||
|
|
alert-enabled: true
|
|||
|
|
|
|||
|
|
# Redis锁超时时间(秒)
|
|||
|
|
lock-timeout: 300
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 添加定时任务
|
|||
|
|
|
|||
|
|
在管理后台的"定时任务"菜单中添加任务:
|
|||
|
|
|
|||
|
|
| 字段 | 值 |
|
|||
|
|
|------|-----|
|
|||
|
|
| 任务名称 | 无交易记录自动结算 |
|
|||
|
|
| 任务组名 | DEFAULT |
|
|||
|
|
| 调用目标字符串 | jsowellTask.autoSettleOrdersWithoutTransactionRecord() |
|
|||
|
|
| cron表达式 | 0 */10 * * * ? |
|
|||
|
|
| 执行策略 | 立即执行 |
|
|||
|
|
| 是否并发 | 否 |
|
|||
|
|
| 状态 | 暂停(灰度期间) |
|
|||
|
|
|
|||
|
|
### 4. 灰度发布流程
|
|||
|
|
|
|||
|
|
#### 阶段1:单站点灰度(第1-3天)
|
|||
|
|
```yaml
|
|||
|
|
auto-settle:
|
|||
|
|
enabled: true
|
|||
|
|
grayscale-station-ids: [1001] # 选择1个业务量适中的站点
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**观察指标**:
|
|||
|
|
- 成功结算数量
|
|||
|
|
- 跳过数量(及原因)
|
|||
|
|
- 失败数量(及异常)
|
|||
|
|
- 金额异常告警
|
|||
|
|
- Redis锁竞争情况
|
|||
|
|
- 数据库慢查询
|
|||
|
|
|
|||
|
|
#### 阶段2:小范围灰度(第4-7天)
|
|||
|
|
```yaml
|
|||
|
|
auto-settle:
|
|||
|
|
enabled: true
|
|||
|
|
grayscale-station-ids: [1001, 1002, 1003, 1004, 1005] # 扩展到5个站点
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 阶段3:大范围灰度(第8-14天)
|
|||
|
|
```yaml
|
|||
|
|
auto-settle:
|
|||
|
|
enabled: true
|
|||
|
|
grayscale-station-ids: [...] # 扩展到30%的站点
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 阶段4:全量上线(第15天+)
|
|||
|
|
```yaml
|
|||
|
|
auto-settle:
|
|||
|
|
enabled: true
|
|||
|
|
grayscale-station-ids: [] # 空数组 = 全量
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5. 监控指标
|
|||
|
|
|
|||
|
|
#### 日志监控
|
|||
|
|
```bash
|
|||
|
|
# 查看执行日志
|
|||
|
|
tail -f logs/jsowell-admin.log | grep "无交易记录自动结算"
|
|||
|
|
|
|||
|
|
# 统计成功数量
|
|||
|
|
grep "【无交易记录自动结算】执行完成,成功" logs/jsowell-admin.log | tail -20
|
|||
|
|
|
|||
|
|
# 查看告警日志
|
|||
|
|
grep "【无交易记录自动结算-金额异常】" logs/jsowell-admin.log
|
|||
|
|
grep "【无交易记录自动结算-处理异常】" logs/jsowell-admin.log
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### 数据库监控
|
|||
|
|
```sql
|
|||
|
|
-- 查看待结算订单数量
|
|||
|
|
SELECT COUNT(*)
|
|||
|
|
FROM order_basic_info
|
|||
|
|
WHERE del_flag = '0'
|
|||
|
|
AND order_status = '3'
|
|||
|
|
AND pay_status = '1'
|
|||
|
|
AND (transaction_code IS NULL OR transaction_code = '')
|
|||
|
|
AND charge_end_time < DATE_SUB(NOW(), INTERVAL 10 MINUTE);
|
|||
|
|
|
|||
|
|
-- 查看最近自动结算的订单
|
|||
|
|
SELECT order_code, station_id, pile_sn,
|
|||
|
|
charge_end_time, settlement_time,
|
|||
|
|
order_amount, refund_amount
|
|||
|
|
FROM order_basic_info
|
|||
|
|
WHERE reason = '无交易记录自动结算'
|
|||
|
|
AND settlement_time > DATE_SUB(NOW(), INTERVAL 1 DAY)
|
|||
|
|
ORDER BY settlement_time DESC
|
|||
|
|
LIMIT 100;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
#### Redis监控
|
|||
|
|
```bash
|
|||
|
|
# 查看当前锁数量
|
|||
|
|
redis-cli KEYS "settle_order_*" | wc -l
|
|||
|
|
|
|||
|
|
# 检查是否有死锁(TTL < 0)
|
|||
|
|
redis-cli KEYS "settle_order_*" | xargs -I {} redis-cli TTL {}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 风险点与应对
|
|||
|
|
|
|||
|
|
### 1. 并发冲突
|
|||
|
|
**风险**: 多个定时任务实例同时处理同一订单
|
|||
|
|
|
|||
|
|
**应对**:
|
|||
|
|
- Redis 分布式锁 + 乐观锁双重保护
|
|||
|
|
- 锁超时时间设置为5分钟,防止死锁
|
|||
|
|
- 乐观锁更新失败时记录日志,不抛出异常
|
|||
|
|
|
|||
|
|
### 2. 金额异常
|
|||
|
|
**风险**: 实时数据的充电金额远大于预付金额
|
|||
|
|
|
|||
|
|
**应对**:
|
|||
|
|
- 设置金额阈值(默认1.5倍)
|
|||
|
|
- 超过阈值告警跳过,人工介入
|
|||
|
|
- 详细记录订单信息、站点ID、充电桩SN
|
|||
|
|
|
|||
|
|
### 3. 数据不新鲜
|
|||
|
|
**风险**: 充电桩"假在线"(最后一条实时数据很久之前)
|
|||
|
|
|
|||
|
|
**应对**:
|
|||
|
|
- 检查实时数据更新时间
|
|||
|
|
- 超过30分钟的数据视为陈旧,跳过结算
|
|||
|
|
- 记录警告日志
|
|||
|
|
|
|||
|
|
### 4. 充电桩离线
|
|||
|
|
**风险**: 充电桩实际已离线,但订单未正常结束
|
|||
|
|
|
|||
|
|
**应对**:
|
|||
|
|
- 从 Redis 检查充电枪状态
|
|||
|
|
- 状态非"充电中"或"已连接"时跳过
|
|||
|
|
- 依赖设备心跳机制更新状态
|
|||
|
|
|
|||
|
|
### 5. 退款失败
|
|||
|
|
**风险**: 结算成功但退款失败,用户损失
|
|||
|
|
|
|||
|
|
**应对**:
|
|||
|
|
- 退款失败记录错误日志
|
|||
|
|
- 告警通知运营人员
|
|||
|
|
- 支持后台手动发起退款
|
|||
|
|
|
|||
|
|
### 6. 性能问题
|
|||
|
|
**风险**: 单次扫描订单过多,影响数据库性能
|
|||
|
|
|
|||
|
|
**应对**:
|
|||
|
|
- 限制单次查询数量(默认100)
|
|||
|
|
- 使用索引优化查询(charge_end_time, order_status, pay_status)
|
|||
|
|
- 定时任务间隔可调整(默认10分钟)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 后续优化建议
|
|||
|
|
|
|||
|
|
### 1. 告警系统集成
|
|||
|
|
- 对接现有告警系统(邮件/短信/钉钉/企业微信)
|
|||
|
|
- 金额异常、处理失败立即通知
|
|||
|
|
- 每日汇总报告(成功数、失败数、异常数)
|
|||
|
|
|
|||
|
|
### 2. 监控大盘
|
|||
|
|
- Grafana 可视化监控
|
|||
|
|
- 实时展示待结算订单数量
|
|||
|
|
- 自动结算成功率、平均处理时长
|
|||
|
|
- 金额异常趋势图
|
|||
|
|
|
|||
|
|
### 3. 智能调度
|
|||
|
|
- 根据待结算订单数量动态调整执行频率
|
|||
|
|
- 业务高峰期降低频率,低谷期提高频率
|
|||
|
|
- 避免影响正常业务
|
|||
|
|
|
|||
|
|
### 4. 数据分析
|
|||
|
|
- 统计哪些站点、哪些充电桩频繁出现无交易记录
|
|||
|
|
- 分析根本原因(设备故障、网络问题、协议异常)
|
|||
|
|
- 针对性优化设备通信逻辑
|
|||
|
|
|
|||
|
|
### 5. 手动补结算
|
|||
|
|
- 后台管理页面添加"手动自动结算"按钮
|
|||
|
|
- 支持批量选择订单执行结算
|
|||
|
|
- 提供详细的执行日志和结果反馈
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 验收标准
|
|||
|
|
|
|||
|
|
### 功能验收
|
|||
|
|
- [x] 配置开关正常工作
|
|||
|
|
- [x] 定时任务正常调度执行
|
|||
|
|
- [x] 查询待结算订单准确
|
|||
|
|
- [x] 结算逻辑正确(金额、电量、时间)
|
|||
|
|
- [x] 退款逻辑正确
|
|||
|
|
- [x] 幂等保护有效
|
|||
|
|
- [x] 数据校验完整
|
|||
|
|
- [x] 告警日志记录详细
|
|||
|
|
- [x] 单元测试通过
|
|||
|
|
|
|||
|
|
### 性能验收
|
|||
|
|
- [ ] 单次处理100个订单耗时 < 30秒
|
|||
|
|
- [ ] Redis 锁无死锁现象
|
|||
|
|
- [ ] 数据库慢查询 < 5%
|
|||
|
|
|
|||
|
|
### 稳定性验收
|
|||
|
|
- [ ] 灰度期间(7天)无P0/P1故障
|
|||
|
|
- [ ] 并发场景下无数据不一致
|
|||
|
|
- [ ] 异常场景正常降级(记录日志、跳过订单)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 附录
|
|||
|
|
|
|||
|
|
### A. 相关文档
|
|||
|
|
- [功能设计文档](./feature-tracker-无交易记录自动结算.md)
|
|||
|
|
- [功能设计附录](./feature-tracker-无交易记录自动结算-附录.md)
|
|||
|
|
- [项目架构文档](../CLAUDE.md)
|
|||
|
|
- [jsowell-pile 模块文档](../jsowell-pile/CLAUDE.md)
|
|||
|
|
- [jsowell-quartz 模块文档](../jsowell-quartz/CLAUDE.md)
|
|||
|
|
|
|||
|
|
### B. 联系方式
|
|||
|
|
- 开发负责人: jsowell
|
|||
|
|
- Git 分支: feature/auto-settle-no-transaction
|
|||
|
|
- 提交哈希: 121b357a2
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
**文档版本**: v1.0
|
|||
|
|
**最后更新**: 2026-08-11
|
|||
|
|
**状态**: ✅ 开发完成,待灰度发布
|