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.ProvincialAgent;
|
import com.tcm.training.admin.agent.excel.ClinicAgentImportRow;
|
import com.tcm.training.admin.agent.mapper.ProvincialAgentMapper;
|
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.excel.ClinicExcelRow;
|
import com.tcm.training.admin.member.mapper.ClinicQueryMapper;
|
import com.tcm.training.admin.member.row.ClinicBoundUserRow;
|
import com.tcm.training.admin.member.row.ClinicDetailRow;
|
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 org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
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.*;
|
|
@Service
|
public class ClinicAppService {
|
|
private final ClinicQueryMapper clinicQueryMapper;
|
private final ClinicMapper clinicMapper;
|
private final ProvincialAgentMapper provincialAgentMapper;
|
|
public ClinicAppService(ClinicQueryMapper clinicQueryMapper, ClinicMapper clinicMapper, ProvincialAgentMapper provincialAgentMapper) {
|
this.clinicQueryMapper = clinicQueryMapper;
|
this.clinicMapper = clinicMapper;
|
this.provincialAgentMapper = provincialAgentMapper;
|
}
|
|
public PageResponse<ClinicListItemVO> page(int page,
|
int pageSize,
|
String regionCode,
|
String name,
|
String phone,
|
LocalDateTime createdFrom,
|
LocalDateTime createdTo,
|
Integer status) {
|
IPage<ClinicListRow> result = clinicQueryMapper.selectClinicPage(
|
new Page<ClinicListRow>(page, pageSize),
|
trimToNull(regionCode),
|
trimToNull(name),
|
trimToNull(phone),
|
createdFrom,
|
createdTo,
|
status
|
);
|
List<ClinicListItemVO> list = new ArrayList<ClinicListItemVO>();
|
for (ClinicListRow row : result.getRecords()) {
|
list.add(toListItem(row));
|
}
|
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,
|
LocalDateTime createdFrom,
|
LocalDateTime createdTo,
|
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");
|
|
List<ClinicListRow> rows = clinicQueryMapper.selectClinicList(
|
trimToNull(regionCode),
|
trimToNull(name),
|
trimToNull(phone),
|
createdFrom,
|
createdTo,
|
status
|
);
|
List<ClinicExcelRow> exports = new ArrayList<ClinicExcelRow>();
|
for (int i = 0; i < rows.size(); i++) {
|
ClinicListRow row = rows.get(i);
|
ClinicExcelRow excel = new ClinicExcelRow();
|
excel.setSerialNo(i + 1);
|
excel.setName(defaultText(row.getName()));
|
excel.setPhone(defaultText(PhoneMasker.mask(row.getPhone())));
|
excel.setRegionName(defaultText(row.getRegionName()));
|
excel.setUserCount(row.getUserCount() == null ? 0 : row.getUserCount());
|
excel.setStatus(statusText(row.getStatus()));
|
excel.setCreatedAt(DateTimes.format(row.getCreatedAt()));
|
exports.add(excel);
|
}
|
FastExcel.write(response.getOutputStream(), ClinicExcelRow.class)
|
.sheet("诊所列表")
|
.doWrite(exports);
|
}
|
|
public List<ClinicRegionOptionVO> regionOptions() {
|
List<ClinicRegionOptionRow> rows = clinicQueryMapper.selectRegionOptions();
|
List<ClinicRegionOptionVO> list = new ArrayList<ClinicRegionOptionVO>();
|
for (ClinicRegionOptionRow row : rows) {
|
list.add(new ClinicRegionOptionVO(row.getRegionCode(), row.getRegionName()));
|
}
|
return list;
|
}
|
|
public ClinicDetailVO detail(Long id) {
|
ClinicDetailRow row = clinicQueryMapper.selectClinicDetail(id);
|
if (row == null) {
|
throw new IllegalArgumentException("诊所不存在");
|
}
|
ClinicDetailVO vo = new ClinicDetailVO();
|
vo.setId(row.getId());
|
vo.setName(row.getName());
|
vo.setPhone(defaultText(row.getContactPhone()));
|
vo.setAddress(defaultText(row.getAddress()));
|
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()));
|
return vo;
|
}
|
|
public ClinicDetailVO updateBankAccount(Long id, ClinicBankAccountUpdateRequest request) {
|
Clinic clinic = clinicMapper.selectById(id);
|
if (clinic == null || (clinic.getDeleted() != null && clinic.getDeleted() == 1)) {
|
throw new IllegalArgumentException("诊所不存在");
|
}
|
clinic.setBankName(trimToNull(request.getBankName()));
|
clinic.setAccountHolder(trimToNull(request.getAccountHolder()));
|
clinic.setAccountNumber(trimToNull(request.getAccountNumber()));
|
clinic.setBranchName(trimToNull(request.getBranchName()));
|
clinicMapper.updateById(clinic);
|
return detail(id);
|
}
|
|
public PageResponse<ClinicBoundUserItemVO> clinicUsers(Long clinicId,
|
int page,
|
int pageSize,
|
String nickname,
|
String phone,
|
Integer status,
|
Integer isMember,
|
LocalDateTime registeredFrom,
|
LocalDateTime registeredTo) {
|
requireClinic(clinicId);
|
IPage<ClinicBoundUserRow> result = clinicQueryMapper.selectClinicUserPage(
|
new Page<ClinicBoundUserRow>(page, pageSize),
|
clinicId,
|
trimToNull(nickname),
|
trimToNull(phone),
|
status,
|
isMember,
|
registeredFrom,
|
registeredTo
|
);
|
List<ClinicBoundUserItemVO> list = new ArrayList<ClinicBoundUserItemVO>();
|
for (ClinicBoundUserRow row : result.getRecords()) {
|
ClinicBoundUserItemVO item = new ClinicBoundUserItemVO();
|
item.setId(row.getId());
|
item.setNickname(defaultText(row.getNickname()));
|
item.setPhone(row.getPhone() == null ? "-" : PhoneMasker.mask(row.getPhone()));
|
item.setAvatar(trimToNull(row.getAvatar()));
|
item.setLivePoints(row.getLivePoints() == null ? 0 : row.getLivePoints());
|
item.setIsMember(row.getIsMember() != null && row.getIsMember() == 1);
|
item.setStatus(row.getStatus());
|
item.setCreatedAt(row.getCreatedAt());
|
list.add(item);
|
}
|
return PageResponse.of(list, result.getTotal(), result.getCurrent(), result.getSize());
|
}
|
|
private String trimToNull(String value) {
|
if (value == null) {
|
return null;
|
}
|
String trimmed = value.trim();
|
return trimmed.isEmpty() ? null : trimmed;
|
}
|
|
private String defaultText(String value) {
|
return value == null || value.trim().isEmpty() ? "-" : value;
|
}
|
|
private ClinicListItemVO toListItem(ClinicListRow row) {
|
ClinicListItemVO item = new ClinicListItemVO();
|
item.setId(row.getId());
|
item.setName(defaultText(row.getName()));
|
item.setPhone(row.getPhone() == null ? "-" : PhoneMasker.mask(row.getPhone()));
|
item.setRegionName(defaultText(row.getRegionName()));
|
item.setStatus(row.getStatus());
|
item.setUserCount(row.getUserCount() == null ? 0 : row.getUserCount());
|
item.setCreatedAt(row.getCreatedAt());
|
item.setBusinessLicenseUrl(trimToNull(row.getBusinessLicenseUrl()));
|
return item;
|
}
|
|
private void requireClinic(Long clinicId) {
|
if (clinicQueryMapper.selectClinicDetail(clinicId) == null) {
|
throw new IllegalArgumentException("诊所不存在");
|
}
|
}
|
|
private String statusText(Integer status) {
|
if (status != null && status == 1) {
|
return "启用";
|
}
|
if (status != null && status == 2) {
|
return "注销";
|
}
|
return "禁用";
|
}
|
}
|