1
zj
2025-09-21 db4f7bbb81d14ba590206b9ba2ebcea76f7de9bf
1
7 files modified
2 files added
251 ■■■■ changed files
ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java 41 ●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/service/MedicalInsuranceAccountService.java 4 ●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/MedicalInsuranceAccountServiceImpl.java 76 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/UserPolicyServiceImpl.java 4 ●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/task/MedicalInsuranceTask.java 81 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/web/controller/product/MedicalInsuranceAccountController.java 8 ●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/web/controller/product/UserPolicyController.java 11 ●●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/UserPolicyDto.java 2 ●●● patch | view | raw | blame | history
ruoyi-system/src/main/java/com/ruoyi/system/domain/out/UserOut.java 24 ●●●●● patch | view | raw | blame | history
ruoyi-admin/src/main/java/com/ruoyi/im/ImApiController.java
@@ -13,12 +13,11 @@
import com.ruoyi.im.service.ImApiServcie;
import com.ruoyi.im.dto.RegisterDto;
import com.ruoyi.im.service.InsuranceProductService;
import com.ruoyi.im.service.MedicalInsuranceAccountService;
import com.ruoyi.im.util.SymmetricCryptoUtil;
import com.ruoyi.im.util.ValidatorUtil;
import com.ruoyi.system.domain.GroupWelcomeConfig;
import com.ruoyi.system.domain.InsuranceProduct;
import com.ruoyi.system.domain.IpBlacklist;
import com.ruoyi.system.domain.UserAccount;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.out.UserOut;
import com.ruoyi.system.domain.vo.UserAccountUpdateVo;
import com.ruoyi.system.service.GroupWelcomeConfigService;
import com.ruoyi.system.service.ISysUserService;
@@ -63,6 +62,8 @@
    @Autowired
    InsuranceProductService insuranceProductService;
    @Autowired
    MedicalInsuranceAccountService medicalInsuranceAccountService;
    @Value("${file.upload-dir}")
@@ -258,5 +259,35 @@
        List<InsuranceProduct> list = insuranceProductService.list(wrapper);
        return Result.success(list);
    }
    /**
     * 获取用户详情
     */
    @GetMapping("/getUserByAccount")
    public Result getUserByAccount(HttpServletRequest request,@RequestParam("account") String account){
        try {
            String clientIp = IpUtils.getClientIp(request);
            if(StringUtils.isEmpty(clientIp)){
                return Result.success();
            }
            UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<>(UserAccount.class).eq(UserAccount::getCloudMessageAccount, account));
            if(ObjectUtil.isEmpty(userAccount)){
                return Result.error("账号不存在!");
            }
            UserOut user = new UserOut();
            MedicalInsuranceAccount insuranceAccount = medicalInsuranceAccountService.getOne(new LambdaQueryWrapper<>(MedicalInsuranceAccount.class)
                    .eq(MedicalInsuranceAccount::getUserId, userAccount.getId())
                    .eq(MedicalInsuranceAccount::getAccountStatus, MedicalInsuranceAccount.AccountStatus.ACTIVE)
            );
            user.setKycStatus(userAccount.getKycStatus());
            if(ObjectUtil.isEmpty(insuranceAccount)){
                return Result.success(user);
            }
            user.setAmountClaimed(insuranceAccount.getAmountClaimed());
            user.setAlreadyReceived(insuranceAccount.getAlreadyReceived());
            return Result.success(user);
        }catch (Exception e){
            log.error("获取失败:",e);
            return Result.error("获取失败,请稍后再试!");
        }
    }
}
ruoyi-admin/src/main/java/com/ruoyi/im/service/MedicalInsuranceAccountService.java
@@ -6,7 +6,7 @@
import com.ruoyi.system.domain.MedicalInsuranceAccount;
public interface MedicalInsuranceAccountService  extends IService<MedicalInsuranceAccount> {
    Result getInsuranceBenefit(Integer id);
    Result getInsuranceBenefit(String account);
    Result getReceiveStatus(Integer userId);
    Result getReceiveStatus(String account);
}
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/MedicalInsuranceAccountServiceImpl.java
@@ -6,8 +6,10 @@
import com.ruoyi.im.service.MedicalInsuranceAccountService;
import com.ruoyi.system.domain.MedicalInsuranceAccount;
import com.ruoyi.system.domain.MedicalInsuranceDailyClaim;
import com.ruoyi.system.domain.UserAccount;
import com.ruoyi.system.mapper.MedicalInsuranceAccountMapper;
import com.ruoyi.system.mapper.MedicalInsuranceDailyClaimMapper;
import com.ruoyi.system.service.UserAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@@ -32,76 +34,80 @@
    private MedicalInsuranceDailyClaimMapper medicalInsuranceDailyClaimMapper;
    // 使用本地锁避免数据库锁竞争
    private final ConcurrentHashMap<Integer, ReentrantLock> accountLocks = new ConcurrentHashMap<>();
    private final ConcurrentHashMap<String, ReentrantLock> accountLocks = new ConcurrentHashMap<>();
    @Autowired
    UserAccountService userAccountService;
    @Override
    public Result getInsuranceBenefit(Integer userId) {
        synchronized (userId) {
    public Result getInsuranceBenefit(String account) {
        synchronized (account) {
            // 获取账户本地锁
            ReentrantLock accountLock = accountLocks.computeIfAbsent(userId, k -> new ReentrantLock());
            ReentrantLock accountLock = accountLocks.computeIfAbsent(account, k -> new ReentrantLock());
            accountLock.lock();
            UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>()
                    .eq(UserAccount::getAccount,account));
            try {
                MedicalInsuranceAccount account = medicalInsuranceAccountMapper.selectOne(new LambdaQueryWrapper<MedicalInsuranceAccount>()
                        .eq(MedicalInsuranceAccount::getUserId, userId)
                MedicalInsuranceAccount medicalInsuranceAccount = medicalInsuranceAccountMapper.selectOne(new LambdaQueryWrapper<MedicalInsuranceAccount>()
                        .eq(MedicalInsuranceAccount::getUserId, userAccount.getId())
                        .eq(MedicalInsuranceAccount::getAccountStatus, MedicalInsuranceAccount.AccountStatus.ACTIVE)
                );
                if (account == null) {
                if (medicalInsuranceAccount == null) {
                    return Result.error("医保账户不存在");
                }
                // 检查账户状态
                if (!"ACTIVE".equals(account.getAccountStatus().name())) {
                if (!"ACTIVE".equals(medicalInsuranceAccount.getAccountStatus().name())) {
                    return Result.error("保单已失效");
                }
                // 检查账户有效期
                LocalDate now = LocalDate.now();
                if (now.isBefore(account.getEffectiveDate()) ||
                        now.isAfter(account.getExpiryDate())) {
                if (now.isBefore(medicalInsuranceAccount.getEffectiveDate()) ||
                        now.isAfter(medicalInsuranceAccount.getExpiryDate())) {
                    return Result.error("已过保单日期");
                }
                // 检查今天是否已经领取
                LocalDate today = LocalDate.now();
                Long todayCount = medicalInsuranceDailyClaimMapper.selectCount(new LambdaQueryWrapper<MedicalInsuranceDailyClaim>()
                        .eq(MedicalInsuranceDailyClaim::getUserId, userId)
                        .eq(MedicalInsuranceDailyClaim::getAccountId, account.getId())
                        .eq(MedicalInsuranceDailyClaim::getUserId, userAccount.getId())
                        .eq(MedicalInsuranceDailyClaim::getAccountId, medicalInsuranceAccount.getId())
                        .eq(MedicalInsuranceDailyClaim::getClaimDate, today)
                );
                if (todayCount > 0) {
                    return Result.error("今日已领取过金额");
                }
                if (account.getTotalQuota().compareTo(account.getAlreadyReceived()) == 0) {
                if (medicalInsuranceAccount.getTotalQuota().compareTo(medicalInsuranceAccount.getAlreadyReceived()) == 0) {
                    return Result.error("你的保险额度已领取完!");
                }
                // 计算剩余天数
                long remainingDays = ChronoUnit.DAYS.between(now, account.getExpiryDate()) + 1;
                long remainingDays = ChronoUnit.DAYS.between(now, medicalInsuranceAccount.getExpiryDate()) + 1;
                // 计算每日金额
                BigDecimal dailyAmount = calculateDailyAmount(
                        account.getTotalQuota(), (int) remainingDays);
                        medicalInsuranceAccount.getTotalQuota(), (int) remainingDays);
                // 如果账户余额不足,则领取剩余全部金额
                if (account.getAmountClaimed().compareTo(dailyAmount) < 0) {
                    dailyAmount = account.getAmountClaimed();
                if (medicalInsuranceAccount.getAmountClaimed().compareTo(dailyAmount) < 0) {
                    dailyAmount = medicalInsuranceAccount.getAmountClaimed();
                }
                // 更新待领金额
                account.setAmountClaimed(account.getAmountClaimed().subtract(dailyAmount));
                medicalInsuranceAccount.setAmountClaimed(medicalInsuranceAccount.getAmountClaimed().subtract(dailyAmount));
                // 更新已领取金额
                BigDecimal currentAmountReceived = account.getAlreadyReceived() != null ?
                        account.getAlreadyReceived(): BigDecimal.ZERO;
                account.setAlreadyReceived(currentAmountReceived.add(dailyAmount));
                BigDecimal currentAmountReceived = medicalInsuranceAccount.getAlreadyReceived() != null ?
                        medicalInsuranceAccount.getAlreadyReceived(): BigDecimal.ZERO;
                medicalInsuranceAccount.setAlreadyReceived(currentAmountReceived.add(dailyAmount));
                medicalInsuranceAccountMapper.updateById(account);
                medicalInsuranceAccountMapper.updateById(medicalInsuranceAccount);
                // 创建领取记录
                MedicalInsuranceDailyClaim claim = new MedicalInsuranceDailyClaim();
                claim.setAccountId(account.getId());
                claim.setUserId(userId);
                claim.setAccountId(medicalInsuranceAccount.getId());
                claim.setUserId(userAccount.getId());
                claim.setClaimDate(today);
                claim.setClaimAmount(dailyAmount);
                claim.setCreatedAt(new Date());
@@ -119,29 +125,31 @@
    }
    @Override
    public Result getReceiveStatus(Integer userId) {
        MedicalInsuranceAccount account = medicalInsuranceAccountMapper.selectOne(new LambdaQueryWrapper<MedicalInsuranceAccount>()
                .eq(MedicalInsuranceAccount::getUserId, userId)
    public Result getReceiveStatus(String account) {
        UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>()
                .eq(UserAccount::getAccount,account));
        MedicalInsuranceAccount medicalInsuranceAccount = medicalInsuranceAccountMapper.selectOne(new LambdaQueryWrapper<MedicalInsuranceAccount>()
                .eq(MedicalInsuranceAccount::getUserId, userAccount.getId())
                .eq(MedicalInsuranceAccount::getAccountStatus, MedicalInsuranceAccount.AccountStatus.ACTIVE)
        );
        if (account == null) {
        if (medicalInsuranceAccount == null) {
            return Result.success(false);
        }
        // 检查账户状态
        if (!"ACTIVE".equals(account.getAccountStatus().name())) {
        if (!"ACTIVE".equals(medicalInsuranceAccount.getAccountStatus().name())) {
            return Result.success(false);
        }
        // 检查账户有效期
        LocalDate now = LocalDate.now();
        if (now.isBefore(account.getEffectiveDate()) ||
                now.isAfter(account.getExpiryDate())) {
        if (now.isBefore(medicalInsuranceAccount.getEffectiveDate()) ||
                now.isAfter(medicalInsuranceAccount.getExpiryDate())) {
            return Result.success(false);
        }
        // 检查今天是否已经领取
        LocalDate today = LocalDate.now();
        Long todayCount = medicalInsuranceDailyClaimMapper.selectCount(new LambdaQueryWrapper<MedicalInsuranceDailyClaim>()
                .eq(MedicalInsuranceDailyClaim::getUserId, userId)
                .eq(MedicalInsuranceDailyClaim::getAccountId, account.getId())
                .eq(MedicalInsuranceDailyClaim::getUserId, userAccount.getId())
                .eq(MedicalInsuranceDailyClaim::getAccountId, medicalInsuranceAccount.getId())
                .eq(MedicalInsuranceDailyClaim::getClaimDate, today)
        );
        if (todayCount > 0) {
ruoyi-admin/src/main/java/com/ruoyi/im/service/impl/UserPolicyServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.im.service.impl;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.im.comm.Result;
import com.ruoyi.im.service.InsuranceProductService;
@@ -32,7 +33,8 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result purchaseApplication(UserPolicyDto dto) {
        UserAccount userAccount = userAccountService.getById(dto.getUserId());
        UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>()
                .eq(UserAccount::getAccount,dto.getAccount()));
        if(ObjectUtil.isEmpty(userAccount)){
            return Result.error("请重新登录,未查询到你的信息!");
        }
ruoyi-admin/src/main/java/com/ruoyi/im/task/MedicalInsuranceTask.java
New file
@@ -0,0 +1,81 @@
package com.ruoyi.im.task;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.im.service.MedicalInsuranceAccountService;
import com.ruoyi.im.service.UserPolicyService;
import com.ruoyi.system.domain.MedicalInsuranceAccount;
import com.ruoyi.system.domain.UserPolicy;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * @program: ruoyiim
 * @description:
 * @create: 2025-09-21 14:21
 **/
@Component
public class MedicalInsuranceTask {
    @Autowired
    UserPolicyService userPolicyService;
    private final AtomicBoolean syncINStockData = new AtomicBoolean(false);
    private final Lock syncINStockDataLock = new ReentrantLock();
    @Autowired
    MedicalInsuranceAccountService medicalInsuranceAccountService;
    /**
     * 定时筛选用户保单状态
     */
    @Scheduled(cron = "0 0 0 * * ?")
    public void insuranceExpires() {
        if (syncINStockData.get()) { // 判断任务是否在处理中
            return;
        }
        if (syncINStockDataLock.tryLock()) {
            try {
                syncINStockData.set(true); // 设置处理中标识为true
                expires();
            } finally {
                syncINStockDataLock.unlock();
                syncINStockData.set(false); // 设置处理中标识为false
            }
        }
    }
    private void expires() {
        List<UserPolicy> list = userPolicyService.list(new LambdaQueryWrapper<UserPolicy>()
                .eq(UserPolicy::getPolicyStatus, UserPolicy.PolicyStatus.ACTIVE)
        );
        List<Integer> ids = new ArrayList<>();
        list.forEach(f->{
            if(isExpired(f.getEndDate())){
                f.setPolicyStatus(UserPolicy.PolicyStatus.EXPIRED);
                ids.add(f.getId());
            }
        });
        userPolicyService.updateBatchById(list);
        List<MedicalInsuranceAccount> insuranceAccountList = medicalInsuranceAccountService.list(new LambdaQueryWrapper<MedicalInsuranceAccount>()
                .in(MedicalInsuranceAccount::getPolicyId, ids)
        );
        insuranceAccountList.forEach(f->{
            f.setAccountStatus(MedicalInsuranceAccount.AccountStatus.SUSPENDED);
        });
        medicalInsuranceAccountService.updateBatchById(insuranceAccountList);
    }
    public boolean isExpired(LocalDate endDate) {
        return LocalDate.now().isAfter(endDate);
    }
}
ruoyi-admin/src/main/java/com/ruoyi/web/controller/product/MedicalInsuranceAccountController.java
@@ -23,9 +23,9 @@
     * 领取保险金
     */
    @GetMapping("/getInsuranceBenefit")
    public Result getInsuranceBenefit(@RequestParam(value = "userId") Integer userId) {
    public Result getInsuranceBenefit(@RequestParam(value = "account") String account) {
        try {
            return medicalInsuranceAccountService.getInsuranceBenefit(userId);
            return medicalInsuranceAccountService.getInsuranceBenefit(account);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("购买失败!");
@@ -36,9 +36,9 @@
     * 查询领取状态
     */
    @GetMapping("/getReceiveStatus")
    public Result getReceiveStatus(@RequestParam(value = "userId") Integer userId) {
    public Result getReceiveStatus(@RequestParam(value = "account") String account) {
        try {
            return medicalInsuranceAccountService.getReceiveStatus(userId);
            return medicalInsuranceAccountService.getReceiveStatus(account);
        }catch (Exception e){
            e.printStackTrace();
            return Result.error("购买失败!");
ruoyi-admin/src/main/java/com/ruoyi/web/controller/product/UserPolicyController.java
@@ -8,9 +8,11 @@
import com.ruoyi.im.comm.Result;
import com.ruoyi.im.service.MedicalInsuranceAccountService;
import com.ruoyi.system.domain.MedicalInsuranceAccount;
import com.ruoyi.system.domain.UserAccount;
import com.ruoyi.system.domain.UserPolicy;
import com.ruoyi.system.domain.dto.UserPolicyDto;
import com.ruoyi.im.service.UserPolicyService;
import com.ruoyi.system.service.UserAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
@@ -34,6 +36,9 @@
    @Autowired
    MedicalInsuranceAccountService medicalInsuranceAccountService;
    @Autowired
    UserAccountService userAccountService;
    /**
     * 保险购买申请
     */
@@ -51,9 +56,11 @@
     * 根据用户id查询保单
     */
    @GetMapping("/getPolicyById")
    public Result getPolicyById(@RequestParam(value = "id") Integer id) {
    public Result getPolicyById(@RequestParam(value = "account") String account) {
        try {
            List<UserPolicy> list = userPolicyService.list(new LambdaQueryWrapper<UserPolicy>().eq(UserPolicy::getUserId, id));
            UserAccount userAccount = userAccountService.getOne(new LambdaQueryWrapper<UserAccount>()
                    .eq(UserAccount::getAccount,account));
            List<UserPolicy> list = userPolicyService.list(new LambdaQueryWrapper<UserPolicy>().eq(UserPolicy::getUserId, userAccount.getId()));
            return Result.success(list);
        }catch (Exception e){
            e.printStackTrace();
ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/UserPolicyDto.java
@@ -11,7 +11,7 @@
public class UserPolicyDto {
    // 系统生成的用户ID
    private String userId;
    private String account;
    // 保险产品ID
    private Integer productId;
ruoyi-system/src/main/java/com/ruoyi/system/domain/out/UserOut.java
New file
@@ -0,0 +1,24 @@
package com.ruoyi.system.domain.out;
import lombok.Data;
import java.math.BigDecimal;
/**
 * @program: ruoyiim
 * @description:
 * @create: 2025-09-21 14:11
 **/
@Data
public class UserOut {
    //领取医疗保险金额
    private BigDecimal amountClaimed = BigDecimal.ZERO;
    //我的医疗报销总额
    private BigDecimal alreadyReceived = BigDecimal.ZERO;
    //实名状态:0 认证中  1 已认证   2 未实名
    private Integer kycStatus = 2;
}