hejianhao
2026-08-28 cc31d303d12f9c7cd2c4574351b67db04069ae0d
tcm-training-admin-backend/src/main/java/com/tcm/training/admin/member/service/ClinicAppService.java
@@ -1,37 +1,71 @@
package com.tcm.training.admin.member.service;
import cn.idev.excel.FastExcel;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tcm.training.admin.agent.entity.AgentRegion;
import com.tcm.training.admin.agent.entity.ProvincialAgent;
import com.tcm.training.admin.agent.excel.ClinicAgentImportRow;
import com.tcm.training.admin.agent.mapper.ProvincialAgentMapper;
import com.tcm.training.admin.app.register.entity.SysRegion;
import com.tcm.training.admin.app.register.mapper.SysRegionMapper;
import com.tcm.training.admin.common.DateTimes;
import com.tcm.training.admin.common.PageResponse;
import com.tcm.training.admin.common.PhoneMasker;
import com.tcm.training.admin.live.entity.Clinic;
import com.tcm.training.admin.live.mapper.ClinicMapper;
import com.tcm.training.admin.member.dto.ClinicBankAccountUpdateRequest;
import com.tcm.training.admin.member.entity.AppUser;
import com.tcm.training.admin.member.excel.ClinicExcelRow;
import com.tcm.training.admin.member.mapper.ClinicQueryMapper;
import com.tcm.training.admin.member.mapper.UserMapper;
import com.tcm.training.admin.member.row.ClinicBoundUserRow;
import com.tcm.training.admin.member.row.ClinicDetailRow;
import com.tcm.training.admin.member.mapper.ClinicQueryMapper;
import com.tcm.training.admin.member.row.ClinicListRow;
import com.tcm.training.admin.member.row.ClinicRegionOptionRow;
import com.tcm.training.admin.member.vo.ClinicBoundUserItemVO;
import com.tcm.training.admin.member.vo.ClinicDetailVO;
import com.tcm.training.admin.member.vo.ClinicListItemVO;
import com.tcm.training.admin.member.vo.ClinicRegionOptionVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
@Service
@Slf4j
public class ClinicAppService {
    private final ClinicQueryMapper clinicQueryMapper;
    private final ClinicMapper clinicMapper;
    private final ProvincialAgentMapper provincialAgentMapper;
    private final UserMapper userMapper;
    private final SysRegionMapper sysRegionMapper;
    private final DataSourceTransactionManager transactionManager;
    public ClinicAppService(ClinicQueryMapper clinicQueryMapper) {
    public ClinicAppService(ClinicQueryMapper clinicQueryMapper,
                           ClinicMapper clinicMapper,
                           ProvincialAgentMapper provincialAgentMapper,
                           UserMapper userMapper,
                           SysRegionMapper sysRegionMapper,
                           DataSourceTransactionManager transactionManager) {
        this.clinicQueryMapper = clinicQueryMapper;
        this.clinicMapper = clinicMapper;
        this.provincialAgentMapper = provincialAgentMapper;
        this.userMapper = userMapper;
        this.sysRegionMapper = sysRegionMapper;
        this.transactionManager = transactionManager;
    }
    public PageResponse<ClinicListItemVO> page(int page,
@@ -39,6 +73,7 @@
                                               String regionCode,
                                               String name,
                                               String phone,
                                               String agentName,
                                               LocalDateTime createdFrom,
                                               LocalDateTime createdTo,
                                               Integer status) {
@@ -47,6 +82,7 @@
                trimToNull(regionCode),
                trimToNull(name),
                trimToNull(phone),
                trimToNull(agentName),
                createdFrom,
                createdTo,
                status
@@ -58,9 +94,87 @@
        return PageResponse.of(list, result.getTotal(), result.getCurrent(), result.getSize());
    }
    public void downloadClinicImportTemplate(HttpServletResponse response) throws IOException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String filename = URLEncoder.encode("诊所省区代理导入模板", "UTF-8").replace("+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + filename + ".xlsx");
        FastExcel.write(response.getOutputStream(), ClinicAgentImportRow.class)
                .sheet("诊所省区代理导入模板")
                .doWrite(Collections.emptyList());
    }
    @Transactional
    public void importAgentBindings(MultipartFile file) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("请选择导入文件");
        }
        List<ClinicAgentImportRow> rows = FastExcel.read(file.getInputStream())
                .head(ClinicAgentImportRow.class).sheet().doReadSync();
        if (rows == null || rows.isEmpty()) {
            throw new IllegalArgumentException("导入文件不能为空");
        }
        Set<String> clinicNames = new LinkedHashSet<String>();
        Set<String> agentNames = new LinkedHashSet<String>();
        Map<String, String> bindingByClinicName = new HashMap<String, String>();
        int rowNumber = 1;
        for (ClinicAgentImportRow row : rows) {
            rowNumber++;
            if (row == null || (trimToNull(row.getClinicName()) == null && trimToNull(row.getAgentName()) == null))
                continue;
            String clinicName = trimToNull(row.getClinicName());
            String agentName = trimToNull(row.getAgentName());
            if (clinicName == null) {
                throw new IllegalArgumentException("第" + rowNumber + "行诊所不能为空");
            }
            if (agentName == null) {
                throw new IllegalArgumentException("第" + rowNumber + "行省区代理名称不能为空");
            }
            String previous = bindingByClinicName.put(clinicName, agentName);
            if (previous != null && !previous.equals(agentName)) {
                throw new IllegalArgumentException("诊所“" + clinicName + "”存在多个代理绑定");
            }
            clinicNames.add(clinicName);
            agentNames.add(agentName);
        }
        if (bindingByClinicName.isEmpty()) {
            throw new IllegalArgumentException("导入文件没有可用数据");
        }
        List<Clinic> clinics = clinicMapper.selectList(new LambdaQueryWrapper<Clinic>().in(Clinic::getName, clinicNames));
        List<ProvincialAgent> agents = provincialAgentMapper.selectList(new LambdaQueryWrapper<ProvincialAgent>()
                .eq(ProvincialAgent::getDeleted, 0).in(ProvincialAgent::getAgentName, agentNames));
        Map<String, ProvincialAgent> agentByName = new LinkedHashMap<String, ProvincialAgent>();
        for (ProvincialAgent agent : agents) {
            agentByName.put(agent.getAgentName(), agent);
        }
        for (String agentName : agentNames) {
            if (!agentByName.containsKey(agentName)) {
                throw new IllegalArgumentException("省区代理不存在:" + agentName);
            }
        }
        Set<String> foundClinicNames = new LinkedHashSet<String>();
        for (Clinic clinic : clinics) {
            foundClinicNames.add(clinic.getName());
            ProvincialAgent agent = agentByName.get(bindingByClinicName.get(clinic.getName()));
            clinic.setAgentId(agent.getId());
            clinicMapper.updateById(clinic);
        }
        for (String clinicName : clinicNames) {
            if (!foundClinicNames.contains(clinicName)) {
                throw new IllegalArgumentException("诊所不存在:" + clinicName);
            }
        }
    }
    public void export(String regionCode,
                       String name,
                       String phone,
                       String agentName,
                       LocalDateTime createdFrom,
                       LocalDateTime createdTo,
                       Integer status,
@@ -74,6 +188,7 @@
                trimToNull(regionCode),
                trimToNull(name),
                trimToNull(phone),
                trimToNull(agentName),
                createdFrom,
                createdTo,
                status
@@ -112,12 +227,99 @@
        }
        ClinicDetailVO vo = new ClinicDetailVO();
        vo.setId(row.getId());
        vo.setAgentId(row.getAgentId());
        vo.setName(row.getName());
        vo.setStatus(row.getStatus());
        vo.setPhone(defaultText(row.getContactPhone()));
        vo.setAddress(defaultText(row.getAddress()));
        vo.setProvinceCode(row.getProvinceCode());
        vo.setCityCode(row.getCityCode());
        vo.setDistrictCode(row.getDistrictCode());
        vo.setBusinessLicenseUrl(trimToNull(row.getBusinessLicenseUrl()));
        vo.setUserCount(row.getUserCount() == null ? 0 : row.getUserCount());
        vo.setBankName(defaultText(row.getBankName()));
        vo.setAccountHolder(defaultText(row.getAccountHolder()));
        vo.setAccountNumber(defaultText(row.getAccountNumber()));
        vo.setBranchName(defaultText(row.getBranchName()));
        vo.setAvatar(row.getAvatar());
        vo.setLoginAccount(row.getLoginAccount());
        return vo;
    }
    public ClinicDetailVO updateBankAccount(Long id, ClinicBankAccountUpdateRequest request) {
        // 手动开启事务
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = transactionManager.getTransaction(def);
        try {
            Clinic clinic = clinicMapper.selectById(id);
            if (clinic == null || (clinic.getDeleted() != null && clinic.getDeleted() == 1)) {
                throw new IllegalArgumentException("诊所不存在");
            }
            String loginAccount = trimToNull(request.getLoginAccount());
            AppUser user = userMapper.selectOne(new LambdaQueryWrapper<AppUser>().eq(AppUser::getPhone, loginAccount).eq(AppUser::getDeleted, 0).last("limit 1"));
            if (user == null) {
                throw new IllegalArgumentException("登录账号不存在");
            }
            user.setAvatar(trimToNull(request.getAvatar()));
            user.setPhone(loginAccount);
            userMapper.updateById(user);
            Set<String> codes = new LinkedHashSet<String>();
            addCode(codes, request.getProvinceCode());
            addCode(codes, request.getCityCode());
            addCode(codes, request.getDistrictCode());
            Map<String, SysRegion> regions = new HashMap<String, SysRegion>();
            List<SysRegion> regionList = sysRegionMapper.selectList(new LambdaQueryWrapper<SysRegion>().in(SysRegion::getCode, codes));
            if (!regionList.isEmpty()) {
                for (SysRegion region : regionList) {
                    regions.put(region.getCode(), region);
                }
            }
            clinic.setName(trimToNull(request.getName()));
            clinic.setContactPhone(loginAccount);
            clinic.setProvinceCode(trimToNull(request.getProvinceCode()));
            clinic.setProvinceName(regionName(request.getProvinceCode(), request.getProvinceName(), regions));
            clinic.setCityCode(trimToNull(request.getCityCode()));
            clinic.setCityName(regionName(request.getCityCode(), request.getCityName(), regions));
            clinic.setDistrictCode(trimToNull(request.getDistrictCode()));
            clinic.setDistrictName(regionName(request.getDistrictCode(), request.getDistrictName(), regions));
            clinic.setAddress(trimToNull(request.getAddress()));
            clinic.setBusinessLicenseUrl(trimToNull(request.getBusinessLicenseUrl()));
            clinic.setStatus(request.getStatus());
            clinic.setAgentId(request.getAgentId());
            clinic.setBankName(trimToNull(request.getBankName()));
            clinic.setAccountHolder(trimToNull(request.getAccountHolder()));
            clinic.setAccountNumber(trimToNull(request.getAccountNumber()));
            clinic.setBranchName(trimToNull(request.getBranchName()));
            clinicMapper.updateById(clinic);
            // 提交事务
            transactionManager.commit(status);
            log.info("诊所本地数据更新成功,clinicId={}", id);
        } catch (Exception e) {
            // 发生异常,回滚事务
            transactionManager.rollback(status);
            log.error("诊所本地数据更新失败,clinicId={}", id, e);
            throw e;
        }
        return detail(id);
    }
    private void addCode(Set<String> codes, String code) {
        String value = trimToNull(code);
        if (value != null) {
            codes.add(value);
        }
    }
    private String regionName(String code, String fallback, Map<String, SysRegion> regions) {
        String value = trimToNull(code);
        SysRegion region = value == null ? null : regions.get(value);
        return region == null ? trimToNull(fallback) : region.getName();
    }
    public PageResponse<ClinicBoundUserItemVO> clinicUsers(Long clinicId,
@@ -175,6 +377,7 @@
        item.setPhone(row.getPhone() == null ? "-" : PhoneMasker.mask(row.getPhone()));
        item.setRegionName(defaultText(row.getRegionName()));
        item.setStatus(row.getStatus());
        item.setAgentName(defaultText(row.getAgentName()));
        item.setUserCount(row.getUserCount() == null ? 0 : row.getUserCount());
        item.setCreatedAt(row.getCreatedAt());
        item.setBusinessLicenseUrl(trimToNull(row.getBusinessLicenseUrl()));