13 Commits

  1. 18
      pom.xml
  2. 58
      src/main/java/com/example/demo/Util/AppleTokenGenerator.java
  3. 6
      src/main/java/com/example/demo/Util/AuthKey_3J2S9VXU3V.p8
  4. 6
      src/main/java/com/example/demo/Util/ExcelHeaderTranslator.java
  5. 42
      src/main/java/com/example/demo/controller/cash/CashCollectionController.java
  6. 63
      src/main/java/com/example/demo/controller/coin/MarketController.java
  7. 29
      src/main/java/com/example/demo/domain/DTO/PerformanceAdjustmentDTO.java
  8. 2
      src/main/java/com/example/demo/mapper/cash/CashCollectionMapper.java
  9. 3
      src/main/java/com/example/demo/service/cash/CashCollectionService.java
  10. 18
      src/main/java/com/example/demo/serviceImpl/cash/CashAuditServiceImpl.java
  11. 81
      src/main/java/com/example/demo/serviceImpl/cash/CashCollectionServiceImpl.java
  12. 4
      src/main/java/com/example/demo/serviceImpl/coin/ExportExcelServiceImpl.java
  13. 16
      src/main/resources/cashMapper/CashCollectionMapper.xml
  14. 2
      src/main/resources/mapper/WorkBenchMapper.xml

18
pom.xml

@ -40,7 +40,23 @@
<artifactId>commons-lang3</artifactId>
<version>3.12.0</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>io.jsonwebtoken</groupId>-->
<!-- <artifactId>jjwt-api</artifactId>-->
<!-- <version>0.11.5</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.jsonwebtoken</groupId>-->
<!-- <artifactId>jjwt-impl</artifactId>-->
<!-- <version>0.11.5</version>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>io.jsonwebtoken</groupId>-->
<!-- <artifactId>jjwt-jackson</artifactId>-->
<!-- <version>0.11.5</version>-->
<!-- <scope>runtime</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>

58
src/main/java/com/example/demo/Util/AppleTokenGenerator.java

@ -0,0 +1,58 @@
//package com.example.demo.Util;
//
//import io.jsonwebtoken.Jwts;
//import io.jsonwebtoken.SignatureAlgorithm;
//import io.jsonwebtoken.io.Decoders;
//import java.nio.file.Files;
//import java.nio.file.Paths;
//import java.security.KeyFactory;
//import java.security.PrivateKey;
//import java.security.spec.PKCS8EncodedKeySpec;
//import java.util.Date;
//
//public class AppleTokenGenerator {
//
// // 你提供的真实信息已全部填好
// private static final String KEY_ID = "3J2S9VXU3V";
// private static final String ISSUER_ID = "69a6de7e-1f9a-47e3-e053-5b8c7c11a4d1";
// private static final String P8_FILE_PATH = "E:/Work/newgold/gold-java/src/main/java/com/example/demo/Util/AuthKey_3J2S9VXU3V.p8";
//
// public static String generateToken() {
// try {
// // 读取 P8 私钥内容
// String p8Content = Files.readString(Paths.get(P8_FILE_PATH))
// .replace("-----BEGIN PRIVATE KEY-----", "")
// .replace("-----END PRIVATE KEY-----", "")
// .replaceAll("\\s+", "");
//
// // 解码私钥
// byte[] keyBytes = Decoders.BASE64.decode(p8Content);
// PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
// KeyFactory keyFactory = KeyFactory.getInstance("EC");
// PrivateKey privateKey = keyFactory.generatePrivate(spec);
//
// // 生成苹果官方标准 JWT补全typ字段完全符合文档要求
// return Jwts.builder()
// .setHeaderParam("alg", "ES256")
// .setHeaderParam("kid", KEY_ID)
// .setHeaderParam("typ", "JWT") // 🔴 苹果官方强制要求之前漏了
// .setIssuer(ISSUER_ID)
// .setAudience("appstoreconnect-v1")
// .setIssuedAt(new Date())
// .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 15)) // 15分钟有效期20分钟
// .signWith(privateKey, SignatureAlgorithm.ES256)
// .compact();
//
// } catch (Exception e) {
// e.printStackTrace();
// return null;
// }
// }
//
//// // 运行直接输出可用 Token
//// public static void main(String[] args) {
//// String token = generateToken();
//// System.out.println("复制下面这一行直接用:");
//// System.out.println("Bearer " + token);
//// }
//}

6
src/main/java/com/example/demo/Util/AuthKey_3J2S9VXU3V.p8

@ -0,0 +1,6 @@
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQge12P08wGtrp8dttS
6fA0dtL46GYnBYEumTnx3/g53qGgCgYIKoZIzj0DAQehRANCAATiWWs9qLs7eYCv
ZIfG0JYRrLjLqotAGdEtfTii1gh+IKK4snS499kwk+vKg1vHy2ZovyZDdvmW/z+i
WSzRu18f
-----END PRIVATE KEY-----

6
src/main/java/com/example/demo/Util/ExcelHeaderTranslator.java

@ -604,6 +604,7 @@ public class ExcelHeaderTranslator {
headers.put("marketName", "所属地区");
headers.put("walletName", "钱包名称");
headers.put("typeText", "交易类型");
headers.put("transactionCurrency", "交易币种");
headers.put("amount", "交易金额");
headers.put("orderCode", "订单号");
headers.put("description", "交易说明");
@ -623,8 +624,9 @@ public class ExcelHeaderTranslator {
*/
public List<String> getUserWalletColumnOrder() {
return Arrays.asList(
"jwcode", "userName", "marketName", "walletName", "typeText", "amount",
"orderCode", "description", "statusText", "createTime"
"jwcode", "userName", "marketName", "walletName", "typeText",
"transactionCurrency", "amount", "orderCode", "description",
"statusText", "createTime"
);
}

42
src/main/java/com/example/demo/controller/cash/CashCollectionController.java

@ -4,6 +4,7 @@ import com.example.demo.Util.JWTUtil;
import com.example.demo.Util.LanguageTranslationUtil;
import com.example.demo.config.interfac.Log;
import com.example.demo.domain.DTO.AddFundsDTO;
import com.example.demo.domain.DTO.PerformanceAdjustmentDTO;
import com.example.demo.domain.DTO.PerformanceDTO;
import com.example.demo.domain.entity.*;
import com.example.demo.domain.vo.cash.*;
@ -461,12 +462,20 @@ public class CashCollectionController {
/**
*新增流水-其他收入
*/
@PostMapping("/addExFund")
public Result addExFund(@RequestBody CashCollection addFundsDTO, @RequestHeader(defaultValue = "zh_CN") String lang) {
try {
// 解析语言代码
String languageCode = parseLanguageCode(lang);
// 如果不是中文环境将查询条件中的翻译文本转换为中文简体
if (!"zh".equalsIgnoreCase(languageCode) && !"zh_cn".equalsIgnoreCase(languageCode)) {
convertTranslatedFieldsToChinese(addFundsDTO, languageCode);
}
String result = cashCollectionService.addExFund(addFundsDTO);
return Result.success(result);
String successMsg = languageTranslationUtil.translate(result, lang);
return Result.success(successMsg);
} catch (Exception e) {
String errorMsg = languageTranslationUtil.translate(e.getMessage(), lang);
return Result.error(errorMsg);
@ -523,6 +532,16 @@ public class CashCollectionController {
return Result.error("查询失败");
}
}
@PostMapping("/adjust")
public Result adjust(@RequestBody PerformanceAdjustmentDTO adjustDTO) {
try {
cashCollectionService.adjust(adjustDTO);
return Result.success("调整成功");
} catch (Exception e) {
return Result.error(e.getMessage());
}
}
/**
* 转换用户钱包 VO 的多语言字段
*/
@ -846,7 +865,24 @@ public class CashCollectionController {
}
// 翻译交易类型
if (vo.getType() != null) {
String typeText = vo.getType() == 0 ? "充值" : (vo.getType() == 1 ? "消耗" : "退款");
String typeText;
switch (vo.getType()) {
case 0:
typeText = "充值";
break;
case 1:
typeText = "消耗";
break;
case 2:
typeText = "退款";
break;
case 3:
typeText = "软件购买";
break;
default:
typeText = "未知";
break;
}
vo.setTypeText(languageTranslationUtil.translate(typeText, lang));
}
// 翻译状态

63
src/main/java/com/example/demo/controller/coin/MarketController.java

@ -3,6 +3,7 @@ package com.example.demo.controller.coin;
import com.example.demo.config.interfac.Log;
import com.example.demo.domain.entity.Market;
import com.example.demo.domain.vo.cash.AreaPayTypeTreeVO;
import com.example.demo.domain.vo.cash.PayTypeVO;
import com.example.demo.domain.vo.coin.Result;
import com.example.demo.service.coin.MarketService;
import com.example.demo.Util.LanguageTranslationUtil;
@ -53,14 +54,24 @@ public class MarketController {
@RequestMapping("/getAreaPayTypeTree")
public Result getAreaPayTypeTree(@RequestHeader(defaultValue = "zh_CN") String lang) {
try {
// 解析语言代码
String languageCode = parseLanguageCode(lang);
List<AreaPayTypeTreeVO> marketsTree = marketService.getAreaPayTypeTree();
// 如果不是中文环境先将翻译后的名称转换为中文简体进行处理
if (!"zh".equalsIgnoreCase(languageCode) && !"zh_cn".equalsIgnoreCase(languageCode)) {
convertTranslatedAreaPayTypeTreeToChinese(marketsTree, languageCode);
}
// 对地区名称和支付方式名称进行多语言转换
translateAreaPayTypeTree(marketsTree, lang);
return Result.success(marketsTree);
} catch (Exception e) {
log.error("获取市场列表失败", e);
return Result.error("获取市场列表失败");
String errorMsg = languageTranslationUtil.translate("获取市场列表失败", lang);
return Result.error(errorMsg);
}
}
@ -82,6 +93,56 @@ public class MarketController {
}
}
/**
* 转换地区支付方式树的多语言字段
*/
private void translateAreaPayTypeTree(List<AreaPayTypeTreeVO> treeList, String lang) {
if (treeList != null) {
for (AreaPayTypeTreeVO node : treeList) {
// 翻译地区名称
if (node.getName() != null) {
node.setName(languageTranslationUtil.translate(node.getName(), lang));
}
// 翻译支付方式名称
if (node.getChildren() != null) {
for (PayTypeVO payType : node.getChildren()) {
if (payType.getName() != null) {
payType.setName(languageTranslationUtil.translate(payType.getName(), lang));
}
}
}
}
}
}
/**
* 将翻译后的地区支付方式树名称转换为中文简体
*/
private void convertTranslatedAreaPayTypeTreeToChinese(List<AreaPayTypeTreeVO> treeList, String languageCode) {
if (treeList != null) {
for (AreaPayTypeTreeVO node : treeList) {
// 转换地区名称
if (node.getName() != null && !node.getName().isEmpty()) {
String chineseName = translationService.findChineseSimplifiedByTranslation(
node.getName(), languageCode);
node.setName(chineseName);
}
// 转换支付方式名称
if (node.getChildren() != null) {
for (PayTypeVO payType : node.getChildren()) {
if (payType.getName() != null && !payType.getName().isEmpty()) {
String chineseName = translationService.findChineseSimplifiedByTranslation(
payType.getName(), languageCode);
payType.setName(chineseName);
}
}
}
}
}
}
/**
* 解析语言代码
*/
private String parseLanguageCode(String langHeader) {

29
src/main/java/com/example/demo/domain/DTO/PerformanceAdjustmentDTO.java

@ -0,0 +1,29 @@
package com.example.demo.domain.DTO;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.Date;
/**
* @program: gold-java
* @ClassName PerformanceAdjustmentDTO
* @description:
* @author: Double
* @create: 202604-03 09:56
* @Version 1.0
**/
@Data
public class PerformanceAdjustmentDTO {
private Integer submitterId; // 提交人ID
private String submitterMarket; // 提交人市场
private int[][] matrix = new int[6][6];
private Double weight; // 权重
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private LocalDateTime Time; // 时间
}

2
src/main/java/com/example/demo/mapper/cash/CashCollectionMapper.java

@ -130,6 +130,8 @@ public interface CashCollectionMapper {
@Param("sortWalletId") Integer sortWalletId);
// 添加流水--其他收入
void addExFund(@Param("addFundsDTO") CashCollection addFundsDTO);
void adjust(CashRecord cashRecord);
// 添加流水--iPay88手续费
void addIpay88Fee(CashCollection cashCollection);
}

3
src/main/java/com/example/demo/service/cash/CashCollectionService.java

@ -1,6 +1,7 @@
package com.example.demo.service.cash;
import com.example.demo.domain.DTO.AddFundsDTO;
import com.example.demo.domain.DTO.PerformanceAdjustmentDTO;
import com.example.demo.domain.DTO.PerformanceDTO;
import com.example.demo.domain.entity.CashRecord;
import com.example.demo.domain.entity.GOrder;
@ -56,6 +57,8 @@ public interface CashCollectionService {
PageInfo<UserWalletVO> selectUserWallets(Integer jwcode, String market, Integer pageNum, Integer pageSize, String sortField, String sortOrder, Integer sortWalletId);
// 添加流水--其他收入
String addExFund(CashCollection addFundsDTO);
// 调整业绩
void adjust(PerformanceAdjustmentDTO adjustDTO);
//添加iPay88手续费
String addIpay88Fee(CashCollection cashCollection);
}

18
src/main/java/com/example/demo/serviceImpl/cash/CashAuditServiceImpl.java

@ -238,6 +238,24 @@ public class CashAuditServiceImpl implements CashAuditService {
user.setRechargeNum(1); //充值次数加一
auditMapper.updateUserGold(user);
}
else {
// 先从数据库中获取订单的 walletId
CashRecord dbRecord = cashCollectionMapper.selectByOrderCode(orderCode);
Integer walletId = dbRecord != null ? dbRecord.getWalletId() : null;
// 创建钱包明细记录
UserWalletRecord walletRecord = new UserWalletRecord();
walletRecord.setJwcode(order.getJwcode());
walletRecord.setWalletId(walletId);
walletRecord.setType(3); // 3=软件购买
walletRecord.setTransactionCurrency(order.getPaymentCurrency());
walletRecord.setAmount(order.getPaymentAmount().intValue());
walletRecord.setOrderCode(orderCode);
walletRecord.setDescription(order.getGoodsName()+order.getGoodNum()+order.getNumUnit());
walletRecord.setStatus(0); // 0=正常
cashCollectionMapper.insertUserWalletRecord(walletRecord);
log.info("创建钱包明细记录:jwcode={}, walletId={}, orderCode={}, amount={}",
order.getJwcode(), walletId, orderCode, order.getPermanentGold());
}
} else if (action == 2) { //驳回
updateOrder.setStatus(2);
updateOrder.setRejectReason(rejectReason);

81
src/main/java/com/example/demo/serviceImpl/cash/CashCollectionServiceImpl.java

@ -4,6 +4,7 @@ import com.example.demo.Util.JWTUtil;
import com.example.demo.Util.LanguageTranslationUtil;
import com.example.demo.config.RabbitMQConfig;
import com.example.demo.domain.DTO.AddFundsDTO;
import com.example.demo.domain.DTO.PerformanceAdjustmentDTO;
import com.example.demo.domain.DTO.PerformanceDTO;
import com.example.demo.domain.entity.*;
import com.example.demo.domain.vo.cash.*;
@ -75,6 +76,9 @@ public class CashCollectionServiceImpl implements CashCollectionService {
if (cashCollection.getActivity() == null || cashCollection.getActivity().isEmpty()) {
throw new IllegalArgumentException("活动不能为空");
}
if (cashCollection.getWalletId() == null || cashCollection.getWalletId() < 1 || cashCollection.getWalletId() > 10) {
throw new IllegalArgumentException("钱包 ID 为 1~10");
}
if (cashCollection.getGoodsName() == null|| cashCollection.getGoodsName().isEmpty()) {
throw new IllegalArgumentException("产品名称不能为空");
}
@ -82,9 +86,6 @@ public class CashCollectionServiceImpl implements CashCollectionService {
if (cashCollection.getPermanentGold() == 0 && cashCollection.getFreeGold() == 0) {
throw new IllegalArgumentException("金币数量不能为空");
}
if (cashCollection.getWalletId() == null || cashCollection.getWalletId() < 1 || cashCollection.getWalletId() > 10) {
throw new IllegalArgumentException("钱包 ID 为 1~10");
}
}
if (!cashCollection.getGoodsName().equals("金币充值")) {
if (cashCollection.getGoodNum() == 0) {
@ -748,6 +749,79 @@ public class CashCollectionServiceImpl implements CashCollectionService {
return "添加成功";
}
@Override
public void adjust(PerformanceAdjustmentDTO adjustDTO) {
if (adjustDTO == null) {
throw new IllegalArgumentException("传参不能为空");
}
int[][] matrix = adjustDTO.getMatrix();
Double weight = adjustDTO.getWeight();
if (weight == null) {
throw new IllegalArgumentException("权重不能为空");
}
// Performance market codes and corresponding Chinese names
String[] performanceMarkets = {"4", "5", "13", "24018", "24022", "24016"};
String[] marketNames = {"新加坡", "马来西亚", "香港", "泰国", "越南", "加拿大"};
// Multiply each element in the matrix by the factor
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
// Calculate adjusted value and round to nearest integer
int adjustedValue = (int) (matrix[i][j] * weight);
matrix[i][j] = adjustedValue;
if (i == j) {
continue;
}
// Skip if value is 0
if (adjustedValue == 0) {
continue;
}
// Create order code with timestamp
String orderCode = "TZ_" + System.currentTimeMillis();
// Determine direction and create remark based on value sign
String fromMarket = performanceMarkets[i];
String toMarket = performanceMarkets[j];
String fromName = marketNames[i];
String toName = marketNames[j];
String remark;
if (adjustedValue > 0) {
// Positive value: row to column (转出方 to 转入方)
remark = fromName + "→" + toName + "调整金额:" + adjustedValue;
} else {
// Negative value: column to row (转入方 to 转出方)
remark = toName + "→" + fromName + "调整金额:" + -adjustedValue;
}
// Create CashRecord objects and call mapper adjust method twice
for (int k = 0; k < 2; k++) {
CashRecord cashRecord = new CashRecord();
cashRecord.setOrderCode(orderCode + "_" + k);
cashRecord.setSubmitterId(adjustDTO.getSubmitterId());
cashRecord.setSubmitterMarket(adjustDTO.getSubmitterMarket());
cashRecord.setRemark(remark);
cashRecord.setPayTime(adjustDTO.getTime());
if(k == 0){
cashRecord.setPerformanceMarket(fromMarket);
cashRecord.setReceivedMarket(fromMarket);
cashRecord.setReceivedAmount(new BigDecimal(-adjustedValue));
}else{
cashRecord.setPerformanceMarket(toMarket);
cashRecord.setReceivedMarket(toMarket);
cashRecord.setReceivedAmount(new BigDecimal(adjustedValue));
}
// Call mapper adjust method
cashCollectionMapper.adjust(cashRecord);
}
}
}
}
/**
* 校验钱包 ID 和到账地区的对应关系
* @param walletId 钱包 ID
@ -784,4 +858,5 @@ public class CashCollectionServiceImpl implements CashCollectionService {
throw new IllegalArgumentException("钱包 ID=" + walletId + " 对应的到账地区应为:" + marketName + "(" + expectedMarket + ")");
}
}
}

4
src/main/java/com/example/demo/serviceImpl/coin/ExportExcelServiceImpl.java

@ -2078,6 +2078,10 @@ public class ExportExcelServiceImpl implements ExportExcelService {
if (item.getDescription() != null && !item.getDescription().isEmpty()) {
item.setDescription(languageTranslationUtil.translate(item.getDescription(), lang));
}
// 翻译交易币种
if (item.getTransactionCurrency() != null && !item.getTransactionCurrency().isEmpty()) {
item.setTransactionCurrency(languageTranslationUtil.translate(item.getTransactionCurrency(), lang));
}
}
}
/**

16
src/main/resources/cashMapper/CashCollectionMapper.xml

@ -228,10 +228,12 @@
<select id="selectAuditByOrderCode" resultType="com.example.demo.domain.entity.CashRecord">
select crc.id,jwcode,name,market,ra.activity_name as activity,
order_code,bank_code,goods_name,good_num,num_unit,permanent_gold,free_gold,
payment_currency,payment_amount,pay_type,pay_time,crc.status,submitter_id,
r1.rate_name as payment_currency,r2.rate_name as received_currency,payment_amount,pay_type,pay_time,crc.status,submitter_id,
voucher,remark,version,received_market
from cash_record_collection crc
left join recharge_activity ra on ra.id = crc.activity
left join rate r1 on r1.id = crc.payment_currency
left join rate r2 on r2.id = crc.received_currency
where order_code=#{orderCode}
</select>
<!--根据精网号获取姓名-->
@ -630,5 +632,15 @@
SET flag = #{flag}
WHERE type_id = #{typeId} AND type = #{type}
</update>
<insert id="adjust" parameterType="com.example.demo.domain.entity.CashRecord"
useGeneratedKeys="true" keyProperty="id">
insert into
cash_record_collection(order_type,jwcode,name,market,activity,performance_market,
order_code,goods_name,permanent_gold,free_gold,
pay_type,pay_time,status,submitter_id,submitter_market,
voucher,remark,received_currency,payment_amount,received_amount,received_market)
values(1,90039082,"HomilyLink",24032,125,#{performanceMarket},
#{orderCode},"业绩",0,0,"调整",#{payTime},
100,#{submitterId},#{submitterMarket},1,#{remark},3,0,#{receivedAmount},#{receivedMarket})
</insert>
</mapper>

2
src/main/resources/mapper/WorkBenchMapper.xml

@ -178,7 +178,7 @@
SUM(CASE WHEN r.id = 6 THEN cr.received_amount/100 ELSE 0 END) AS cad,
SUM(CASE WHEN r.id = 7 THEN cr.received_amount/100 ELSE 0 END) AS vdn,
SUM(CASE WHEN r.id = 8 THEN cr.received_amount/100 ELSE 0 END) AS krw,
ROUND( SUM(cr.received_amount/100 * r.num), 2) AS totalSGD
ROUND( SUM(cr.received_amount/100 / r.num), 2) AS totalSGD
FROM cash_record_collection cr
JOIN market m ON cr.received_market = m.id
JOIN rate r ON cr.received_currency = r.id

Loading…
Cancel
Save