| | |
| | | |
| | | 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.tcm.training.admin.app.register.entity.SysRegion; |
| | | import com.tcm.training.admin.app.register.mapper.SysRegionMapper; |
| | | 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.utils.VzanHttpUtil; |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Collections; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.LinkedHashMap; |
| | | |
| | | @Slf4j |
| | | @Service |
| | |
| | | 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, VzanHttpUtil vzanHttpUtil) { |
| | |
| | | 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>() |
| | |
| | | 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(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(); |
| | |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | /** 更新省代理及其负责区域。 */ |
| | | public ProvincialAgentDetailVO update(Long id, ProvincialAgentSaveRequest request) { |
| | | ProvincialAgent agent = require(id); |
| | | fill(agent, request); |
| | |
| | | } |
| | | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | /** 删除省代理。 */ |
| | | public void delete(Long id) { |
| | | require(id); |
| | | agentMapper.deleteById(id); |
| | |
| | | |
| | | 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); |
| | | } |
| | | } |
| | | |
| | |
| | | ProvincialAgentListItemVO vo = new ProvincialAgentListItemVO(); |
| | | vo.setId(agent.getId()); |
| | | vo.setAgentName(agent.getAgentName()); |
| | | vo.setContactInfo(PhoneMasker.mask(agent.getContactInfo())); |
| | | vo.setContactInfo(agent.getContactInfo()); |
| | | vo.setAddress(agent.getAddress()); |
| | | vo.setCreatedAt(agent.getCreatedAt()); |
| | | vo.setStatus(agent.getStatus()); |
| | |
| | | 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); |
| | |
| | | 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) { |
| | | if (value == null) return null; |
| | | String trimmed = value.trim(); |