Compare commits
11
Commits
v1.0.5
...
c49686c411
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c49686c411 | ||
|
|
65161a7fad | ||
|
|
187f270866 | ||
|
|
50d4bba045 | ||
|
|
6eedc06a07 | ||
|
|
b55b43eba4 | ||
|
|
20289a3168 | ||
|
|
d45bf11477 | ||
|
|
7370b2fc98 | ||
|
|
2f366fe219 | ||
|
|
f1715a3e32 |
@@ -11,7 +11,7 @@
|
||||
|
||||
<groupId>com.imyeyu.timiserverapi</groupId>
|
||||
<artifactId>TimiServerAPI</artifactId>
|
||||
<version>1.0.3</version>
|
||||
<version>1.0.6</version>
|
||||
<packaging>jar</packaging>
|
||||
<name>TimiServerAPI</name>
|
||||
<description>imyeyu.com API</description>
|
||||
@@ -173,7 +173,7 @@
|
||||
<dependency>
|
||||
<groupId>com.imyeyu.spring</groupId>
|
||||
<artifactId>timi-spring</artifactId>
|
||||
<version>0.0.17</version>
|
||||
<version>0.0.18</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.imyeyu.network</groupId>
|
||||
@@ -188,7 +188,7 @@
|
||||
<dependency>
|
||||
<groupId>com.imyeyu.java</groupId>
|
||||
<artifactId>timi-java</artifactId>
|
||||
<version>0.0.6</version>
|
||||
<version>0.0.7</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.imyeyu.utils</groupId>
|
||||
@@ -230,6 +230,10 @@
|
||||
<artifactId>spring-boot-starter-freemarker</artifactId>
|
||||
<version>${springboot.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.datatype</groupId>
|
||||
<artifactId>jackson-datatype-jsr310</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-mongodb</artifactId>
|
||||
|
||||
@@ -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)
|
||||
// 日期格式化
|
||||
|
||||
+4
-4
@@ -46,8 +46,8 @@ public class TempFileServiceImplement implements TempFileService {
|
||||
|
||||
public List<TempFileResp> create(List<MultipartFile> files, Long ttl) throws TimiException {
|
||||
Logger logger = new Logger();
|
||||
logger.setModule("TEMP_FILE");
|
||||
logger.setOperation("STORE");
|
||||
logger.setModule(Logger.Module.COMMON);
|
||||
logger.setOperation("TEMP_FILE_STORE");
|
||||
logger.setIp(TimiSpring.getRequestIP());
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(logRequestArgs(files, ttl)));
|
||||
@@ -116,8 +116,8 @@ public class TempFileServiceImplement implements TempFileService {
|
||||
@Override
|
||||
public void save(TempFileSaveReq request) {
|
||||
Logger logger = new Logger();
|
||||
logger.setModule("TEMP_FILE");
|
||||
logger.setOperation("SAVE");
|
||||
logger.setModule(Logger.Module.COMMON);
|
||||
logger.setOperation("TEMP_FILE_SAVE");
|
||||
logger.setIp(TimiSpring.getRequestIP());
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(request));
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.imyeyu.api.modules.forevermc.controller;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* 服务器接口
|
||||
*
|
||||
* @author 夜雨
|
||||
* @since 2024-08-06 17:20
|
||||
*/
|
||||
@Slf4j
|
||||
@Validated
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping("/fmc/server")
|
||||
public class ServerController {
|
||||
|
||||
/**
|
||||
* 服务器状态报告,由 FMCServer 服务端插件发送
|
||||
*/
|
||||
@PostMapping("/report")
|
||||
public void report() {
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
|
||||
|
||||
CUSTOMER_READ("CUSTOMER:READ", "客户读取"),
|
||||
|
||||
CUSTOMER_EXPORT("CUSTOMER:EXPORT", "客户导出", true),
|
||||
|
||||
CUSTOMER_UPDATE("CUSTOMER:UPDATE", "客户修改"),
|
||||
|
||||
CUSTOMER_DELETE("CUSTOMER:DELETE", "客户删除"),
|
||||
@@ -30,6 +32,8 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
|
||||
|
||||
REGISTRATION_EVENT_RECORD_READ("REGISTRATION_EVENT_RECORD:READ", "登记事件记录读取"),
|
||||
|
||||
REGISTRATION_EVENT_RECORD_EXPORT("REGISTRATION_EVENT_RECORD:EXPORT", "登记事件记录导出", true),
|
||||
|
||||
REGISTRATION_EVENT_RECORD_UPDATE("REGISTRATION_EVENT_RECORD:UPDATE", "登记事件记录修改"),
|
||||
|
||||
REGISTRATION_EVENT_RECORD_DELETE("REGISTRATION_EVENT_RECORD:DELETE", "登记事件记录删除"),
|
||||
|
||||
@@ -88,7 +88,7 @@ public class GaoCustomerController {
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@IgnoreGlobalReturn
|
||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_EXPORT)
|
||||
@PostMapping("/export")
|
||||
public void export(@RequestBody GaoCustomerSearchReq req, HttpServletResponse resp) throws IOException {
|
||||
String fileName = URLEncoder.encode("客户列表.xlsx", "UTF-8").replace("+", "%20");
|
||||
|
||||
+8
@@ -72,6 +72,14 @@ public class GaoRegistrationEventController {
|
||||
service.update(registrationEvent);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_UPDATE)
|
||||
@PostMapping("/sort")
|
||||
public void sort(@RequestBody List<String> idList) {
|
||||
service.sort(idList);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_DELETE)
|
||||
|
||||
+13
-3
@@ -10,6 +10,7 @@ import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord;
|
||||
import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationRankView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
||||
@@ -79,8 +80,8 @@ public class GaoRegistrationEventRecordController {
|
||||
@RequestRateLimit
|
||||
@PostMapping("/create")
|
||||
@JsonView(ResponseView.Public.class)
|
||||
public GaoRegistrationEventRecord create(@RequestBody GaoRegistrationEventRecordCreateReq req) {
|
||||
return service.createRecord(req);
|
||||
public List<GaoRegistrationEventRecord> create(@RequestBody GaoRegistrationEventRecordCreateReq req) {
|
||||
return service.createRecords(req);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@@ -128,7 +129,7 @@ public class GaoRegistrationEventRecordController {
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@IgnoreGlobalReturn
|
||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_EXPORT)
|
||||
@PostMapping("/range/export")
|
||||
public void rangeExport(@RequestBody GaoRegistrationEventRecordRangeReq req, HttpServletResponse resp) throws IOException {
|
||||
String fileName = URLEncoder.encode("登记事件记录.xlsx", "UTF-8").replace("+", "%20");
|
||||
@@ -171,6 +172,15 @@ public class GaoRegistrationEventRecordController {
|
||||
return service.statAllCustomerByRange(req);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.STAT_READ)
|
||||
@PostMapping("/customer/registration-rank")
|
||||
/// 按时间范围查询客户登记排行榜
|
||||
public List<GaoCustomerRegistrationRankView> customerRegistrationRank(@RequestBody(required = false) GaoRegistrationEventRecordRangeReq req) {
|
||||
return service.listCustomerRegistrationRank(req);
|
||||
}
|
||||
|
||||
@AOPLog
|
||||
@RequestRateLimit
|
||||
@RequireGaoPermission(GaoPermissionCode.STAT_READ)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -16,18 +16,82 @@ import java.util.List;
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class GaoRegistrationEvent extends UUIDEntity {
|
||||
|
||||
///
|
||||
/// 登记事件状态
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-08-01
|
||||
public enum Status {
|
||||
|
||||
/// 草稿,未发布不可登记
|
||||
DRAFT,
|
||||
|
||||
/// 可登记
|
||||
ACTIVE,
|
||||
|
||||
/// 无效,不可登记但保留统计
|
||||
INACTIVE,
|
||||
|
||||
/// 已删除,不可登记但保留统计
|
||||
DELETED
|
||||
}
|
||||
|
||||
///
|
||||
/// 登记限制类型
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-08-01
|
||||
public enum LimitType {
|
||||
|
||||
/// 不限制
|
||||
NONE,
|
||||
|
||||
/// 每天上午、下午各一次
|
||||
DAILY_HALF_DAY,
|
||||
|
||||
/// 每个自然日一次
|
||||
NATURAL_DAY,
|
||||
|
||||
/// 每隔 N 小时一次
|
||||
INTERVAL_HOUR,
|
||||
|
||||
/// 每个自然月一次
|
||||
NATURAL_MONTH,
|
||||
|
||||
/// 事件总登记次数上限
|
||||
TOTAL_LIMIT,
|
||||
|
||||
/// 单个客户总登记次数上限
|
||||
CUSTOMER_TOTAL_LIMIT
|
||||
}
|
||||
|
||||
/// 登记事件名称
|
||||
private String name;
|
||||
|
||||
/// 说明
|
||||
private String description;
|
||||
|
||||
/// true 为启用
|
||||
private Boolean enabled;
|
||||
/// 统计图表颜色
|
||||
private String color;
|
||||
|
||||
/// 状态
|
||||
private Status status;
|
||||
|
||||
/// true 为登记时要求拍照
|
||||
private Boolean requirePhoto;
|
||||
|
||||
/// 登记限制类型
|
||||
private LimitType limitType;
|
||||
|
||||
/// 登记限制数值,按限制类型表示小时数或次数
|
||||
private Integer limitValue;
|
||||
|
||||
/// 可登记起始时间戳,毫秒,空为不限制
|
||||
private Long beginAt;
|
||||
|
||||
/// 可登记终止时间戳,毫秒,空为不限制
|
||||
private Long endAt;
|
||||
|
||||
/// 排序值
|
||||
private Integer sort;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.imyeyu.api.modules.gao.mapper;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import org.apache.ibatis.annotations.Select;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -16,6 +15,5 @@ public interface GaoRegistrationEventMapper extends BaseMapper<GaoRegistrationEv
|
||||
|
||||
List<GaoRegistrationEvent> selectByIdList(@Param("idList") List<String> idList);
|
||||
|
||||
@Select("SELECT * FROM `gao_registration_event` WHERE `enabled` = TRUE AND `deleted_at` IS NULL ORDER BY `sort` ASC, `created_at` ASC")
|
||||
List<GaoRegistrationEvent> selectEnabledList();
|
||||
List<GaoRegistrationEvent> selectEnabledList(@Param("now") Long now);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.imyeyu.api.modules.gao.mapper;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationDayStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView;
|
||||
@@ -27,6 +28,28 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper<GaoRegistra
|
||||
/// @return 最后登记事件记录列表
|
||||
List<GaoRegistrationEventRecord> selectByRegistrationEventAndPeriod(@Param("registrationEventId") String registrationEventId, @Param("periodType") GaoRegistrationEventRecordPeriodReq.PeriodType periodType, @Param("periodValue") Integer periodValue);
|
||||
|
||||
/// 统计客户指定登记事件在时间范围内的登记数
|
||||
///
|
||||
/// @param customerId 客户 ID
|
||||
/// @param registrationEventId 登记事件 ID
|
||||
/// @param beginRegisteredAt 开始登记时间
|
||||
/// @param endRegisteredAt 结束登记时间
|
||||
/// @return 登记数
|
||||
Long countByCustomerIdAndRegistrationEventIdRange(@Param("customerId") String customerId, @Param("registrationEventId") String registrationEventId, @Param("beginRegisteredAt") Long beginRegisteredAt, @Param("endRegisteredAt") Long endRegisteredAt);
|
||||
|
||||
/// 统计客户指定登记事件总登记数
|
||||
///
|
||||
/// @param customerId 客户 ID
|
||||
/// @param registrationEventId 登记事件 ID
|
||||
/// @return 登记数
|
||||
Long countByCustomerIdAndRegistrationEventId(@Param("customerId") String customerId, @Param("registrationEventId") String registrationEventId);
|
||||
|
||||
/// 统计登记事件总登记数
|
||||
///
|
||||
/// @param registrationEventId 登记事件 ID
|
||||
/// @return 登记数
|
||||
Long countByRegistrationEventId(@Param("registrationEventId") String registrationEventId);
|
||||
|
||||
/// 按周期统计登记事件记录
|
||||
///
|
||||
/// @param registrationEventId 登记事件 ID
|
||||
@@ -55,6 +78,12 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper<GaoRegistra
|
||||
/// @return 统计结果
|
||||
List<GaoCustomerRegisterStatView> statAllCustomerByRange(@Param("beginRegisteredAt") Long beginRegisteredAt, @Param("endRegisteredAt") Long endRegisteredAt);
|
||||
|
||||
/// 按时间范围统计全部客户每日登记
|
||||
///
|
||||
/// @param req 范围查询请求
|
||||
/// @return 每个有登记客户的每日统计
|
||||
List<GaoCustomerRegistrationDayStatView> statCustomerRegistrationDay(@Param("req") GaoRegistrationEventRecordRangeReq req);
|
||||
|
||||
/// 统计单个客户单个登记事件的每日登记事件记录数
|
||||
///
|
||||
/// @param customerId 客户 ID
|
||||
|
||||
+11
-4
@@ -3,6 +3,7 @@ package com.imyeyu.api.modules.gao.service;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationRankView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
||||
@@ -26,11 +27,11 @@ import java.util.List;
|
||||
/// @since 2026-07-27
|
||||
public interface GaoRegistrationEventRecordService extends BaseService<GaoRegistrationEventRecord, String> {
|
||||
|
||||
/// 创建登记事件记录
|
||||
/// 批量创建登记事件记录
|
||||
///
|
||||
/// @param req 创建请求
|
||||
/// @return 创建后的登记事件记录
|
||||
GaoRegistrationEventRecord createRecord(GaoRegistrationEventRecordCreateReq req);
|
||||
/// @param req 批量创建请求
|
||||
/// @return 创建后的登记事件记录列表
|
||||
List<GaoRegistrationEventRecord> createRecords(GaoRegistrationEventRecordCreateReq req);
|
||||
|
||||
/// 快速录入客户并创建登记事件记录
|
||||
///
|
||||
@@ -100,6 +101,12 @@ public interface GaoRegistrationEventRecordService extends BaseService<GaoRegist
|
||||
/// @return 统计结果
|
||||
List<GaoCustomerRegisterStatView> statAllCustomerByRange(GaoRegistrationEventRecordStatReq req);
|
||||
|
||||
/// 按时间范围查询客户登记排行榜
|
||||
///
|
||||
/// @param req 范围查询请求,不传时间为全部时间
|
||||
/// @return 客户登记排行榜
|
||||
List<GaoCustomerRegistrationRankView> listCustomerRegistrationRank(GaoRegistrationEventRecordRangeReq req);
|
||||
|
||||
/// 按时间段统计单个客户单个登记事件每日趋势
|
||||
///
|
||||
/// @param req 趋势统计请求
|
||||
|
||||
@@ -30,4 +30,9 @@ public interface GaoRegistrationEventService extends BaseService<GaoRegistration
|
||||
/// @param registrationEventId 登记事件 ID
|
||||
/// @return 角色代码列表
|
||||
List<String> listRoleCode(String registrationEventId);
|
||||
|
||||
/// 按客户端提交的顺序更新登记事件排序
|
||||
///
|
||||
/// @param idList 登记事件 ID 列表
|
||||
void sort(List<String> idList);
|
||||
}
|
||||
|
||||
+142
-6
@@ -1,5 +1,6 @@
|
||||
package com.imyeyu.api.modules.gao.service.implement;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||
@@ -7,21 +8,25 @@ import com.imyeyu.api.modules.common.vo.attach.BizUpdateReq;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||
import com.imyeyu.api.modules.gao.mapper.GaoCustomerMapper;
|
||||
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||
import com.imyeyu.api.modules.user.service.UserService;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView;
|
||||
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.api.modules.system.entity.Logger;
|
||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||
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.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.TimiSpring;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
@@ -35,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;
|
||||
@@ -50,6 +56,7 @@ import java.util.stream.Collectors;
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-07-27
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustomer, String> implements GaoCustomerService {
|
||||
@@ -58,7 +65,9 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
||||
private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
|
||||
|
||||
private final GaoCustomerMapper mapper;
|
||||
private final ObjectMapper jackson;
|
||||
private final AttachmentService attachmentService;
|
||||
private final LoggerService loggerService;
|
||||
private final UserLoginService userLoginService;
|
||||
private final UserService userService;
|
||||
|
||||
@@ -67,30 +76,96 @@ 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");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(entity));
|
||||
checkEntity(entity, false);
|
||||
entity.setCreatorUserId(userLoginService.getRequireLoginUserId());
|
||||
entity.setInvitedCount(0L);
|
||||
super.create(entity);
|
||||
saveAttachment(entity.getId(), resolveAttachmentList(entity));
|
||||
changeInvitedCount(entity.getIntroducerCustomerId(), 1L);
|
||||
loadDetailTransient(entity);
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(entity.getId());
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("新增 GAO 客户失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "新增 GAO 客户失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(GaoCustomer entity) {
|
||||
GaoCustomer dbCustomer = checkEntity(entity, true);
|
||||
super.update(entity);
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_UPDATE");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(entity));
|
||||
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);
|
||||
mapper.update(entity);
|
||||
saveAttachment(entity.getId(), resolveAttachmentList(entity));
|
||||
syncIntroducerInvitedCount(dbCustomer.getIntroducerCustomerId(), entity.getIntroducerCustomerId());
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(entity.getId());
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("修改 GAO 客户失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "修改 GAO 客户失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_DELETE");
|
||||
try {
|
||||
logger.setContent(id);
|
||||
GaoCustomer customer = super.get(id);
|
||||
super.delete(id);
|
||||
changeInvitedCount(customer.getIntroducerCustomerId(), -1L);
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(id);
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("删除 GAO 客户失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "删除 GAO 客户失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -176,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()),
|
||||
@@ -194,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));
|
||||
}
|
||||
@@ -214,6 +291,9 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void saveInviteRelation(GaoCustomerInviteUpdateReq req) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_SAVE_INVITE_RELATION");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(req));
|
||||
TimiException.required(req, "not found invite req");
|
||||
TimiException.required(req.getCustomerId(), "not found invite req.customerId");
|
||||
GaoCustomer customer = super.get(req.getCustomerId());
|
||||
@@ -222,17 +302,48 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
||||
checkEntity(customer, true);
|
||||
super.update(customer);
|
||||
syncIntroducerInvitedCount(oldIntroducerCustomerId, customer.getIntroducerCustomerId());
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(req.getCustomerId());
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("保存 GAO 客户邀请关系失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "保存 GAO 客户邀请关系失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void deleteInviteRelation(String customerId) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_DELETE_INVITE_RELATION");
|
||||
try {
|
||||
logger.setContent(customerId);
|
||||
TimiException.required(customerId, "not found customerId");
|
||||
GaoCustomer customer = super.get(customerId);
|
||||
String oldIntroducerCustomerId = customer.getIntroducerCustomerId();
|
||||
customer.setIntroducerCustomerId(null);
|
||||
super.update(customer);
|
||||
changeInvitedCount(oldIntroducerCustomerId, -1L);
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(customerId);
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("删除 GAO 客户邀请关系失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "删除 GAO 客户邀请关系失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -285,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());
|
||||
@@ -314,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()));
|
||||
@@ -322,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;
|
||||
@@ -442,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 "";
|
||||
|
||||
+289
-27
@@ -1,5 +1,6 @@
|
||||
package com.imyeyu.api.modules.gao.service.implement;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||
@@ -16,6 +17,8 @@ import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService;
|
||||
import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationDayStatView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationRankView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView;
|
||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
||||
@@ -25,18 +28,23 @@ 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.api.modules.system.entity.Logger;
|
||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||
import com.imyeyu.api.modules.user.service.RoleChecker;
|
||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||
import com.imyeyu.api.modules.user.service.UserService;
|
||||
import com.imyeyu.api.modules.user.mapper.UserMapper;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.java.bean.timi.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.TimiSpring;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.CellStyle;
|
||||
import org.apache.poi.ss.usermodel.Font;
|
||||
import org.apache.poi.ss.usermodel.Row;
|
||||
@@ -47,6 +55,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
@@ -55,6 +64,7 @@ import java.time.temporal.ChronoUnit;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -68,18 +78,21 @@ import java.util.stream.Collectors;
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-07-27
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GaoRegistrationEventRecordServiceImplement extends AbstractEntityService<GaoRegistrationEventRecord, String> implements GaoRegistrationEventRecordService {
|
||||
|
||||
private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.BASIC_ISO_DATE;
|
||||
private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
|
||||
|
||||
private final GaoRegistrationEventRecordMapper mapper;
|
||||
private final ObjectMapper jackson;
|
||||
private final GaoCustomerMapper customerMapper;
|
||||
private final GaoRegistrationEventMapper registrationEventMapper;
|
||||
private final UserMapper userMapper;
|
||||
private final AttachmentService attachmentService;
|
||||
private final LoggerService loggerService;
|
||||
private final RoleChecker roleChecker;
|
||||
private final UserLoginService userLoginService;
|
||||
private final UserService userService;
|
||||
@@ -93,45 +106,123 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public GaoRegistrationEventRecord createRecord(GaoRegistrationEventRecordCreateReq req) {
|
||||
public List<GaoRegistrationEventRecord> createRecords(GaoRegistrationEventRecordCreateReq req) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_RECORD_BATCH_CREATE");
|
||||
try {
|
||||
TimiException.required(req, "not found req");
|
||||
TimiException.required(req.getRegistrationEventId(), "not found req.registrationEventId");
|
||||
String customerId = resolveCustomerId(req);
|
||||
GaoRegistrationEvent registrationEvent = registrationEventService.get(req.getRegistrationEventId());
|
||||
checkRegistrationEventPermission(registrationEvent);
|
||||
if (Boolean.TRUE.equals(registrationEvent.getRequirePhoto())) {
|
||||
TimiException.requiredTrue(req.getAttachmentIdList() != null && !req.getAttachmentIdList().isEmpty(), "required record photo");
|
||||
TimiException.requiredTrue(req.getCustomerIdList() != null && !req.getCustomerIdList().isEmpty(), "customerIdList is empty");
|
||||
logger.setContent(jackson.writeValueAsString(req));
|
||||
List<GaoRegistrationEventRecord> recordList = new ArrayList<>();
|
||||
for (int index = 0; index < req.getCustomerIdList().size(); index++) {
|
||||
String customerId = req.getCustomerIdList().get(index);
|
||||
GaoRegistrationEventRecordCreateReq customerReq = copyCreateReq(req);
|
||||
customerReq.setAttachmentIdList(0 == index && canUseSourceTempFileList(req.getAttachmentIdList())
|
||||
? req.getAttachmentIdList()
|
||||
: duplicateTempFileList(req.getAttachmentIdList()));
|
||||
recordList.add(doCreateRecord(customerReq, customerId));
|
||||
}
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(recordList.stream().map(GaoRegistrationEventRecord::getId).collect(Collectors.joining(",")));
|
||||
return recordList;
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("批量新增 GAO 登记记录失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "批量新增 GAO 登记记录失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
GaoRegistrationEventRecord record = new GaoRegistrationEventRecord();
|
||||
record.setCustomerId(customerId);
|
||||
record.setRegistrationEventId(req.getRegistrationEventId());
|
||||
record.setOperatorUserId(userLoginService.getRequireLoginUserId());
|
||||
record.setRemark(req.getRemark());
|
||||
record.setRegisteredAt(TimiJava.defaultIfNull(req.getRegisteredAt(), Time.now()));
|
||||
super.create(record);
|
||||
saveAttachment(record.getId(), buildPhotoAttachmentList(req.getAttachmentIdList()));
|
||||
return get(record.getId());
|
||||
private List<String> duplicateTempFileList(List<String> sourceIdList) {
|
||||
if (sourceIdList == null) {
|
||||
return null;
|
||||
}
|
||||
List<String> targetIdList = new ArrayList<>();
|
||||
for (String sourceId : sourceIdList) {
|
||||
if (sourceId == null || sourceId.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
Attachment source = attachmentService.get(sourceId.trim());
|
||||
TimiException.required(source, "not found attachment");
|
||||
TimiException.required(source.getMongoId(), "not found attachment.mongoId");
|
||||
Attachment target = new Attachment();
|
||||
target.setBizType(Attachment.BizType.TEMP_FILE);
|
||||
target.setName(source.getName());
|
||||
target.setInputStream(new ByteArrayInputStream(attachmentService.readAllByMongoId(source.getMongoId())));
|
||||
attachmentService.create(target);
|
||||
targetIdList.add(target.getId());
|
||||
}
|
||||
return targetIdList;
|
||||
}
|
||||
|
||||
private boolean canUseSourceTempFileList(List<String> sourceIdList) {
|
||||
if (sourceIdList == null || sourceIdList.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
for (String sourceId : sourceIdList) {
|
||||
if (sourceId == null || sourceId.isBlank()) {
|
||||
continue;
|
||||
}
|
||||
Attachment source = attachmentService.get(sourceId.trim());
|
||||
if (source == null || source.getBizType() != Attachment.BizType.TEMP_FILE) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private GaoRegistrationEventRecordCreateReq copyCreateReq(GaoRegistrationEventRecordCreateReq source) {
|
||||
GaoRegistrationEventRecordCreateReq target = new GaoRegistrationEventRecordCreateReq();
|
||||
target.setRegistrationEventId(source.getRegistrationEventId());
|
||||
target.setRemark(source.getRemark());
|
||||
target.setRegisteredAt(source.getRegisteredAt());
|
||||
return target;
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public GaoRegistrationEventRecord quickRegister(GaoQuickRegistrationEventRecordReq req) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_RECORD_QUICK_REGISTER");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(req));
|
||||
TimiException.required(req, "not found req");
|
||||
TimiException.required(req.getCustomerCode(), "not found req.customerCode");
|
||||
TimiException.required(req.getRegistrationEventId(), "not found req.registrationEventId");
|
||||
GaoCustomer customer = customerService.getOrQuickCreateByCode(req.getCustomerCode());
|
||||
GaoRegistrationEventRecordCreateReq recordReq = new GaoRegistrationEventRecordCreateReq();
|
||||
recordReq.setCustomerId(customer.getId());
|
||||
recordReq.setCustomerIdList(List.of(customer.getId()));
|
||||
recordReq.setRegistrationEventId(req.getRegistrationEventId());
|
||||
recordReq.setRemark(req.getRemark());
|
||||
recordReq.setAttachmentIdList(req.getAttachmentIdList());
|
||||
return createRecord(recordReq);
|
||||
GaoRegistrationEventRecord record = createRecords(recordReq).get(0);
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(record.getId());
|
||||
return record;
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("GAO 快速登记失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "GAO 快速登记失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void update(GaoRegistrationEventRecord entity) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_RECORD_UPDATE");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(entity));
|
||||
TimiException.required(entity, "not found record");
|
||||
TimiException.required(entity.getId(), "not found record.id");
|
||||
TimiException.required(entity.getCustomerId(), "not found record.customerId");
|
||||
@@ -142,6 +233,20 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
||||
entity.setRegisteredAt(TimiJava.defaultIfNull(entity.getRegisteredAt(), Time.now()));
|
||||
super.update(entity);
|
||||
saveAttachment(entity.getId(), resolveAttachmentList(entity));
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(entity.getId());
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("修改 GAO 登记记录失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "修改 GAO 登记记录失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -277,6 +382,29 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
||||
return mapper.statAllCustomerByRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GaoCustomerRegistrationRankView> listCustomerRegistrationRank(GaoRegistrationEventRecordRangeReq req) {
|
||||
GaoRegistrationEventRecordRangeReq rangeReq = TimiJava.defaultIfNull(req, new GaoRegistrationEventRecordRangeReq());
|
||||
if (rangeReq.getBeginRegisteredAt() != null || rangeReq.getEndRegisteredAt() != null) {
|
||||
checkStatRange(rangeReq.getBeginRegisteredAt(), rangeReq.getEndRegisteredAt());
|
||||
}
|
||||
List<GaoCustomerRegistrationDayStatView> dayStatList = mapper.statCustomerRegistrationDay(rangeReq);
|
||||
Map<String, List<GaoCustomerRegistrationDayStatView>> customerDayStatMap = dayStatList.stream()
|
||||
.collect(Collectors.groupingBy(GaoCustomerRegistrationDayStatView::getCustomerId));
|
||||
List<GaoCustomerRegistrationRankView> rankList = new ArrayList<>();
|
||||
for (Map.Entry<String, List<GaoCustomerRegistrationDayStatView>> entry : customerDayStatMap.entrySet()) {
|
||||
rankList.add(buildCustomerRegistrationRank(entry.getValue()));
|
||||
}
|
||||
rankList.sort(Comparator
|
||||
.comparing(GaoCustomerRegistrationRankView::getTotalRegistrationDays, Comparator.nullsLast(Comparator.reverseOrder()))
|
||||
.thenComparing(GaoCustomerRegistrationRankView::getTotalRegistrationCount, Comparator.nullsLast(Comparator.reverseOrder()))
|
||||
.thenComparing(GaoCustomerRegistrationRankView::getLatestRegisteredAt, Comparator.nullsLast(Comparator.reverseOrder())));
|
||||
for (int index = 0; index < rankList.size(); index++) {
|
||||
rankList.get(index).setRank(index + 1);
|
||||
}
|
||||
return rankList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<GaoRegistrationEventRecordDailyStatView> statDailyByCustomerAndRegistrationEvent(GaoRegistrationEventRecordTrendStatReq req) {
|
||||
TimiException.required(req, "not found req");
|
||||
@@ -299,21 +427,118 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
||||
return list;
|
||||
}
|
||||
|
||||
private String resolveCustomerId(GaoRegistrationEventRecordCreateReq req) {
|
||||
if (TimiJava.isNotEmpty(req.getCustomerId())) {
|
||||
customerService.get(req.getCustomerId());
|
||||
return req.getCustomerId();
|
||||
private String resolveCustomerId(String customerId) {
|
||||
TimiException.required(customerId, "not found customerId");
|
||||
customerService.get(customerId);
|
||||
return customerId;
|
||||
}
|
||||
TimiException.required(req.getCustomerCode(), "not found req.customerCode");
|
||||
GaoCustomer customer = customerService.getByCode(req.getCustomerCode());
|
||||
return customer.getId();
|
||||
|
||||
private GaoRegistrationEventRecord doCreateRecord(GaoRegistrationEventRecordCreateReq req, String customerId) {
|
||||
TimiException.required(req, "not found req");
|
||||
TimiException.required(req.getRegistrationEventId(), "not found req.registrationEventId");
|
||||
customerId = resolveCustomerId(customerId);
|
||||
GaoRegistrationEvent registrationEvent = registrationEventService.get(req.getRegistrationEventId());
|
||||
checkRegistrationEventPermission(registrationEvent);
|
||||
long registeredAt = TimiJava.defaultIfNull(req.getRegisteredAt(), Time.now());
|
||||
checkRegistrationEventCreatable(registrationEvent, customerId, registeredAt);
|
||||
if (Boolean.TRUE.equals(registrationEvent.getRequirePhoto())) {
|
||||
TimiException.requiredTrue(req.getAttachmentIdList() != null && !req.getAttachmentIdList().isEmpty(), "required record photo");
|
||||
}
|
||||
|
||||
GaoRegistrationEventRecord record = new GaoRegistrationEventRecord();
|
||||
record.setCustomerId(customerId);
|
||||
record.setRegistrationEventId(req.getRegistrationEventId());
|
||||
record.setOperatorUserId(userLoginService.getRequireLoginUserId());
|
||||
record.setRemark(req.getRemark());
|
||||
record.setRegisteredAt(registeredAt);
|
||||
super.create(record);
|
||||
saveAttachment(record.getId(), buildPhotoAttachmentList(req.getAttachmentIdList()));
|
||||
return get(record.getId());
|
||||
}
|
||||
|
||||
private void checkRegistrationEventPermission(GaoRegistrationEvent registrationEvent) {
|
||||
List<String> roleCodeList = registrationEventService.listRoleCode(registrationEvent.getId());
|
||||
if (roleCodeList != null && !roleCodeList.isEmpty()) {
|
||||
TimiException.requiredTrue(roleCodeList != null && !roleCodeList.isEmpty(), "登记事件未配置可登记角色");
|
||||
roleChecker.checkAny(ModuleCode.GAO, roleCodeList.toArray(String[]::new));
|
||||
}
|
||||
|
||||
private void checkRegistrationEventCreatable(GaoRegistrationEvent registrationEvent, String customerId, long registeredAt) {
|
||||
TimiException.requiredTrue(registrationEvent.getStatus() == null || registrationEvent.getStatus() == GaoRegistrationEvent.Status.ACTIVE, "登记事件不可登记");
|
||||
TimiException.requiredTrue(registrationEvent.getBeginAt() == null || registrationEvent.getBeginAt() <= registeredAt, "登记事件未到可登记时间");
|
||||
TimiException.requiredTrue(registrationEvent.getEndAt() == null || registeredAt <= registrationEvent.getEndAt(), "登记事件已过可登记时间");
|
||||
GaoRegistrationEvent.LimitType limitType = TimiJava.defaultIfNull(registrationEvent.getLimitType(), GaoRegistrationEvent.LimitType.NONE);
|
||||
switch (limitType) {
|
||||
case DAILY_HALF_DAY -> checkRegistrationLimitRange(customerId, registrationEvent.getId(), getHalfDayBegin(registeredAt), getHalfDayEnd(registeredAt), "该客户当前半日已登记该事件");
|
||||
case NATURAL_DAY -> checkRegistrationLimitRange(customerId, registrationEvent.getId(), getDayBegin(registeredAt), getDayEnd(registeredAt), "该客户当日已登记该事件");
|
||||
case INTERVAL_HOUR -> checkIntervalHourRegistrationLimit(registrationEvent, customerId, registeredAt);
|
||||
case NATURAL_MONTH -> checkRegistrationLimitRange(customerId, registrationEvent.getId(), getMonthBegin(registeredAt), getMonthEnd(registeredAt), "该客户当月已登记该事件");
|
||||
case TOTAL_LIMIT -> checkTotalRegistrationLimit(registrationEvent);
|
||||
case CUSTOMER_TOTAL_LIMIT -> checkCustomerTotalRegistrationLimit(registrationEvent, customerId);
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRegistrationLimitRange(String customerId, String registrationEventId, long beginRegisteredAt, long endRegisteredAt, String message) {
|
||||
Long count = mapper.countByCustomerIdAndRegistrationEventIdRange(customerId, registrationEventId, beginRegisteredAt, endRegisteredAt);
|
||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, message);
|
||||
}
|
||||
|
||||
private void checkIntervalHourRegistrationLimit(GaoRegistrationEvent registrationEvent, String customerId, long registeredAt) {
|
||||
Integer limitValue = registrationEvent.getLimitValue();
|
||||
TimiException.requiredTrue(limitValue != null && 0 < limitValue, "登记事件间隔小时配置错误");
|
||||
long beginRegisteredAt = registeredAt - limitValue * 60L * 60L * 1000L + 1;
|
||||
checkRegistrationLimitRange(customerId, registrationEvent.getId(), beginRegisteredAt, registeredAt, "该客户登记该事件间隔不足");
|
||||
}
|
||||
|
||||
private void checkCustomerTotalRegistrationLimit(GaoRegistrationEvent registrationEvent, String customerId) {
|
||||
Integer limitValue = registrationEvent.getLimitValue();
|
||||
TimiException.requiredTrue(limitValue != null && 0 < limitValue, "登记事件单客户总次数配置错误");
|
||||
Long count = mapper.countByCustomerIdAndRegistrationEventId(customerId, registrationEvent.getId());
|
||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < limitValue, "该客户登记该事件次数已达上限");
|
||||
}
|
||||
|
||||
private void checkTotalRegistrationLimit(GaoRegistrationEvent registrationEvent) {
|
||||
Integer limitValue = registrationEvent.getLimitValue();
|
||||
TimiException.requiredTrue(limitValue != null && 0 < limitValue, "登记事件总次数配置错误");
|
||||
Long count = mapper.countByRegistrationEventId(registrationEvent.getId());
|
||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < limitValue, "登记事件总次数已达上限");
|
||||
}
|
||||
|
||||
private long getDayBegin(long registeredAt) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
return Instant.ofEpochMilli(registeredAt).atZone(zoneId).toLocalDate().atStartOfDay(zoneId).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
private long getDayEnd(long registeredAt) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
return Instant.ofEpochMilli(registeredAt).atZone(zoneId).toLocalDate().plusDays(1).atStartOfDay(zoneId).toInstant().toEpochMilli() - 1;
|
||||
}
|
||||
|
||||
private long getHalfDayBegin(long registeredAt) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
int hour = Instant.ofEpochMilli(registeredAt).atZone(zoneId).getHour();
|
||||
long dayBegin = getDayBegin(registeredAt);
|
||||
return hour < 12 ? dayBegin : dayBegin + 12L * 60L * 60L * 1000L;
|
||||
}
|
||||
|
||||
private long getHalfDayEnd(long registeredAt) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
int hour = Instant.ofEpochMilli(registeredAt).atZone(zoneId).getHour();
|
||||
long dayBegin = getDayBegin(registeredAt);
|
||||
return hour < 12 ? dayBegin + 12L * 60L * 60L * 1000L - 1 : getDayEnd(registeredAt);
|
||||
}
|
||||
|
||||
private long getMonthBegin(long registeredAt) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
LocalDate date = Instant.ofEpochMilli(registeredAt).atZone(zoneId).toLocalDate();
|
||||
return date.withDayOfMonth(1).atStartOfDay(zoneId).toInstant().toEpochMilli();
|
||||
}
|
||||
|
||||
private long getMonthEnd(long registeredAt) {
|
||||
ZoneId zoneId = ZoneId.systemDefault();
|
||||
LocalDate date = Instant.ofEpochMilli(registeredAt).atZone(zoneId).toLocalDate();
|
||||
return date.withDayOfMonth(1).plusMonths(1).atStartOfDay(zoneId).toInstant().toEpochMilli() - 1;
|
||||
}
|
||||
|
||||
private void checkStatRange(Long beginRegisteredAt, Long endRegisteredAt) {
|
||||
@@ -356,6 +581,43 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
||||
return list;
|
||||
}
|
||||
|
||||
private GaoCustomerRegistrationRankView buildCustomerRegistrationRank(List<GaoCustomerRegistrationDayStatView> dayStatList) {
|
||||
List<GaoCustomerRegistrationDayStatView> sortedDayStatList = dayStatList.stream()
|
||||
.sorted(Comparator.comparing(GaoCustomerRegistrationDayStatView::getDateValue, Comparator.nullsLast(Comparator.reverseOrder())))
|
||||
.toList();
|
||||
GaoCustomerRegistrationDayStatView first = sortedDayStatList.get(0);
|
||||
GaoCustomerRegistrationRankView view = new GaoCustomerRegistrationRankView();
|
||||
view.setCustomerId(first.getCustomerId());
|
||||
view.setCustomerCode(first.getCustomerCode());
|
||||
view.setCustomerName(first.getCustomerName());
|
||||
view.setCustomerPhotoAttachmentId(first.getCustomerPhotoAttachmentId());
|
||||
view.setTotalRegistrationDays((long) sortedDayStatList.size());
|
||||
view.setTotalRegistrationCount(sortedDayStatList.stream().mapToLong(item -> TimiJava.defaultIfNull(item.getDailyCount(), 0L)).sum());
|
||||
view.setLatestRegisteredAt(sortedDayStatList.stream().map(GaoCustomerRegistrationDayStatView::getLatestRegisteredAt).filter(Objects::nonNull).max(Long::compareTo).orElse(null));
|
||||
view.setRecentContinuousRegistrationDays(countRecentContinuousRegistrationDays(sortedDayStatList));
|
||||
return view;
|
||||
}
|
||||
|
||||
private long countRecentContinuousRegistrationDays(List<GaoCustomerRegistrationDayStatView> sortedDayStatList) {
|
||||
if (sortedDayStatList.isEmpty() || sortedDayStatList.get(0).getDateValue() == null) {
|
||||
return 0;
|
||||
}
|
||||
LocalDate expectedDate = LocalDate.parse(String.valueOf(sortedDayStatList.get(0).getDateValue()), DAY_FORMATTER);
|
||||
long count = 0;
|
||||
for (GaoCustomerRegistrationDayStatView item : sortedDayStatList) {
|
||||
if (item.getDateValue() == null) {
|
||||
continue;
|
||||
}
|
||||
LocalDate date = LocalDate.parse(String.valueOf(item.getDateValue()), DAY_FORMATTER);
|
||||
if (!date.equals(expectedDate)) {
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
expectedDate = expectedDate.minusDays(1);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void loadTransient(List<GaoRegistrationEventRecord> recordList) {
|
||||
if (recordList == null || recordList.isEmpty()) {
|
||||
return;
|
||||
|
||||
+137
-23
@@ -1,17 +1,24 @@
|
||||
package com.imyeyu.api.modules.gao.service.implement;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRoleRelation;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent;
|
||||
import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventRoleRelationMapper;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRoleRelation;
|
||||
import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventMapper;
|
||||
import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventRoleRelationMapper;
|
||||
import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService;
|
||||
import com.imyeyu.api.modules.system.entity.Logger;
|
||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||
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 com.imyeyu.utils.Time;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -25,12 +32,17 @@ import java.util.stream.Collectors;
|
||||
///
|
||||
/// 登记事件服务实现
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-07-27
|
||||
/// @author 夜雨
|
||||
/// @since 2026-07-27 09:00
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GaoRegistrationEventServiceImplement extends AbstractEntityService<GaoRegistrationEvent, String> implements GaoRegistrationEventService {
|
||||
|
||||
private final ObjectMapper jackson;
|
||||
|
||||
private final LoggerService loggerService;
|
||||
|
||||
private final GaoRegistrationEventMapper mapper;
|
||||
private final GaoRegistrationEventRoleRelationMapper roleRelationMapper;
|
||||
|
||||
@@ -42,6 +54,7 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
||||
@Override
|
||||
public PageResult<GaoRegistrationEvent> pageWithRegistrationEventLimit(Page<GaoRegistrationEvent> page) {
|
||||
PageResult<GaoRegistrationEvent> result = page(page);
|
||||
result.setList(result.getList().stream().filter(item -> item.getStatus() != GaoRegistrationEvent.Status.DELETED).toList());
|
||||
loadRegistrationEventLimit(result.getList());
|
||||
return result;
|
||||
}
|
||||
@@ -49,24 +62,90 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void create(GaoRegistrationEvent entity) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_CREATE");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(entity));
|
||||
checkEntity(entity, false);
|
||||
super.create(entity);
|
||||
saveRoleRelation(entity.getId(), entity.getRoleCodeList());
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(entity.getId());
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("新增 GAO 登记事件失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "新增 GAO 登记事件失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void update(GaoRegistrationEvent entity) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_UPDATE");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(entity));
|
||||
Integer sort = entity.getSort();
|
||||
checkEntity(entity, true);
|
||||
super.update(entity);
|
||||
GaoRegistrationEvent current = get(entity.getId());
|
||||
current.setName(entity.getName());
|
||||
current.setDescription(entity.getDescription());
|
||||
current.setColor(entity.getColor());
|
||||
current.setStatus(entity.getStatus());
|
||||
current.setRequirePhoto(entity.getRequirePhoto());
|
||||
current.setLimitType(entity.getLimitType());
|
||||
current.setLimitValue(entity.getLimitValue());
|
||||
current.setBeginAt(entity.getBeginAt());
|
||||
current.setEndAt(entity.getEndAt());
|
||||
if (sort != null) {
|
||||
current.setSort(sort);
|
||||
}
|
||||
mapper.update(current);
|
||||
saveRoleRelation(entity.getId(), entity.getRoleCodeList());
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(entity.getId());
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("修改 GAO 登记事件失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "修改 GAO 登记事件失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void delete(String id) {
|
||||
roleRelationMapper.deleteByRegistrationEventId(id);
|
||||
super.delete(id);
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_REGISTRATION_EVENT_DELETE");
|
||||
try {
|
||||
logger.setContent(id);
|
||||
GaoRegistrationEvent entity = get(id);
|
||||
entity.setStatus(GaoRegistrationEvent.Status.DELETED);
|
||||
super.update(entity);
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(id);
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("删除 GAO 登记事件失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "删除 GAO 登记事件失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,8 +157,9 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
||||
|
||||
@Override
|
||||
public List<GaoRegistrationEvent> listEnabled() {
|
||||
List<GaoRegistrationEvent> list = mapper.selectEnabledList();
|
||||
List<GaoRegistrationEvent> list = mapper.selectEnabledList(Time.now());
|
||||
loadRegistrationEventLimit(list);
|
||||
list = list.stream().filter(item -> !TimiJava.isEmpty(item.getRoleCodeList())).toList();
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -88,23 +168,66 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
||||
return roleRelationMapper.selectRoleCodeListByRegistrationEventId(registrationEventId);
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void sort(List<String> idList) {
|
||||
if (idList == null || idList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> distinctIdList = new ArrayList<>(new LinkedHashSet<>(idList));
|
||||
Map<String, GaoRegistrationEvent> eventMap = mapper.selectByIdList(distinctIdList).stream().collect(Collectors.toMap(GaoRegistrationEvent::getId, item -> item));
|
||||
TimiException.requiredTrue(eventMap.size() == distinctIdList.size(), "not found registrationEvent");
|
||||
for (int index = 0; index < distinctIdList.size(); index++) {
|
||||
GaoRegistrationEvent registrationEvent = eventMap.get(distinctIdList.get(index));
|
||||
registrationEvent.setSort(index);
|
||||
mapper.update(registrationEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEntity(GaoRegistrationEvent entity, boolean requireId) {
|
||||
TimiException.required(entity, "not found registrationEvent");
|
||||
if (requireId) {
|
||||
TimiException.required(entity.getId(), "not found registrationEvent.id");
|
||||
}
|
||||
TimiException.required(entity.getName(), "not found registrationEvent.name");
|
||||
if (entity.getEnabled() == null) {
|
||||
entity.setEnabled(true);
|
||||
if (entity.getStatus() == null) {
|
||||
entity.setStatus(GaoRegistrationEvent.Status.ACTIVE);
|
||||
}
|
||||
if (entity.getRequirePhoto() == null) {
|
||||
entity.setRequirePhoto(false);
|
||||
}
|
||||
if (entity.getLimitType() == null) {
|
||||
entity.setLimitType(GaoRegistrationEvent.LimitType.NONE);
|
||||
}
|
||||
TimiException.requiredTrue(entity.getRoleCodeList() != null && entity.getRoleCodeList()
|
||||
.stream()
|
||||
.anyMatch(item -> item != null && !item.isBlank()), "not found registrationEvent.roleCodeList");
|
||||
checkRegistrationLimit(entity);
|
||||
checkRegisterablePeriod(entity);
|
||||
if (entity.getColor() != null) {
|
||||
entity.setColor(entity.getColor().trim());
|
||||
}
|
||||
if (entity.getSort() == null) {
|
||||
entity.setSort(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkRegistrationLimit(GaoRegistrationEvent entity) {
|
||||
if (entity.getLimitType() == GaoRegistrationEvent.LimitType.INTERVAL_HOUR || entity.getLimitType() == GaoRegistrationEvent.LimitType.TOTAL_LIMIT || entity.getLimitType() == GaoRegistrationEvent.LimitType.CUSTOMER_TOTAL_LIMIT) {
|
||||
TimiException.required(entity.getLimitValue(), "not found registrationEvent.limitValue");
|
||||
TimiException.requiredTrue(0 < entity.getLimitValue(), "registrationEvent.limitValue lte 0");
|
||||
return;
|
||||
}
|
||||
entity.setLimitValue(null);
|
||||
}
|
||||
|
||||
private void checkRegisterablePeriod(GaoRegistrationEvent entity) {
|
||||
if (entity.getBeginAt() == null && entity.getEndAt() == null) {
|
||||
return;
|
||||
}
|
||||
TimiException.requiredTrue(entity.getBeginAt() == null || entity.getEndAt() == null || entity.getBeginAt() <= entity.getEndAt(), "registrationEvent.beginAt gt registrationEvent.endAt");
|
||||
}
|
||||
|
||||
private void saveRoleRelation(String registrationEventId, List<String> roleCodeList) {
|
||||
roleRelationMapper.deleteByRegistrationEventId(registrationEventId);
|
||||
if (roleCodeList == null || roleCodeList.isEmpty()) {
|
||||
@@ -122,23 +245,14 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
||||
}
|
||||
}
|
||||
|
||||
private void loadRegistrationEventLimit(GaoRegistrationEvent registrationEvent) {
|
||||
registrationEvent.setRoleCodeList(roleRelationMapper.selectRoleCodeListByRegistrationEventId(registrationEvent.getId()));
|
||||
}
|
||||
|
||||
private void loadRegistrationEventLimit(List<GaoRegistrationEvent> registrationEventList) {
|
||||
if (registrationEventList == null || registrationEventList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<String> registrationEventIdList = registrationEventList.stream()
|
||||
.map(GaoRegistrationEvent::getId)
|
||||
.distinct()
|
||||
.toList();
|
||||
Map<String, List<String>> roleCodeMap = roleRelationMapper.selectByRegistrationEventIdList(new ArrayList<>(registrationEventIdList)).stream()
|
||||
.collect(Collectors.groupingBy(
|
||||
GaoRegistrationEventRoleRelation::getRegistrationEventId,
|
||||
Collectors.mapping(GaoRegistrationEventRoleRelation::getRoleCode, Collectors.toList())
|
||||
));
|
||||
List<String> registrationEventIdList = registrationEventList.stream().map(GaoRegistrationEvent::getId).distinct().toList();
|
||||
Map<String, List<String>> roleCodeMap = roleRelationMapper.selectByRegistrationEventIdList(new ArrayList<>(registrationEventIdList))
|
||||
.stream()
|
||||
.collect(Collectors.groupingBy(GaoRegistrationEventRoleRelation::getRegistrationEventId, Collectors.mapping(GaoRegistrationEventRoleRelation::getRoleCode, Collectors.toList())));
|
||||
for (GaoRegistrationEvent registrationEvent : registrationEventList) {
|
||||
registrationEvent.setRoleCodeList(roleCodeMap.getOrDefault(registrationEvent.getId(), List.of()));
|
||||
}
|
||||
|
||||
+42
@@ -1,10 +1,13 @@
|
||||
package com.imyeyu.api.modules.gao.service.implement;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.gao.entity.GaoUser;
|
||||
import com.imyeyu.api.modules.gao.mapper.GaoUserMapper;
|
||||
import com.imyeyu.api.modules.gao.service.GaoUserService;
|
||||
import com.imyeyu.api.modules.system.entity.Logger;
|
||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||
import com.imyeyu.api.modules.user.entity.Role;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.api.modules.user.mapper.UserMapper;
|
||||
@@ -14,12 +17,14 @@ import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeReq;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.java.bean.timi.TimiCode;
|
||||
import com.imyeyu.java.bean.timi.TimiException;
|
||||
import com.imyeyu.spring.TimiSpring;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -34,11 +39,14 @@ import java.util.stream.Collectors;
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-07-30
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, String> implements GaoUserService {
|
||||
|
||||
private final GaoUserMapper mapper;
|
||||
private final ObjectMapper jackson;
|
||||
private final LoggerService loggerService;
|
||||
private final UserMapper userMapper;
|
||||
private final UserService userService;
|
||||
private final RoleService roleService;
|
||||
@@ -51,20 +59,54 @@ public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, Stri
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void create(GaoUser entity) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_USER_CREATE");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(entity));
|
||||
prepareUser(entity);
|
||||
checkEntity(entity, false);
|
||||
super.create(entity);
|
||||
saveUserRole(entity);
|
||||
loadUser(entity);
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(entity.getId());
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("新增 GAO 用户失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "新增 GAO 用户失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||
@Override
|
||||
public void update(GaoUser entity) {
|
||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_USER_UPDATE");
|
||||
try {
|
||||
logger.setContent(jackson.writeValueAsString(entity));
|
||||
checkEntity(entity, true);
|
||||
updateUser(entity);
|
||||
super.update(entity);
|
||||
saveUserRole(entity);
|
||||
logger.setLevel(Logger.Level.INFO);
|
||||
logger.setResult(entity.getId());
|
||||
} catch (TimiException e) {
|
||||
logger.setLevel(Logger.Level.WARN);
|
||||
logger.setException(e.getMessage());
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
logger.setLevel(Logger.Level.ERROR);
|
||||
logger.setException(TimiJava.serializeThrowable(e));
|
||||
log.error("修改 GAO 用户失败", e);
|
||||
throw new TimiException(TimiCode.ERROR, "修改 GAO 用户失败", e);
|
||||
} finally {
|
||||
loggerService.create(logger);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.imyeyu.api.modules.gao.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
///
|
||||
/// 客户登记日期统计视图
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-08-03
|
||||
@Data
|
||||
public class GaoCustomerRegistrationDayStatView {
|
||||
|
||||
/// 客户 ID
|
||||
private String customerId;
|
||||
|
||||
/// 客户编码
|
||||
private String customerCode;
|
||||
|
||||
/// 客户姓名
|
||||
private String customerName;
|
||||
|
||||
/// 客户头像附件 ID
|
||||
private String customerPhotoAttachmentId;
|
||||
|
||||
/// 登记日期,格式 yyyyMMdd
|
||||
private Integer dateValue;
|
||||
|
||||
/// 当日登记次数
|
||||
private Long dailyCount;
|
||||
|
||||
/// 当日最后登记时间
|
||||
private Long latestRegisteredAt;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.imyeyu.api.modules.gao.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
///
|
||||
/// 客户登记排行榜视图
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-08-03
|
||||
@Data
|
||||
public class GaoCustomerRegistrationRankView {
|
||||
|
||||
/// 排名
|
||||
private Integer rank;
|
||||
|
||||
/// 客户 ID
|
||||
private String customerId;
|
||||
|
||||
/// 客户编码
|
||||
private String customerCode;
|
||||
|
||||
/// 客户姓名
|
||||
private String customerName;
|
||||
|
||||
/// 客户头像附件 ID
|
||||
private String customerPhotoAttachmentId;
|
||||
|
||||
/// 累计登记天数
|
||||
private Long totalRegistrationDays;
|
||||
|
||||
/// 累计登记次数
|
||||
private Long totalRegistrationCount;
|
||||
|
||||
/// 最近连续登记天数
|
||||
private Long recentContinuousRegistrationDays;
|
||||
|
||||
/// 最后登记时间
|
||||
private Long latestRegisteredAt;
|
||||
}
|
||||
+2
-5
@@ -13,11 +13,8 @@ import java.util.List;
|
||||
@Data
|
||||
public class GaoRegistrationEventRecordCreateReq {
|
||||
|
||||
/// 客户 ID
|
||||
private String customerId;
|
||||
|
||||
/// 客户编码,扫码登记可直接传这个
|
||||
private String customerCode;
|
||||
/// 客户 ID 列表,批量登记时使用
|
||||
private List<String> customerIdList = new ArrayList<>();
|
||||
|
||||
/// 登记事件 ID
|
||||
private String registrationEventId;
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
package com.imyeyu.api.modules.gao.vo;
|
||||
|
||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
///
|
||||
/// 登记事件保存请求
|
||||
///
|
||||
/// @author Codex
|
||||
/// @since 2026-07-27
|
||||
@Data
|
||||
public class GaoRegistrationEventSaveReq {
|
||||
|
||||
/// 登记事件
|
||||
private GaoRegistrationEvent registrationEvent;
|
||||
|
||||
/// 可登记角色代码列表
|
||||
private List<String> roleCodeList = new ArrayList<>();
|
||||
}
|
||||
@@ -17,6 +17,21 @@ import lombok.NoArgsConstructor;
|
||||
@NoArgsConstructor
|
||||
public class Logger implements IDEntity<String>, Creatable {
|
||||
|
||||
///
|
||||
///
|
||||
/// @author 夜雨
|
||||
/// @since 2026-08-03 11:43
|
||||
public enum Module {
|
||||
|
||||
SYSTEM,
|
||||
|
||||
COMMON,
|
||||
|
||||
USER,
|
||||
|
||||
GAO,
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志级别
|
||||
*
|
||||
@@ -43,7 +58,7 @@ public class Logger implements IDEntity<String>, Creatable {
|
||||
private Level level;
|
||||
|
||||
/** 模块名称 */
|
||||
private String module;
|
||||
private Module module;
|
||||
|
||||
/** 操作描述 */
|
||||
private String operation;
|
||||
@@ -69,7 +84,26 @@ public class Logger implements IDEntity<String>, Creatable {
|
||||
/** 创建时间 */
|
||||
private Long createdAt;
|
||||
|
||||
public Logger(Level level) {
|
||||
public Logger(Module module, String operation) {
|
||||
this.module = module;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public Logger(Module module, Level level, String operation) {
|
||||
this.module = module;
|
||||
this.level = level;
|
||||
this.operation = operation;
|
||||
}
|
||||
|
||||
public static Logger info(Module module, String operation) {
|
||||
return new Logger(module, Level.INFO, operation);
|
||||
}
|
||||
|
||||
public static Logger warning(Module module, String operation) {
|
||||
return new Logger(module, Level.WARN, operation);
|
||||
}
|
||||
|
||||
public static Logger error(Module module, String operation) {
|
||||
return new Logger(module, Level.ERROR, operation);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,41 +16,29 @@ public interface LoggerService extends GettableService<Logger, String>, Pageable
|
||||
|
||||
void createSync(Logger logger);
|
||||
|
||||
void create(Logger.Level level, String module, String operation, String userId, String content, String result);
|
||||
void create(Logger.Module module, Logger.Level level, String operation, String content, String result);
|
||||
|
||||
default void info(String module, String operation, String userId) {
|
||||
create(Logger.Level.INFO, module, operation, userId, null, null);
|
||||
default void info(Logger.Module module, String operation) {
|
||||
create(module, Logger.Level.INFO, operation, null, null);
|
||||
}
|
||||
|
||||
default void info(String module, String operation, String content, String result) {
|
||||
create(Logger.Level.INFO, module, operation, null, content, result);
|
||||
default void info(Logger.Module module, String operation, String content, String result) {
|
||||
create(module, Logger.Level.INFO, operation, content, result);
|
||||
}
|
||||
|
||||
default void info(String module, String operation, String userId, String content, String result) {
|
||||
create(Logger.Level.INFO, module, operation, userId, content, result);
|
||||
default void warning(Logger.Module module, String operation) {
|
||||
create(module, Logger.Level.WARN, operation, null, null);
|
||||
}
|
||||
|
||||
default void warning(String module, String operation, String userId) {
|
||||
create(Logger.Level.WARN, module, operation, userId, null, null);
|
||||
default void warning(Logger.Module module, String operation, String content, String result) {
|
||||
create(module, Logger.Level.WARN, operation, content, result);
|
||||
}
|
||||
|
||||
default void warning(String module, String operation, String content, String result) {
|
||||
create(Logger.Level.WARN, module, operation, null, content, result);
|
||||
default void error(Logger.Module module, String operation) {
|
||||
create(module, Logger.Level.ERROR, operation, null, null);
|
||||
}
|
||||
|
||||
default void warning(String module, String operation, String userId, String content, String result) {
|
||||
create(Logger.Level.WARN, module, operation, userId, content, result);
|
||||
}
|
||||
|
||||
default void error(String module, String operation, String userId) {
|
||||
create(Logger.Level.ERROR, module, operation, userId, null, null);
|
||||
}
|
||||
|
||||
default void error(String module, String operation, String content, String result) {
|
||||
create(Logger.Level.ERROR, module, operation, null, content, result);
|
||||
}
|
||||
|
||||
default void error(String module, String operation, String userId, String content, String result) {
|
||||
create(Logger.Level.ERROR, module, operation, userId, content, result);
|
||||
default void error(Logger.Module module, String operation, String content, String result) {
|
||||
create(module, Logger.Level.ERROR, operation, content, result);
|
||||
}
|
||||
}
|
||||
|
||||
+16
-6
@@ -3,6 +3,10 @@ package com.imyeyu.api.modules.system.service.implement;
|
||||
import com.imyeyu.api.modules.system.entity.Logger;
|
||||
import com.imyeyu.api.modules.system.mapper.LoggerMapper;
|
||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||
import com.imyeyu.api.modules.user.entity.User;
|
||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||
import com.imyeyu.java.TimiJava;
|
||||
import com.imyeyu.spring.TimiSpring;
|
||||
import com.imyeyu.spring.mapper.BaseMapper;
|
||||
import com.imyeyu.spring.service.AbstractEntityService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -18,6 +22,8 @@ import org.springframework.stereotype.Service;
|
||||
@RequiredArgsConstructor
|
||||
public class LoggerServiceImplement extends AbstractEntityService<Logger, String> implements LoggerService {
|
||||
|
||||
private final UserLoginService userLoginService;
|
||||
|
||||
private final LoggerMapper mapper;
|
||||
|
||||
@Override
|
||||
@@ -28,19 +34,23 @@ public class LoggerServiceImplement extends AbstractEntityService<Logger, String
|
||||
@Override
|
||||
public void create(Logger logger) {
|
||||
// 默认异步
|
||||
Thread.startVirtualThread(() -> super.create(logger));
|
||||
Thread.startVirtualThread(() -> createSync(logger));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSync(Logger logger) {
|
||||
if (TimiJava.isEmpty(logger.getUserId())) {
|
||||
User loginUser = userLoginService.getLoginUser();
|
||||
if (TimiJava.isNotEmpty(loginUser)) {
|
||||
logger.setUserId(loginUser.getId());
|
||||
}
|
||||
}
|
||||
logger.setIp(TimiJava.defaultIfEmpty(logger.getIp(), TimiSpring.getRequestIP()));
|
||||
super.create(logger);
|
||||
}
|
||||
|
||||
public void create(Logger.Level level, String module, String operation, String userId, String content, String result) {
|
||||
Logger log = new Logger(level);
|
||||
log.setModule(module);
|
||||
log.setOperation(operation);
|
||||
log.setUserId(userId);
|
||||
public void create(Logger.Module module, Logger.Level level, String operation, String content, String result) {
|
||||
Logger log = new Logger(module, level, operation);
|
||||
log.setContent(content);
|
||||
log.setResult(result);
|
||||
create(log);
|
||||
|
||||
+4
-2
@@ -25,8 +25,8 @@ import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/// 用户登录服务实现
|
||||
///
|
||||
@@ -95,7 +95,9 @@ public class UserLoginServiceImplement implements UserLoginService, TimiJava {
|
||||
@Override
|
||||
public User getLoginUser() {
|
||||
String token = TimiSpring.getToken();
|
||||
TimiException.required(token, "not found token");
|
||||
if (TimiJava.isEmpty(token)) {
|
||||
return null;
|
||||
}
|
||||
String userId = redisUserToken.get(getUserTokenKey(token));
|
||||
if (TimiJava.isEmpty(userId)) {
|
||||
return null;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package com.imyeyu.api.util;
|
||||
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.bean.ModuleCode;
|
||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||
import com.imyeyu.api.modules.common.bean.ImageType;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||
import com.imyeyu.api.modules.system.entity.Logger;
|
||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||
import com.imyeyu.api.modules.user.bean.BootstrapData;
|
||||
import com.imyeyu.api.modules.user.bean.BuiltinAuthRegistry;
|
||||
@@ -92,7 +93,13 @@ public class InitBuiltinUser implements ApplicationRunner {
|
||||
userService.create(user);
|
||||
|
||||
String logContent = "初始化 %s 自举用户成功,请立即修改密码:%s".formatted(BootstrapData.SYS_USER_NAME, password);
|
||||
loggerService.info("SYSTEM", "INITIALIZE_SYSTEM_USER", user.getId(), logContent, null);
|
||||
|
||||
Logger logger = new Logger();
|
||||
logger.setModule(Logger.Module.SYSTEM);
|
||||
logger.setOperation("INITIALIZE_SYSTEM_USER");
|
||||
logger.setUserId(user.getId());
|
||||
logger.setContent(logContent);
|
||||
loggerService.create(logger);
|
||||
}
|
||||
// 授权系统用户角色
|
||||
{
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
ALTER TABLE `gao_registration_event`
|
||||
ADD COLUMN `color` VARCHAR(32) NULL COMMENT '统计图表颜色' AFTER `id`,
|
||||
ADD COLUMN `status` VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态,ACTIVE 可登记,INACTIVE 无效,DELETED 已删除' AFTER `sort`,
|
||||
ADD COLUMN `limit_type` VARCHAR(32) NOT NULL DEFAULT 'NONE' COMMENT '登记限制类型' AFTER `require_photo`,
|
||||
ADD COLUMN `limit_value` INT NULL COMMENT '登记限制数值,按限制类型表示小时数或次数' AFTER `limit_type`,
|
||||
ADD KEY `idx_gao_registration_event_status` (`status`, `enabled`, `deleted_at`, `sort`);
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE `gao_registration_event`
|
||||
DROP KEY `idx_gao_registration_event_status`,
|
||||
DROP COLUMN `enabled`,
|
||||
MODIFY COLUMN `status` VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态,DRAFT 草稿,ACTIVE 可登记,INACTIVE 不可登记,DELETED 已删除',
|
||||
ADD COLUMN `begin_at` BIGINT NULL COMMENT '可登记起始时间戳,毫秒,空为不限制' AFTER `limit_value`,
|
||||
ADD COLUMN `end_at` BIGINT NULL COMMENT '可登记终止时间戳,毫秒,空为不限制' AFTER `begin_at`,
|
||||
ADD KEY `idx_gao_registration_event_status` (`status`, `deleted_at`, `sort`, `created_at`);
|
||||
@@ -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`;
|
||||
@@ -18,4 +18,16 @@
|
||||
</if>
|
||||
AND `deleted_at` IS NULL
|
||||
</select>
|
||||
|
||||
<select id="selectEnabledList" resultType="com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent">
|
||||
SELECT
|
||||
*
|
||||
FROM `gao_registration_event`
|
||||
WHERE
|
||||
(`status` IS NULL OR `status` = 'ACTIVE')
|
||||
AND (`begin_at` IS NULL OR `begin_at` <= #{now})
|
||||
AND (`end_at` IS NULL OR #{now} <= `end_at`)
|
||||
AND `deleted_at` IS NULL
|
||||
ORDER BY `sort` ASC, `created_at` ASC
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -20,6 +20,37 @@
|
||||
ORDER BY `registered_at` DESC
|
||||
</select>
|
||||
|
||||
<select id="countByCustomerIdAndRegistrationEventIdRange" resultType="java.lang.Long">
|
||||
SELECT
|
||||
COUNT(1)
|
||||
FROM `gao_registration_event_record`
|
||||
WHERE
|
||||
`customer_id` = #{customerId}
|
||||
AND `registration_event_id` = #{registrationEventId}
|
||||
AND `registered_at` >= #{beginRegisteredAt}
|
||||
AND `registered_at` <= #{endRegisteredAt}
|
||||
AND `deleted_at` IS NULL
|
||||
</select>
|
||||
|
||||
<select id="countByCustomerIdAndRegistrationEventId" resultType="java.lang.Long">
|
||||
SELECT
|
||||
COUNT(1)
|
||||
FROM `gao_registration_event_record`
|
||||
WHERE
|
||||
`customer_id` = #{customerId}
|
||||
AND `registration_event_id` = #{registrationEventId}
|
||||
AND `deleted_at` IS NULL
|
||||
</select>
|
||||
|
||||
<select id="countByRegistrationEventId" resultType="java.lang.Long">
|
||||
SELECT
|
||||
COUNT(1)
|
||||
FROM `gao_registration_event_record`
|
||||
WHERE
|
||||
`registration_event_id` = #{registrationEventId}
|
||||
AND `deleted_at` IS NULL
|
||||
</select>
|
||||
|
||||
<select id="statByRegistrationEventAndPeriodType" resultType="com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView">
|
||||
SELECT
|
||||
`registration_event_id` AS `registrationEventId`,
|
||||
@@ -112,6 +143,54 @@
|
||||
ORDER BY `latestRegisteredAt` DESC
|
||||
</select>
|
||||
|
||||
<select id="statCustomerRegistrationDay" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerRegistrationDayStatView">
|
||||
SELECT
|
||||
r.`customer_id` AS `customerId`,
|
||||
c.`code` AS `customerCode`,
|
||||
c.`name` AS `customerName`,
|
||||
(
|
||||
SELECT a.`id`
|
||||
FROM `attachment` a
|
||||
WHERE
|
||||
a.`biz_type` = 'GAO_CUSTOMER'
|
||||
AND a.`biz_id` = c.`id`
|
||||
AND a.`attach_type` = 'PHOTO'
|
||||
AND a.`deleted_at` IS NULL
|
||||
AND (a.`destroy_at` IS NULL OR UNIX_TIMESTAMP() < a.`destroy_at`)
|
||||
ORDER BY a.`created_at` ASC
|
||||
LIMIT 1
|
||||
) AS `customerPhotoAttachmentId`,
|
||||
CAST(DATE_FORMAT(FROM_UNIXTIME(r.`registered_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
|
||||
COUNT(1) AS `dailyCount`,
|
||||
MAX(r.`registered_at`) AS `latestRegisteredAt`
|
||||
FROM `gao_registration_event_record` r
|
||||
LEFT JOIN `gao_customer` c ON r.`customer_id` = c.`id`
|
||||
WHERE
|
||||
r.`deleted_at` IS NULL
|
||||
AND c.`deleted_at` IS NULL
|
||||
<if test="req.beginRegisteredAt != null">
|
||||
AND r.`registered_at` >= #{req.beginRegisteredAt}
|
||||
</if>
|
||||
<if test="req.endRegisteredAt != null">
|
||||
AND r.`registered_at` <= #{req.endRegisteredAt}
|
||||
</if>
|
||||
<if test="req.registrationEventId != null and req.registrationEventId != ''">
|
||||
AND r.`registration_event_id` = #{req.registrationEventId}
|
||||
</if>
|
||||
<if test="req.registrationEventIdList != null and req.registrationEventIdList.size() > 0">
|
||||
AND r.`registration_event_id` IN
|
||||
<foreach collection="req.registrationEventIdList" item="registrationEventId" open="(" separator="," close=")">
|
||||
#{registrationEventId}
|
||||
</foreach>
|
||||
</if>
|
||||
GROUP BY
|
||||
r.`customer_id`,
|
||||
c.`code`,
|
||||
c.`name`,
|
||||
DATE_FORMAT(FROM_UNIXTIME(r.`registered_at` / 1000), '%Y%m%d')
|
||||
ORDER BY r.`customer_id` ASC, `dateValue` DESC
|
||||
</select>
|
||||
|
||||
<select id="statDailyCountByCustomerIdAndRegistrationEventIdRange" resultType="com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView">
|
||||
SELECT
|
||||
CAST(DATE_FORMAT(FROM_UNIXTIME(`registered_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
|
||||
|
||||
Reference in New Issue
Block a user