1
zj
2025-10-09 df30c88c2c76da0cb607bcf129446f43c9a521da
1
20 files modified
11 files added
1147 ■■■■■ changed files
ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java 28 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/comm/PayProduct.java 29 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/comm/PayStatus.java 31 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/dto/RegisterDto.java 4 ●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/service/UserPolicyService.java 2 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/ImApiServcieImpl.java 80 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/MedicalInsuranceAccountServiceImpl.java 32 ●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/UserPolicyServiceImpl.java 112 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/util/HttpUtil.java 48 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/util/PayService.java 152 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/util/PaySignUtil.java 89 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/util/SimplePayUtil.java 175 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/web/controller/product/UserKycController.java 33 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/web/controller/product/UserPolicyController.java 76 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BasicSetupController.java 8 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/InvitationBlacklistController.java 80 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java 20 ●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/resources/application.yml 6 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/GroupWelcomeConfig.java 11 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/InvitationBlacklist.java 30 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/MedicalInsuranceAccount.java 2 ●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/UserAccount.java 7 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/UserKyc.java 12 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/UserPolicy.java 11 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/UserKycDto.java 8 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/UserPolicyDto.java 3 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/out/UserOut.java 15 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserAccountUpdateVo.java 11 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/mapper/InvitationBlacklistMapper.java 10 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/service/InvitationBlacklistService.java 8 ●●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/InvitationBlacklistServiceImpl.java 14 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java
@@ -3,10 +3,6 @@
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.im.comm.Result;
import com.ruoyi.im.config.IpUtils;
@@ -14,7 +10,8 @@
import com.ruoyi.im.service.*;
import com.ruoyi.im.dto.RegisterDto;
import com.ruoyi.im.service.impl.InsurancePositionServiceImpl;
import com.ruoyi.im.util.SymmetricCryptoUtil;
import com.ruoyi.im.util.PayService;
import com.ruoyi.im.util.SimplePayUtil;
import com.ruoyi.im.util.UserPolicyUtils;
import com.ruoyi.im.util.ValidatorUtil;
import com.ruoyi.system.domain.*;
@@ -23,15 +20,11 @@
import com.ruoyi.system.domain.out.UserTeamAndPositionOut;
import com.ruoyi.system.domain.vo.UserAccountUpdateVo;
import com.ruoyi.system.service.GroupWelcomeConfigService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.service.IpBlacklistService;
import com.ruoyi.system.service.UserAccountService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -89,6 +82,8 @@
    private String prefix;
    /**
     * 注册
     */
@@ -133,7 +128,7 @@
    @PostMapping("/updateUser")
    public Result updateUser(UserAccountUpdateVo vo){
        try {
            UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>().eq(UserAccount::getAccount,vo.getAccountId()));
            UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>().eq(UserAccount::getAccount,vo.getAccount()));
            if (StringUtils.isNotBlank(vo.getNickname())) {
                userAccount.setNickname(vo.getNickname());
@@ -289,7 +284,17 @@
            if(ObjectUtil.isEmpty(userAccount)){
                return Result.error("账号不存在!");
            }
            GroupWelcomeConfig groupWelcomeConfig = groupWelcomeConfigService.getOne(new LambdaQueryWrapper<>(GroupWelcomeConfig.class)
                    .eq(GroupWelcomeConfig::getConfigurationName, "IM-BASICS").last(" limit 1"));
            UserOut user = new UserOut();
            if(ObjectUtil.isNotEmpty(groupWelcomeConfig)){
                user.setCustomerServiceUrl(groupWelcomeConfig.getCustomerServiceUrl());
                user.setAboutUs(groupWelcomeConfig.getAboutUs());
            }
            user.setBalance(userAccount.getBalance());
            MedicalInsuranceAccount insuranceAccount = medicalInsuranceAccountService.getOne(new LambdaQueryWrapper<>(MedicalInsuranceAccount.class)
                    .eq(MedicalInsuranceAccount::getUserId, userAccount.getId())
                    .eq(MedicalInsuranceAccount::getAccountStatus, MedicalInsuranceAccount.AccountStatus.ACTIVE)
@@ -298,9 +303,10 @@
            if(ObjectUtil.isEmpty(insuranceAccount)){
                return Result.success(user);
            }
            user.setBalance(userAccount.getBalance());
            user.setAmountClaimed(insuranceAccount.getAmountClaimed());
            user.setAlreadyReceived(insuranceAccount.getAlreadyReceived());
            user.setGroupPermissions(userAccount.getGroupPermissions());
            user.setAddFriend(userAccount.getAddFriend());
            return Result.success(user);
        }catch (Exception e){
            log.error("获取失败:",e);
ruoyi-admin/src/main/java/com/ruoyi/im/comm/PayProduct.java
New file
@@ -0,0 +1,29 @@
package com.ruoyi.im.comm;
/**
 * 支付产品枚举
 */
public enum PayProduct {
    ALIPAY(8000, "支付宝"),
    WECHAT(8001, "微信");
    private final int code;
    private final String name;
    PayProduct(int code, String name) {
        this.code = code;
        this.name = name;
    }
    public int getCode() { return code; }
    public String getName() { return name; }
    public static PayProduct getByCode(int code) {
        for (PayProduct product : values()) {
            if (product.code == code) {
                return product;
            }
        }
        return null;
    }
}
ruoyi-admin/src/main/java/com/ruoyi/im/comm/PayStatus.java
New file
@@ -0,0 +1,31 @@
package com.ruoyi.im.comm;
/**
 * 支付状态枚举
 */
public enum PayStatus {
    INIT(0, "订单生成"),
    PAYING(1, "支付中"),
    SUCCESS(2, "支付成功"),
    COMPLETED(3, "业务处理完成");
    private final int code;
    private final String desc;
    PayStatus(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }
    public int getCode() { return code; }
    public String getDesc() { return desc; }
    public static PayStatus getByCode(int code) {
        for (PayStatus status : values()) {
            if (status.code == code) {
                return status;
            }
        }
        return null;
    }
}
ruoyi-admin/src/main/java/com/ruoyi/im/dto/RegisterDto.java
@@ -15,7 +15,7 @@
    private String confirmPassword; // 再次确认密码
    private String nickname; // 昵称
    private String nikeName; // 昵称
    private Integer type;//类型 1 批量  2 单一
@@ -27,6 +27,4 @@
    private Integer accountType = 0;
//    @NotNull(message = "验证码不能为空")
//    private Integer verificationCode; // 验证码
}
ruoyi-admin/src/main/java/com/ruoyi/im/service/UserPolicyService.java
@@ -7,7 +7,9 @@
import com.ruoyi.system.domain.dto.UserPolicyDto;
import java.text.ParseException;
import java.util.Map;
public interface UserPolicyService extends IService<UserPolicy> {
    Result purchaseApplication(UserPolicyDto dto) throws ParseException;
}
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/ImApiServcieImpl.java
@@ -23,6 +23,7 @@
import com.ruoyi.im.service.NeteaseTeamService;
import com.ruoyi.imenum.ErrorCodeEnum;
import com.ruoyi.system.domain.GroupWelcomeConfig;
import com.ruoyi.system.domain.InvitationBlacklist;
import com.ruoyi.system.domain.NeteaseTeam;
import com.ruoyi.system.domain.UserAccount;
import com.ruoyi.im.service.ImApiServcie;
@@ -32,6 +33,7 @@
import com.ruoyi.system.service.GroupWelcomeConfigService;
import com.ruoyi.system.service.UserAccountService;
import com.ruoyi.im.util.SymmetricCryptoUtil;
import com.ruoyi.system.service.impl.InvitationBlacklistServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpResponse;
@@ -77,6 +79,9 @@
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private NeteaseTeamMapper neteaseTeamMapper;
    @Autowired
    InvitationBlacklistServiceImpl invitationBlacklistService;
    @Resource
    private final YunxinApiHttpClient yunxinClient;
@@ -125,6 +130,13 @@
            return Result.error("邀请码不能为空!");
        }
        long count = invitationBlacklistService.count(new LambdaQueryWrapper<InvitationBlacklist>()
                .eq(InvitationBlacklist::getInvitationCode, dto.getInvitationCode())
        );
        if(count > 0){
            return Result.error("邀请码已被限制邀请!");
        }
        String invitationCode = getInvitationCode();
        UserAccount user = new UserAccount();
        if(dto.getAccountType() == 0 && StringUtils.isNotEmpty(dto.getInvitationCode()) &&  !dto.getInvitationCode().equals("00000000")){
@@ -142,7 +154,7 @@
        userAccount.setCloudMessageAccount(dto.getAccount());
        userAccount.setPassword(SymmetricCryptoUtil.encryptPassword(dto.getPassword()));
        userAccount.setCreateTime(new Date());
        userAccount.setNickname(dto.getNickname());
        userAccount.setNickname(dto.getNikeName());
        userAccount.setCreateTime(new Date());
        userAccount.setUpdateTime(new Date());
        userAccount.setInvitationCode(invitationCode);
@@ -151,13 +163,12 @@
        if (!userAccountService.save(userAccount)) {
            throw new RuntimeException("保存用户账户失败");
        }
        try {
            // 注册云信账号(远程调用)
            Map<String, String> paramMap = new HashMap<>();
            paramMap.put("accid", dto.getAccount());
            if(StringUtils.isNotEmpty(dto.getNickname())){
                paramMap.put("name", dto.getNickname());
            if(StringUtils.isNotEmpty(dto.getNikeName())){
                paramMap.put("name", dto.getNikeName());
            }
            paramMap.put("token", dto.getPassword());
@@ -175,6 +186,10 @@
                }
                log.error("-----------注册账号异常:"+ErrorCodeEnum.getByCode(code).getComment()+"----im信息:"+ErrorCodeEnum.getByCode(code).getDesc());
                throw new RuntimeException(errorMsg);
            }
            //默认添加邀请人为好友
            if(ObjectUtil.isNotEmpty(user)){
                addFriends(userAccount.getAccount(),user.getAccount());
            }
            // 注册成功后的其他操作
@@ -371,31 +386,33 @@
    @Override
    public AjaxResult updateUserAccount(UserAccountUpdateVo vo) {
        //更新用户名片
        UpdateUserBusinessDto dto = new UpdateUserBusinessDto();
        if(StringUtils.isNotEmpty(vo.getPhoneNumber())){
            dto.setMobile(vo.getPhoneNumber());
        }
        if(StringUtils.isNotEmpty(vo.getNickname())){
            dto.setName(vo.getNickname());
        }
        if(StringUtils.isNotEmpty(vo.getSignature())){
            dto.setSign(vo.getSignature());
        }
        if(ObjectUtil.isNotEmpty(vo.getGender())){
            dto.setGender(vo.getGender());
        }
        Map<String, Object> map = updateUserAvatar(vo.getAccountId(), dto);
//        UpdateUserBusinessDto dto = new UpdateUserBusinessDto();
//        if(StringUtils.isNotEmpty(vo.getPhoneNumber())){
//            dto.setMobile(vo.getPhoneNumber());
//        }
//        if(StringUtils.isNotEmpty(vo.getNickname())){
//            dto.setName(vo.getNickname());
//        }
//        if(StringUtils.isNotEmpty(vo.getSignature())){
//            dto.setSign(vo.getSignature());
//        }
//        if(ObjectUtil.isNotEmpty(vo.getGender())){
//            dto.setGender(vo.getGender());
//        }
//        Map<String, Object> map = updateUserAvatar(vo.getAccountId(), dto);
        //更新用户属性 状态 密码
        if ((Boolean) map.get("success")) {
            AjaxResult ajaxResult = updateAccountProperties(vo.getAccountId(), vo);
//        if ((Boolean) map.get("success")) {
            AjaxResult ajaxResult = updateAccountProperties(vo.getAccount(), vo);
            if(ajaxResult.isSuccess()){
                UserAccount userAccount = userAccountService.getById(vo.getId());
                UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>()
                        .eq(UserAccount::getAccount,vo.getAccount())
                );
                if (StringUtils.isNotBlank(vo.getPhoneNumber())) {
                    userAccount.setPhoneNumber(vo.getPhoneNumber());
                }
                if (StringUtils.isNotBlank(vo.getAccountId())) {
                    userAccount.setAccount(vo.getAccountId());
                if (StringUtils.isNotBlank(vo.getAccount())) {
                    userAccount.setAccount(vo.getAccount());
                }
                if (StringUtils.isNotBlank(vo.getNickname())) {
@@ -409,15 +426,17 @@
                if (StringUtils.isNotBlank(vo.getSignature())) {
                    userAccount.setSignature(vo.getSignature());
                }
                userAccount.setGroupPermissions(vo.getGroupPermissions());
                userAccount.setAddFriend(vo.getAddFriend());
                userAccount.setStatus(vo.getStatus());
                userAccount.setUpdateTime(new Date());
                userAccountService.updateById(userAccount);
            }else{
                return AjaxResult.error("更新用户属性失败!");
            }
        } else {
            return AjaxResult.error("更新用户名片失败!");
        }
//        } else {
//            return AjaxResult.error("更新用户名片失败!");
//        }
        return AjaxResult.success("更新成功!");
    }
@@ -468,17 +487,14 @@
            NeteaseResponse neteaseResponse = objectMapper.readValue(responseString, NeteaseResponse.class);
            if (neteaseResponse.isSuccess()) {
                AjaxResult.success("账号属性更新成功");
                return AjaxResult.success("账号属性更新成功");
            } else {
                AjaxResult.error("账号属性更新失败");
                return AjaxResult.error("账号属性更新失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
            AjaxResult.error("请求网易云信API失败");
            return AjaxResult.error("请求网易云信API失败");
        }
        return AjaxResult.success();
    }
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/MedicalInsuranceAccountServiceImpl.java
@@ -82,25 +82,25 @@
                    return Result.error("你的保险额度已领取完!");
                }
                // 计算剩余天数
                long remainingDays = ChronoUnit.DAYS.between(now, medicalInsuranceAccount.getExpiryDate()) + 1;
                // 计算每日金额
                BigDecimal dailyAmount = calculateDailyAmount(
                        medicalInsuranceAccount.getTotalQuota(), (int) remainingDays);
                // 如果账户余额不足,则领取剩余全部金额
                if (medicalInsuranceAccount.getAmountClaimed().compareTo(dailyAmount) < 0) {
                    dailyAmount = medicalInsuranceAccount.getAmountClaimed();
                }
                // 更新待领金额
                medicalInsuranceAccount.setAmountClaimed(medicalInsuranceAccount.getAmountClaimed().subtract(dailyAmount));
//                // 计算剩余天数
//                long remainingDays = ChronoUnit.DAYS.between(now, medicalInsuranceAccount.getExpiryDate()) + 1;
//
//                // 计算每日金额
//                BigDecimal dailyAmount = calculateDailyAmount(
//                        medicalInsuranceAccount.getTotalQuota(), (int) remainingDays);
//
//                // 如果账户余额不足,则领取剩余全部金额
//                if (medicalInsuranceAccount.getAmountClaimed().compareTo(dailyAmount) < 0) {
//                    dailyAmount = medicalInsuranceAccount.getAmountClaimed();
//                }
//
//                // 更新待领金额
//                medicalInsuranceAccount.setAmountClaimed(medicalInsuranceAccount.getAmountClaimed().subtract(dailyAmount));
                // 更新已领取金额
                BigDecimal currentAmountReceived = medicalInsuranceAccount.getAlreadyReceived() != null ?
                        medicalInsuranceAccount.getAlreadyReceived(): BigDecimal.ZERO;
                medicalInsuranceAccount.setAlreadyReceived(currentAmountReceived.add(dailyAmount));
                medicalInsuranceAccount.setAlreadyReceived(currentAmountReceived.add(medicalInsuranceAccount.getAmountClaimed()));
                medicalInsuranceAccountMapper.updateById(medicalInsuranceAccount);
@@ -109,7 +109,7 @@
                claim.setAccountId(medicalInsuranceAccount.getId());
                claim.setUserId(userAccount.getId());
                claim.setClaimDate(today);
                claim.setClaimAmount(dailyAmount);
                claim.setClaimAmount(medicalInsuranceAccount.getAmountClaimed());
                claim.setCreatedAt(new Date());
                medicalInsuranceDailyClaimMapper.insert(claim);
                return Result.success("领取成功");
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/UserPolicyServiceImpl.java
@@ -1,12 +1,16 @@
package com.ruoyi.im.service.impl;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.im.comm.Result;
import com.ruoyi.im.service.InsuranceProductService;
import com.ruoyi.im.service.UserPolicyService;
import com.ruoyi.im.util.PayService;
import com.ruoyi.im.util.ValidatorUtil;
import com.ruoyi.system.domain.InsuranceProduct;
import com.ruoyi.system.domain.UserAccount;
@@ -14,15 +18,18 @@
import com.ruoyi.system.domain.dto.UserPolicyDto;
import com.ruoyi.system.mapper.UserPolicyMapper;
import com.ruoyi.system.service.UserAccountService;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.atomic.AtomicLong;
@@ -33,6 +40,8 @@
    InsuranceProductService insuranceProductService;
    @Autowired
    UserAccountService userAccountService;
    @Autowired
    private PayService payService;
    @Override
@@ -59,7 +68,7 @@
        long count = count(new LambdaQueryWrapper<UserPolicy>()
                .eq(UserPolicy::getUserId, userAccount.getId())
                .eq(UserPolicy::getProductId,dto.getProductId())
                .eq(UserPolicy::getPolicyStatus, UserPolicy.PolicyStatus.ACTIVE)
                .eq(UserPolicy::getPolicyStatus, UserPolicy.PolicyStatus.PENDING)
                .and(a-> a.eq(UserPolicy::getApprovalStatus, 0)
                .or()
                .eq(UserPolicy::getApprovalStatus, 1))
@@ -73,10 +82,15 @@
            return Result.error("该产品停止购买或已下架!");
        }
        if(userAccount.getBalance().compareTo(insuranceProduct.getPremium()) < 0){
            return Result.error("余额不足!");
            String orderNo = generateOrderNo();
            String payOrder = payService.createOrder(insuranceProduct.getPremium().multiply(new BigDecimal("100")), orderNo,dto.getPayProductId());
            Map<String, Object> parse = (Map<String, Object>) JSONUtils.parse(payOrder);
            if("0014".equals(parse.get("errCode"))){
                return Result.error("当前支付不可用,请更换其他支付方式!");
        }
        userAccount.setBalance(userAccount.getBalance().subtract(insuranceProduct.getPremium()));
            if("FAIL".equals(parse.get("retCode"))){
                return Result.error("获取支付通道失败!");
            }
        userAccountService.updateById(userAccount);
@@ -90,7 +104,8 @@
        userPolicy.setTerm(insuranceProduct.getTerm());
        userPolicy.setName(dto.getName());
        userPolicy.setGender(dto.getGender());
            userPolicy.setPayStatus(0);
            userPolicy.setOrderNo(orderNo);
        userPolicy.setBirthDate(LocalDate.parse(dto.getBirthDate()));
        userPolicy.setOccupation(dto.getOccupation());
@@ -104,14 +119,95 @@
        userPolicy.setIsLifelong(insuranceProduct.getTerm() == 0 ? 0 : 1);
        save(userPolicy);
            // 获取 payUrl
            Object payParamsObj = parse.get("payParams");
            if (payParamsObj instanceof Map) {
                Map<?, ?> payParamsMap = (Map<?, ?>) payParamsObj;
                String payUrl = (String) payParamsMap.get("payUrl");
                if (payUrl != null && !payUrl.trim().isEmpty()) {
                    return Result.success(payUrl);
                }
            }
            return Result.error("支付链接获取失败,请联系客服!");
        }else{
            userAccount.setBalance(userAccount.getBalance().subtract(insuranceProduct.getPremium()));
            userAccountService.updateById(userAccount);
            String orderNo = generateOrderNo();
            UserPolicy userPolicy = new UserPolicy();
            userPolicy.setAccount(userAccount.getAccount());
            userPolicy.setProductName(insuranceProduct.getProductName());
            userPolicy.setUserId(userAccount.getId());
            userPolicy.setProductId(insuranceProduct.getId());
            userPolicy.setCoverageAmount(insuranceProduct.getCoverageAmount());
            userPolicy.setPremium(insuranceProduct.getPremium());
            userPolicy.setTerm(insuranceProduct.getTerm());
            userPolicy.setName(dto.getName());
            userPolicy.setGender(dto.getGender());
            userPolicy.setPayStatus(2);
            userPolicy.setOrderNo(orderNo);
            userPolicy.setBirthDate(LocalDate.parse(dto.getBirthDate()));
            userPolicy.setOccupation(dto.getOccupation());
            userPolicy.setIdCard(dto.getIdCard());
            userPolicy.setPhone(dto.getPhone());
            userPolicy.setPolicyNumber(generatePolicyNumber());
            userPolicy.setPolicyStatus(UserPolicy.PolicyStatus.PENDING);
            userPolicy.setCreatedAt(new Date());
            userPolicy.setUpdatedAt(new Date());
            userPolicy.setApprovalStatus(0);
            userPolicy.setIsLifelong(insuranceProduct.getTerm() == 0 ? 0 : 1);
            save(userPolicy);
            return Result.success();
        }
    }
    private final Random random = new Random();
    /**
     * 生成随机订单号 (格式: 时间戳 + 6位随机数)
     */
    public String generateOrderNo() {
        long timestamp = System.currentTimeMillis();
        int randomNum = random.nextInt(900000) + 100000; // 6位随机数
        return "ORDER" + timestamp + randomNum;
    }
        return Result.success("购买成功,注意查看资料审核状态!");
    /**
     * 处理支付结果 - 这里您自己实现业务逻辑
     */
    private void verifySign(String orderNo, String status, String amount, Map<String, String> params) {
        // TODO: 在这里实现您的具体业务逻辑
        if ("2".equals(status)) {
            // 支付成功
            System.out.println("=== 支付成功 ===");
            System.out.println("订单号: " + orderNo);
            System.out.println("金额: " + amount);
            System.out.println("=================");
            // 示例业务逻辑:
            // 1. 更新订单状态为已支付
            // 2. 记录支付时间
            // 3. 发放商品或服务
            // 4. 发送通知等
        } else if ("3".equals(status)) {
            // 业务处理完成
            System.out.println("订单 " + orderNo + " 业务处理完成");
        } else {
            System.out.println("订单 " + orderNo + " 状态: " + status);
        }
    }
    // 使用原子长整型确保线程安全
    private static final AtomicLong lastTimestamp = new AtomicLong(0);
    private static final Random random = new Random();
    private static final String PREFIX = "POL";
    /**
@@ -119,7 +215,7 @@
     * 格式: POL + 时间戳 + 随机数
     * 示例: POL16973512345671234
     */
    public static String generatePolicyNumber() {
    public String generatePolicyNumber() {
        long currentTimestamp = System.currentTimeMillis();
        long lastTime = lastTimestamp.get();
ruoyi-admin/src/main/java/com/ruoyi/im/util/HttpUtil.java
New file
@@ -0,0 +1,48 @@
package com.ruoyi.im.util;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Map;
/**
 * HTTP请求工具类
 */
public class HttpUtil {
    /**
     * 发送POST请求(表单格式)
     */
    public static String postForm(String urlStr, Map<String, Object> params) throws IOException {
        // 构建参数字符串
        StringBuilder postData = new StringBuilder();
        for (Map.Entry<String, Object> param : params.entrySet()) {
            if (postData.length() != 0) postData.append('&');
            postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setDoOutput(true);
        conn.getOutputStream().write(postDataBytes);
        // 读取响应
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
        StringBuilder response = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        reader.close();
        return response.toString();
    }
}
ruoyi-admin/src/main/java/com/ruoyi/im/util/PayService.java
New file
@@ -0,0 +1,152 @@
package com.ruoyi.im.util;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.*;
@Component
public class PayService {
    @Value("${pay.mch-id}")
    private String mchId;
    @Value("${pay.key}")
    private String key;
    @Value("${pay.base-url}")
    private String baseUrl;
    @Value("${pay.call-back-url}")
    private String callBackUrl;
    /**
     * 创建支付订单
     */
    public String createOrder(BigDecimal amount,String orderNo,String payProductId ) {
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("mchId", mchId);
            params.put("productId", payProductId);
            params.put("mchOrderNo",orderNo );
            params.put("amount", amount.intValue());
            params.put("notifyUrl", callBackUrl);
            String sign = generateSign(params);
            params.put("sign", sign);
            String url = baseUrl + "/api/pay/create_order";
            return sendPost(url, params);
        } catch (Exception e) {
            return "{\"retCode\":\"FAIL\",\"retMsg\":\"" + e.getMessage() + "\"}";
        }
    }
    /**
     * 查询订单
     */
    public String queryOrder(String orderNo) {
        try {
            Map<String, Object> params = new HashMap<>();
            params.put("mchId", mchId);
            params.put("mchOrderNo", orderNo);
            String sign = generateSign(params);
            params.put("sign", sign);
            String url = baseUrl + "/api/pay/query_order";
            return sendPost(url, params);
        } catch (Exception e) {
            return "{\"retCode\":\"FAIL\",\"retMsg\":\"" + e.getMessage() + "\"}";
        }
    }
    /**
     * 验证回调签名
     */
    public boolean verifySign(Map<String, String> params) {
        try {
            String receivedSign = params.get("sign");
            Map<String, Object> signParams = new HashMap<>(params);
            String calculatedSign = generateSign(signParams);
            return calculatedSign.equals(receivedSign);
        } catch (Exception e) {
            return false;
        }
    }
    /**
     * 生成签名
     */
    private String generateSign(Map<String, Object> params) throws Exception {
        // 移除sign参数
        Map<String, Object> signParams = new HashMap<>(params);
        signParams.remove("sign");
        // 过滤空值并排序
        List<String> keys = new ArrayList<>();
        for (Map.Entry<String, Object> entry : signParams.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().toString().trim().isEmpty()) {
                keys.add(entry.getKey());
            }
        }
        Collections.sort(keys);
        // 拼接字符串
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = signParams.get(key).toString();
            if (i > 0) sb.append("&");
            sb.append(key).append("=").append(value);
        }
        // MD5加密
        String stringSignTemp = sb.toString() + "&key=" + key;
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(stringSignTemp.getBytes("UTF-8"));
        StringBuilder result = new StringBuilder();
        for (byte item : array) {
            result.append(String.format("%02x", item));
        }
        return result.toString().toUpperCase();
    }
    /**
     * 发送POST请求
     */
    private String sendPost(String urlStr, Map<String, Object> params) throws Exception {
        // 构建参数字符串
        StringBuilder postData = new StringBuilder();
        for (Map.Entry<String, Object> param : params.entrySet()) {
            if (postData.length() != 0) postData.append('&');
            postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setDoOutput(true);
        conn.getOutputStream().write(postDataBytes);
        // 读取响应
        Scanner scanner = new Scanner(conn.getInputStream(), "UTF-8");
        String response = scanner.useDelimiter("\\A").next();
        scanner.close();
        return response;
    }
}
ruoyi-admin/src/main/java/com/ruoyi/im/util/PaySignUtil.java
New file
@@ -0,0 +1,89 @@
package com.ruoyi.im.util;
import java.security.MessageDigest;
import java.util.*;
/**
 * 支付签名工具类
 */
public class PaySignUtil {
    /**
     * 生成签名
     * @param params 参数Map
     * @param key 商户密钥
     * @return 签名值
     */
    public static String generateSign(Map<String, Object> params, String key) {
        try {
            // 第一步:参数按ASCII码排序
            String stringA = createSignString(params);
            // 第二步:拼接key
            String stringSignTemp = stringA + "&key=" + key;
            // 第三步:MD5加密并转为大写
            return md5(stringSignTemp).toUpperCase();
        } catch (Exception e) {
            throw new RuntimeException("生成签名失败", e);
        }
    }
    /**
     * 验证签名
     * @param params 参数Map
     * @param key 商户密钥
     * @param sign 待验证签名
     * @return 验证结果
     */
    public static boolean verifySign(Map<String, Object> params, String key, String sign) {
        String generatedSign = generateSign(params, key);
        return generatedSign.equals(sign);
    }
    /**
     * 创建待签名字符串
     */
    private static String createSignString(Map<String, Object> params) {
        // 移除sign参数
        Map<String, Object> signParams = new HashMap<>(params);
        signParams.remove("sign");
        // 过滤空值并排序
        List<String> keys = new ArrayList<>();
        for (Map.Entry<String, Object> entry : signParams.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().toString().trim().isEmpty()) {
                keys.add(entry.getKey());
            }
        }
        // ASCII码排序
        Collections.sort(keys);
        // 拼接字符串
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = signParams.get(key).toString();
            if (i > 0) {
                sb.append("&");
            }
            sb.append(key).append("=").append(value);
        }
        return sb.toString();
    }
    /**
     * MD5加密
     */
    private static String md5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString();
    }
}
ruoyi-admin/src/main/java/com/ruoyi/im/util/SimplePayUtil.java
New file
@@ -0,0 +1,175 @@
package com.ruoyi.im.util;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.*;
/**
 * 简化版支付工具类
 */
public class SimplePayUtil {
    private String mchId;        // 商户ID
    private String key;          // 商户密钥
    private String baseUrl;      // 支付系统基础URL
    public SimplePayUtil(String mchId, String key, String baseUrl) {
        this.mchId = mchId;
        this.key = key;
        this.baseUrl = baseUrl;
    }
    /**
     * 统一下单 - 最简单版本
     */
    public String createOrder(String productId, String orderNo, int amount, String notifyUrl) {
        try {
            // 构建参数
            Map<String, Object> params = new HashMap<>();
            params.put("mchId", mchId);
            params.put("productId", productId);
            params.put("mchOrderNo", orderNo);
            params.put("amount", amount);
            params.put("notifyUrl", notifyUrl);
            // 生成签名
            String sign = generateSign(params);
            params.put("sign", sign);
            // 发送请求
            String url = baseUrl + "/api/pay/create_order";
            String result = sendPost(url, params);
            return result;
        } catch (Exception e) {
            return "{\"retCode\":\"FAIL\",\"retMsg\":\"" + e.getMessage() + "\"}";
        }
    }
    /**
     * 查询订单 - 最简单版本
     */
    public String queryOrder(String orderNo) {
        try {
            // 构建参数
            Map<String, Object> params = new HashMap<>();
            params.put("mchId", mchId);
            params.put("mchOrderNo", orderNo);
            // 生成签名
            String sign = generateSign(params);
            params.put("sign", sign);
            // 发送请求
            String url = baseUrl + "/api/pay/query_order";
            String result = sendPost(url, params);
            return result;
        } catch (Exception e) {
            return "{\"retCode\":\"FAIL\",\"retMsg\":\"" + e.getMessage() + "\"}";
        }
    }
    /**
     * 生成签名
     */
    private String generateSign(Map<String, Object> params) throws Exception {
        // 移除sign参数
        Map<String, Object> signParams = new HashMap<>(params);
        signParams.remove("sign");
        // 过滤空值并排序
        List<String> keys = new ArrayList<>();
        for (Map.Entry<String, Object> entry : signParams.entrySet()) {
            if (entry.getValue() != null && !entry.getValue().toString().trim().isEmpty()) {
                keys.add(entry.getKey());
            }
        }
        // ASCII码排序
        Collections.sort(keys);
        // 拼接字符串
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            String value = signParams.get(key).toString();
            if (i > 0) {
                sb.append("&");
            }
            sb.append(key).append("=").append(value);
        }
        // 拼接key并MD5加密
        String stringSignTemp = sb.toString() + "&key=" + key;
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(stringSignTemp.getBytes("UTF-8"));
        StringBuilder result = new StringBuilder();
        for (byte item : array) {
            result.append(String.format("%02x", item));
        }
        return result.toString().toUpperCase();
    }
    /**
     * 发送POST请求
     */
    private String sendPost(String urlStr, Map<String, Object> params) throws Exception {
        // 构建参数字符串
        StringBuilder postData = new StringBuilder();
        for (Map.Entry<String, Object> param : params.entrySet()) {
            if (postData.length() != 0) postData.append('&');
            postData.append(URLEncoder.encode(param.getKey(), "UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()), "UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        conn.setRequestProperty("Content-Length", String.valueOf(postDataBytes.length));
        conn.setDoOutput(true);
        // 发送数据
        OutputStream os = conn.getOutputStream();
        os.write(postDataBytes);
        os.flush();
        os.close();
        // 读取响应
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
        StringBuilder response = new StringBuilder();
        String line;
        while ((line = reader.readLine()) != null) {
            response.append(line);
        }
        reader.close();
        return response.toString();
    }
    /**
     * 验证回调签名
     */
    public boolean verifyNotifySign(Map<String, String> params) {
        try {
            String receivedSign = params.get("sign");
            Map<String, Object> signParams = new HashMap<>(params);
            String calculatedSign = generateSign(signParams);
            return calculatedSign.equals(receivedSign);
        } catch (Exception e) {
            return false;
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/product/UserKycController.java
@@ -17,6 +17,7 @@
import com.ruoyi.system.domain.dto.UserPolicyDto;
import com.ruoyi.system.mapper.UserKycMapper;
import com.ruoyi.system.service.UserAccountService;
import org.apache.catalina.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
@@ -25,6 +26,7 @@
import javax.validation.Valid;
import java.util.Date;
import java.util.List;
import java.util.Optional;
@RestController
@RequestMapping("/kyc")
@@ -60,6 +62,8 @@
                userKyc.setHeadPortraitImg(dto.getHeadPortraitImg());
                userKyc.setNationalEmblemImg(dto.getNationalEmblemImg());
                userKyc.setHandImg(dto.getHandImg());
                userKyc.setName(dto.getName());
                userKyc.setIdCard(dto.getIdCard());
                userKycService.save(userKyc);
            }else{
                if(userKyc.getState() == 0){
@@ -69,6 +73,8 @@
                userKyc.setHeadPortraitImg(dto.getHeadPortraitImg());
                userKyc.setNationalEmblemImg(dto.getNationalEmblemImg());
                userKyc.setHandImg(dto.getHandImg());
                userKyc.setName(dto.getName());
                userKyc.setIdCard(dto.getIdCard());
                userKycService.updateById(userKyc);
            }
            userAccount.setKycStatus(0);
@@ -140,4 +146,31 @@
        List<UserKyc> list = userKycService.list(wrapper);
        return getDataTable(list);
    }
    /**
     * 根据账户查询实名认证信息
     */
    @GetMapping("/getByAccount")
    public Result getByAccount(@RequestParam(value = "account") String account) {
        LambdaQueryWrapper<UserKyc> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserKyc::getAccount,account);
        // 按创建时间倒序排列
        wrapper.orderByDesc(UserKyc::getCreatedAt);
        // 查询用户KYC信息
        UserKyc userKyc = userKycService.getOne(new LambdaQueryWrapper<UserKyc>()
                .eq(UserKyc::getAccount, account));
        // 如果KYC信息存在,补充昵称信息
        UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>()
                .eq(UserAccount::getAccount, account));
        // 如果KYC信息不存在,创建空实体
        if (ObjectUtil.isEmpty(userKyc)) {
            userKyc = new UserKyc();
        }
        if (StringUtils.isNotEmpty(userAccount.getNickname())) {
            userKyc.setNickName(userAccount.getNickname());
        }
        return Result.success(userKyc);
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/product/UserPolicyController.java
@@ -12,6 +12,7 @@
import com.ruoyi.im.service.InsuranceProductService;
import com.ruoyi.im.service.MedicalInsuranceAccountService;
import com.ruoyi.im.service.impl.InsurancePositionServiceImpl;
import com.ruoyi.im.util.PayService;
import com.ruoyi.im.util.RedisDistributedLock;
import com.ruoyi.im.util.UserPolicyUtils;
import com.ruoyi.system.domain.*;
@@ -26,12 +27,10 @@
import javax.validation.Valid;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.*;
import java.util.stream.Collectors;
@RestController
@@ -55,6 +54,8 @@
    @Autowired
    InsuranceProductService insuranceProductService;
    @Autowired
    private PayService payService;
    /**
     * 保险购买申请
@@ -97,7 +98,10 @@
        try {
            UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>()
                    .eq(UserAccount::getAccount,account));
            List<UserPolicy> list = userPolicyService.list(new LambdaQueryWrapper<UserPolicy>().eq(UserPolicy::getUserId, userAccount.getId()));
            List<UserPolicy> list = userPolicyService.list(new LambdaQueryWrapper<UserPolicy>()
                    .eq(UserPolicy::getUserId, userAccount.getId())
                    .eq(UserPolicy::getPayStatus,2)
            );
            return Result.success(list);
        }catch (Exception e){
            e.printStackTrace();
@@ -131,6 +135,9 @@
            wrapper.ne(UserPolicy::getApprovalStatus, 0);
        }else{
            wrapper.eq(UserPolicy::getApprovalStatus, 0);
            wrapper.eq(UserPolicy::getPayStatus,3)
                    .or()
                    .eq(UserPolicy::getPayStatus,2);
        }
        // 按创建时间倒序排列
@@ -160,6 +167,9 @@
            if(approvalStatus == 2 && StringUtils.isEmpty(message)){
                return AjaxResult.error("驳回理由不能为空!");
            }
            if(userPolicy.getPayStatus() != 3 && userPolicy.getPayStatus() != 2){
                return AjaxResult.error("保单未支付完成,不能进行审批!");
            }
            UserAccount userAccount = userAccountService.getById(userPolicy.getUserId());
            if(approvalStatus == 2){
                userPolicy.setApprovalStatus(approvalStatus);
@@ -183,13 +193,18 @@
            userPolicy.setUpdatedAt(new Date());
            userPolicyService.updateById(userPolicy);
            //每天可领
            BigDecimal amountClaimed = userPolicy.getCoverageAmount()
                    .divide(new BigDecimal(userPolicy.getTerm()), 4, RoundingMode.HALF_UP);
            MedicalInsuranceAccount medicalInsuranceAccount = new MedicalInsuranceAccount();
            medicalInsuranceAccount.setUserId(userPolicy.getUserId());
            medicalInsuranceAccount.setPolicyId(userPolicy.getId());
            medicalInsuranceAccount.setProductId(userPolicy.getProductId());
            medicalInsuranceAccount.setTotalQuota(userPolicy.getCoverageAmount());
            medicalInsuranceAccount.setRemainingBalance(BigDecimal.ZERO);
            medicalInsuranceAccount.setAmountClaimed(userPolicy.getCoverageAmount());
            medicalInsuranceAccount.setAmountClaimed(amountClaimed);
            medicalInsuranceAccount.setAlreadyReceived(BigDecimal.ZERO);
            medicalInsuranceAccount.setAmountAlreadyUsed(BigDecimal.ZERO);
            medicalInsuranceAccount.setEffectiveDate(userPolicy.getStartDate());
@@ -297,4 +312,53 @@
            throw new IllegalArgumentException("基准日期不能为null");
        }
    }
    /**
     * 支付回调接口 - 支付平台会调用这个接口
     */
    @PostMapping("/notify")
    public String payNotify(@RequestParam Map<String, String> params) {
        System.out.println("收到支付回调: " + params);
        // 验证签名
        if (!payService.verifySign(params)) {
            System.out.println("签名验证失败");
            return "fail";
        }
        // 获取关键参数
        String orderNo = params.get("mchOrderNo");
        String status = params.get("status");
        String amount = params.get("amount");
        System.out.println("订单号: " + orderNo + ", 状态: " + status + ", 金额: " + amount);
        // 这里调用您的业务处理逻辑
        handlePayResult(orderNo, Integer.valueOf(status), params);
        return "success";
    }
    /**
     * 处理支付结果 - 这里您自己实现业务逻辑
     */
    private void handlePayResult(String orderNo, Integer status, Map<String, String> params) {
        UserPolicy userPolicy = userPolicyService.getOne(new LambdaQueryWrapper<UserPolicy>()
                .eq(UserPolicy::getOrderNo,orderNo)
        );
        if(ObjectUtil.isNotEmpty(userPolicy)){
            if ("2".equals(status)) {
                userPolicy.setPayStatus(status);
            } else if ("3".equals(status)) {
                userPolicy.setPayStatus(status);
            } else if ("0010".equals(status)) {
                userPolicy.setPayMsg("系统超时或异常");
            } else if ("0014".equals(status)) {
            userPolicy.setPayMsg("mchId是系统分配的商户号,不能自己生成");
        }
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/BasicSetupController.java
@@ -52,6 +52,8 @@
        configServiceById.setLegalInstitution(vo.getLegalInstitution());
        configServiceById.setCopyrightInfo(vo.getCopyrightInfo());
        configServiceById.setCodeUrl(vo.getCodeUrl());
        configServiceById.setCustomerServiceUrl(vo.getCustomerServiceUrl());
        configServiceById.setAboutUs(vo.getAboutUs());
        groupWelcomeConfigService.updateById(configServiceById);
        return AjaxResult.success("保存成功!");
    }
@@ -71,14 +73,14 @@
     */
//    @PreAuthorize("@ss.hasPermi('im:group:list')")
    @GetMapping("/list")
    public TableDataInfo list(@RequestParam(value = "keyword", required = false) String keyword)
    public TableDataInfo list(@RequestParam(value = "keywords", required = false) String keywords)
    {
        // 创建查询条件包装器
        LambdaQueryWrapper<IpBlacklist> queryWrapper = new LambdaQueryWrapper<>();
        // 只有当 keyword 不为空时才添加 OR 条件
        if (ObjectUtil.isNotEmpty(keyword)) {
            queryWrapper.and(wrapper -> wrapper.eq(IpBlacklist::getIpAddress,keyword)
        if (ObjectUtil.isNotEmpty(keywords)) {
            queryWrapper.and(wrapper -> wrapper.eq(IpBlacklist::getIpAddress,keywords)
            );
        }
ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/InvitationBlacklistController.java
New file
@@ -0,0 +1,80 @@
package com.ruoyi.web.controller.system;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.system.domain.InvitationBlacklist;
import com.ruoyi.system.domain.IpBlacklist;
import com.ruoyi.system.service.impl.InvitationBlacklistServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
import java.util.List;
@RestController
@RequestMapping("/system/Invitation")
public class InvitationBlacklistController extends BaseController {
    @Autowired
    InvitationBlacklistServiceImpl service;
    /**
     * 邀请码黑名单列表
     */
//    @PreAuthorize("@ss.hasPermi('im:group:list')")
    @GetMapping("/list")
    public TableDataInfo list(@RequestParam(value = "keywords", required = false) String keywords)
    {
        // 创建查询条件包装器
        LambdaQueryWrapper<InvitationBlacklist> queryWrapper = new LambdaQueryWrapper<>();
        // 只有当 keyword 不为空时才添加 OR 条件
        if (ObjectUtil.isNotEmpty(keywords)) {
            queryWrapper.and(wrapper -> wrapper.eq(InvitationBlacklist::getInvitationCode,keywords)
            );
        }
        // 默认按创建时间倒序
        queryWrapper.orderByDesc(InvitationBlacklist::getCreateTime);
        startPage();
        List<InvitationBlacklist> list = service.list(queryWrapper);
        return getDataTable(list);
    }
    /**
     * 新增邀请码黑名单
     */
    @PostMapping("/addCode")
    public AjaxResult addIp(@RequestParam("code") String code) {
        long count = service.count(new LambdaQueryWrapper<>(InvitationBlacklist.class).eq(InvitationBlacklist::getInvitationCode, code));
        if(count > 0){
            return AjaxResult.error("邀请码已存在!");
        }
        InvitationBlacklist invitationBlacklist = new InvitationBlacklist();
        invitationBlacklist.setInvitationCode(code);
        invitationBlacklist.setCreateTime(new Date());
        service.save(invitationBlacklist);
        return AjaxResult.success("添加成功");
    }
    /**
     * 删除邀请码黑名单
     */
    @PostMapping("/deleteCode")
    public AjaxResult deleteCode(@RequestParam("id") Integer id) {
        InvitationBlacklist invitationBlacklist  = service.getById(id);
        if(ObjectUtil.isEmpty(invitationBlacklist)){
            return AjaxResult.error("邀请码不存在!");
        }
        service.removeById(id);
        return AjaxResult.success("删除成功");
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/user/UserController.java
@@ -15,6 +15,7 @@
import com.ruoyi.im.service.ImApiServcie;
import com.ruoyi.im.util.ConverterUtil;
import com.ruoyi.im.util.PhoneNumberValidatorUtil;
import com.ruoyi.im.util.SymmetricCryptoUtil;
import com.ruoyi.system.domain.UserAccount;
import com.ruoyi.system.domain.vo.UserAccountUpdateVo;
import com.ruoyi.system.domain.vo.UserAccountVo;
@@ -243,15 +244,28 @@
    public AjaxResult updateUserAccount(UserAccountUpdateVo vo) {
        try {
            UserAccount userAccount = userAccountService.getById(vo.getId());
            UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>()
                    .eq(UserAccount::getAccount,vo.getAccount())
            );
            if(ObjectUtil.isEmpty(userAccount)){
                return AjaxResult.error("会员不存在!");
            }
            if(StringUtils.isNotEmpty(vo.getPhoneNumber())){
            PhoneNumberValidatorUtil.ValidationResult result = PhoneNumberValidatorUtil.validatePhoneNumber(vo.getPhoneNumber());
            if(!result.isValid()){
                return AjaxResult.error("手机号格式不正确!");
            }
            vo.setAccountId(userAccount.getCloudMessageAccount());
            }
            if(StringUtils.isNotEmpty(vo.getPassword()) && StringUtils.isEmpty(vo.getOldPassword())){
                return AjaxResult.error("旧密码不能为空!");
            }
            if(StringUtils.isNotEmpty(vo.getPassword())){
                String s = SymmetricCryptoUtil.decryptPassword(userAccount.getPassword());
                if(!vo.getOldPassword().equals(s)){
                    return AjaxResult.error("旧密码不正确!");
                }
            }
            vo.setAccount(userAccount.getCloudMessageAccount());
            return imApiServcie.updateUserAccount(vo);
        }catch (Exception e){
            e.printStackTrace();
@@ -275,7 +289,7 @@
                if(StringUtils.isEmpty(dto.getPassword())){
                    return Result.error("密码不能为空");
                }
                if(StringUtils.isEmpty(dto.getNickname())){
                if(StringUtils.isEmpty(dto.getNikeName())){
                    return Result.error("昵称不能为空");
                }
            }else if (dto.getType() == 1){
ruoyi-admin/src/main/resources/application.yml
@@ -153,3 +153,9 @@
netease:
  im:
    api-head-portrait-url: https://open.yunxinapi.com
pay:
  mch-id: "10761"
  key: "UHI4O7SDWRP8CTRDSGHN9KW3MIAT7GWWJ8QGL6GGZIKVLHZT3XIYEVFXDLBBWYPNXGHFN9MNN1JCCQKZFQQOVMZEH8PVTUVW2ECYDGAFOQU6GREKZOF4AOHSIRF2SY8E"
  base-url: "http://pay.hwpal.xyz"
  call-back-url: "http://localhost:8080/userPolicy/notify"
ruoyi-system/src/main/java/com/ruoyi/system/domain/GroupWelcomeConfig.java
@@ -47,6 +47,17 @@
    private String welcomeMessage;
    /**
     * 客服连接
     */
    private String customerServiceUrl;
    /**
     * 关于我们
     */
    private String  aboutUs;
    /**
     * 法律机构
     */
    private String legalInstitution;
ruoyi-system/src/main/java/com/ruoyi/system/domain/InvitationBlacklist.java
New file
@@ -0,0 +1,30 @@
package com.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@Data
public class InvitationBlacklist {
    /**
     * 主键ID
     */
    @TableId(type = IdType.AUTO)
    private Long id;
    /**
     * 邀请码
     */
    private String invitationCode;
    /**
     * 创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date createTime;
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/MedicalInsuranceAccount.java
@@ -34,7 +34,7 @@
    // 账户余额(用户申请使用才扣)
    private BigDecimal remainingBalance ;
    //待领金额
    //待领金额(现在改成了每天可领多少了)
    private BigDecimal amountClaimed;
    //已领取金额
ruoyi-system/src/main/java/com/ruoyi/system/domain/UserAccount.java
@@ -94,4 +94,11 @@
    //达成时间
    private LocalDate agreedTime;
    //创建群开关 0 开启 1关闭
    private Integer groupPermissions = 1;
    //添加好友 0 开启 1 关闭
    private Integer addFriend = 1;
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/UserKyc.java
@@ -1,9 +1,11 @@
package com.ruoyi.system.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import java.util.Date;
/**
@@ -42,4 +44,14 @@
    // 更新时间
    private Date updatedAt;
    //手持照片
    private String name;
    //手持照片
    private String idCard;
    //昵称
    @TableField(exist = false)
    private String nickName;
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/UserPolicy.java
@@ -38,7 +38,7 @@
    // 保费
    private BigDecimal premium;
    // 保险期限(如:1年/终身)
    // 保险期限(如:1天/终身)
    private Integer term;
    // 姓名
@@ -86,6 +86,15 @@
    //驳回信息
    private String message;
    //支付状态,0-订单生成,1-支付中,2-支付成功,3-业务处理完成
    private Integer payStatus;
    //支付订单号
    private String orderNo;
    //支付失败原因
    private String payMsg;
    // 性别枚举 M:男  F:女  OTHER:其他
    public enum Gender {
        M, F, OTHER
ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/UserKycDto.java
@@ -26,4 +26,12 @@
    @NotEmpty(message = "手持照片不能为空")
    private String handImg;
    //手持照片
    @NotEmpty(message = "姓名不能为空")
    private String name;
    //手持照片
    @NotEmpty(message = "身份证不能为空")
    private String idCard;
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/UserPolicyDto.java
@@ -34,4 +34,7 @@
    // 手机号码
    private String phone;
    //支付产品id
    private String payProductId;
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/out/UserOut.java
@@ -24,4 +24,19 @@
    //实名状态:0 认证中  1 已认证   2 未实名
    private Integer kycStatus = 2;
    /**
     * 客服连接
     */
    private String customerServiceUrl;
    /**
     * 关于我们
     */
    private String  aboutUs;
    //创建群开关 0 开启 1关闭
    private Integer groupPermissions = 1;
    //添加好友 0 开启 1 关闭
    private Integer addFriend = 1;
}
ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/UserAccountUpdateVo.java
@@ -23,13 +23,16 @@
    private Integer id;
    // 云信账号
    private String accountId;
    private String account;
    // 手机号(唯一)
    private String phoneNumber;
    // 密码
    private String password;
    // 旧密码
    private String oldPassword;
    // 账号类型: 0:真实 1:虚拟
    private Integer accountType;
@@ -45,6 +48,12 @@
    // 用户性别,0-未知,1-男,2-女。
    private Integer gender;
    //创建群开关 0 开启 1关闭
    private Integer groupPermissions = 1;
    //添加好友 0 开启 1 关闭
    private Integer addFriend = 1;
//    // 是否支持昵称搜索
//    private Boolean supportNicknameSearch = true;
//
ruoyi-system/src/main/java/com/ruoyi/system/mapper/InvitationBlacklistMapper.java
New file
@@ -0,0 +1,10 @@
package com.ruoyi.system.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.system.domain.InvitationBlacklist;
import com.ruoyi.system.domain.IpBlacklist;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface InvitationBlacklistMapper extends BaseMapper<InvitationBlacklist> {
}
ruoyi-system/src/main/java/com/ruoyi/system/service/InvitationBlacklistService.java
New file
@@ -0,0 +1,8 @@
package com.ruoyi.system.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.system.domain.InvitationBlacklist;
import com.ruoyi.system.domain.IpBlacklist;
public interface InvitationBlacklistService extends IService<InvitationBlacklist> {
}
ruoyi-system/src/main/java/com/ruoyi/system/service/impl/InvitationBlacklistServiceImpl.java
New file
@@ -0,0 +1,14 @@
package com.ruoyi.system.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.system.domain.InvitationBlacklist;
import com.ruoyi.system.domain.IpBlacklist;
import com.ruoyi.system.mapper.InvitationBlacklistMapper;
import com.ruoyi.system.mapper.IpBlacklistMapper;
import com.ruoyi.system.service.InvitationBlacklistService;
import com.ruoyi.system.service.IpBlacklistService;
import org.springframework.stereotype.Service;
@Service
public class InvitationBlacklistServiceImpl extends ServiceImpl<InvitationBlacklistMapper, InvitationBlacklist> implements InvitationBlacklistService {
}