| | |
| | | package com.tcm.training.admin.agent.service; |
| | | |
| | | import cn.hutool.json.JSONUtil; |
| | | import cn.idev.excel.FastExcel; |
| | | import cn.idev.excel.ExcelWriter; |
| | | import cn.idev.excel.write.metadata.WriteSheet; |
| | | import com.tcm.training.admin.agent.excel.ProvincialAgentExcelRow; |
| | | import com.tcm.training.admin.common.DateTimes; |
| | | import com.fasterxml.jackson.databind.JsonNode; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.IPage; |
| | |
| | | import com.tcm.training.admin.common.PageResponse; |
| | | import com.tcm.training.admin.live.entity.Clinic; |
| | | import com.tcm.training.admin.live.mapper.ClinicMapper; |
| | | import com.tcm.training.admin.utils.VzanHttpUtil; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import com.tcm.training.admin.common.enums.EnabledStatusEnum; |
| | | |
| | | import javax.servlet.http.HttpServletResponse; |
| | | import java.io.IOException; |
| | | import java.net.URLEncoder; |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.LinkedHashMap; |
| | | |
| | | @Slf4j |
| | | @Service |
| | | public class ProvincialAgentAppService { |
| | | private final ProvincialAgentMapper agentMapper; |
| | | private final AgentRegionMapper regionMapper; |
| | | private final SysRegionMapper sysRegionMapper; |
| | | private final ClinicMapper clinicMapper; |
| | | private final VzanHttpUtil vzanHttpUtil; |
| | | private volatile Map<String, SysRegion> regionCache; |
| | | |
| | | public ProvincialAgentAppService(ProvincialAgentMapper agentMapper, AgentRegionMapper regionMapper, |
| | | SysRegionMapper sysRegionMapper, ClinicMapper clinicMapper) { |
| | | SysRegionMapper sysRegionMapper, ClinicMapper clinicMapper, VzanHttpUtil vzanHttpUtil) { |
| | | this.agentMapper = agentMapper; |
| | | this.regionMapper = regionMapper; |
| | | this.sysRegionMapper = sysRegionMapper; |
| | | this.clinicMapper = clinicMapper; |
| | | this.vzanHttpUtil = vzanHttpUtil; |
| | | } |
| | | |
| | | /** 分页查询省代理。 */ |
| | | public PageResponse<ProvincialAgentListItemVO> page(int page, int pageSize, String regionCode, |
| | | String clinicName, String contactInfo, Integer status) { |
| | | LambdaQueryWrapper<ProvincialAgent> query = new LambdaQueryWrapper<ProvincialAgent>() |
| | |
| | | if (trim(regionCode) != null) { |
| | | List<Long> ids = new ArrayList<Long>(); |
| | | for (AgentRegion region : regionMapper.selectList(new LambdaQueryWrapper<AgentRegion>() |
| | | .eq(AgentRegion::getRegionCode, trim(regionCode)))) ids.add(region.getAgentId()); |
| | | if (ids.isEmpty()) return emptyPage(page, pageSize); |
| | | .eq(AgentRegion::getRegionCode, trim(regionCode)))) |
| | | ids.add(region.getAgentId()); |
| | | if (ids.isEmpty()) { |
| | | return emptyPage(page, pageSize); |
| | | } |
| | | query.in(ProvincialAgent::getId, ids); |
| | | } |
| | | if (trim(clinicName) != null) { |
| | |
| | | .like(Clinic::getName, trim(clinicName)))) { |
| | | if (clinic.getAgentId() != null && !ids.contains(clinic.getAgentId())) ids.add(clinic.getAgentId()); |
| | | } |
| | | if (ids.isEmpty()) return emptyPage(page, pageSize); |
| | | if (ids.isEmpty()) { |
| | | return emptyPage(page, pageSize); |
| | | } |
| | | query.in(ProvincialAgent::getId, ids); |
| | | } |
| | | IPage<ProvincialAgent> result = agentMapper.selectPage(new Page<ProvincialAgent>(page, pageSize), query); |
| | | List<ProvincialAgentListItemVO> list = new ArrayList<ProvincialAgentListItemVO>(); |
| | | for (ProvincialAgent item : result.getRecords()) list.add(toList(item)); |
| | | for (ProvincialAgent item : result.getRecords()) { |
| | | list.add(toList(item)); |
| | | } |
| | | return PageResponse.of(list, result.getTotal(), result.getCurrent(), result.getSize()); |
| | | } |
| | | |
| | | private PageResponse<ProvincialAgentListItemVO> emptyPage(int page, int pageSize) { |
| | | return PageResponse.of(new ArrayList<ProvincialAgentListItemVO>(), 0, page, pageSize); |
| | | } |
| | | |
| | | /** 分批复用列表查询,确保导出筛选、区域名称及排序与页面一致。 */ |
| | | public void export(String regionCode, String clinicName, String contactInfo, Integer status, |
| | | 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"); |
| | | final int batchSize = 200; |
| | | long serialNo = 0; |
| | | try (ExcelWriter writer = FastExcel.write(response.getOutputStream(), ProvincialAgentExcelRow.class).build()) { |
| | | WriteSheet sheet = FastExcel.writerSheet("省代用户列表").build(); |
| | | for (int pageNumber = 1; ; pageNumber++) { |
| | | PageResponse<ProvincialAgentListItemVO> result = |
| | | page(pageNumber, batchSize, regionCode, clinicName, contactInfo, status); |
| | | List<ProvincialAgentExcelRow> rows = new ArrayList<>(); |
| | | for (ProvincialAgentListItemVO item : result.getList()) { |
| | | rows.add(toExcelRow(item, ++serialNo)); |
| | | } |
| | | writer.write(rows, sheet); |
| | | if (result.getList().isEmpty() || serialNo >= result.getTotal()) { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private ProvincialAgentExcelRow toExcelRow(ProvincialAgentListItemVO item, long serialNo) { |
| | | ProvincialAgentExcelRow row = new ProvincialAgentExcelRow(); |
| | | row.setSerialNo(serialNo); |
| | | row.setAgentName(exportText(item.getAgentName())); |
| | | row.setContactInfo(exportText(item.getContactInfo())); |
| | | row.setAddress(exportText(item.getAddress())); |
| | | row.setRegionNames(exportText(String.join("、", item.getRegionNames()))); |
| | | row.setClinicCount(item.getClinicCount() == null ? 0L : item.getClinicCount()); |
| | | row.setStatus(Integer.valueOf(1).equals(item.getStatus()) ? "启用" |
| | | : Integer.valueOf(2).equals(item.getStatus()) ? "注销" : "禁用"); |
| | | row.setCreatedAt(DateTimes.format(item.getCreatedAt())); |
| | | return row; |
| | | } |
| | | |
| | | private String exportText(String value) { |
| | | return trim(value) == null ? "-" : value; |
| | | } |
| | | |
| | | /** 查询省代理详情。 */ |
| | | public ProvincialAgentDetailVO detail(Long id) { |
| | | return toDetail(require(id)); |
| | | } |
| | | |
| | | @Transactional |
| | | @Transactional(rollbackFor = Exception.class) |
| | | /** 创建省代理并同步区域及微赞代理信息。 */ |
| | | public ProvincialAgentDetailVO create(ProvincialAgentSaveRequest request) { |
| | | // STEP 1:保存本地代理与负责区域;STEP 2:同步第三方代理;失败时整体回滚。 |
| | | boolean firstAgent = agentMapper.selectCount(new LambdaQueryWrapper<ProvincialAgent>() |
| | | .eq(ProvincialAgent::getDeleted, 0)) == 0; |
| | | ProvincialAgent agent = new ProvincialAgent(); |
| | |
| | | if (firstAgent) { |
| | | clinicMapper.update(null, new LambdaUpdateWrapper<Clinic>().set(Clinic::getAgentId, agent.getId())); |
| | | } |
| | | log.info("调用微赞创建代理,入参 agentMobile={}, agentName={}, levelCode={}, parentMobile={}, storeName={}", |
| | | request.getContactInfo(), request.getAgentName(), 2, null, null); |
| | | try { |
| | | JsonNode vzanResponse = vzanHttpUtil.createAgent( |
| | | request.getContactInfo(), request.getAgentName(), 2, null, null); |
| | | log.info("微赞创建代理成功,出参={}", vzanResponse); |
| | | } catch (RuntimeException ex) { |
| | | log.error("微赞创建代理失败,本地事务将回滚,入参 agentMobile={}, agentName={}, levelCode={}, parentMobile={}, storeName={}", |
| | | request.getContactInfo(), request.getAgentName(), 1, null, request.getAgentName(), ex); |
| | | // throw ex; |
| | | throw new IllegalStateException("微赞创建代理失败", ex); |
| | | } |
| | | return detail(agent.getId()); |
| | | } |
| | | |
| | | @Transactional |
| | | @Transactional(rollbackFor = Exception.class) |
| | | /** 更新省代理及其负责区域。 */ |
| | | public ProvincialAgentDetailVO update(Long id, ProvincialAgentSaveRequest request) { |
| | | ProvincialAgent agent = require(id); |
| | | fill(agent, request); |
| | |
| | | return detail(id); |
| | | } |
| | | |
| | | @Transactional |
| | | @Transactional(rollbackFor = Exception.class) |
| | | /** 删除省代理。 */ |
| | | public void delete(Long id) { |
| | | require(id); |
| | | agentMapper.deleteById(id); |
| | |
| | | agent.setAccountHolder(trim(request.getAccountHolder())); |
| | | agent.setBranchName(trim(request.getBranchName())); |
| | | agent.setContactInfo(trim(request.getContactInfo())); |
| | | agent.setStatus(request.getStatus() == null ? 1 : request.getStatus()); |
| | | agent.setStatus(request.getStatus() == null ? EnabledStatusEnum.ENABLED.getValue() : request.getStatus()); |
| | | agent.setAddress(trim(request.getAddress())); |
| | | } |
| | | |
| | | private void saveRegions(ProvincialAgent agent, ProvincialAgentSaveRequest request) { |
| | | if (request.getRegions() == null) return; |
| | | List<AgentRegion> regions = new ArrayList<AgentRegion>(); |
| | | for (ProvincialAgentSaveRequest.RegionItem item : request.getRegions()) { |
| | | if (item == null || trim(item.getRegionCode()) == null) continue; |
| | | RegionInfo info = resolveRegion(item.getRegionCode()); |
| | |
| | | region.setRegionCode(trim(item.getRegionCode())); |
| | | region.setRegionName(info.name); |
| | | region.setRegionLevel(info.path.size()); |
| | | regionMapper.insert(region); |
| | | regions.add(region); |
| | | } |
| | | if (!regions.isEmpty()) { |
| | | regionMapper.insertBatch(regions); |
| | | } |
| | | } |
| | | |
| | |
| | | private RegionInfo resolveRegion(String code) { |
| | | List<String> path = new ArrayList<String>(); |
| | | List<String> names = new ArrayList<String>(); |
| | | SysRegion current = sysRegionMapper.selectByCode(code); |
| | | SysRegion current = getRegionCache().get(code); |
| | | while (current != null) { |
| | | path.add(0, current.getCode()); |
| | | names.add(0, current.getName()); |
| | | current = current.getParentId() == null || current.getParentId() == 0 ? null : sysRegionMapper.selectById(current.getParentId()); |
| | | current = current.getParentId() == null || current.getParentId() == 0 ? null : getRegionById(current.getParentId()); |
| | | } |
| | | if (path.isEmpty()) { |
| | | path.add(code); |
| | | names.add(code); |
| | | } |
| | | return new RegionInfo(path, String.join("", names)); |
| | | } |
| | | |
| | | private Map<String, SysRegion> getRegionCache() { |
| | | Map<String, SysRegion> cache = regionCache; |
| | | if (cache == null) { |
| | | synchronized (this) { |
| | | cache = regionCache; |
| | | if (cache == null) { |
| | | cache = new LinkedHashMap<String, SysRegion>(); |
| | | for (SysRegion region : sysRegionMapper.selectAllOrdered()) cache.put(region.getCode(), region); |
| | | regionCache = cache; |
| | | } |
| | | } |
| | | } |
| | | return cache; |
| | | } |
| | | |
| | | private SysRegion getRegionById(Long id) { |
| | | for (SysRegion region : getRegionCache().values()) if (id.equals(region.getId())) { |
| | | return region; |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | private String trim(String value) { |
| | |
| | | this.name = name; |
| | | } |
| | | } |
| | | } |
| | | } |