diff --git a/pom.xml b/pom.xml index d751ab9..54394d3 100644 --- a/pom.xml +++ b/pom.xml @@ -11,7 +11,7 @@ com.imyeyu.timiserverapi TimiServerAPI - 1.0.1 + 1.0.3 jar TimiServerAPI imyeyu.com API @@ -178,7 +178,7 @@ com.imyeyu.network timi-network - 0.0.12 + 0.0.13 com.imyeyu.lang @@ -323,6 +323,11 @@ jsoup 1.18.1 + + org.apache.poi + poi-ooxml + 5.4.1 + commons-codec commons-codec diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerController.java index 8d30908..62e6d3f 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerController.java +++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoCustomerController.java @@ -17,9 +17,11 @@ import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq; import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq; import com.imyeyu.spring.annotation.AOPLog; +import com.imyeyu.spring.annotation.IgnoreGlobalReturn; import com.imyeyu.spring.annotation.RequestRateLimit; import com.imyeyu.spring.bean.Page; import com.imyeyu.spring.bean.PageResult; +import jakarta.servlet.http.HttpServletResponse; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -27,6 +29,8 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import java.io.IOException; +import java.net.URLEncoder; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -67,6 +71,26 @@ public class GaoCustomerController { return service.search(req); } + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) + @PostMapping("/search/page") + public PageResult searchPage(@RequestBody Page page) { + return service.searchPage(page); + } + + @AOPLog + @RequestRateLimit + @IgnoreGlobalReturn + @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) + @PostMapping("/export") + public void export(@RequestBody GaoCustomerSearchReq req, HttpServletResponse resp) throws IOException { + String fileName = URLEncoder.encode("客户列表.xlsx", "UTF-8").replace("+", "%20"); + resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + resp.setHeader("Content-Disposition", "attachment; filename=\"gao-customer.xlsx\"; filename*=UTF-8''" + fileName); + resp.getOutputStream().write(service.exportSearchExcel(req)); + } + @AOPLog @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ) @@ -95,8 +119,9 @@ public class GaoCustomerController { @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.CUSTOMER_CREATE) @PostMapping("/create") - public void create(@RequestBody GaoCustomer customer) { + public GaoCustomer create(@RequestBody GaoCustomer customer) { service.create(customer); + return customer; } @AOPLog diff --git a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventRecordController.java b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventRecordController.java index cf2ea74..e01922d 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventRecordController.java +++ b/src/main/java/com/imyeyu/api/modules/gao/controller/GaoRegistrationEventRecordController.java @@ -29,7 +29,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.io.IOException; -import java.nio.charset.StandardCharsets; +import java.net.URLEncoder; import java.util.List; /// @@ -53,6 +53,14 @@ public class GaoRegistrationEventRecordController { return service.page(page); } + @AOPLog + @RequestRateLimit + @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) + @PostMapping("/range/page") + public PageResult rangePage(@RequestBody Page page) { + return service.pageByRange(page); + } + @AOPLog @RequestRateLimit @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) @@ -106,10 +114,10 @@ public class GaoRegistrationEventRecordController { @RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ) @PostMapping("/range/export") public void rangeExport(@RequestBody GaoRegistrationEventRecordRangeReq req, HttpServletResponse resp) throws IOException { - List list = service.listByRange(req); - resp.setContentType("application/vnd.ms-excel;charset=UTF-8"); - resp.setHeader("Content-Disposition", "attachment; filename=\"gao-registration-event-record.csv\""); - resp.getOutputStream().write(buildCsv(list).getBytes(StandardCharsets.UTF_8)); + String fileName = URLEncoder.encode("登记事件记录.xlsx", "UTF-8").replace("+", "%20"); + resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"); + resp.setHeader("Content-Disposition", "attachment; filename=\"gao-registration-event-record.xlsx\"; filename*=UTF-8''" + fileName); + resp.getOutputStream().write(service.exportRangeExcel(req)); } @AOPLog @@ -163,30 +171,4 @@ public class GaoRegistrationEventRecordController { public List allCustomerRegistrationEventDailyStat(@RequestBody GaoRegistrationEventRecordTrendStatReq req) { return service.statDailyByRegistrationEvent(req); } - - private String buildCsv(List list) { - StringBuilder builder = new StringBuilder(); - builder.append((char) 65279); - builder.append("客户编码,客户姓名,登记事件,登记时间,登记人用户 ID,备注\n"); - for (GaoRegistrationEventRecord record : list) { - builder.append(csv(record.getCustomer() == null ? null : record.getCustomer().getCode())).append(','); - builder.append(csv(record.getCustomer() == null ? null : record.getCustomer().getName())).append(','); - builder.append(csv(record.getRegistrationEvent() == null ? null : record.getRegistrationEvent().getName())).append(','); - builder.append(csv(record.getRegisteredAt())).append(','); - builder.append(csv(record.getOperatorUserId())).append(','); - builder.append(csv(record.getRemark())).append('\n'); - } - return builder.toString(); - } - - private String csv(Object value) { - if (value == null) { - return ""; - } - String text = value.toString(); - if (!text.contains(",") && !text.contains("\"") && !text.contains("\n") && !text.contains("\r")) { - return text; - } - return "\"%s\"".formatted(text.replace("\"", "\"\"")); - } } diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoCustomerMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoCustomerMapper.java index d0e8399..dcabc54 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoCustomerMapper.java +++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoCustomerMapper.java @@ -20,6 +20,10 @@ public interface GaoCustomerMapper extends BaseMapper { List search(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId); + Long countSearch(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId); + + List searchPage(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId, @Param("offset") Long offset, @Param("size") Long size); + List selectInvitedList(@Param("introducerCustomerId") String introducerCustomerId); Long countInvited(@Param("introducerCustomerId") String introducerCustomerId); diff --git a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRecordMapper.java b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRecordMapper.java index ad96232..bfb8655 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRecordMapper.java +++ b/src/main/java/com/imyeyu/api/modules/gao/mapper/GaoRegistrationEventRecordMapper.java @@ -103,4 +103,18 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper selectByRange(@Param("req") GaoRegistrationEventRecordRangeReq req); + + /// 按任意时间范围统计登记事件记录 + /// + /// @param req 范围查询请求 + /// @return 登记事件记录数 + Long countByRange(@Param("req") GaoRegistrationEventRecordRangeReq req); + + /// 按任意时间范围分页查询登记事件记录 + /// + /// @param req 范围查询请求 + /// @param offset 偏移量 + /// @param size 每页条数 + /// @return 登记事件记录列表 + List selectPageByRange(@Param("req") GaoRegistrationEventRecordRangeReq req, @Param("offset") Long offset, @Param("size") Long size); } diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerService.java index a6e92bf..5b61f5d 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerService.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoCustomerService.java @@ -5,8 +5,11 @@ import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView; import com.imyeyu.api.modules.gao.vo.GaoCustomerInviteUpdateReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq; import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq; +import com.imyeyu.spring.bean.Page; +import com.imyeyu.spring.bean.PageResult; import com.imyeyu.spring.service.BaseService; +import java.io.IOException; import java.util.List; /// @@ -40,6 +43,18 @@ public interface GaoCustomerService extends BaseService { /// @return 客户列表 List search(GaoCustomerSearchReq req); + /// 分页搜索客户 + /// + /// @param page 分页搜索请求 + /// @return 客户分页结果 + PageResult searchPage(Page page); + + /// 按搜索条件导出客户 Excel + /// + /// @param req 搜索请求 + /// @return xlsx 文件字节 + byte[] exportSearchExcel(GaoCustomerSearchReq req) throws IOException; + /// 查询邀请的客户 /// /// @param introducerCustomerId 介绍人客户 ID diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventRecordService.java b/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventRecordService.java index 29f0fd5..8985d94 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventRecordService.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/GaoRegistrationEventRecordService.java @@ -10,8 +10,11 @@ import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq; import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordTrendStatReq; +import com.imyeyu.spring.bean.Page; +import com.imyeyu.spring.bean.PageResult; import com.imyeyu.spring.service.BaseService; +import java.io.IOException; import java.util.List; /// @@ -39,6 +42,18 @@ public interface GaoRegistrationEventRecordService extends BaseService listByRange(GaoRegistrationEventRecordRangeReq req); + /// 按任意时间范围分页查询登记事件记录 + /// + /// @param page 分页参数 + /// @return 登记事件记录分页结果 + PageResult pageByRange(Page page); + + /// 按任意时间范围导出登记事件记录 Excel + /// + /// @param req 范围查询请求 + /// @return xlsx 文件字节 + byte[] exportRangeExcel(GaoRegistrationEventRecordRangeReq req) throws IOException; + /// 按周期查询登记事件记录 /// /// @param req 周期请求 diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerServiceImplement.java index 2ec356a..72d0222 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoCustomerServiceImplement.java @@ -14,12 +14,22 @@ import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq; import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiCode; import com.imyeyu.java.bean.timi.TimiException; +import com.imyeyu.spring.bean.Page; +import com.imyeyu.spring.bean.PageResult; import com.imyeyu.spring.mapper.BaseMapper; import com.imyeyu.spring.service.AbstractEntityService; import lombok.RequiredArgsConstructor; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; @@ -40,6 +50,7 @@ import java.util.Map; public class GaoCustomerServiceImplement extends AbstractEntityService implements GaoCustomerService { private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); + private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()); private final GaoCustomerMapper mapper; private final AttachmentService attachmentService; @@ -104,14 +115,75 @@ public class GaoCustomerServiceImplement extends AbstractEntityService search(GaoCustomerSearchReq req) { - if (req == null) { - req = new GaoCustomerSearchReq(); - } + req = resolveSearchReq(req); List list = mapper.search(req.getKeyword(), req.getIntroducerCustomerId()); list.forEach(this::loadTransient); return list; } + @Override + public PageResult searchPage(Page page) { + TimiException.required(page, "not found page"); + TimiException.required(page.getIndex(), "not found page.index"); + TimiException.required(page.getSize(), "not found page.size"); + TimiException.requiredTrue(0 <= page.getIndex(), "page.index lt 0"); + TimiException.requiredTrue(0 < page.getSize(), "page.size lte 0"); + GaoCustomerSearchReq req = resolveSearchReq(page.getEqualsExample()); + Long total = TimiJava.defaultIfNull(mapper.countSearch(req.getKeyword(), req.getIntroducerCustomerId()), 0L); + List list = mapper.searchPage(req.getKeyword(), req.getIntroducerCustomerId(), page.getIndex() * page.getSize(), page.getSize()); + list.forEach(this::loadTransient); + PageResult result = new PageResult<>(); + result.setTotal(total); + result.setList(list); + return result; + } + + @Override + public byte[] exportSearchExcel(GaoCustomerSearchReq req) throws IOException { + List list = search(req); + try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream output = new ByteArrayOutputStream()) { + Sheet sheet = workbook.createSheet("客户列表"); + CellStyle titleStyle = workbook.createCellStyle(); + Font titleFont = workbook.createFont(); + titleFont.setBold(true); + titleFont.setFontHeightInPoints((short) 14); + titleStyle.setFont(titleFont); + CellStyle headerStyle = workbook.createCellStyle(); + Font headerFont = workbook.createFont(); + headerFont.setBold(true); + headerStyle.setFont(headerFont); + + appendRow(sheet, 0, titleStyle, "客户列表导出"); + appendRow(sheet, 1, null, "生成时间", EXPORT_TIME_FORMATTER.format(Instant.now())); + appendRow(sheet, 2, null, "关键词", req == null || req.getKeyword() == null || req.getKeyword().isBlank() ? "全部" : req.getKeyword().trim()); + appendRow(sheet, 3, null, "记录总数", String.valueOf(list.size())); + appendRow(sheet, 5, headerStyle, "客户编码", "姓名", "性别", "年龄", "电话", "地址", "病症", "备注", "邀请人", "邀请客户数", "创建时间"); + int rowIndex = 6; + for (GaoCustomer customer : list) { + appendRow(sheet, rowIndex, null, + text(customer.getCode()), + text(customer.getName()), + formatGender(customer), + customer.getAge() == null ? "" : String.valueOf(customer.getAge()), + text(customer.getTelephone()), + text(customer.getAddress()), + text(customer.getDisease()), + text(customer.getRemark()), + customer.getIntroducerCustomer() == null ? "" : text(customer.getIntroducerCustomer().getName()), + customer.getInvitedCount() == null ? "0" : String.valueOf(customer.getInvitedCount()), + formatExportTime(customer.getCreatedAt()) + ); + rowIndex++; + } + for (int index = 0; index < 11; index++) { + sheet.autoSizeColumn(index); + sheet.setColumnWidth(index, Math.min(Math.max(sheet.getColumnWidth(index), 10 * 256), 36 * 256)); + } + workbook.write(output); + return output.toByteArray(); + } + } + @Override public List listInvited(String introducerCustomerId) { TimiException.required(introducerCustomerId, "not found introducerCustomerId"); @@ -176,16 +248,21 @@ public class GaoCustomerServiceImplement extends AbstractEntityService "男"; + case FEMALE -> "女"; + }; + } + + private String formatExportTime(Long value) { + if (value == null) { + return ""; + } + return EXPORT_TIME_FORMATTER.format(Instant.ofEpochMilli(value)); + } + + private String text(Object value) { + return value == null ? "" : value.toString(); + } } diff --git a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventRecordServiceImplement.java b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventRecordServiceImplement.java index 1958453..5f61a61 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventRecordServiceImplement.java +++ b/src/main/java/com/imyeyu/api/modules/gao/service/implement/GaoRegistrationEventRecordServiceImplement.java @@ -26,13 +26,23 @@ import com.imyeyu.api.modules.user.service.UserLoginService; import com.imyeyu.api.modules.user.service.UserService; import com.imyeyu.java.TimiJava; import com.imyeyu.java.bean.timi.TimiException; +import com.imyeyu.spring.bean.Page; +import com.imyeyu.spring.bean.PageResult; import com.imyeyu.spring.mapper.BaseMapper; import com.imyeyu.spring.service.AbstractEntityService; import com.imyeyu.utils.Time; import lombok.RequiredArgsConstructor; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.time.Instant; import java.time.LocalDate; import java.time.ZoneId; @@ -43,6 +53,8 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; /// /// 登记事件记录服务实现 @@ -54,6 +66,7 @@ import java.util.Map; public class GaoRegistrationEventRecordServiceImplement extends AbstractEntityService implements GaoRegistrationEventRecordService { private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); + private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()); private final GaoRegistrationEventRecordMapper mapper; private final AttachmentService attachmentService; @@ -148,6 +161,67 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe return list; } + @Override + public PageResult pageByRange(Page page) { + TimiException.required(page, "not found page"); + TimiException.required(page.getIndex(), "not found page.index"); + TimiException.required(page.getSize(), "not found page.size"); + TimiException.requiredTrue(0 <= page.getIndex(), "page.index lt 0"); + TimiException.requiredTrue(0 < page.getSize(), "page.size lte 0"); + GaoRegistrationEventRecordRangeReq req = TimiJava.defaultIfNull(page.getEqualsExample(), new GaoRegistrationEventRecordRangeReq()); + checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt()); + Long total = TimiJava.defaultIfNull(mapper.countByRange(req), 0L); + List list = mapper.selectPageByRange(req, page.getIndex() * page.getSize(), page.getSize()); + list.forEach(this::loadTransient); + PageResult result = new PageResult<>(); + result.setTotal(total); + result.setList(list); + return result; + } + + @Override + public byte[] exportRangeExcel(GaoRegistrationEventRecordRangeReq req) throws IOException { + List list = listByRange(req); + try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream output = new ByteArrayOutputStream()) { + Sheet sheet = workbook.createSheet("登记事件记录"); + CellStyle titleStyle = workbook.createCellStyle(); + Font titleFont = workbook.createFont(); + titleFont.setBold(true); + titleFont.setFontHeightInPoints((short) 14); + titleStyle.setFont(titleFont); + CellStyle headerStyle = workbook.createCellStyle(); + Font headerFont = workbook.createFont(); + headerFont.setBold(true); + headerStyle.setFont(headerFont); + + appendRow(sheet, 0, titleStyle, "登记事件记录导出"); + appendRow(sheet, 1, null, "生成时间", EXPORT_TIME_FORMATTER.format(Instant.now())); + appendRow(sheet, 2, null, "时间范围", "%s ~ %s".formatted(formatExportTime(req.getBeginRegisteredAt()), formatExportTime(req.getEndRegisteredAt()))); + appendRow(sheet, 3, null, "事件筛选", buildEventFilterText(req)); + appendRow(sheet, 4, null, "关键词", req.getKeyword() == null || req.getKeyword().isBlank() ? "全部" : req.getKeyword().trim()); + appendRow(sheet, 5, null, "记录总数", String.valueOf(list.size())); + appendRow(sheet, 7, headerStyle, "客户编码", "客户姓名", "登记事件", "登记时间", "登记人", "备注"); + int rowIndex = 8; + for (GaoRegistrationEventRecord record : list) { + appendRow(sheet, rowIndex, null, + record.getCustomer() == null ? "" : text(record.getCustomer().getCode()), + record.getCustomer() == null ? "" : text(record.getCustomer().getName()), + record.getRegistrationEvent() == null ? "" : text(record.getRegistrationEvent().getName()), + formatExportTime(record.getRegisteredAt()), + getOperatorName(record), + text(record.getRemark()) + ); + rowIndex++; + } + for (int index = 0; index < 6; index++) { + sheet.autoSizeColumn(index); + sheet.setColumnWidth(index, Math.min(Math.max(sheet.getColumnWidth(index), 12 * 256), 40 * 256)); + } + workbook.write(output); + return output.toByteArray(); + } + } + @Override public List statByRegistrationEventAndPeriodType(String registrationEventId, GaoRegistrationEventRecordPeriodReq.PeriodType periodType) { TimiException.required(registrationEventId, "not found registrationEventId"); @@ -322,4 +396,53 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe } return list; } + + private void appendRow(Sheet sheet, int rowIndex, CellStyle style, String... values) { + Row row = sheet.createRow(rowIndex); + for (int index = 0; index < values.length; index++) { + row.createCell(index).setCellValue(values[index]); + if (style != null) { + row.getCell(index).setCellStyle(style); + } + } + } + + private String buildEventFilterText(GaoRegistrationEventRecordRangeReq req) { + if ((req.getRegistrationEventId() == null || req.getRegistrationEventId().isBlank()) && (req.getRegistrationEventIdList() == null || req.getRegistrationEventIdList().isEmpty())) { + return "全部事件"; + } + if (req.getRegistrationEventId() != null && !req.getRegistrationEventId().isBlank()) { + return "事件 ID:" + req.getRegistrationEventId(); + } + StringJoiner joiner = new StringJoiner("、"); + req.getRegistrationEventIdList().stream() + .filter(Objects::nonNull) + .filter(item -> !item.isBlank()) + .forEach(joiner::add); + return "事件 ID:" + joiner; + } + + private String formatExportTime(Long value) { + if (value == null) { + return ""; + } + return EXPORT_TIME_FORMATTER.format(Instant.ofEpochMilli(value)); + } + + private String getOperatorName(GaoRegistrationEventRecord record) { + if (record.getOperator() == null) { + return text(record.getOperatorUserId()); + } + if (record.getOperator().getNick() != null && !record.getOperator().getNick().isBlank()) { + return record.getOperator().getNick(); + } + if (record.getOperator().getName() != null && !record.getOperator().getName().isBlank()) { + return record.getOperator().getName(); + } + return text(record.getOperatorUserId()); + } + + private String text(Object value) { + return value == null ? "" : value.toString(); + } } diff --git a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordRangeReq.java b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordRangeReq.java index 6e7f1d8..d579c34 100644 --- a/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordRangeReq.java +++ b/src/main/java/com/imyeyu/api/modules/gao/vo/GaoRegistrationEventRecordRangeReq.java @@ -2,6 +2,8 @@ package com.imyeyu.api.modules.gao.vo; import lombok.Data; +import java.util.List; + /// /// 登记事件记录范围查询请求 /// @@ -16,6 +18,12 @@ public class GaoRegistrationEventRecordRangeReq { /// 登记事件 ID,为空查询全部登记事件 private String registrationEventId; + /// 登记事件 ID 列表,为空查询全部登记事件 + private List registrationEventIdList; + + /// 关键词,匹配客户、登记事件、备注、登记人 + private String keyword; + /// 开始登记时间 private Long beginRegisteredAt; diff --git a/src/main/resources/db/migration/timiserver/V15__create_gao_registration_event_tables.sql b/src/main/resources/db/migration/timiserver/V15__create_gao_registration_event_tables.sql index 3906755..ca7b3ae 100644 --- a/src/main/resources/db/migration/timiserver/V15__create_gao_registration_event_tables.sql +++ b/src/main/resources/db/migration/timiserver/V15__create_gao_registration_event_tables.sql @@ -1,6 +1,6 @@ CREATE TABLE IF NOT EXISTS `gao_customer` ( `id` VARCHAR(36) NOT NULL, - `code` VARCHAR(64) NOT NULL COMMENT '客户编码', + `code` VARCHAR(64) NULL COMMENT '客户编码', `name` VARCHAR(64) NOT NULL COMMENT '姓名', `gender` VARCHAR(16) NULL COMMENT '性别代码,MALE 男,FEMALE 女', `age` INT NULL COMMENT '年龄', diff --git a/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml b/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml index f302e6f..15e9d46 100644 --- a/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml +++ b/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml @@ -1,29 +1,51 @@ + + 1 = 1 + AND `deleted_at` IS NULL + + AND ( + `code` LIKE CONCAT('%', #{keyword}, '%') + OR `name` LIKE CONCAT('%', #{keyword}, '%') + OR `telephone` LIKE CONCAT('%', #{keyword}, '%') + OR `address` LIKE CONCAT('%', #{keyword}, '%') + OR `disease` LIKE CONCAT('%', #{keyword}, '%') + OR CAST(`conditioning_part` AS CHAR) LIKE CONCAT('%', #{keyword}, '%') + ) + + + AND `introducer_customer_id` = #{introducerCustomerId} + + + + + + + + + r.`registered_at` >= #{req.beginRegisteredAt} + AND r.`registered_at` <= #{req.endRegisteredAt} + AND r.`deleted_at` IS NULL + + AND r.`customer_id` = #{req.customerId} + + + AND r.`registration_event_id` = #{req.registrationEventId} + + + AND r.`registration_event_id` IN + + #{registrationEventId} + + + + AND ( + c.`code` LIKE CONCAT('%', #{req.keyword}, '%') + OR c.`name` LIKE CONCAT('%', #{req.keyword}, '%') + OR e.`name` LIKE CONCAT('%', #{req.keyword}, '%') + OR r.`remark` LIKE CONCAT('%', #{req.keyword}, '%') + OR u.`name` LIKE CONCAT('%', #{req.keyword}, '%') + OR u.`nick` LIKE CONCAT('%', #{req.keyword}, '%') + OR r.`operator_user_id` LIKE CONCAT('%', #{req.keyword}, '%') + ) + + + + + FROM `gao_registration_event_record` r + LEFT JOIN `gao_customer` c ON r.`customer_id` = c.`id` + LEFT JOIN `gao_registration_event` e ON r.`registration_event_id` = e.`id` + LEFT JOIN `user` u ON r.`operator_user_id` = u.`id` + + + + + +