From b7ace278c8486eb6299f6668f8d092fb859352ca Mon Sep 17 00:00:00 2001
From: liujie <1793218484@qq.com>
Date: 星期二, 28 四月 2026 09:12:55 +0800
Subject: [PATCH] p0功能 小程序

---
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TExchangeCodePackageServiceImpl.java |   52 +++++++++++++
 ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/KsolarUtils.java                       |    4 
 ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/dto/ExchangeCodeUseRecordQuery.java           |   17 ++++
 sql/20260427_balance_exchange.sql                                                                         |    8 ++
 ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUser.java                       |    4 +
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TExchangeCodePackageController.java    |   16 ++++
 ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/TExchangeCodePackageService.java          |    7 +
 ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TExchangeCodeUseRecord.java            |   22 +++++
 ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/OtherClient.java                  |   10 ++
 ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserController.java            |   49 ++++++++++++
 ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TAppUserMapper.xml                          |    3 
 ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/OtherFallbackFactory.java             |   10 ++
 12 files changed, 198 insertions(+), 4 deletions(-)

diff --git a/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUser.java b/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUser.java
index bd12b62..2ad2a5d 100644
--- a/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUser.java
+++ b/ruoyi-api/ruoyi-api-account/src/main/java/com/ruoyi/account/api/model/TAppUser.java
@@ -82,6 +82,10 @@
     @ApiModelProperty(value = "积分")
     @TableField("points")
     private Integer points;
+
+    @ApiModelProperty(value = "余额")
+    @TableField("balance")
+    private BigDecimal balance;
     @ApiModelProperty(value = "积分")
     @TableField("first_add")
     private Integer firstAdd;
diff --git a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TExchangeCodeUseRecord.java b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TExchangeCodeUseRecord.java
index 3b1c621..4f9557f 100644
--- a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TExchangeCodeUseRecord.java
+++ b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/domain/TExchangeCodeUseRecord.java
@@ -11,6 +11,7 @@
 import lombok.EqualsAndHashCode;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
 
 @Data
 @EqualsAndHashCode(callSuper = false)
@@ -37,4 +38,25 @@
     @TableField("used_amount")
     @ApiModelProperty("本次使用金额")
     private BigDecimal usedAmount;
+
+    @TableField(exist = false)
+    private String uid;
+
+    @TableField(exist = false)
+    private String code;
+
+    @TableField(exist = false)
+    private String orderCode;
+
+    @TableField(exist = false)
+    private Integer changeType;
+
+    @TableField(exist = false)
+    private BigDecimal changeAmount;
+
+    @TableField(exist = false)
+    private BigDecimal currentBalance;
+
+    @TableField(exist = false)
+    private LocalDateTime dateTime;
 }
diff --git a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/dto/ExchangeCodeUseRecordQuery.java b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/dto/ExchangeCodeUseRecordQuery.java
new file mode 100644
index 0000000..655ca87
--- /dev/null
+++ b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/dto/ExchangeCodeUseRecordQuery.java
@@ -0,0 +1,17 @@
+package com.ruoyi.other.api.dto;
+
+import com.ruoyi.common.core.web.page.BasePage;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+@ApiModel("兑换码使用流水查询DTO")
+public class ExchangeCodeUseRecordQuery extends BasePage {
+
+    @ApiModelProperty("用户ID")
+    private Long userId;
+
+    @ApiModelProperty("变动类型:1=兑换,2=充电")
+    private Integer changeType;
+}
diff --git a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/OtherFallbackFactory.java b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/OtherFallbackFactory.java
index 686b0b8..4db86e3 100644
--- a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/OtherFallbackFactory.java
+++ b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/factory/OtherFallbackFactory.java
@@ -5,6 +5,7 @@
 import com.ruoyi.other.api.domain.*;
 import com.ruoyi.other.api.dto.ExchangeCodeBindDTO;
 import com.ruoyi.other.api.dto.ExchangeCodeConsumeDTO;
+import com.ruoyi.other.api.dto.ExchangeCodeUseRecordQuery;
 import com.ruoyi.other.api.dto.TagListQueryDto;
 import com.ruoyi.other.api.dto.UnitListQueryDto;
 import com.ruoyi.other.api.feignClient.OtherClient;
@@ -160,6 +161,15 @@
             public R<ExchangeCodeConsumeResultVO> consumeExchangeCodeBalance(ExchangeCodeConsumeDTO dto) {
                 return R.fail("扣减兑换码余额失败:" + throwable.getMessage());
             }
+            @Override
+            public R<Page<TExchangeCodeUseRecord>> exchangeCodeUseRecordPage(ExchangeCodeUseRecordQuery query) {
+                return R.fail("查询兑换码流水失败:" + throwable.getMessage());
+            }
+
+            @Override
+            public R<TExchangeCodeUseRecord> exchangeCodeUseRecordDetail(Long id, Long userId) {
+                return R.fail("查询兑换码流水详情失败:" + throwable.getMessage());
+            }
         };
     }
 }
diff --git a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/OtherClient.java b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/OtherClient.java
index afb131b..9fed459 100644
--- a/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/OtherClient.java
+++ b/ruoyi-api/ruoyi-api-other/src/main/java/com/ruoyi/other/api/feignClient/OtherClient.java
@@ -6,12 +6,15 @@
 import com.ruoyi.other.api.domain.*;
 import com.ruoyi.other.api.dto.ExchangeCodeBindDTO;
 import com.ruoyi.other.api.dto.ExchangeCodeConsumeDTO;
+import com.ruoyi.other.api.dto.ExchangeCodeUseRecordQuery;
 import com.ruoyi.other.api.dto.TagListQueryDto;
 import com.ruoyi.other.api.dto.UnitListQueryDto;
 import com.ruoyi.other.api.factory.OtherFallbackFactory;
 import com.ruoyi.other.api.vo.CouponListVOVO;
 import com.ruoyi.other.api.vo.ExchangeCodeBindResultVO;
 import com.ruoyi.other.api.vo.ExchangeCodeConsumeResultVO;
+import com.ruoyi.other.api.domain.TExchangeCodeUseRecord;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import org.springframework.cloud.openfeign.FeignClient;
 import org.springframework.web.bind.annotation.*;
 
@@ -111,4 +114,11 @@
     @PostMapping(value = "/exchange-code-package/consumeBalance")
     R<ExchangeCodeConsumeResultVO> consumeExchangeCodeBalance(@RequestBody ExchangeCodeConsumeDTO dto);
 
+    @PostMapping(value = "/exchange-code-package/useRecord/page")
+    R<Page<TExchangeCodeUseRecord>> exchangeCodeUseRecordPage(@RequestBody ExchangeCodeUseRecordQuery query);
+
+    @GetMapping(value = "/exchange-code-package/useRecord/detail")
+    R<TExchangeCodeUseRecord> exchangeCodeUseRecordDetail(@RequestParam("id") Long id,
+                                                           @RequestParam("userId") Long userId);
+
 }
diff --git a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserController.java b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserController.java
index b0f87e2..ae86d75 100644
--- a/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserController.java
+++ b/ruoyi-service/ruoyi-account/src/main/java/com/ruoyi/account/controller/TAppUserController.java
@@ -44,9 +44,13 @@
 import com.ruoyi.other.api.domain.*;
 import com.ruoyi.other.api.domain.TCoupon;
 import com.ruoyi.other.api.domain.TVip;
+import com.ruoyi.other.api.dto.ExchangeCodeBindDTO;
+import com.ruoyi.other.api.dto.ExchangeCodeUseRecordQuery;
 import com.ruoyi.other.api.dto.UnitListQueryDto;
 import com.ruoyi.other.api.feignClient.IntegralRuleClient;
 import com.ruoyi.other.api.feignClient.OtherClient;
+import com.ruoyi.other.api.vo.ExchangeCodeBindResultVO;
+import com.ruoyi.other.api.domain.TExchangeCodeUseRecord;
 import com.ruoyi.other.api.feignClient.VipClient;
 import com.ruoyi.system.api.model.LoginUser;
 import com.ruoyi.system.api.model.LoginUserApplet;
@@ -727,7 +731,46 @@
         }
         
         return R.ok(page);
-        
+
+    }
+
+    @ApiOperation(value = "余额明细", tags = {"小程序-个人中心"})
+    @PostMapping(value = "/user/balance/page1")
+    public R<Page<TExchangeCodeUseRecord>> balanceDetail(@RequestBody ExchangeCodeUseRecordQuery queryDto) {
+        if (queryDto.getUserId() == null) {
+            queryDto.setUserId(tokenService.getLoginUserApplet().getUserId());
+        }
+        return otherClient.exchangeCodeUseRecordPage(queryDto);
+    }
+
+    @ApiOperation(value = "余额明细详情", tags = {"小程序-个人中心"})
+    @GetMapping(value = "/user/balance/detail")
+    public R<TExchangeCodeUseRecord> balanceDetail(@RequestParam("id") Long id) {
+        Long userId = tokenService.getLoginUserApplet().getUserId();
+        return otherClient.exchangeCodeUseRecordDetail(id, userId);
+    }
+
+    @ApiOperation(value = "兑换余额", tags = {"小程序-个人中心"})
+    @PostMapping(value = "/user/balance/exchange")
+    public R<BigDecimal> exchangeBalance(@RequestBody ExchangeCodeBindDTO dto) {
+        LoginUserApplet loginUser = tokenService.getLoginUserApplet();
+        TAppUser appUser = appUserService.getById(loginUser.getUserId());
+        R<ExchangeCodeBindResultVO> bindResult = otherClient.bindExchangeCode(dto, appUser.getId(), appUser.getPhone());
+        if (bindResult.getData() == null) {
+            return R.fail(bindResult.getMsg());
+        }
+        Map<Long, BigDecimal> balanceMap = otherClient.getExchangeCodeBalanceMap(Collections.singletonList(appUser.getId())).getData();
+        BigDecimal totalExchangeBalance = balanceMap == null ? BigDecimal.ZERO : balanceMap.getOrDefault(appUser.getId(), BigDecimal.ZERO);
+        BigDecimal oldBalance = defaultBalance(appUser.getBalance());
+        BigDecimal exchangeAmount = totalExchangeBalance.subtract(oldBalance);
+        if (exchangeAmount.compareTo(BigDecimal.ZERO) <= 0) {
+            return R.fail("兑换金额异常");
+        }
+        BigDecimal newBalance = oldBalance.add(exchangeAmount);
+        appUser.setBalance(newBalance);
+        appUserService.updateById(appUser);
+
+        return R.ok(exchangeAmount);
     }
     
     @ApiOperation(value = "积分详情", tags = {"小程序-个人中心"})
@@ -1479,5 +1522,9 @@
         }
         return R.ok();
     }
+
+    private BigDecimal defaultBalance(BigDecimal balance) {
+        return balance == null ? BigDecimal.ZERO : balance;
+    }
     
 }
diff --git a/ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TAppUserMapper.xml b/ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TAppUserMapper.xml
index 6a665e0..d87aef4 100644
--- a/ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TAppUserMapper.xml
+++ b/ruoyi-service/ruoyi-account/src/main/resources/mapper/account/TAppUserMapper.xml
@@ -16,6 +16,7 @@
         <result column="wx_openid" property="wxOpenid" />
         <result column="ali_openid" property="aliOpenid" />
         <result column="points" property="points" />
+        <result column="balance" property="balance" />
         <result column="province" property="province" />
         <result column="province_code" property="provinceCode" />
         <result column="city" property="city" />
@@ -29,7 +30,7 @@
 
     <!-- 通用查询结果列 -->
     <sql id="Base_Column_List">
-        id, name, phone, avatar, vip_id, vip_end_time, company_id, id_card, auth_status, wx_openid, ali_openid, points, province, province_code, city, city_code, status, create_time, del_flag, last_login_time,invite_user_id
+        id, name, phone, avatar, vip_id, vip_end_time, company_id, id_card, auth_status, wx_openid, ali_openid, points, balance, province, province_code, city, city_code, status, create_time, del_flag, last_login_time,invite_user_id
     </sql>
 
 </mapper>
diff --git a/ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/KsolarUtils.java b/ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/KsolarUtils.java
index 93c7395..515cc60 100644
--- a/ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/KsolarUtils.java
+++ b/ruoyi-service/ruoyi-jianguan/src/main/java/com/ruoyi/jianguan/util/KsolarUtils.java
@@ -225,8 +225,8 @@
     }
 
     public static void main(String[] args) throws Exception {
-        String electricity = getElectricity();
-        System.out.println(electricity);
+        Double allEnergy = getAllEnergy(LocalDate.now().toString());
+        System.out.println(allEnergy);
     }
 
 
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TExchangeCodePackageController.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TExchangeCodePackageController.java
index 8b314fd..ea3599c 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TExchangeCodePackageController.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/controller/TExchangeCodePackageController.java
@@ -15,6 +15,8 @@
 import com.ruoyi.other.api.dto.ExchangeCodeBindDTO;
 import com.ruoyi.other.api.dto.ExchangeCodeConsumeDTO;
 import com.ruoyi.other.api.dto.ExchangeCodePackageSaveDTO;
+import com.ruoyi.other.api.dto.ExchangeCodeUseRecordQuery;
+import com.ruoyi.other.api.domain.TExchangeCodeUseRecord;
 import com.ruoyi.other.api.vo.ExchangeCodeBindResultVO;
 import com.ruoyi.other.api.vo.ExchangeCodeConsumeResultVO;
 import com.ruoyi.other.api.vo.ExchangeCodePackageDetailVO;
@@ -41,6 +43,7 @@
 import java.util.Map;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 
 @RestController
 @RequestMapping("/exchange-code-package")
@@ -184,6 +187,19 @@
         return R.ok(exchangeCodePackageService.consumeBalance(dto));
     }
 
+    @PostMapping("/useRecord/page")
+    @ApiOperation(value = "兑换码余额流水分页", tags = {"小程序-兑换码"})
+    public R<Page<TExchangeCodeUseRecord>> useRecordPage(@RequestBody ExchangeCodeUseRecordQuery query) {
+        return R.ok(exchangeCodePackageService.useRecordPage(query));
+    }
+
+    @GetMapping("/useRecord/detail")
+    @ApiOperation(value = "兑换码余额流水详情", tags = {"小程序-兑换码"})
+    public R<TExchangeCodeUseRecord> useRecordDetail(@RequestParam("id") Long id,
+                                                      @RequestParam("userId") Long userId) {
+        return R.ok(exchangeCodePackageService.useRecordDetail(id, userId));
+    }
+
     private String buildQrPayload(ExchangeCodeDetailVO detail) {
         return "code=" + detail.getCode() + "&password=" + detail.getPassword();
     }
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/TExchangeCodePackageService.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/TExchangeCodePackageService.java
index 2232dec..0f96eb3 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/TExchangeCodePackageService.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/TExchangeCodePackageService.java
@@ -6,6 +6,8 @@
 import com.ruoyi.other.api.dto.ExchangeCodeBindDTO;
 import com.ruoyi.other.api.dto.ExchangeCodeConsumeDTO;
 import com.ruoyi.other.api.dto.ExchangeCodePackageSaveDTO;
+import com.ruoyi.other.api.dto.ExchangeCodeUseRecordQuery;
+import com.ruoyi.other.api.domain.TExchangeCodeUseRecord;
 import com.ruoyi.other.api.vo.ExchangeCodeBindResultVO;
 import com.ruoyi.other.api.vo.ExchangeCodeConsumeResultVO;
 import com.ruoyi.other.api.vo.ExchangeCodePackageDetailVO;
@@ -17,6 +19,7 @@
 
 import java.util.List;
 import java.util.Map;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 
 public interface TExchangeCodePackageService extends IService<TExchangeCodePackage> {
 
@@ -45,4 +48,8 @@
     Map<Long, java.math.BigDecimal> getUserExchangeCodeBalanceMap(List<Long> userIds);
 
     ExchangeCodeConsumeResultVO consumeBalance(ExchangeCodeConsumeDTO dto);
+
+    Page<TExchangeCodeUseRecord> useRecordPage(ExchangeCodeUseRecordQuery query);
+
+    TExchangeCodeUseRecord useRecordDetail(Long id, Long userId);
 }
diff --git a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TExchangeCodePackageServiceImpl.java b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TExchangeCodePackageServiceImpl.java
index b326cff..6fae99a 100644
--- a/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TExchangeCodePackageServiceImpl.java
+++ b/ruoyi-service/ruoyi-other/src/main/java/com/ruoyi/other/service/impl/TExchangeCodePackageServiceImpl.java
@@ -1,6 +1,7 @@
 package com.ruoyi.other.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ruoyi.common.core.exception.ServiceException;
 import com.ruoyi.common.core.utils.StringUtils;
@@ -13,6 +14,7 @@
 import com.ruoyi.other.api.dto.ExchangeCodeConsumeDTO;
 import com.ruoyi.other.api.dto.ExchangeCodePackageSaveDTO;
 import com.ruoyi.other.api.dto.ExchangeCodePackageSpecDTO;
+import com.ruoyi.other.api.dto.ExchangeCodeUseRecordQuery;
 import com.ruoyi.other.api.vo.ExchangeCodeBindResultVO;
 import com.ruoyi.other.api.vo.ExchangeCodeConsumeResultVO;
 import com.ruoyi.other.api.vo.ExchangeCodePackageDetailVO;
@@ -276,6 +278,13 @@
         detail.setBindPhone(bindPhone);
         detail.setBindTime(LocalDateTime.now());
         codeDetailMapper.updateById(detail);
+        BigDecimal amount = getDetailRemainAmount(detail);
+        TExchangeCodeUseRecord record = new TExchangeCodeUseRecord();
+        record.setDetailId(detail.getId());
+        record.setOrderId(0L);
+        record.setUserId(userId);
+        record.setUsedAmount(amount);
+        useRecordMapper.insert(record);
         refreshPackageStats(exchangePackage.getId());
         ExchangeCodeBindResultVO resultVO = new ExchangeCodeBindResultVO();
         resultVO.setDetailId(detail.getId());
@@ -283,6 +292,28 @@
         resultVO.setPackageName(exchangePackage.getPackageName());
         resultVO.setBindPhone(bindPhone);
         return resultVO;
+    }
+
+    @Override
+    public Page<TExchangeCodeUseRecord> useRecordPage(ExchangeCodeUseRecordQuery query) {
+        Page<TExchangeCodeUseRecord> page = useRecordMapper.selectPage(Page.of(query.getPageCurr(), query.getPageSize()),
+                new QueryWrapper<TExchangeCodeUseRecord>()
+                        .eq("user_id", query.getUserId())
+                        .eq(Objects.equals(query.getChangeType(), 1), "IFNULL(order_id, 0)", 0)
+                        .gt(Objects.equals(query.getChangeType(), 2), "order_id", 0)
+                        .orderByDesc("create_time"));
+        page.getRecords().forEach(this::fillUseRecordView);
+        return page;
+    }
+
+    @Override
+    public TExchangeCodeUseRecord useRecordDetail(Long id, Long userId) {
+        TExchangeCodeUseRecord record = useRecordMapper.selectOne(new QueryWrapper<TExchangeCodeUseRecord>()
+                .eq("id", id)
+                .eq("user_id", userId)
+                .last("limit 1"));
+        fillUseRecordView(record);
+        return record;
     }
 
     @Override
@@ -318,6 +349,7 @@
         }
         List<TExchangeCodeUseRecord> existingRecords = useRecordMapper.selectList(new QueryWrapper<TExchangeCodeUseRecord>()
                 .eq("order_id", dto.getOrderId())
+                .gt("order_id", 0)
                 .eq("del_flag", 0));
         if (!existingRecords.isEmpty()) {
             BigDecimal deducted = existingRecords.stream()
@@ -530,6 +562,26 @@
         return UUID.randomUUID().toString().replace("-", "").substring(0, 8).toUpperCase();
     }
 
+    private void fillUseRecordView(TExchangeCodeUseRecord record) {
+        if (record == null) {
+            return;
+        }
+        record.setUid(String.valueOf(record.getId()));
+        record.setDateTime(record.getCreateTime());
+        record.setChangeAmount(defaultMoney(record.getUsedAmount()));
+        record.setCurrentBalance(defaultMoney(record.getUsedAmount()));
+        record.setChangeType(record.getOrderId() == null || record.getOrderId() == 0 ? 1 : 2);
+        if (record.getDetailId() != null) {
+            TExchangeCodeDetail detail = codeDetailMapper.selectById(record.getDetailId());
+            if (detail != null) {
+                record.setCode(detail.getCode());
+            }
+        }
+        if (record.getOrderId() != null && record.getOrderId() > 0) {
+            record.setOrderCode(String.valueOf(record.getOrderId()));
+        }
+    }
+
     private BigDecimal defaultMoney(BigDecimal amount) {
         return amount == null ? BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP)
                 : amount.setScale(2, RoundingMode.HALF_UP);
diff --git a/sql/20260427_balance_exchange.sql b/sql/20260427_balance_exchange.sql
new file mode 100644
index 0000000..bcd9444
--- /dev/null
+++ b/sql/20260427_balance_exchange.sql
@@ -0,0 +1,8 @@
+ALTER TABLE `t_app_user`
+    ADD COLUMN `balance` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '余额' AFTER `points`;
+
+ALTER TABLE `t_exchange_code_use_record`
+    MODIFY COLUMN `order_id` bigint NULL DEFAULT 0 COMMENT '订单ID,0表示兑换入账';
+
+CREATE INDEX `idx_exchange_code_use_record_user_time`
+    ON `t_exchange_code_use_record` (`user_id`, `create_time`);

--
Gitblit v1.7.1