add customer lunar birthdate

This commit is contained in:
Timi
2026-08-03 18:54:17 +08:00
parent 50d4bba045
commit 187f270866
6 changed files with 87 additions and 3 deletions
@@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategies;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.imyeyu.utils.Time;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -22,6 +23,7 @@ public class BeanConfig {
@Bean
public ObjectMapper jackson() {
return JsonMapper.builder()
.addModule(new JavaTimeModule())
.serializationInclusion(JsonInclude.Include.NON_NULL)
.defaultDateFormat(Time.dateTime)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.imyeyu.api.annotation.EnableSettingInterceptor;
import com.imyeyu.api.annotation.RequestRateLimitInterceptor;
import com.imyeyu.api.annotation.RequireCorePermissionInterceptor;
@@ -78,6 +79,7 @@ public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
JsonMapper jsonMapper = JsonMapper.builder()
.addModule(new JavaTimeModule())
// 设置默认属性包含规则:忽略 null 值
.serializationInclusion(JsonInclude.Include.NON_NULL)
// 日期格式化
@@ -1,5 +1,7 @@
package com.imyeyu.api.modules.gao.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.JsonNode;
import com.imyeyu.api.modules.common.entity.Attachment;
import com.imyeyu.api.modules.user.entity.User;
@@ -9,6 +11,7 @@ import com.imyeyu.spring.entity.UUIDEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDate;
import java.util.List;
///
@@ -30,6 +33,18 @@ public class GaoCustomer extends UUIDEntity {
PHOTO
}
///
/// 出生日期使用的历法
///
public enum BirthdateCalendar {
/// 公历
SOLAR,
/// 农历
LUNAR
}
/// 客户编码
private String code;
@@ -42,6 +57,22 @@ public class GaoCustomer extends UUIDEntity {
/// 年龄
private Integer age;
/// 出生日期,数据库只保存公历日期
@JsonFormat(pattern = "yyyy-MM-dd")
private LocalDate birthdate;
/// 出生日期录入时使用的历法
private BirthdateCalendar birthdateCalendar;
@JsonIgnore
@Transient
private boolean birthdateProvided;
public void setBirthdate(LocalDate birthdate) {
this.birthdate = birthdate;
this.birthdateProvided = true;
}
/// 电话
private String telephone;
@@ -40,6 +40,7 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.Period;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
@@ -75,6 +76,13 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
return mapper;
}
@Override
public PageResult<GaoCustomer> page(Page<GaoCustomer> page) {
PageResult<GaoCustomer> result = super.page(page);
loadListTransient(result.getList());
return result;
}
@Override
public void create(GaoCustomer entity) {
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_CREATE");
@@ -108,7 +116,14 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_UPDATE");
try {
logger.setContent(jackson.writeValueAsString(entity));
GaoCustomer dbCustomer = checkEntity(entity, true);
TimiException.required(entity, "not found customer");
TimiException.required(entity.getId(), "not found customer.id");
GaoCustomer dbCustomer = super.get(entity.getId());
if (!entity.isBirthdateProvided()) {
entity.setBirthdate(dbCustomer.getBirthdate());
entity.setBirthdateCalendar(dbCustomer.getBirthdateCalendar());
}
checkEntity(entity, true);
super.update(entity);
saveAttachment(entity.getId(), resolveAttachmentList(entity));
syncIntroducerInvitedCount(dbCustomer.getIntroducerCustomerId(), entity.getIntroducerCustomerId());
@@ -236,13 +251,15 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
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, "客户编码", "姓名", "性别", "年龄", "电话", "地址", "病症", "备注", "邀请人", "邀请客户数", "创建时间");
appendRow(sheet, 5, headerStyle, "客户编码", "姓名", "性别", "出生日期(公历)", "出生日期历法", "年龄", "电话", "地址", "病症", "备注", "邀请人", "邀请客户数", "创建时间");
int rowIndex = 6;
for (GaoCustomer customer : list) {
appendRow(sheet, rowIndex, null,
text(customer.getCode()),
text(customer.getName()),
formatGender(customer),
text(customer.getBirthdate()),
formatBirthdateCalendar(customer),
customer.getAge() == null ? "" : String.valueOf(customer.getAge()),
text(customer.getTelephone()),
text(customer.getAddress()),
@@ -254,7 +271,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
);
rowIndex++;
}
for (int index = 0; index < 11; index++) {
for (int index = 0; index < 13; index++) {
sheet.autoSizeColumn(index);
sheet.setColumnWidth(index, Math.min(Math.max(sheet.getColumnWidth(index), 10 * 256), 36 * 256));
}
@@ -379,6 +396,10 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
GaoCustomer dbCustomer = null;
entity.setCode(normalizeText(entity.getCode()));
entity.setIntroducerCustomerId(normalizeText(entity.getIntroducerCustomerId()));
if (entity.getBirthdateCalendar() == null) {
entity.setBirthdateCalendar(GaoCustomer.BirthdateCalendar.SOLAR);
}
refreshAge(entity);
if (requireId) {
TimiException.required(entity.getId(), "not found customer.id");
dbCustomer = super.get(entity.getId());
@@ -408,6 +429,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
if (customer == null) {
return;
}
refreshAge(customer);
loadIntroducerCustomer(List.of(customer));
if (TimiJava.isNotEmpty(customer.getCreatorUserId())) {
customer.setCreatorUser(userService.get(customer.getCreatorUserId()));
@@ -416,9 +438,22 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
}
private void loadListTransient(List<GaoCustomer> customerList) {
if (customerList != null) {
customerList.forEach(this::refreshAge);
}
loadAttachmentList(customerList);
}
/// 根据出生日期计算当前周岁。出生日期为空时保留旧数据中的手工年龄。
private void refreshAge(GaoCustomer customer) {
if (customer.getBirthdate() == null) {
return;
}
LocalDate today = LocalDate.now();
TimiException.requiredTrue(!customer.getBirthdate().isAfter(today), "customer.birthdate invalid");
customer.setAge(Period.between(customer.getBirthdate(), today).getYears());
}
private void loadIntroducerCustomer(List<GaoCustomer> customerList) {
if (customerList == null || customerList.isEmpty()) {
return;
@@ -536,6 +571,13 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
};
}
private String formatBirthdateCalendar(GaoCustomer customer) {
if (customer.getBirthdateCalendar() == null) {
return "公历";
}
return customer.getBirthdateCalendar() == GaoCustomer.BirthdateCalendar.LUNAR ? "农历" : "公历";
}
private String formatExportTime(Long value) {
if (value == null) {
return "";
@@ -0,0 +1,3 @@
ALTER TABLE `gao_customer`
ADD COLUMN `birthdate` DATE NULL COMMENT '出生日期,统一保存为公历' AFTER `gender`,
ADD COLUMN `birthdate_calendar` VARCHAR(16) NOT NULL DEFAULT 'SOLAR' COMMENT '出生日期录入历法,SOLAR 公历,LUNAR 农历' AFTER `birthdate`;