| | |
| | | @ApiModelProperty(value = "积分") |
| | | @TableField("points") |
| | | private Integer points; |
| | | |
| | | @ApiModelProperty(value = "余额") |
| | | @TableField("balance") |
| | | private BigDecimal balance; |
| | | @ApiModelProperty(value = "积分") |
| | | @TableField("first_add") |
| | | private Integer firstAdd; |
| | |
| | | import lombok.EqualsAndHashCode; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | |
| | | @Data |
| | | @EqualsAndHashCode(callSuper = false) |
| | |
| | | @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; |
| | | } |
| New file |
| | |
| | | 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; |
| | | } |
| | |
| | | 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; |
| | |
| | | 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()); |
| | | } |
| | | }; |
| | | } |
| | | } |
| | |
| | | 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.*; |
| | | |
| | |
| | | @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); |
| | | |
| | | } |
| | |
| | | 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; |
| | |
| | | |
| | | 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 = {"小程序-个人中心"}) |
| | |
| | | return R.ok(); |
| | | } |
| | | |
| | | private BigDecimal defaultBalance(BigDecimal balance) { |
| | | return balance == null ? BigDecimal.ZERO : balance; |
| | | } |
| | | |
| | | } |
| | |
| | | <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" /> |
| | |
| | | |
| | | <!-- 通用查询结果列 --> |
| | | <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> |
| | |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | |
| | | |
| | |
| | | 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; |
| | |
| | | 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") |
| | |
| | | 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(); |
| | | } |
| | |
| | | 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; |
| | |
| | | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
| | | |
| | | public interface TExchangeCodePackageService extends IService<TExchangeCodePackage> { |
| | | |
| | |
| | | Map<Long, java.math.BigDecimal> getUserExchangeCodeBalanceMap(List<Long> userIds); |
| | | |
| | | ExchangeCodeConsumeResultVO consumeBalance(ExchangeCodeConsumeDTO dto); |
| | | |
| | | Page<TExchangeCodeUseRecord> useRecordPage(ExchangeCodeUseRecordQuery query); |
| | | |
| | | TExchangeCodeUseRecord useRecordDetail(Long id, Long userId); |
| | | } |
| | |
| | | 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; |
| | |
| | | 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; |
| | |
| | | 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()); |
| | |
| | | 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 |
| | |
| | | } |
| | | 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() |
| | |
| | | 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); |
| New file |
| | |
| | | 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`); |