主管理员 2 months ago
parent
commit
7060106bab
48 changed files with 1803 additions and 170 deletions
  1. +6
    -0
      jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/AppletUser.java
  2. +119
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/controller/AppletStatisticsController.java
  3. +51
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/entity/StatisticsItem.java
  4. +1
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/AppletApiWaterService.java
  5. +9
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiWaterServiceImpl.java
  6. +131
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/WxAppletService.java
  7. +153
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/common/wxUtils/transfer/TransferToUser.java
  8. +381
    -0
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/common/wxUtils/transfer/WXPayUtility.java
  9. +16
    -16
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/controller/AppletTtsPlayLogController.java
  10. +9
    -9
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/entity/AppletTtsPlayLog.java
  11. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/mapper/AppletTtsPlayLogMapper.java
  12. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/service/IAppletTtsPlayLogService.java
  13. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/service/impl/AppletTtsPlayLogServiceImpl.java
  14. +3
    -4
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp/AppletTtsPlayLogForm.vue
  15. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp/AppletTtsPlayLogList.vue
  16. +2
    -10
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp3/AppletTtsPlayLogData.ts
  17. +13
    -20
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp3/AppletTtsPlayLogForm.vue
  18. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp3/AppletTtsPlayLogList.vue
  19. +7
    -18
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/vue3/AppletTtsPlayLog.data.ts
  20. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/vue3/AppletTtsPlayLogList.vue
  21. +21
    -17
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/controller/AppletTtsTimbreController.java
  22. +18
    -5
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/entity/AppletTtsTimbre.java
  23. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/mapper/AppletTtsTimbreMapper.java
  24. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/service/IAppletTtsTimbreService.java
  25. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/service/impl/AppletTtsTimbreServiceImpl.java
  26. +19
    -1
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp/AppletTtsTimbreForm.vue
  27. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp/AppletTtsTimbreList.vue
  28. +20
    -1
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp3/AppletTtsTimbreData.ts
  29. +51
    -11
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp3/AppletTtsTimbreForm.vue
  30. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp3/AppletTtsTimbreList.vue
  31. +58
    -4
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/vue3/AppletTtsTimbre.data.ts
  32. +2
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/vue3/AppletTtsTimbreList.vue
  33. +14
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/controller/AppletWithdrawalController.java
  34. +11
    -4
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/entity/AppletWithdrawal.java
  35. +1
    -1
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/mapper/AppletWithdrawalMapper.java
  36. +1
    -1
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/service/IAppletWithdrawalService.java
  37. +1
    -1
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/service/impl/AppletWithdrawalServiceImpl.java
  38. +8
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/uniapp/AppletWithdrawalForm.vue
  39. +7
    -2
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/uniapp3/AppletWithdrawalData.ts
  40. +18
    -11
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/uniapp3/AppletWithdrawalForm.vue
  41. +22
    -5
      jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/vue3/AppletWithdrawal.data.ts
  42. +1
    -1
      jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml
  43. +64
    -0
      jeecgboot-vue3/src/views/applet/withdrawal/AppletWithdrawal.api.ts
  44. +142
    -0
      jeecgboot-vue3/src/views/applet/withdrawal/AppletWithdrawal.data.ts
  45. +206
    -0
      jeecgboot-vue3/src/views/applet/withdrawal/AppletWithdrawalList.vue
  46. +26
    -0
      jeecgboot-vue3/src/views/applet/withdrawal/V20250919_1__menu_insert_AppletWithdrawal.sql
  47. +70
    -0
      jeecgboot-vue3/src/views/applet/withdrawal/components/AppletWithdrawalForm.vue
  48. +99
    -0
      jeecgboot-vue3/src/views/applet/withdrawal/components/AppletWithdrawalModal.vue

+ 6
- 0
jeecg-boot/jeecg-boot-base-core/src/main/java/org/jeecg/common/system/vo/AppletUser.java View File

@ -108,4 +108,10 @@ public class AppletUser implements Serializable {
@Excel(name = "邀请人", width = 15)
@Schema(description = "邀请人")
private String inviter;
@Schema(description = "推广官")
private String isPromote;
@Schema(description = "开通时间")
private String promoteTime;
}

+ 119
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/controller/AppletStatisticsController.java View File

@ -0,0 +1,119 @@
package org.jeecg.modules.applet.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.IAppletUserService;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.AppletUser;
import org.jeecg.config.shiro.IgnoreAuth;
import org.jeecg.modules.applet.entity.StatisticsItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* @Description: 管理系统统计数据接口
* @Author: jeecg-boot
* @Date: 2025-01-27
* @Version: V1.0
*/
@Slf4j
@Tag(name = "管理系统统计", description = "管理系统统计数据接口")
@RestController
@RequestMapping("/statistics")
public class AppletStatisticsController {
@Autowired
private IAppletUserService appletUserService;
/**
* 获取管理系统统计数据
* 包含总用户数今日新增注册用户数本月新增注册用户数总推广官数
*
* @return 统计数据列表
*/
@Operation(summary = "获取管理系统统计数据", description = "获取总用户数、今日新增、本月新增、总推广官数等统计数据")
@GetMapping(value = "/dashboard")
@IgnoreAuth
public List<StatisticsItem> getDashboardStatistics() {
try {
List<StatisticsItem> statisticsList = new ArrayList<>();
// 1. 总用户数
long totalUsers = appletUserService.count();
statisticsList.add(StatisticsItem.builder()
.title("总用户数")
.icon("ant-design:user-outlined")
.value(totalUsers)
.color("blue")
.suffix("人")
.build());
// 2. 今日新增注册用户数
LocalDate today = LocalDate.now();
LocalDateTime todayStart = today.atStartOfDay();
LocalDateTime todayEnd = today.plusDays(1).atStartOfDay();
QueryWrapper<AppletUser> todayQuery = new QueryWrapper<>();
todayQuery.ge("create_time", todayStart);
todayQuery.lt("create_time", todayEnd);
long todayNewUsers = appletUserService.count(todayQuery);
statisticsList.add(StatisticsItem.builder()
.title("今日新增用户")
.icon("ant-design:user-add-outlined")
.value(todayNewUsers)
.color("green")
.suffix("人")
.build());
// 3. 本月新增注册用户数
LocalDate monthStart = today.withDayOfMonth(1);
LocalDateTime monthStartTime = monthStart.atStartOfDay();
LocalDateTime monthEndTime = monthStart.plusMonths(1).atStartOfDay();
QueryWrapper<AppletUser> monthQuery = new QueryWrapper<>();
monthQuery.ge("create_time", monthStartTime);
monthQuery.lt("create_time", monthEndTime);
long monthNewUsers = appletUserService.count(monthQuery);
statisticsList.add(StatisticsItem.builder()
.title("本月新增用户")
.icon("ant-design:calendar-outlined")
.value(monthNewUsers)
.color("orange")
.suffix("人")
.build());
// 4. 总推广官数有邀请过其他用户的用户
long totalPromoters = appletUserService.count(Wrappers.<AppletUser>lambdaQuery()
.eq(AppletUser::getIsPromote, "Y"));
statisticsList.add(StatisticsItem.builder()
.title("总推广官数")
.icon("ant-design:team-outlined")
.value(totalPromoters)
.color("purple")
.suffix("人")
.build());
log.info("获取管理系统统计数据成功,总用户数: {}, 今日新增: {}, 本月新增: {}, 总推广官: {}",
totalUsers, todayNewUsers, monthNewUsers, totalPromoters);
return statisticsList;
} catch (Exception e) {
log.error("获取管理系统统计数据异常", e);
return null;
}
}
}

+ 51
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/entity/StatisticsItem.java View File

@ -0,0 +1,51 @@
package org.jeecg.modules.applet.entity;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @Description: 统计数据项
* @Author: jeecg-boot
* @Date: 2025-01-20
* @Version: V1.0
*/
@Data
@Accessors(chain = true)
@Schema(description = "统计数据项")
@Builder
public class StatisticsItem {
/**标题*/
@Schema(description = "标题")
private String title;
/**图标*/
@Schema(description = "图标")
private String icon;
/**数值*/
@Schema(description = "数值")
private Object value;
/**颜色*/
@Schema(description = "颜色")
private String color;
/**后缀*/
@Schema(description = "后缀")
private String suffix;
public StatisticsItem() {}
public StatisticsItem(String title, String icon, Object value, String color, String suffix) {
this.title = title;
this.icon = icon;
this.value = value;
this.color = color;
this.suffix = suffix;
}
}

+ 1
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/AppletApiWaterService.java View File

@ -38,4 +38,5 @@ public interface AppletApiWaterService {
AppletWithdrawal getWithdraw(AppletWithdrawal appletWithdrawal);
StatisticsVo statistics();
}

+ 9
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/AppletApiWaterServiceImpl.java View File

@ -2,10 +2,12 @@ package org.jeecg.modules.applet.service.impl;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.IAppletUserService;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.util.AppletUserUtil;
import org.jeecg.common.system.vo.AppletUser;
@ -13,12 +15,15 @@ import org.jeecg.modules.applet.entity.StatisticsVo;
import org.jeecg.modules.applet.service.AppletApiWaterService;
import org.jeecg.modules.common.IdUtils;
import org.jeecg.modules.common.wxUtils.WxHttpUtils;
import org.jeecg.modules.common.wxUtils.transfer.TransferToUser;
import org.jeecg.modules.common.wxUtils.transfer.WXPayUtility;
import org.jeecg.modules.demo.appletConfig.service.IAppletConfigService;
import org.jeecg.modules.demo.appletWater.entity.AppletWater;
import org.jeecg.modules.demo.appletWater.service.IAppletWaterService;
import org.jeecg.modules.demo.appletWithdrawal.entity.AppletWithdrawal;
import org.jeecg.modules.demo.appletWithdrawal.service.IAppletWithdrawalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
@ -35,6 +40,7 @@ import java.io.File;
import java.math.BigDecimal;
import java.net.URL;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@ -53,6 +59,7 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
@Autowired
private WxHttpUtils wxHttpUtils;
@Override
public byte[] getInviteCode(){
AppletUser user = AppletUserUtil.getCurrentAppletUser();
@ -249,4 +256,6 @@ public class AppletApiWaterServiceImpl implements AppletApiWaterService {
.num(count)
.build();
}
}

+ 131
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/applet/service/impl/WxAppletService.java View File

@ -3,11 +3,20 @@ package org.jeecg.modules.applet.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.IAppletUserService;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.AppletUser;
import org.jeecg.modules.common.wxUtils.WxHttpUtils;
import org.jeecg.modules.common.wxUtils.transfer.TransferToUser;
import org.jeecg.modules.common.wxUtils.transfer.WXPayUtility;
import org.jeecg.modules.demo.appletWithdrawal.entity.AppletWithdrawal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@ -24,6 +33,31 @@ public class WxAppletService {
@Autowired
private WxHttpUtils wxHttpUtils;
@Autowired
private IAppletUserService appletUserService;
//微信小程序的 AppID
@Value("${wechat.mpAppId}")
private String appid;
//商户号
@Value("${wechat.merchantId}")
private String mchid;
//商户API私钥路径
@Value("${wechat.privateKeyPath}")
private String privateKeyFilePath;
//商户API公钥路径
@Value("${wechat.publicKeyPath}")
private String wechatPayPublicKeyFilePath;
//商户API公钥ID
@Value("${wechat.publicKeyId}")
private String wechatPayPublicKeyId;
//商户证书序列号
@Value("${wechat.merchantSerialNumber}")
private String certiticateSerialNo;
//提现转账回调地址
@Value("${wechat.transferNotify}")
private String transferNotify;
/**
* 获取小程序码
*
@ -169,4 +203,101 @@ public class WxAppletService {
return Result.error("获取失败: " + e.getMessage());
}
}
public void approveWithdrawal(AppletWithdrawal withdrawal) {
//权限验证
AppletUser user = appletUserService.getById(withdrawal.getUserId());
//提现结果
String massage = "提现申请失败";
//1.微信提现基础参数
//变化的用户信息参数
// map.put("openid", member.getAppletOpenid());//用户openid(小程序)
// map.put("userName", commonMoneyLog.getUserName());//用户真实姓名
// map.put("transferAmount", commonMoneyLog.getMoney());//提现金额, 单位为
// String idStr = "H" + IdWorker.getIdStr();
// map.put("outBillNo", idStr);//商户单号
TransferToUser client = new TransferToUser(
mchid, // 商户号是由微信支付系统生成并分配给每个商户的唯一标识符商户号获取方式参考 https://pay.weixin.qq.com/doc/v3/merchant/4013070756
certiticateSerialNo, // 商户API证书序列号如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013053053
privateKeyFilePath, // 商户API证书私钥文件路径本地文件路径
wechatPayPublicKeyId, // 微信支付公钥ID如何获取请参考 https://pay.weixin.qq.com/doc/v3/merchant/4013038816
wechatPayPublicKeyFilePath // 微信支付公钥文件路径本地文件路径
);
//2场景信息
TransferToUser.TransferToUserRequest request = new TransferToUser.TransferToUserRequest();
request.appid = appid;
request.outBillNo = withdrawal.getId();
request.transferSceneId = "1010";//商户转账场景ID 1010-二手回收
request.openid = user.getOpenid();
request.userName = withdrawal.getName();
request.transferAmount = withdrawal.getMoney().multiply(new BigDecimal(100)).longValue();//单位为分
request.transferRemark = "备注";
request.notifyUrl = transferNotify;
// request.notifyUrl = "https://www.yurangongfang.com/massage-admin/massage/cash/cashoutNotify/";
request.userRecvPerception = "";
request.transferSceneReportInfos = new ArrayList<>();
{
TransferToUser.TransferSceneReportInfo item0 = new TransferToUser.TransferSceneReportInfo();
item0.infoType = "回收商品名称";
item0.infoContent = "衣服";
request.transferSceneReportInfos.add(item0);
}
//3执行提现
TransferToUser.TransferToUserResponse response = null;
try {
response = client.run(request);
}catch (WXPayUtility.ApiException e){
if (e.statusCode == 400){
throw new JeecgBootException("请输入您的真实姓名");
}
throw new JeecgBootException("提现失败");
}
log.info("提现发起成功,outBillNo:"+response.outBillNo + ",transferBillNo:" +response.transferBillNo + ",state:" +response.state+ ",packageInfo:" + response.packageInfo);
switch (response.state){
case ACCEPTED:
log.info("转账已受理");
massage = "转账已受理";
break;
case PROCESSING:
log.info("转账锁定资金中。如果一直停留在该状态,建议检查账户余额是否足够,如余额不足,可充值后再原单重试");
massage = "转账锁定资金中。如果一直停留在该状态,建议检查账户余额是否足够,如余额不足,可充值后再原单重试";
break;
case WAIT_USER_CONFIRM:
log.info("待收款用户确认,可拉起微信收款确认页面进行收款确认");
massage = "待收款用户确认,可拉起微信收款确认页面进行收款确认";
break;
case TRANSFERING:
log.info("转账中,可拉起微信收款确认页面再次重试确认收款");
massage = "转账中,可拉起微信收款确认页面再次重试确认收款";
break;
case SUCCESS:
log.info("转账成功");
massage = "转账成功";
break;
case FAIL:
log.info("转账失败");
massage = "转账失败";
break;
case CANCELING:
log.info("商户撤销请求受理成功,该笔转账正在撤销中");
massage = "商户撤销请求受理成功,该笔转账正在撤销中";
break;
case CANCELLED:
log.info("转账撤销完成");
massage = "转账撤销完成";
break;
}
log.info("提现结果:" + massage);
withdrawal.setPackageInfo(response.packageInfo);//参数
}
}

+ 153
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/common/wxUtils/transfer/TransferToUser.java View File

@ -0,0 +1,153 @@
package org.jeecg.modules.common.wxUtils.transfer;
import com.google.gson.annotations.SerializedName;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.List;
import java.util.Map;
/**
* 发起转账
*/
@Slf4j
public class TransferToUser {
private final String mchid;
private final String certificateSerialNo;
private final PrivateKey privateKey;
private final String wechatPayPublicKeyId;
private final PublicKey wechatPayPublicKey;
public TransferToUser(String mchid, String certificateSerialNo, String privateKeyFilePath, String wechatPayPublicKeyId, String wechatPayPublicKeyFilePath) {
this.mchid = mchid;
this.certificateSerialNo = certificateSerialNo;
this.privateKey = WXPayUtility.loadPrivateKeyFromPath(privateKeyFilePath);
this.wechatPayPublicKeyId = wechatPayPublicKeyId;
this.wechatPayPublicKey = WXPayUtility.loadPublicKeyFromPath(wechatPayPublicKeyFilePath);
}
public TransferToUserResponse run(TransferToUserRequest request) {
// map.put("host", "https://api.mch.weixin.qq.com");//请求地址
// map.put("method", "POST");//请求类型
// map.put("path", "/v3/fund-app/mch-transfer/transfer-bills");//提现接口
String uri = "https://api.mch.weixin.qq.com";
String host = "https://api.mch.weixin.qq.com";
String method = "POST";
String reqBody = WXPayUtility.toJson(request);
Request.Builder reqBuilder = new Request.Builder().url(host + uri);
reqBuilder.addHeader("Accept", "application/json");
reqBuilder.addHeader("Wechatpay-Serial", wechatPayPublicKeyId);
reqBuilder.addHeader("Authorization", WXPayUtility.buildAuthorization(mchid, certificateSerialNo,privateKey, method, uri, reqBody));
reqBuilder.addHeader("Content-Type", "application/json");
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), reqBody);
reqBuilder.method(method, requestBody);
Request httpRequest = reqBuilder.build();
// 发送HTTP请求
OkHttpClient client = new OkHttpClient.Builder().build();
try (Response httpResponse = client.newCall(httpRequest).execute()) {
String respBody = WXPayUtility.extractBody(httpResponse);
if (httpResponse.code() >= 200 && httpResponse.code() < 300) {
// 2XX 成功验证应答签名
WXPayUtility.validateResponse(this.wechatPayPublicKeyId, this.wechatPayPublicKey,
httpResponse.headers(), respBody);
// 从HTTP应答报文构建返回数据
return WXPayUtility.fromJson(respBody, TransferToUserResponse.class);
} else {
throw new WXPayUtility.ApiException(httpResponse.code(), respBody, httpResponse.headers());
}
} catch (IOException e) {
throw new UncheckedIOException("Sending request to " + uri + " failed.", e);
}
}
public String encrypt(String plainText) {
return WXPayUtility.encrypt(this.wechatPayPublicKey, plainText);
}
public static class TransferToUserResponse {
@SerializedName("out_bill_no")
public String outBillNo;
@SerializedName("transfer_bill_no")
public String transferBillNo;
@SerializedName("create_time")
public String createTime;
@SerializedName("state")
public TransferBillStatus state;
@SerializedName("package_info")
public String packageInfo;
}
public enum TransferBillStatus {
@SerializedName("ACCEPTED")
ACCEPTED,
@SerializedName("PROCESSING")
PROCESSING,
@SerializedName("WAIT_USER_CONFIRM")
WAIT_USER_CONFIRM,
@SerializedName("TRANSFERING")
TRANSFERING,
@SerializedName("SUCCESS")
SUCCESS,
@SerializedName("FAIL")
FAIL,
@SerializedName("CANCELING")
CANCELING,
@SerializedName("CANCELLED")
CANCELLED
}
public static class TransferSceneReportInfo {
@SerializedName("info_type")
public String infoType;
@SerializedName("info_content")
public String infoContent;
}
public static class TransferToUserRequest {
@SerializedName("appid")
public String appid;
@SerializedName("out_bill_no")
public String outBillNo;
@SerializedName("transfer_scene_id")
public String transferSceneId;
@SerializedName("openid")
public String openid;
@SerializedName("user_name")
public String userName;
@SerializedName("transfer_amount")
public Long transferAmount;
@SerializedName("transfer_remark")
public String transferRemark;
@SerializedName("notify_url")
public String notifyUrl;
@SerializedName("user_recv_perception")
public String userRecvPerception;
@SerializedName("transfer_scene_report_infos")
public List<TransferSceneReportInfo> transferSceneReportInfos;
}
}

+ 381
- 0
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/common/wxUtils/transfer/WXPayUtility.java View File

@ -0,0 +1,381 @@
package org.jeecg.modules.common.wxUtils.transfer;
import com.google.gson.*;
import com.google.gson.annotations.Expose;
import okhttp3.Headers;
import okhttp3.Response;
import okio.BufferedSource;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.time.DateTimeException;
import java.time.Duration;
import java.time.Instant;
import java.util.Base64;
import java.util.Map;
import java.util.Objects;
public class WXPayUtility {
private static final Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.addSerializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
final Expose expose = fieldAttributes.getAnnotation(Expose.class);
return expose != null && !expose.serialize();
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
})
.addDeserializationExclusionStrategy(new ExclusionStrategy() {
@Override
public boolean shouldSkipField(FieldAttributes fieldAttributes) {
final Expose expose = fieldAttributes.getAnnotation(Expose.class);
return expose != null && !expose.deserialize();
}
@Override
public boolean shouldSkipClass(Class<?> aClass) {
return false;
}
})
.create();
private static final char[] SYMBOLS =
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray();
private static final SecureRandom random = new SecureRandom();
/**
* Object 转换为 JSON 字符串
*/
public static String toJson(Object object) {
return gson.toJson(object);
}
/**
* JSON 字符串解析为特定类型的实例
*/
public static <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
return gson.fromJson(json, classOfT);
}
/**
* 从公私钥文件路径中读取文件内容
*
* @param keyPath 文件路径
* @return 文件内容
*/
private static String readKeyStringFromPath(String keyPath) {
try {
return new String(Files.readAllBytes(Paths.get(keyPath)), StandardCharsets.UTF_8);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
/**
* 读取 PKCS#8 格式的私钥字符串并加载为私钥对象
*
* @param keyString 私钥文件内容 -----BEGIN PRIVATE KEY----- 开头
* @return PrivateKey 对象
*/
public static PrivateKey loadPrivateKeyFromString(String keyString) {
try {
keyString = keyString.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
return KeyFactory.getInstance("RSA").generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(keyString)));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(e);
}
}
/**
* PKCS#8 格式的私钥文件中加载私钥
*
* @param keyPath 私钥文件路径
* @return PrivateKey 对象
*/
public static PrivateKey loadPrivateKeyFromPath(String keyPath) {
return loadPrivateKeyFromString(readKeyStringFromPath(keyPath));
}
/**
* 读取 PKCS#8 格式的公钥字符串并加载为公钥对象
*
* @param keyString 公钥文件内容 -----BEGIN PUBLIC KEY----- 开头
* @return PublicKey 对象
*/
public static PublicKey loadPublicKeyFromString(String keyString) {
try {
keyString = keyString.replace("-----BEGIN PUBLIC KEY-----", "")
.replace("-----END PUBLIC KEY-----", "")
.replaceAll("\\s+", "");
return KeyFactory.getInstance("RSA").generatePublic(
new X509EncodedKeySpec(Base64.getDecoder().decode(keyString)));
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
} catch (InvalidKeySpecException e) {
throw new IllegalArgumentException(e);
}
}
/**
* PKCS#8 格式的公钥文件中加载公钥
*
* @param keyPath 公钥文件路径
* @return PublicKey 对象
*/
public static PublicKey loadPublicKeyFromPath(String keyPath) {
return loadPublicKeyFromString(readKeyStringFromPath(keyPath));
}
/**
* 创建指定长度的随机字符串字符集为[0-9a-zA-Z]可用于安全相关用途
*/
public static String createNonce(int length) {
char[] buf = new char[length];
for (int i = 0; i < length; ++i) {
buf[i] = SYMBOLS[random.nextInt(SYMBOLS.length)];
}
return new String(buf);
}
/**
* 使用公钥按照 RSA_PKCS1_OAEP_PADDING 算法进行加密
*
* @param publicKey 加密用公钥对象
* @param plaintext 待加密明文
* @return 加密后密文
*/
public static String encrypt(PublicKey publicKey, String plaintext) {
final String transformation = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
try {
Cipher cipher = Cipher.getInstance(transformation);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encodeToString(cipher.doFinal(plaintext.getBytes(StandardCharsets.UTF_8)));
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalArgumentException("The current Java environment does not support " + transformation, e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("RSA encryption using an illegal publicKey", e);
} catch (BadPaddingException | IllegalBlockSizeException e) {
throw new IllegalArgumentException("Plaintext is too long", e);
}
}
/**
* 使用私钥按照指定算法进行签名
*
* @param message 待签名串
* @param algorithm 签名算法 SHA256withRSA
* @param privateKey 签名用私钥对象
* @return 签名结果
*/
public static String sign(String message, String algorithm, PrivateKey privateKey) {
byte[] sign;
try {
Signature signature = Signature.getInstance(algorithm);
signature.initSign(privateKey);
signature.update(message.getBytes(StandardCharsets.UTF_8));
sign = signature.sign();
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("The current Java environment does not support " + algorithm, e);
} catch (InvalidKeyException e) {
throw new IllegalArgumentException(algorithm + " signature uses an illegal privateKey.", e);
} catch (SignatureException e) {
throw new RuntimeException("An error occurred during the sign process.", e);
}
return Base64.getEncoder().encodeToString(sign);
}
/**
* 使用公钥按照特定算法验证签名
*
* @param message 待签名串
* @param signature 待验证的签名内容
* @param algorithm 签名算法SHA256withRSA
* @param publicKey 验签用公钥对象
* @return 签名验证是否通过
*/
public static boolean verify(String message, String signature, String algorithm,
PublicKey publicKey) {
try {
Signature sign = Signature.getInstance(algorithm);
sign.initVerify(publicKey);
sign.update(message.getBytes(StandardCharsets.UTF_8));
return sign.verify(Base64.getDecoder().decode(signature));
} catch (SignatureException e) {
return false;
} catch (InvalidKeyException e) {
throw new IllegalArgumentException("verify uses an illegal publickey.", e);
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("The current Java environment does not support" + algorithm, e);
}
}
/**
* 根据微信支付APIv3请求签名规则构造 Authorization 签名
*
* @param mchid 商户号
* @param certificateSerialNo 商户API证书序列号
* @param privateKey 商户API证书私钥
* @param method 请求接口的HTTP方法请使用全大写表述 GETPOSTPUTDELETE
* @param uri 请求接口的URL
* @param body 请求接口的Body
* @return 构造好的微信支付APIv3 Authorization
*/
public static String buildAuthorization(String mchid, String certificateSerialNo,
PrivateKey privateKey,
String method, String uri, String body) {
String nonce = createNonce(32);
long timestamp = Instant.now().getEpochSecond();
String message = String.format("%s\n%s\n%d\n%s\n%s\n", method, uri, timestamp, nonce,
body == null ? "" : body);
String signature = sign(message, "SHA256withRSA", privateKey);
return String.format(
"WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",signature=\"%s\"," +
"timestamp=\"%d\",serial_no=\"%s\"",
mchid, nonce, signature, timestamp, certificateSerialNo);
}
/**
* 对参数进行 URL 编码
*
* @param content 参数内容
* @return 编码后的内容
*/
public static String urlEncode(String content) {
try {
return URLEncoder.encode(content, StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
/**
* 对参数Map进行 URL 编码生成 QueryString
*
* @param params Query参数Map
* @return QueryString
*/
public static String urlEncode(Map<String, Object> params) {
if (params == null || params.isEmpty()) {
return "";
}
int index = 0;
StringBuilder result = new StringBuilder();
for (Map.Entry<String, Object> entry : params.entrySet()) {
result.append(entry.getKey())
.append("=")
.append(urlEncode(entry.getValue().toString()));
index++;
if (index < params.size()) {
result.append("&");
}
}
return result.toString();
}
/**
* 从应答中提取 Body
*
* @param response HTTP 请求应答对象
* @return 应答中的Body内容Body为空时返回空字符串
*/
public static String extractBody(Response response) {
if (response.body() == null) {
return "";
}
try {
BufferedSource source = response.body().source();
return source.readUtf8();
} catch (IOException e) {
throw new RuntimeException(String.format("An error occurred during reading response body. Status: %d", response.code()), e);
}
}
/**
* 根据微信支付APIv3应答验签规则对应答签名进行验证验证不通过时抛出异常
*
* @param wechatpayPublicKeyId 微信支付公钥ID
* @param wechatpayPublicKey 微信支付公钥对象
* @param headers 微信支付应答 Header 列表
* @param body 微信支付应答 Body
*/
public static void validateResponse(String wechatpayPublicKeyId, PublicKey wechatpayPublicKey,
Headers headers,
String body) {
String timestamp = headers.get("Wechatpay-Timestamp");
try {
Instant responseTime = Instant.ofEpochSecond(Long.parseLong(timestamp));
// 拒绝过期请求
if (Duration.between(responseTime, Instant.now()).abs().toMinutes() >= 5) {
throw new IllegalArgumentException(
String.format("Validate http response,timestamp[%s] of httpResponse is expires, "
+ "request-id[%s]",
timestamp, headers.get("Request-ID")));
}
} catch (DateTimeException | NumberFormatException e) {
throw new IllegalArgumentException(
String.format("Validate http response,timestamp[%s] of httpResponse is invalid, " +
"request-id[%s]", timestamp,
headers.get("Request-ID")));
}
String message = String.format("%s\n%s\n%s\n", timestamp, headers.get("Wechatpay-Nonce"),
body == null ? "" : body);
String serialNumber = headers.get("Wechatpay-Serial");
if (!Objects.equals(serialNumber, wechatpayPublicKeyId)) {
throw new IllegalArgumentException(
String.format("Invalid Wechatpay-Serial, Local: %s, Remote: %s", wechatpayPublicKeyId,
serialNumber));
}
String signature = headers.get("Wechatpay-Signature");
boolean success = verify(message, signature, "SHA256withRSA", wechatpayPublicKey);
if (!success) {
throw new IllegalArgumentException(
String.format("Validate response failed,the WechatPay signature is incorrect.%n"
+ "Request-ID[%s]\tresponseHeader[%s]\tresponseBody[%.1024s]",
headers.get("Request-ID"), headers, body));
}
}
/**
* 微信支付API错误异常发送HTTP请求成功但返回状态码不是 2XX 时抛出本异常
*/
public static class ApiException extends RuntimeException {
public final int statusCode;
public final String body;
public final Headers headers;
public ApiException(int statusCode, String body, Headers headers) {
super(String.format("微信支付API访问失败,StatusCode: %s, Body: %s", statusCode, body));
this.statusCode = statusCode;
this.body = body;
this.headers = headers;
}
}
}

+ 16
- 16
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/controller/AppletTtsPlayLogController.java View File

@ -39,12 +39,12 @@ import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 小程序语音朗读记录
* @Description: 朗读记录
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
@Tag(name="小程序语音朗读记录")
@Tag(name="朗读记录")
@RestController
@RequestMapping("/appletTtsPlayLog/appletTtsPlayLog")
@Slf4j
@ -61,8 +61,8 @@ public class AppletTtsPlayLogController extends JeecgController<AppletTtsPlayLog
* @param req
* @return
*/
//@AutoLog(value = "小程序语音朗读记录-分页列表查询")
@Operation(summary="小程序语音朗读记录-分页列表查询")
//@AutoLog(value = "朗读记录-分页列表查询")
@Operation(summary="朗读记录-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<AppletTtsPlayLog>> queryPageList(AppletTtsPlayLog appletTtsPlayLog,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@ -82,8 +82,8 @@ public class AppletTtsPlayLogController extends JeecgController<AppletTtsPlayLog
* @param appletTtsPlayLog
* @return
*/
@AutoLog(value = "小程序语音朗读记录-添加")
@Operation(summary="小程序语音朗读记录-添加")
@AutoLog(value = "朗读记录-添加")
@Operation(summary="朗读记录-添加")
@RequiresPermissions("appletTtsPlayLog:applet_tts_play_log:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody AppletTtsPlayLog appletTtsPlayLog) {
@ -98,8 +98,8 @@ public class AppletTtsPlayLogController extends JeecgController<AppletTtsPlayLog
* @param appletTtsPlayLog
* @return
*/
@AutoLog(value = "小程序语音朗读记录-编辑")
@Operation(summary="小程序语音朗读记录-编辑")
@AutoLog(value = "朗读记录-编辑")
@Operation(summary="朗读记录-编辑")
@RequiresPermissions("appletTtsPlayLog:applet_tts_play_log:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody AppletTtsPlayLog appletTtsPlayLog) {
@ -113,8 +113,8 @@ public class AppletTtsPlayLogController extends JeecgController<AppletTtsPlayLog
* @param id
* @return
*/
@AutoLog(value = "小程序语音朗读记录-通过id删除")
@Operation(summary="小程序语音朗读记录-通过id删除")
@AutoLog(value = "朗读记录-通过id删除")
@Operation(summary="朗读记录-通过id删除")
@RequiresPermissions("appletTtsPlayLog:applet_tts_play_log:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
@ -128,8 +128,8 @@ public class AppletTtsPlayLogController extends JeecgController<AppletTtsPlayLog
* @param ids
* @return
*/
@AutoLog(value = "小程序语音朗读记录-批量删除")
@Operation(summary="小程序语音朗读记录-批量删除")
@AutoLog(value = "朗读记录-批量删除")
@Operation(summary="朗读记录-批量删除")
@RequiresPermissions("appletTtsPlayLog:applet_tts_play_log:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
@ -143,8 +143,8 @@ public class AppletTtsPlayLogController extends JeecgController<AppletTtsPlayLog
* @param id
* @return
*/
//@AutoLog(value = "小程序语音朗读记录-通过id查询")
@Operation(summary="小程序语音朗读记录-通过id查询")
//@AutoLog(value = "朗读记录-通过id查询")
@Operation(summary="朗读记录-通过id查询")
@GetMapping(value = "/queryById")
public Result<AppletTtsPlayLog> queryById(@RequestParam(name="id",required=true) String id) {
AppletTtsPlayLog appletTtsPlayLog = appletTtsPlayLogService.getById(id);
@ -163,7 +163,7 @@ public class AppletTtsPlayLogController extends JeecgController<AppletTtsPlayLog
@RequiresPermissions("appletTtsPlayLog:applet_tts_play_log:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, AppletTtsPlayLog appletTtsPlayLog) {
return super.exportXls(request, appletTtsPlayLog, AppletTtsPlayLog.class, "小程序语音朗读记录");
return super.exportXls(request, appletTtsPlayLog, AppletTtsPlayLog.class, "朗读记录");
}
/**


+ 9
- 9
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/entity/AppletTtsPlayLog.java View File

@ -20,22 +20,22 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 小程序语音朗读记录
* @Description: 朗读记录
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
@Data
@TableName("applet_tts_play_log")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="小程序语音朗读记录")
@Schema(description="朗读记录")
public class AppletTtsPlayLog implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
/**id*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
@Schema(description = "id")
private java.lang.String id;
/**创建人*/
@Schema(description = "创建人")
@ -59,9 +59,9 @@ public class AppletTtsPlayLog implements Serializable {
@Excel(name = "文本", width = 15)
@Schema(description = "文本")
private java.lang.String text;
/**音色*/
@Excel(name = "音色", width = 15)
@Schema(description = "音色")
/**音色ID*/
@Excel(name = "音色ID", width = 15)
@Schema(description = "音色ID")
private java.lang.Integer voicetype;
/**音量*/
@Excel(name = "音量", width = 15)
@ -81,7 +81,7 @@ public class AppletTtsPlayLog implements Serializable {
@Schema(description = "耗时")
private java.lang.Double elapsedTime;
/**是否成功*/
@Excel(name = "是否成功", width = 15,replace = {"是_Y","否_N"} )
@Excel(name = "是否成功", width = 15)
@Schema(description = "是否成功")
private java.lang.String success;
}

+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/mapper/AppletTtsPlayLogMapper.java View File

@ -7,9 +7,9 @@ import org.jeecg.modules.demo.appletTtsPlayLog.entity.AppletTtsPlayLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 小程序语音朗读记录
* @Description: 朗读记录
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
public interface AppletTtsPlayLogMapper extends BaseMapper<AppletTtsPlayLog> {


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/service/IAppletTtsPlayLogService.java View File

@ -4,9 +4,9 @@ import org.jeecg.modules.demo.appletTtsPlayLog.entity.AppletTtsPlayLog;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 小程序语音朗读记录
* @Description: 朗读记录
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
public interface IAppletTtsPlayLogService extends IService<AppletTtsPlayLog> {


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/service/impl/AppletTtsPlayLogServiceImpl.java View File

@ -8,9 +8,9 @@ import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 小程序语音朗读记录
* @Description: 朗读记录
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
@Service


+ 3
- 4
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp/AppletTtsPlayLogForm.vue View File

@ -3,7 +3,7 @@
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack :backRouterName="backRouteName">
<block slot="backText">返回</block>
<block slot="content">小程序语音朗读记录</block>
<block slot="content">朗读记录</block>
</cu-custom>
<!--表单区域-->
<view>
@ -22,8 +22,8 @@
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">音色</text></view>
<input type="number" placeholder="请输入音色" v-model="model.voicetype"/>
<view class="title"><text space="ensp">音色ID</text></view>
<input type="number" placeholder="请输入音色ID" v-model="model.voicetype"/>
</view>
</view>
<view class="cu-form-group">
@ -38,7 +38,6 @@
<input type="number" placeholder="请输入语速" v-model="model.speed"/>
</view>
</view>
<my-date label="创建日期:" v-model="model.createTime" placeholder="请输入创建日期"></my-date>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">耗时</text></view>


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp/AppletTtsPlayLogList.vue View File

@ -3,7 +3,7 @@
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack>
<block slot="backText">返回</block>
<block slot="content">小程序语音朗读记录</block>
<block slot="content">朗读记录</block>
</cu-custom>
<!--滚动加载列表-->
<mescroll-body ref="mescrollRef" bottom="88" @init="mescrollInit" :up="upOption" :down="downOption" @down="downCallback" @up="upCallback">
@ -25,7 +25,7 @@
import Mixin from "@/common/mixin/Mixin.js";
export default {
name: '小程序语音朗读记录',
name: '朗读记录',
mixins: [MescrollMixin,Mixin],
data() {
return {


+ 2
- 10
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp3/AppletTtsPlayLogData.ts View File

@ -12,7 +12,7 @@ export const columns = [
dataIndex: 'text'
},
{
title: '音色',
title: '音色ID',
align:"center",
dataIndex: 'voicetype'
},
@ -26,11 +26,6 @@ export const columns = [
align:"center",
dataIndex: 'speed'
},
{
title: '创建日期',
align:"center",
dataIndex: 'createTime'
},
{
title: '耗时',
align:"center",
@ -39,9 +34,6 @@ export const columns = [
{
title: '是否成功',
align:"center",
dataIndex: 'success',
customRender:({text}) => {
return render.renderSwitch(text, [{text:'是',value:'Y'},{text:'否',value:'N'}])
},
dataIndex: 'success'
},
];

+ 13
- 20
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp3/AppletTtsPlayLogForm.vue View File

@ -3,7 +3,7 @@
layout: 'default',
style: {
navigationStyle: 'custom',
navigationBarTitleText: '小程序语音朗读记录',
navigationBarTitleText: '朗读记录',
},
}
</route>
@ -43,10 +43,10 @@ navigationBarTitleText: '小程序语音朗读记录',
<wd-input
label-width="100px"
v-model="myFormData['voicetype']"
:label="get4Label('音色')"
:label="get4Label('音色ID')"
name='voicetype'
prop='voicetype'
placeholder="请选择音色"
placeholder="请选择音色ID"
inputMode="numeric"
:rules="[
]"
@ -82,8 +82,6 @@ navigationBarTitleText: '小程序语音朗读记录',
/>
</view>
<view class="{ 'mt-14px': 1 == 0 }">
</view>
<view class="{ 'mt-14px': 0 == 0 }">
<wd-input
label-width="100px"
v-model="myFormData['elapsedTime']"
@ -97,23 +95,18 @@ navigationBarTitleText: '小程序语音朗读记录',
clearable
/>
</view>
<view class="{ 'mt-14px': 1 == 0 }">
<!-- 开关 -->
<wd-cell
:label="get4Label('是否成功')"
name='success'
title-width="100px"
center
>
<wd-switch
<view class="{ 'mt-14px': 0 == 0 }">
<wd-input
label-width="100px"
v-model="myFormData['success']"
:label="get4Label('是否成功')"
name='success'
size="18px"
v-model="myFormData['success']"
active-value="Y"
inactive-value="N"
/>
</wd-cell>
prop='success'
placeholder="请选择是否成功"
:rules="[
]"
clearable
/>
</view>
</wd-cell-group>
</wd-form>


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/uniapp3/AppletTtsPlayLogList.vue View File

@ -2,13 +2,13 @@
{
layout: 'default',
style: {
navigationBarTitleText: '小程序语音朗读记录',
navigationBarTitleText: '朗读记录',
navigationStyle: 'custom',
},
}
</route>
<template>
<PageLayout navTitle="小程序语音朗读记录" backRouteName="index" routeMethod="pushTab">
<PageLayout navTitle="朗读记录" backRouteName="index" routeMethod="pushTab">
<view class="wrap">
<z-paging
ref="paging"


+ 7
- 18
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/vue3/AppletTtsPlayLog.data.ts View File

@ -16,7 +16,7 @@ export const columns: BasicColumn[] = [
dataIndex: 'text'
},
{
title: '音色',
title: '音色ID',
align:"center",
dataIndex: 'voicetype'
},
@ -30,11 +30,6 @@ export const columns: BasicColumn[] = [
align:"center",
dataIndex: 'speed'
},
{
title: '创建日期',
align:"center",
dataIndex: 'createTime'
},
{
title: '耗时',
align:"center",
@ -43,10 +38,7 @@ export const columns: BasicColumn[] = [
{
title: '是否成功',
align:"center",
dataIndex: 'success',
customRender:({text}) => {
return render.renderSwitch(text, [{text:'是',value:'Y'},{text:'否',value:'N'}])
},
dataIndex: 'success'
},
];
//查询数据
@ -65,7 +57,7 @@ export const formSchema: FormSchema[] = [
component: 'Input',
},
{
label: '音色',
label: '音色ID',
field: 'voicetype',
component: 'InputNumber',
},
@ -87,9 +79,7 @@ export const formSchema: FormSchema[] = [
{
label: '是否成功',
field: 'success',
component: 'JSwitch',
componentProps:{
},
component: 'Input',
},
// TODO 主键隐藏字段,目前写死为ID
{
@ -104,12 +94,11 @@ export const formSchema: FormSchema[] = [
export const superQuerySchema = {
userId: {title: '用户',order: 0,view: 'text', type: 'string',},
text: {title: '文本',order: 1,view: 'text', type: 'string',},
voicetype: {title: '音色',order: 2,view: 'number', type: 'number',},
voicetype: {title: '音色ID',order: 2,view: 'number', type: 'number',},
volume: {title: '音量',order: 3,view: 'number', type: 'number',},
speed: {title: '语速',order: 4,view: 'number', type: 'number',},
createTime: {title: '创建日期',order: 5,view: 'datetime', type: 'string',},
elapsedTime: {title: '耗时',order: 6,view: 'number', type: 'number',},
success: {title: '是否成功',order: 7,view: 'switch', type: 'string',},
elapsedTime: {title: '耗时',order: 5,view: 'number', type: 'number',},
success: {title: '是否成功',order: 6,view: 'text', type: 'string',},
};
/**


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsPlayLog/vue3/AppletTtsPlayLogList.vue View File

@ -61,7 +61,7 @@
//table
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '小程序语音朗读记录',
title: '朗读记录',
api: list,
columns,
canResize:true,
@ -91,7 +91,7 @@
},
},
exportConfig: {
name:"小程序语音朗读记录",
name:"朗读记录",
url: getExportUrl,
params: queryParam,
},


+ 21
- 17
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/controller/AppletTtsTimbreController.java View File

@ -39,12 +39,12 @@ import io.swagger.v3.oas.annotations.Operation;
import org.jeecg.common.aspect.annotation.AutoLog;
import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 小程序语音音色
* @Description: 音色管理
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
@Tag(name="小程序语音音色")
@Tag(name="音色管理")
@RestController
@RequestMapping("/appletTtsTimbre/appletTtsTimbre")
@Slf4j
@ -61,8 +61,8 @@ public class AppletTtsTimbreController extends JeecgController<AppletTtsTimbre,
* @param req
* @return
*/
//@AutoLog(value = "小程序语音音色-分页列表查询")
@Operation(summary="小程序语音音色-分页列表查询")
//@AutoLog(value = "音色管理-分页列表查询")
@Operation(summary="音色管理-分页列表查询")
@GetMapping(value = "/list")
public Result<IPage<AppletTtsTimbre>> queryPageList(AppletTtsTimbre appletTtsTimbre,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
@ -70,7 +70,11 @@ public class AppletTtsTimbreController extends JeecgController<AppletTtsTimbre,
HttpServletRequest req) {
QueryWrapper<AppletTtsTimbre> queryWrapper = QueryGenerator.initQueryWrapper(appletTtsTimbre, req.getParameterMap());
// 自定义查询规则
Map<String, QueryRuleEnum> customeRuleMap = new HashMap<>();
// 自定义多选的查询规则为LIKE_WITH_OR
customeRuleMap.put("language", QueryRuleEnum.LIKE_WITH_OR);
QueryWrapper<AppletTtsTimbre> queryWrapper = QueryGenerator.initQueryWrapper(appletTtsTimbre, req.getParameterMap(),customeRuleMap);
Page<AppletTtsTimbre> page = new Page<AppletTtsTimbre>(pageNo, pageSize);
IPage<AppletTtsTimbre> pageList = appletTtsTimbreService.page(page, queryWrapper);
return Result.OK(pageList);
@ -82,8 +86,8 @@ public class AppletTtsTimbreController extends JeecgController<AppletTtsTimbre,
* @param appletTtsTimbre
* @return
*/
@AutoLog(value = "小程序语音音色-添加")
@Operation(summary="小程序语音音色-添加")
@AutoLog(value = "音色管理-添加")
@Operation(summary="音色管理-添加")
@RequiresPermissions("appletTtsTimbre:applet_tts_timbre:add")
@PostMapping(value = "/add")
public Result<String> add(@RequestBody AppletTtsTimbre appletTtsTimbre) {
@ -98,8 +102,8 @@ public class AppletTtsTimbreController extends JeecgController<AppletTtsTimbre,
* @param appletTtsTimbre
* @return
*/
@AutoLog(value = "小程序语音音色-编辑")
@Operation(summary="小程序语音音色-编辑")
@AutoLog(value = "音色管理-编辑")
@Operation(summary="音色管理-编辑")
@RequiresPermissions("appletTtsTimbre:applet_tts_timbre:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody AppletTtsTimbre appletTtsTimbre) {
@ -113,8 +117,8 @@ public class AppletTtsTimbreController extends JeecgController<AppletTtsTimbre,
* @param id
* @return
*/
@AutoLog(value = "小程序语音音色-通过id删除")
@Operation(summary="小程序语音音色-通过id删除")
@AutoLog(value = "音色管理-通过id删除")
@Operation(summary="音色管理-通过id删除")
@RequiresPermissions("appletTtsTimbre:applet_tts_timbre:delete")
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name="id",required=true) String id) {
@ -128,8 +132,8 @@ public class AppletTtsTimbreController extends JeecgController<AppletTtsTimbre,
* @param ids
* @return
*/
@AutoLog(value = "小程序语音音色-批量删除")
@Operation(summary="小程序语音音色-批量删除")
@AutoLog(value = "音色管理-批量删除")
@Operation(summary="音色管理-批量删除")
@RequiresPermissions("appletTtsTimbre:applet_tts_timbre:deleteBatch")
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
@ -143,8 +147,8 @@ public class AppletTtsTimbreController extends JeecgController<AppletTtsTimbre,
* @param id
* @return
*/
//@AutoLog(value = "小程序语音音色-通过id查询")
@Operation(summary="小程序语音音色-通过id查询")
//@AutoLog(value = "音色管理-通过id查询")
@Operation(summary="音色管理-通过id查询")
@GetMapping(value = "/queryById")
public Result<AppletTtsTimbre> queryById(@RequestParam(name="id",required=true) String id) {
AppletTtsTimbre appletTtsTimbre = appletTtsTimbreService.getById(id);
@ -163,7 +167,7 @@ public class AppletTtsTimbreController extends JeecgController<AppletTtsTimbre,
@RequiresPermissions("appletTtsTimbre:applet_tts_timbre:exportXls")
@RequestMapping(value = "/exportXls")
public ModelAndView exportXls(HttpServletRequest request, AppletTtsTimbre appletTtsTimbre) {
return super.exportXls(request, appletTtsTimbre, AppletTtsTimbre.class, "小程序语音音色");
return super.exportXls(request, appletTtsTimbre, AppletTtsTimbre.class, "音色管理");
}
/**


+ 18
- 5
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/entity/AppletTtsTimbre.java View File

@ -20,22 +20,22 @@ import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* @Description: 小程序语音音色
* @Description: 音色管理
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
@Data
@TableName("applet_tts_timbre")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@Schema(description="小程序语音音色")
@Schema(description="音色管理")
public class AppletTtsTimbre implements Serializable {
private static final long serialVersionUID = 1L;
/**主键*/
/**id*/
@TableId(type = IdType.ASSIGN_ID)
@Schema(description = "主键")
@Schema(description = "id")
private java.lang.String id;
/**创建人*/
@Schema(description = "创建人")
@ -60,6 +60,10 @@ public class AppletTtsTimbre implements Serializable {
@Excel(name = "名称", width = 15)
@Schema(description = "名称")
private java.lang.String name;
/**描述*/
@Excel(name = "描述", width = 15)
@Schema(description = "描述")
private java.lang.String info;
/**音色ID*/
@Excel(name = "音色ID", width = 15)
@Schema(description = "音色ID")
@ -68,4 +72,13 @@ public class AppletTtsTimbre implements Serializable {
@Excel(name = "头像", width = 15)
@Schema(description = "头像")
private java.lang.String image;
/**语言*/
@Excel(name = "语言", width = 15, dicCode = "applet_tts_timbre_language")
@Dict(dicCode = "applet_tts_timbre_language")
@Schema(description = "语言")
private java.lang.String language;
/**启用*/
@Excel(name = "启用", width = 15,replace = {"是_Y","否_N"} )
@Schema(description = "启用")
private java.lang.String status;
}

+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/mapper/AppletTtsTimbreMapper.java View File

@ -7,9 +7,9 @@ import org.jeecg.modules.demo.appletTtsTimbre.entity.AppletTtsTimbre;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 小程序语音音色
* @Description: 音色管理
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
public interface AppletTtsTimbreMapper extends BaseMapper<AppletTtsTimbre> {


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/service/IAppletTtsTimbreService.java View File

@ -4,9 +4,9 @@ import org.jeecg.modules.demo.appletTtsTimbre.entity.AppletTtsTimbre;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 小程序语音音色
* @Description: 音色管理
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
public interface IAppletTtsTimbreService extends IService<AppletTtsTimbre> {


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/service/impl/AppletTtsTimbreServiceImpl.java View File

@ -8,9 +8,9 @@ import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 小程序语音音色
* @Description: 音色管理
* @Author: jeecg-boot
* @Date: 2025-09-12
* @Date: 2025-09-19
* @Version: V1.0
*/
@Service


+ 19
- 1
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp/AppletTtsTimbreForm.vue View File

@ -3,7 +3,7 @@
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack :backRouterName="backRouteName">
<block slot="backText">返回</block>
<block slot="content">小程序语音音色</block>
<block slot="content">音色管理</block>
</cu-custom>
<!--表单区域-->
<view>
@ -14,6 +14,12 @@
<input placeholder="请输入名称" v-model="model.name"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">描述</text></view>
<input placeholder="请输入描述" v-model="model.info"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">音色ID</text></view>
@ -25,6 +31,18 @@
<view class="title"><text space="ensp">头像</text></view>
<input placeholder="请输入头像" v-model="model.image"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">语言</text></view>
<input placeholder="请输入语言" v-model="model.language"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">启用</text></view>
<input placeholder="请输入启用" v-model="model.status"/>
</view>
</view>
<view class="padding">
<button class="cu-btn block bg-blue margin-tb-sm lg" @click="onSubmit">


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp/AppletTtsTimbreList.vue View File

@ -3,7 +3,7 @@
<!--标题和返回-->
<cu-custom :bgColor="NavBarColor" isBack>
<block slot="backText">返回</block>
<block slot="content">小程序语音音色</block>
<block slot="content">音色管理</block>
</cu-custom>
<!--滚动加载列表-->
<mescroll-body ref="mescrollRef" bottom="88" @init="mescrollInit" :up="upOption" :down="downOption" @down="downCallback" @up="upCallback">
@ -25,7 +25,7 @@
import Mixin from "@/common/mixin/Mixin.js";
export default {
name: '小程序语音音色',
name: '音色管理',
mixins: [MescrollMixin,Mixin],
data() {
return {


+ 20
- 1
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp3/AppletTtsTimbreData.ts View File

@ -6,6 +6,11 @@ export const columns = [
align:"center",
dataIndex: 'name'
},
{
title: '描述',
align:"center",
dataIndex: 'info'
},
{
title: '音色ID',
align:"center",
@ -14,6 +19,20 @@ export const columns = [
{
title: '头像',
align:"center",
dataIndex: 'image'
dataIndex: 'image',
customRender:render.renderImage,
},
{
title: '语言',
align:"center",
dataIndex: 'language_dictText'
},
{
title: '启用',
align:"center",
dataIndex: 'status',
customRender:({text}) => {
return render.renderSwitch(text, [{text:'是',value:'Y'},{text:'否',value:'N'}])
},
},
];

+ 51
- 11
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp3/AppletTtsTimbreForm.vue View File

@ -3,7 +3,7 @@
layout: 'default',
style: {
navigationStyle: 'custom',
navigationBarTitleText: '小程序语音音色',
navigationBarTitleText: '音色管理',
},
}
</route>
@ -27,6 +27,19 @@ navigationBarTitleText: '小程序语音音色',
/>
</view>
<view class="{ 'mt-14px': 1 == 0 }">
<wd-input
label-width="100px"
v-model="myFormData['info']"
:label="get4Label('描述')"
name='info'
prop='info'
placeholder="请选择描述"
:rules="[
]"
clearable
/>
</view>
<view class="{ 'mt-14px': 0 == 0 }">
<wd-input
label-width="100px"
v-model="myFormData['voiceType']"
@ -40,18 +53,45 @@ navigationBarTitleText: '小程序语音音色',
clearable
/>
</view>
<view class="{ 'mt-14px': 0 == 0 }">
<wd-input
label-width="100px"
v-model="myFormData['image']"
:label="get4Label('头像')"
<view class="{ 'mt-14px': 1 == 0 }">
<!-- 图片 -->
<wd-cell
:title="get4Label('头像')"
title-width="100px"
>
<online-image
v-model:value="myFormData['image']"
name='image'
prop='image'
placeholder="请选择头像"
:rules="[
]"
clearable
/>
</wd-cell>
</view>
<view class="{ 'mt-14px': 0 == 0 }">
<online-checkbox
:label="get4Label('语言')"
labelWidth="100px"
type="checkbox"
name='language'
dict="applet_tts_timbre_language"
v-model="myFormData['language']"
></online-checkbox>
</view>
<view class="{ 'mt-14px': 1 == 0 }">
<!-- 开关 -->
<wd-cell
:label="get4Label('启用')"
name='status'
title-width="100px"
center
>
<wd-switch
:label="get4Label('启用')"
name='status'
size="18px"
v-model="myFormData['status']"
active-value="Y"
inactive-value="N"
/>
</wd-cell>
</view>
</wd-cell-group>
</wd-form>


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/uniapp3/AppletTtsTimbreList.vue View File

@ -2,13 +2,13 @@
{
layout: 'default',
style: {
navigationBarTitleText: '小程序语音音色',
navigationBarTitleText: '音色管理',
navigationStyle: 'custom',
},
}
</route>
<template>
<PageLayout navTitle="小程序语音音色" backRouteName="index" routeMethod="pushTab">
<PageLayout navTitle="音色管理" backRouteName="index" routeMethod="pushTab">
<view class="wrap">
<z-paging
ref="paging"


+ 58
- 4
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/vue3/AppletTtsTimbre.data.ts View File

@ -10,6 +10,11 @@ export const columns: BasicColumn[] = [
align:"center",
dataIndex: 'name'
},
{
title: '描述',
align:"center",
dataIndex: 'info'
},
{
title: '音色ID',
align:"center",
@ -18,11 +23,34 @@ export const columns: BasicColumn[] = [
{
title: '头像',
align:"center",
dataIndex: 'image'
dataIndex: 'image',
customRender:render.renderImage,
},
{
title: '语言',
align:"center",
dataIndex: 'language_dictText'
},
{
title: '启用',
align:"center",
dataIndex: 'status',
customRender:({text}) => {
return render.renderSwitch(text, [{text:'是',value:'Y'},{text:'否',value:'N'}])
},
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
{
label: "语言",
field: 'language',
component: 'JSelectMultiple',
componentProps:{
dictCode:"applet_tts_timbre_language"
},
//colProps: {span: 6},
},
];
//表单数据
export const formSchema: FormSchema[] = [
@ -31,6 +59,11 @@ export const formSchema: FormSchema[] = [
field: 'name',
component: 'Input',
},
{
label: '描述',
field: 'info',
component: 'Input',
},
{
label: '音色ID',
field: 'voiceType',
@ -39,7 +72,25 @@ export const formSchema: FormSchema[] = [
{
label: '头像',
field: 'image',
component: 'Input',
component: 'JImageUpload',
componentProps:{
fileMax: 0
},
},
{
label: '语言',
field: 'language',
component: 'JCheckbox',
componentProps:{
dictCode:"applet_tts_timbre_language"
},
},
{
label: '启用',
field: 'status',
component: 'JSwitch',
componentProps:{
},
},
// TODO 主键隐藏字段,目前写死为ID
{
@ -53,8 +104,11 @@ export const formSchema: FormSchema[] = [
// 高级查询数据
export const superQuerySchema = {
name: {title: '名称',order: 0,view: 'text', type: 'string',},
voiceType: {title: '音色ID',order: 1,view: 'number', type: 'number',},
image: {title: '头像',order: 2,view: 'text', type: 'string',},
info: {title: '描述',order: 1,view: 'text', type: 'string',},
voiceType: {title: '音色ID',order: 2,view: 'number', type: 'number',},
image: {title: '头像',order: 3,view: 'image', type: 'string',},
language: {title: '语言',order: 4,view: 'checkbox', type: 'string',dictCode: 'applet_tts_timbre_language',},
status: {title: '启用',order: 5,view: 'switch', type: 'string',},
};
/**


+ 2
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletTtsTimbre/vue3/AppletTtsTimbreList.vue View File

@ -61,7 +61,7 @@
//table
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '小程序语音音色',
title: '音色管理',
api: list,
columns,
canResize:true,
@ -91,7 +91,7 @@
},
},
exportConfig: {
name:"小程序语音音色",
name:"音色管理",
url: getExportUrl,
params: queryParam,
},


+ 14
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/controller/AppletWithdrawalController.java View File

@ -10,10 +10,13 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.query.QueryRuleEnum;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.applet.service.impl.WxAppletService;
import org.jeecg.modules.demo.appletWithdrawal.entity.AppletWithdrawal;
import org.jeecg.modules.demo.appletWithdrawal.service.IAppletWithdrawalService;
@ -41,7 +44,7 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
/**
* @Description: 提现
* @Author: jeecg-boot
* @Date: 2025-09-14
* @Date: 2025-09-19
* @Version: V1.0
*/
@Tag(name="提现")
@ -51,7 +54,10 @@ import org.apache.shiro.authz.annotation.RequiresPermissions;
public class AppletWithdrawalController extends JeecgController<AppletWithdrawal, IAppletWithdrawalService> {
@Autowired
private IAppletWithdrawalService appletWithdrawalService;
@Autowired
private WxAppletService wxAppletService;
/**
* 分页列表查询
*
@ -103,6 +109,12 @@ public class AppletWithdrawalController extends JeecgController<AppletWithdrawal
@RequiresPermissions("appletWithdrawal:applet_withdrawal:edit")
@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
public Result<String> edit(@RequestBody AppletWithdrawal appletWithdrawal) {
if ("1".equals(appletWithdrawal.getStatus()) && "0".equals(appletWithdrawal.getMethod())
&& StringUtils.isEmpty(appletWithdrawal.getPackageInfo())){
wxAppletService.approveWithdrawal(appletWithdrawal);
}
appletWithdrawalService.updateById(appletWithdrawal);
return Result.OK("编辑成功!");
}


+ 11
- 4
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/entity/AppletWithdrawal.java View File

@ -22,7 +22,7 @@ import lombok.experimental.Accessors;
/**
* @Description: 提现
* @Author: jeecg-boot
* @Date: 2025-09-14
* @Date: 2025-09-19
* @Version: V1.0
*/
@Data
@ -56,9 +56,10 @@ public class AppletWithdrawal implements Serializable {
/**所属部门*/
@Schema(description = "所属部门")
private java.lang.String sysOrgCode;
/**用户*/
@Excel(name = "用户", width = 15)
@Schema(description = "用户")
/**用户id*/
@Excel(name = "用户id", width = 15, dictTable = "applet_user", dicText = "name", dicCode = "id")
@Dict(dictTable = "applet_user", dicText = "name", dicCode = "id")
@Schema(description = "用户id")
private java.lang.String userId;
/**申请人*/
@Excel(name = "申请人", width = 15)
@ -87,6 +88,12 @@ public class AppletWithdrawal implements Serializable {
@Dict(dicCode = "applet_withdraw_type")
@Schema(description = "提现状态")
private java.lang.String withdrawStatus;
/**流水号*/
@Excel(name = "流水号", width = 15, dictTable = "applet_water", dicText = "number", dicCode = "id")
@Dict(dictTable = "applet_water", dicText = "number", dicCode = "id")
@Schema(description = "流水号")
private java.lang.String waterId;
@Schema(description = "领取参数")
private String packageInfo;
}

+ 1
- 1
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/mapper/AppletWithdrawalMapper.java View File

@ -9,7 +9,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* @Description: 提现
* @Author: jeecg-boot
* @Date: 2025-09-14
* @Date: 2025-09-19
* @Version: V1.0
*/
public interface AppletWithdrawalMapper extends BaseMapper<AppletWithdrawal> {


+ 1
- 1
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/service/IAppletWithdrawalService.java View File

@ -6,7 +6,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
/**
* @Description: 提现
* @Author: jeecg-boot
* @Date: 2025-09-14
* @Date: 2025-09-19
* @Version: V1.0
*/
public interface IAppletWithdrawalService extends IService<AppletWithdrawal> {


+ 1
- 1
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/service/impl/AppletWithdrawalServiceImpl.java View File

@ -10,7 +10,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* @Description: 提现
* @Author: jeecg-boot
* @Date: 2025-09-14
* @Date: 2025-09-19
* @Version: V1.0
*/
@Service


+ 8
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/uniapp/AppletWithdrawalForm.vue View File

@ -10,8 +10,8 @@
<form>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">用户</text></view>
<input placeholder="请输入用户" v-model="model.userId"/>
<view class="title"><text space="ensp">用户id</text></view>
<input placeholder="请输入用户id" v-model="model.userId"/>
</view>
</view>
<view class="cu-form-group">
@ -49,6 +49,12 @@
<view class="title"><text space="ensp">提现状态</text></view>
<input placeholder="请输入提现状态" v-model="model.withdrawStatus"/>
</view>
</view>
<view class="cu-form-group">
<view class="flex align-center">
<view class="title"><text space="ensp">流水号</text></view>
<input placeholder="请输入流水号" v-model="model.waterId"/>
</view>
</view>
<view class="padding">
<button class="cu-btn block bg-blue margin-tb-sm lg" @click="onSubmit">


+ 7
- 2
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/uniapp3/AppletWithdrawalData.ts View File

@ -2,9 +2,9 @@ import { render } from '@/common/renderUtils';
//列表数据
export const columns = [
{
title: '用户',
title: '用户id',
align:"center",
dataIndex: 'userId'
dataIndex: 'userId_dictText'
},
{
title: '申请人',
@ -39,4 +39,9 @@ export const columns = [
align:"center",
dataIndex: 'withdrawStatus_dictText'
},
{
title: '流水号',
align:"center",
dataIndex: 'waterId_dictText'
},
];

+ 18
- 11
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/uniapp3/AppletWithdrawalForm.vue View File

@ -14,17 +14,14 @@ navigationBarTitleText: '提现',
<wd-form ref="form" :model="myFormData">
<wd-cell-group border>
<view class="{ 'mt-14px': 0 == 0 }">
<wd-input
label-width="100px"
v-model="myFormData['userId']"
:label="get4Label('用户')"
name='userId'
prop='userId'
placeholder="请选择用户"
:rules="[
]"
clearable
/>
<online-select
:label="get4Label('用户id')"
labelWidth="100px"
type="sel_search"
name='userId'
dict="applet_user,name,id"
v-model="myFormData['userId']"
></online-select>
</view>
<view class="{ 'mt-14px': 1 == 0 }">
<wd-input
@ -100,6 +97,16 @@ navigationBarTitleText: '提现',
dict="applet_withdraw_type"
v-model="myFormData['withdrawStatus']"
></online-select>
</view>
<view class="{ 'mt-14px': 1 == 0 }">
<online-select
:label="get4Label('流水号')"
labelWidth="100px"
type="sel_search"
name='waterId'
dict="applet_water,number,id"
v-model="myFormData['waterId']"
></online-select>
</view>
</wd-cell-group>
</wd-form>


+ 22
- 5
jeecg-boot/jeecg-boot-module/jeecgboot-boot-applet/src/main/java/org/jeecg/modules/demo/appletWithdrawal/vue3/AppletWithdrawal.data.ts View File

@ -6,9 +6,9 @@ import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '用户',
title: '用户id',
align:"center",
dataIndex: 'userId'
dataIndex: 'userId_dictText'
},
{
title: '申请人',
@ -43,6 +43,11 @@ export const columns: BasicColumn[] = [
align:"center",
dataIndex: 'withdrawStatus_dictText'
},
{
title: '流水号',
align:"center",
dataIndex: 'waterId_dictText'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
@ -50,9 +55,12 @@ export const searchFormSchema: FormSchema[] = [
//表单数据
export const formSchema: FormSchema[] = [
{
label: '用户',
label: '用户id',
field: 'userId',
component: 'Input',
component: 'JSearchSelect',
componentProps:{
dict:"applet_user,name,id"
},
},
{
label: '申请人',
@ -94,6 +102,14 @@ export const formSchema: FormSchema[] = [
componentProps:{
dictCode:"applet_withdraw_type"
},
},
{
label: '流水号',
field: 'waterId',
component: 'JSearchSelect',
componentProps:{
dict:"applet_water,number,id"
},
},
// TODO 主键隐藏字段,目前写死为ID
{
@ -106,13 +122,14 @@ export const formSchema: FormSchema[] = [
// 高级查询数据
export const superQuerySchema = {
userId: {title: '用户',order: 0,view: 'text', type: 'string',},
userId: {title: '用户id',order: 0,view: 'sel_search', type: 'string',dictTable: "applet_user", dictCode: 'id', dictText: 'name',},
name: {title: '申请人',order: 1,view: 'text', type: 'string',},
money: {title: '提现金额',order: 2,view: 'number', type: 'number',},
method: {title: '提现方式',order: 3,view: 'list', type: 'string',dictCode: 'applett_translate_type',},
upload: {title: '凭证上传',order: 4,view: 'switch', type: 'string',},
status: {title: '审核状态',order: 5,view: 'list', type: 'string',dictCode: 'applett_money_type',},
withdrawStatus: {title: '提现状态',order: 6,view: 'list', type: 'string',dictCode: 'applet_withdraw_type',},
waterId: {title: '流水号',order: 7,view: 'sel_search', type: 'string',dictTable: "applet_water", dictCode: 'id', dictText: 'number',},
};
/**


+ 1
- 1
jeecg-boot/jeecg-module-system/jeecg-system-start/src/main/resources/application-dev.yml View File

@ -341,7 +341,7 @@ wechat:
merchantSerialNumber: 4B672D1BCB20B22081FD6C5ECAA7C1277AF1B772 # 商户API证书序列号
apiV3Key: 0fdb77429ffdf206c151af76a663041c # 商户APIV3密钥
refundNotifyUrl: # 退款通知地址(正式环境)
transferNotify: https://www.yurangongfang.com/massage-admin/massage/cash/cashoutNotify/ # 转账结果通知地址


+ 64
- 0
jeecgboot-vue3/src/views/applet/withdrawal/AppletWithdrawal.api.ts View File

@ -0,0 +1,64 @@
import {defHttp} from '/@/utils/http/axios';
import { useMessage } from "/@/hooks/web/useMessage";
const { createConfirm } = useMessage();
enum Api {
list = '/appletWithdrawal/appletWithdrawal/list',
save='/appletWithdrawal/appletWithdrawal/add',
edit='/appletWithdrawal/appletWithdrawal/edit',
deleteOne = '/appletWithdrawal/appletWithdrawal/delete',
deleteBatch = '/appletWithdrawal/appletWithdrawal/deleteBatch',
importExcel = '/appletWithdrawal/appletWithdrawal/importExcel',
exportXls = '/appletWithdrawal/appletWithdrawal/exportXls',
}
/**
* api
* @param params
*/
export const getExportUrl = Api.exportXls;
/**
* api
*/
export const getImportUrl = Api.importExcel;
/**
*
* @param params
*/
export const list = (params) =>
defHttp.get({url: Api.list, params});
/**
*
*/
export const deleteOne = (params,handleSuccess) => {
return defHttp.delete({url: Api.deleteOne, params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
/**
*
* @param params
*/
export const batchDelete = (params, handleSuccess) => {
createConfirm({
iconType: 'warning',
title: '确认删除',
content: '是否删除选中数据',
okText: '确认',
cancelText: '取消',
onOk: () => {
return defHttp.delete({url: Api.deleteBatch, data: params}, {joinParamsToUrl: true}).then(() => {
handleSuccess();
});
}
});
}
/**
*
* @param params
*/
export const saveOrUpdate = (params, isUpdate) => {
let url = isUpdate ? Api.edit : Api.save;
return defHttp.post({url: url, params});
}

+ 142
- 0
jeecgboot-vue3/src/views/applet/withdrawal/AppletWithdrawal.data.ts View File

@ -0,0 +1,142 @@
import {BasicColumn} from '/@/components/Table';
import {FormSchema} from '/@/components/Table';
import { rules} from '/@/utils/helper/validator';
import { render } from '/@/utils/common/renderUtils';
import { getWeekMonthQuarterYear } from '/@/utils';
//列表数据
export const columns: BasicColumn[] = [
{
title: '用户id',
align:"center",
dataIndex: 'userId_dictText'
},
{
title: '申请人',
align:"center",
dataIndex: 'name'
},
{
title: '提现金额',
align:"center",
dataIndex: 'money'
},
{
title: '提现方式',
align:"center",
dataIndex: 'method_dictText'
},
{
title: '凭证上传',
align:"center",
dataIndex: 'upload',
customRender:({text}) => {
return render.renderSwitch(text, [{text:'是',value:'Y'},{text:'否',value:'N'}])
},
},
{
title: '审核状态',
align:"center",
dataIndex: 'status_dictText'
},
{
title: '提现状态',
align:"center",
dataIndex: 'withdrawStatus_dictText'
},
{
title: '流水号',
align:"center",
dataIndex: 'waterId_dictText'
},
];
//查询数据
export const searchFormSchema: FormSchema[] = [
];
//表单数据
export const formSchema: FormSchema[] = [
{
label: '用户id',
field: 'userId',
component: 'JSearchSelect',
componentProps:{
dict:"applet_user,name,id"
},
},
{
label: '申请人',
field: 'name',
component: 'Input',
},
{
label: '提现金额',
field: 'money',
component: 'InputNumber',
},
{
label: '提现方式',
field: 'method',
component: 'JDictSelectTag',
componentProps:{
dictCode:"applett_translate_type"
},
},
{
label: '凭证上传',
field: 'upload',
component: 'JSwitch',
componentProps:{
},
},
{
label: '审核状态',
field: 'status',
component: 'JDictSelectTag',
componentProps:{
dictCode:"applett_money_type"
},
},
{
label: '提现状态',
field: 'withdrawStatus',
component: 'JDictSelectTag',
componentProps:{
dictCode:"applet_withdraw_type"
},
},
{
label: '流水号',
field: 'waterId',
component: 'JSearchSelect',
componentProps:{
dict:"applet_water,number,id"
},
},
// TODO 主键隐藏字段,目前写死为ID
{
label: '',
field: 'id',
component: 'Input',
show: false
},
];
// 高级查询数据
export const superQuerySchema = {
userId: {title: '用户id',order: 0,view: 'sel_search', type: 'string',dictTable: "applet_user", dictCode: 'id', dictText: 'name',},
name: {title: '申请人',order: 1,view: 'text', type: 'string',},
money: {title: '提现金额',order: 2,view: 'number', type: 'number',},
method: {title: '提现方式',order: 3,view: 'list', type: 'string',dictCode: 'applett_translate_type',},
upload: {title: '凭证上传',order: 4,view: 'switch', type: 'string',},
status: {title: '审核状态',order: 5,view: 'list', type: 'string',dictCode: 'applett_money_type',},
withdrawStatus: {title: '提现状态',order: 6,view: 'list', type: 'string',dictCode: 'applet_withdraw_type',},
waterId: {title: '流水号',order: 7,view: 'sel_search', type: 'string',dictTable: "applet_water", dictCode: 'id', dictText: 'number',},
};
/**
* formSchema
* @param param
*/
export function getBpmFormSchema(_formData): FormSchema[]{
// 默认和原始表单保持一致 如果流程中配置了权限数据,这里需要单独处理formSchema
return formSchema;
}

+ 206
- 0
jeecgboot-vue3/src/views/applet/withdrawal/AppletWithdrawalList.vue View File

@ -0,0 +1,206 @@
<template>
<div>
<!--引用表格-->
<BasicTable @register="registerTable" :rowSelection="rowSelection">
<!--插槽:table标题-->
<template #tableTitle>
<a-button type="primary" v-auth="'appletWithdrawal:applet_withdrawal:add'" @click="handleAdd" preIcon="ant-design:plus-outlined"> 新增</a-button>
<a-button type="primary" v-auth="'appletWithdrawal:applet_withdrawal:exportXls'" preIcon="ant-design:export-outlined" @click="onExportXls"> 导出</a-button>
<j-upload-button type="primary" v-auth="'appletWithdrawal:applet_withdrawal:importExcel'" preIcon="ant-design:import-outlined" @click="onImportXls">导入</j-upload-button>
<a-dropdown v-if="selectedRowKeys.length > 0">
<template #overlay>
<a-menu>
<a-menu-item key="1" @click="batchHandleDelete">
<Icon icon="ant-design:delete-outlined"></Icon>
删除
</a-menu-item>
</a-menu>
</template>
<a-button v-auth="'appletWithdrawal:applet_withdrawal:deleteBatch'">批量操作
<Icon icon="mdi:chevron-down"></Icon>
</a-button>
</a-dropdown>
<!-- 高级查询 -->
<super-query :config="superQueryConfig" @search="handleSuperQuery" />
</template>
<!--操作栏-->
<template #action="{ record }">
<TableAction :actions="getTableAction(record)" :dropDownActions="getDropDownAction(record)"/>
</template>
<!--字段回显插槽-->
<template v-slot:bodyCell="{ column, record, index, text }">
</template>
</BasicTable>
<!-- 表单区域 -->
<AppletWithdrawalModal @register="registerModal" @success="handleSuccess"></AppletWithdrawalModal>
</div>
</template>
<script lang="ts" name="appletWithdrawal-appletWithdrawal" setup>
import {ref, reactive, computed, unref} from 'vue';
import {BasicTable, useTable, TableAction} from '/@/components/Table';
import {useModal} from '/@/components/Modal';
import { useListPage } from '/@/hooks/system/useListPage'
import AppletWithdrawalModal from './components/AppletWithdrawalModal.vue'
import {columns, searchFormSchema, superQuerySchema} from './AppletWithdrawal.data';
import {list, deleteOne, batchDelete, getImportUrl,getExportUrl} from './AppletWithdrawal.api';
import { downloadFile } from '/@/utils/common/renderUtils';
import { useUserStore } from '/@/store/modules/user';
import { useMessage } from '/@/hooks/web/useMessage';
import { getDateByPicker } from '/@/utils';
//
const fieldPickers = reactive({
});
const queryParam = reactive<any>({});
const checkedKeys = ref<Array<string | number>>([]);
const userStore = useUserStore();
const { createMessage } = useMessage();
//model
const [registerModal, {openModal}] = useModal();
//table
const { prefixCls,tableContext,onExportXls,onImportXls } = useListPage({
tableProps:{
title: '提现',
api: list,
columns,
canResize:true,
formConfig: {
//labelWidth: 120,
schemas: searchFormSchema,
autoSubmitOnEnter:true,
showAdvancedButton:true,
fieldMapToNumber: [
],
fieldMapToTime: [
],
},
actionColumn: {
width: 120,
fixed:'right'
},
beforeFetch: (params) => {
if (params && fieldPickers) {
for (let key in fieldPickers) {
if (params[key]) {
params[key] = getDateByPicker(params[key], fieldPickers[key]);
}
}
}
return Object.assign(params, queryParam);
},
},
exportConfig: {
name:"提现",
url: getExportUrl,
params: queryParam,
},
importConfig: {
url: getImportUrl,
success: handleSuccess
},
})
const [registerTable, {reload},{ rowSelection, selectedRowKeys }] = tableContext
//
const superQueryConfig = reactive(superQuerySchema);
/**
* 高级查询事件
*/
function handleSuperQuery(params) {
Object.keys(params).map((k) => {
queryParam[k] = params[k];
});
reload();
}
/**
* 新增事件
*/
function handleAdd() {
openModal(true, {
isUpdate: false,
showFooter: true,
});
}
/**
* 编辑事件
*/
function handleEdit(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: true,
});
}
/**
* 详情
*/
function handleDetail(record: Recordable) {
openModal(true, {
record,
isUpdate: true,
showFooter: false,
});
}
/**
* 删除事件
*/
async function handleDelete(record) {
await deleteOne({id: record.id}, handleSuccess);
}
/**
* 批量删除事件
*/
async function batchHandleDelete() {
await batchDelete({ids: selectedRowKeys.value}, handleSuccess);
}
/**
* 成功回调
*/
function handleSuccess() {
(selectedRowKeys.value = []) && reload();
}
/**
* 操作栏
*/
function getTableAction(record){
return [
{
label: '编辑',
onClick: handleEdit.bind(null, record),
auth: 'appletWithdrawal:applet_withdrawal:edit'
}
]
}
/**
* 下拉操作栏
*/
function getDropDownAction(record){
return [
{
label: '详情',
onClick: handleDetail.bind(null, record),
}, {
label: '删除',
popConfirm: {
title: '是否确认删除',
confirm: handleDelete.bind(null, record),
placement: 'topLeft',
},
auth: 'appletWithdrawal:applet_withdrawal:delete'
}
]
}
</script>
<style lang="less" scoped>
:deep(.ant-picker),:deep(.ant-input-number){
width: 100%;
}
</style>

+ 26
- 0
jeecgboot-vue3/src/views/applet/withdrawal/V20250919_1__menu_insert_AppletWithdrawal.sql View File

@ -0,0 +1,26 @@
-- 注意:该页面对应的前台目录为views/appletWithdrawal文件夹下
-- 如果你想更改到其他目录,请修改sql中component字段对应的值
INSERT INTO sys_permission(id, parent_id, name, url, component, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_route, is_leaf, keep_alive, hidden, hide_tab, description, status, del_flag, rule_flag, create_by, create_time, update_by, update_time, internal_or_external)
VALUES ('2025091903554910460', NULL, '提现', '/appletWithdrawal/appletWithdrawalList', 'appletWithdrawal/AppletWithdrawalList', NULL, NULL, 0, NULL, '1', 0.00, 0, NULL, 1, 0, 0, 0, 0, NULL, '1', 0, 0, 'admin', '2025-09-19 15:55:46', NULL, NULL, 0);
-- 权限控制sql
-- 新增
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2025091903554910461', '2025091903554910460', '添加提现', NULL, NULL, 0, NULL, NULL, 2, 'appletWithdrawal:applet_withdrawal:add', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-09-19 15:55:46', NULL, NULL, 0, 0, '1', 0);
-- 编辑
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2025091903554910462', '2025091903554910460', '编辑提现', NULL, NULL, 0, NULL, NULL, 2, 'appletWithdrawal:applet_withdrawal:edit', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-09-19 15:55:46', NULL, NULL, 0, 0, '1', 0);
-- 删除
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2025091903554910463', '2025091903554910460', '删除提现', NULL, NULL, 0, NULL, NULL, 2, 'appletWithdrawal:applet_withdrawal:delete', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-09-19 15:55:46', NULL, NULL, 0, 0, '1', 0);
-- 批量删除
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2025091903554910464', '2025091903554910460', '批量删除提现', NULL, NULL, 0, NULL, NULL, 2, 'appletWithdrawal:applet_withdrawal:deleteBatch', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-09-19 15:55:46', NULL, NULL, 0, 0, '1', 0);
-- 导出excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2025091903554910465', '2025091903554910460', '导出excel_提现', NULL, NULL, 0, NULL, NULL, 2, 'appletWithdrawal:applet_withdrawal:exportXls', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-09-19 15:55:46', NULL, NULL, 0, 0, '1', 0);
-- 导入excel
INSERT INTO sys_permission(id, parent_id, name, url, component, is_route, component_name, redirect, menu_type, perms, perms_type, sort_no, always_show, icon, is_leaf, keep_alive, hidden, hide_tab, description, create_by, create_time, update_by, update_time, del_flag, rule_flag, status, internal_or_external)
VALUES ('2025091903554910466', '2025091903554910460', '导入excel_提现', NULL, NULL, 0, NULL, NULL, 2, 'appletWithdrawal:applet_withdrawal:importExcel', '1', NULL, 0, NULL, 1, 0, 0, 0, NULL, 'admin', '2025-09-19 15:55:46', NULL, NULL, 0, 0, '1', 0);

+ 70
- 0
jeecgboot-vue3/src/views/applet/withdrawal/components/AppletWithdrawalForm.vue View File

@ -0,0 +1,70 @@
<template>
<div style="min-height: 400px">
<BasicForm @register="registerForm"></BasicForm>
<div style="width: 100%;text-align: center" v-if="!formDisabled">
<a-button @click="submitForm" pre-icon="ant-design:check" type="primary"> </a-button>
</div>
</div>
</template>
<script lang="ts">
import {BasicForm, useForm} from '/@/components/Form/index';
import {computed, defineComponent} from 'vue';
import {defHttp} from '/@/utils/http/axios';
import { propTypes } from '/@/utils/propTypes';
import {getBpmFormSchema} from '../AppletWithdrawal.data';
import {saveOrUpdate} from '../AppletWithdrawal.api';
export default defineComponent({
name: "AppletWithdrawalForm",
components:{
BasicForm
},
props:{
formData: propTypes.object.def({}),
formBpm: propTypes.bool.def(true),
},
setup(props){
const [registerForm, { setFieldsValue, setProps, getFieldsValue }] = useForm({
labelWidth: 150,
schemas: getBpmFormSchema(props.formData),
showActionButtonGroup: false,
baseColProps: {span: 24}
});
const formDisabled = computed(()=>{
if(props.formData.disabled === false){
return false;
}
return true;
});
let formData = {};
const queryByIdUrl = '/appletWithdrawal/appletWithdrawal/queryById';
async function initFormData(){
let params = {id: props.formData.dataId};
const data = await defHttp.get({url: queryByIdUrl, params});
formData = {...data}
//
await setFieldsValue(formData);
//
await setProps({disabled: formDisabled.value})
}
async function submitForm() {
let data = getFieldsValue();
let params = Object.assign({}, formData, data);
console.log('表单数据', params)
await saveOrUpdate(params, true)
}
initFormData();
return {
registerForm,
formDisabled,
submitForm,
}
}
});
</script>

+ 99
- 0
jeecgboot-vue3/src/views/applet/withdrawal/components/AppletWithdrawalModal.vue View File

@ -0,0 +1,99 @@
<template>
<BasicModal v-bind="$attrs" @register="registerModal" destroyOnClose :title="title" :width="800" @ok="handleSubmit">
<BasicForm @register="registerForm" name="AppletWithdrawalForm" />
</BasicModal>
</template>
<script lang="ts" setup>
import {ref, computed, unref, reactive} from 'vue';
import {BasicModal, useModalInner} from '/@/components/Modal';
import {BasicForm, useForm} from '/@/components/Form/index';
import {formSchema} from '../AppletWithdrawal.data';
import {saveOrUpdate} from '../AppletWithdrawal.api';
import { useMessage } from '/@/hooks/web/useMessage';
import { getDateByPicker } from '/@/utils';
const { createMessage } = useMessage();
// Emits
const emit = defineEmits(['register','success']);
const isUpdate = ref(true);
const isDetail = ref(false);
//
const [registerForm, { setProps,resetFields, setFieldsValue, validate, scrollToField }] = useForm({
labelWidth: 150,
schemas: formSchema,
showActionButtonGroup: false,
baseColProps: {span: 24}
});
//
const [registerModal, {setModalProps, closeModal}] = useModalInner(async (data) => {
//
await resetFields();
setModalProps({confirmLoading: false,showCancelBtn:!!data?.showFooter,showOkBtn:!!data?.showFooter});
isUpdate.value = !!data?.isUpdate;
isDetail.value = !!data?.showFooter;
if (unref(isUpdate)) {
//
await setFieldsValue({
...data.record,
});
}
//
setProps({ disabled: !data?.showFooter })
});
//
const fieldPickers = reactive({
});
//
const title = computed(() => (!unref(isUpdate) ? '新增' : !unref(isDetail) ? '详情' : '编辑'));
//
async function handleSubmit(v) {
try {
let values = await validate();
//
changeDateValue(values);
setModalProps({confirmLoading: true});
//
await saveOrUpdate(values, isUpdate.value);
//
closeModal();
//
emit('success');
} catch ({ errorFields }) {
if (errorFields) {
const firstField = errorFields[0];
if (firstField) {
scrollToField(firstField.name, { behavior: 'smooth', block: 'center' });
}
}
return Promise.reject(errorFields);
} finally {
setModalProps({confirmLoading: false});
}
}
/**
* 处理日期值
* @param formData 表单数据
*/
const changeDateValue = (formData) => {
if (formData && fieldPickers) {
for (let key in fieldPickers) {
if (formData[key]) {
formData[key] = getDateByPicker(formData[key], fieldPickers[key]);
}
}
}
};
</script>
<style lang="less" scoped>
/** 时间和数字输入框样式 */
:deep(.ant-input-number) {
width: 100%;
}
:deep(.ant-calendar-picker) {
width: 100%;
}
</style>

Loading…
Cancel
Save