Compare commits
19
Commits
22e415dd7b
..
v1.0.7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da288338cd | ||
|
|
2f366fe219 | ||
|
|
ea430f2468 | ||
|
|
f1715a3e32 | ||
|
|
f76f79744a | ||
|
|
833a303bb6 | ||
|
|
19daaff907 | ||
|
|
1658be7d8d | ||
|
|
db94d8f932 | ||
|
|
6c537852a0 | ||
|
|
53618fe362 | ||
|
|
15bf9bd688 | ||
|
|
ce22661a9b | ||
|
|
523edffc4e | ||
|
|
c7ddb1a8b0 | ||
|
|
45c9fc814a | ||
|
|
407dc13ac4 | ||
|
|
0c06bf16c2 | ||
|
|
1db39e77d3 |
@@ -14,7 +14,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
deployment_status: ${{ steps.set_status.outputs.status }}
|
deployment_status: ${{ steps.set_status.outputs.status }}
|
||||||
env:
|
env:
|
||||||
JAVA_HOME: /usr/lib/jvm/java-21-openjdk
|
JAVA_HOME: /usr/lib/jvm/java-25-openjdk
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<groupId>com.imyeyu.timiserverapi</groupId>
|
<groupId>com.imyeyu.timiserverapi</groupId>
|
||||||
<artifactId>TimiServerAPI</artifactId>
|
<artifactId>TimiServerAPI</artifactId>
|
||||||
<version>1.0.3</version>
|
<version>1.0.6</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>TimiServerAPI</name>
|
<name>TimiServerAPI</name>
|
||||||
<description>imyeyu.com API</description>
|
<description>imyeyu.com API</description>
|
||||||
@@ -173,7 +173,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.spring</groupId>
|
<groupId>com.imyeyu.spring</groupId>
|
||||||
<artifactId>timi-spring</artifactId>
|
<artifactId>timi-spring</artifactId>
|
||||||
<version>0.0.16</version>
|
<version>0.0.17</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.network</groupId>
|
<groupId>com.imyeyu.network</groupId>
|
||||||
@@ -183,7 +183,12 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.lang</groupId>
|
<groupId>com.imyeyu.lang</groupId>
|
||||||
<artifactId>timi-lang</artifactId>
|
<artifactId>timi-lang</artifactId>
|
||||||
<version>0.0.4</version>
|
<version>0.0.5</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.imyeyu.java</groupId>
|
||||||
|
<artifactId>timi-java</artifactId>
|
||||||
|
<version>0.0.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.utils</groupId>
|
<groupId>com.imyeyu.utils</groupId>
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ public class RequestRateLimitInterceptor extends RequestRateLimitAbstractInterce
|
|||||||
redis.setAndKeepTTL(key, ++count);
|
redis.setAndKeepTTL(key, ++count);
|
||||||
} else {
|
} else {
|
||||||
log.warn("请求频率过高:[" + key + "].C" + count + "L" + limit);
|
log.warn("请求频率过高:[" + key + "].C" + count + "L" + limit);
|
||||||
throw new TimiException(TimiCode.REQUEST_BAD).msgKey("request_rate_limit");
|
throw new TimiException(TimiCode.REQUEST_BAD, "request_rate_limit");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ public enum CoreRoleCode implements BuiltinRoleCode {
|
|||||||
|
|
||||||
SYSTEM("系统", true, null),
|
SYSTEM("系统", true, null),
|
||||||
|
|
||||||
ADMIN("管理员", false, SYSTEM.name());
|
ADMIN("管理员", false, SYSTEM.name()),
|
||||||
|
|
||||||
|
USER_ROLE_ADMIN("授权管理", false, ADMIN.name());
|
||||||
|
|
||||||
final String defaultName;
|
final String defaultName;
|
||||||
final boolean protectedRole;
|
final boolean protectedRole;
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.imyeyu.api.modules.common.entity.Attachment;
|
|||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.mapper.RawMapper;
|
import com.imyeyu.spring.mapper.RawMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -31,6 +32,8 @@ public interface AttachmentMapper extends BaseMapper<Attachment, String>, RawMap
|
|||||||
|
|
||||||
List<Attachment> selectByBizId(Attachment.BizType bizType, String bizId, List<String> attachTypes, Page<Attachment> page);
|
List<Attachment> selectByBizId(Attachment.BizType bizType, String bizId, List<String> attachTypes, Page<Attachment> page);
|
||||||
|
|
||||||
|
List<Attachment> selectByBizIdList(@Param("bizType") Attachment.BizType bizType, @Param("bizIdList") List<String> bizIdList, @Param("attachTypes") List<String> attachTypes);
|
||||||
|
|
||||||
long countByBizId(Attachment.BizType bizType, String bizId, List<String> attachTypes);
|
long countByBizId(Attachment.BizType bizType, String bizId, List<String> attachTypes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.imyeyu.spring.service.BaseService;
|
|||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 附件服务
|
* 附件服务
|
||||||
@@ -50,6 +51,16 @@ public interface AttachmentService extends BaseService<Attachment, String> {
|
|||||||
*/
|
*/
|
||||||
List<Attachment> listByBizId(Attachment.BizType bizType, String bizId, String... attachTypes);
|
List<Attachment> listByBizId(Attachment.BizType bizType, String bizId, String... attachTypes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据多个业务 ID 批量获取附件。
|
||||||
|
*
|
||||||
|
* @param bizType 业务类型
|
||||||
|
* @param bizIdList 业务 ID 列表
|
||||||
|
* @param attachTypes 附件类型,可为 null
|
||||||
|
* @return 按业务 ID 分组的附件列表
|
||||||
|
*/
|
||||||
|
Map<String, List<Attachment>> mapByBizIdList(Attachment.BizType bizType, List<String> bizIdList, String... attachTypes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据业务获取所有附件
|
* 根据业务获取所有附件
|
||||||
*
|
*
|
||||||
|
|||||||
+23
-5
@@ -43,7 +43,9 @@ import java.io.ByteArrayOutputStream;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
@@ -97,7 +99,7 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("delete mongo file error, id={}", attach.getId(), e);
|
log.error("delete mongo file error, id={}", attach.getId(), e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO delete mongo file error");
|
throw new TimiException(TimiCode.ERROR, "TODO delete mongo file error");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mapper.selectThumbsBySourceId(id).forEach(doDestroy::handler);
|
mapper.selectThumbsBySourceId(id).forEach(doDestroy::handler);
|
||||||
@@ -145,7 +147,7 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(mongoId)));
|
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(mongoId)));
|
||||||
}
|
}
|
||||||
log.error("create error", e);
|
log.error("create error", e);
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("TODO read attachment input stream error");
|
throw new TimiException(TimiCode.ARG_BAD, "TODO read attachment input stream error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -200,7 +202,7 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(newMongoId)));
|
gridFsTemplate.delete(Query.query(Criteria.where("_id").is(newMongoId)));
|
||||||
}
|
}
|
||||||
log.error("update error", e);
|
log.error("update error", e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO update file error");
|
throw new TimiException(TimiCode.ERROR, "TODO update file error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +273,7 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
return thumb;
|
return thumb;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("create thumbnail error", e);
|
log.error("create thumbnail error", e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("exception.attachment.create.error");
|
throw new TimiException(TimiCode.ERROR, "exception.attachment.create.error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,6 +312,22 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
return mapper.selectByBizId(bizType, bizId, List.of(attachTypes), null);
|
return mapper.selectByBizId(bizType, bizId, List.of(attachTypes), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<Attachment>> mapByBizIdList(Attachment.BizType bizType, List<String> bizIdList, String... attachTypes) {
|
||||||
|
if (bizIdList == null || bizIdList.isEmpty()) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
List<String> normalizedBizIdList = bizIdList.stream()
|
||||||
|
.filter(TimiJava::isNotEmpty)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
if (normalizedBizIdList.isEmpty()) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
return mapper.selectByBizIdList(bizType, new ArrayList<>(normalizedBizIdList), List.of(attachTypes)).stream()
|
||||||
|
.collect(Collectors.groupingBy(Attachment::getBizId));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long countByBizId(Attachment.BizType bizType, String bizId, String... attachTypes) {
|
public long countByBizId(Attachment.BizType bizType, String bizId, String... attachTypes) {
|
||||||
return mapper.countByBizId(bizType, bizId, List.of(attachTypes));
|
return mapper.countByBizId(bizType, bizId, List.of(attachTypes));
|
||||||
@@ -354,7 +372,7 @@ public class AttachmentServiceImplement extends AbstractEntityService<Attachment
|
|||||||
if (isNew) {
|
if (isNew) {
|
||||||
// 请求有、数据库无:将临时文件记录直接转存为永久附件
|
// 请求有、数据库无:将临时文件记录直接转存为永久附件
|
||||||
if (TimiJava.isEmpty(tempFileId)) {
|
if (TimiJava.isEmpty(tempFileId)) {
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("exception.attachment.file.required");
|
throw new TimiException(TimiCode.ERROR, "exception.attachment.file.required");
|
||||||
}
|
}
|
||||||
Attachment tempFile = mapper.selectRaw(tempFileId);
|
Attachment tempFile = mapper.selectRaw(tempFileId);
|
||||||
tempFile.setBizType(bizType);
|
tempFile.setBizType(bizType);
|
||||||
|
|||||||
+3
-3
@@ -51,11 +51,11 @@ public class ClipboardServiceImplement implements ClipboardService {
|
|||||||
public void setContent(String id, String content) {
|
public void setContent(String id, String content) {
|
||||||
validateId(id);
|
validateId(id);
|
||||||
if (content == null) {
|
if (content == null) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("剪切板内容不能为空");
|
throw new TimiException(TimiCode.ARG_MISS, "剪切板内容不能为空");
|
||||||
}
|
}
|
||||||
byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
|
byte[] contentBytes = content.getBytes(StandardCharsets.UTF_8);
|
||||||
if (MAX_CONTENT_SIZE < contentBytes.length) {
|
if (MAX_CONTENT_SIZE < contentBytes.length) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("剪切板内容不能超过 10MB");
|
throw new TimiException(TimiCode.ARG_BAD, "剪切板内容不能超过 10MB");
|
||||||
}
|
}
|
||||||
redisClipboard.set(getKey(id), content, Time.D * 7);
|
redisClipboard.set(getKey(id), content, Time.D * 7);
|
||||||
notifySubscribers(id, content);
|
notifySubscribers(id, content);
|
||||||
@@ -78,7 +78,7 @@ public class ClipboardServiceImplement implements ClipboardService {
|
|||||||
|
|
||||||
private void validateId(String id) {
|
private void validateId(String id) {
|
||||||
if (TimiJava.isEmpty(id)) {
|
if (TimiJava.isEmpty(id)) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("id 不能为空");
|
throw new TimiException(TimiCode.ARG_MISS, "id 不能为空");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -39,7 +39,9 @@ public class MultilingualServiceImplement extends AbstractEntityService<Multilin
|
|||||||
Multilingual result = redisLanguage.get(getKey(id));
|
Multilingual result = redisLanguage.get(getKey(id));
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = super.get(id);
|
result = super.get(id);
|
||||||
redisLanguage.set(getKey(id), result, Time.D * 7);
|
if (result != null) {
|
||||||
|
redisLanguage.set(getKey(id), result, Time.D * 7);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.imyeyu.api.modules.gao.controller;
|
package com.imyeyu.api.modules.gao.controller;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||||
import com.imyeyu.api.bean.RoleMatchMode;
|
import com.imyeyu.api.bean.RoleMatchMode;
|
||||||
@@ -12,6 +13,7 @@ import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService;
|
|||||||
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService;
|
import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView;
|
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.GaoCustomerInviteUpdateReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq;
|
||||||
@@ -21,6 +23,7 @@ import com.imyeyu.spring.annotation.IgnoreGlobalReturn;
|
|||||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.bean.PageResult;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import com.imyeyu.spring.util.ResponseView;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@@ -57,6 +60,7 @@ public class GaoCustomerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public PageResult<GaoCustomer> list(@RequestBody Page<GaoCustomer> page) {
|
public PageResult<GaoCustomer> list(@RequestBody Page<GaoCustomer> page) {
|
||||||
PageResult<GaoCustomer> result = service.page(page);
|
PageResult<GaoCustomer> result = service.page(page);
|
||||||
fillLastSignInAt(result.getList());
|
fillLastSignInAt(result.getList());
|
||||||
@@ -67,6 +71,7 @@ public class GaoCustomerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/search")
|
@PostMapping("/search")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public List<GaoCustomer> search(@RequestBody GaoCustomerSearchReq req) {
|
public List<GaoCustomer> search(@RequestBody GaoCustomerSearchReq req) {
|
||||||
return service.search(req);
|
return service.search(req);
|
||||||
}
|
}
|
||||||
@@ -75,6 +80,7 @@ public class GaoCustomerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/search/page")
|
@PostMapping("/search/page")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public PageResult<GaoCustomer> searchPage(@RequestBody Page<GaoCustomerSearchReq> page) {
|
public PageResult<GaoCustomer> searchPage(@RequestBody Page<GaoCustomerSearchReq> page) {
|
||||||
return service.searchPage(page);
|
return service.searchPage(page);
|
||||||
}
|
}
|
||||||
@@ -95,6 +101,7 @@ public class GaoCustomerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/detail")
|
@PostMapping("/detail")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoCustomer detail(@RequestParam String id) {
|
public GaoCustomer detail(@RequestParam String id) {
|
||||||
return service.get(id);
|
return service.get(id);
|
||||||
}
|
}
|
||||||
@@ -103,14 +110,25 @@ public class GaoCustomerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/detail/code")
|
@PostMapping("/detail/code")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoCustomer detailByCode(@RequestParam String code) {
|
public GaoCustomer detailByCode(@RequestParam String code) {
|
||||||
return service.getByCode(code);
|
return service.getByCode(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
|
@PostMapping("/detail/code/nullable")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
|
public GaoCustomer nullableDetailByCode(@RequestParam String code) {
|
||||||
|
return service.getNullableByCode(code);
|
||||||
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/invited/list")
|
@PostMapping("/invited/list")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public List<GaoCustomer> invitedList(@RequestParam String introducerCustomerId) {
|
public List<GaoCustomer> invitedList(@RequestParam String introducerCustomerId) {
|
||||||
return service.listInvited(introducerCustomerId);
|
return service.listInvited(introducerCustomerId);
|
||||||
}
|
}
|
||||||
@@ -119,6 +137,7 @@ public class GaoCustomerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_CREATE)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_CREATE)
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoCustomer create(@RequestBody GaoCustomer customer) {
|
public GaoCustomer create(@RequestBody GaoCustomer customer) {
|
||||||
service.create(customer);
|
service.create(customer);
|
||||||
return customer;
|
return customer;
|
||||||
@@ -127,6 +146,7 @@ public class GaoCustomerController {
|
|||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@PostMapping("/quick/register")
|
@PostMapping("/quick/register")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoRegistrationEventRecord quickRegister(@RequestBody GaoQuickRegistrationEventRecordReq req) {
|
public GaoRegistrationEventRecord quickRegister(@RequestBody GaoQuickRegistrationEventRecordReq req) {
|
||||||
return registrationEventRecordService.quickRegister(req);
|
return registrationEventRecordService.quickRegister(req);
|
||||||
}
|
}
|
||||||
@@ -159,6 +179,7 @@ public class GaoCustomerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/invite/detail")
|
@PostMapping("/invite/detail")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoCustomer inviteDetail(@RequestParam String customerId) {
|
public GaoCustomer inviteDetail(@RequestParam String customerId) {
|
||||||
return service.get(customerId);
|
return service.get(customerId);
|
||||||
}
|
}
|
||||||
@@ -188,6 +209,15 @@ public class GaoCustomerController {
|
|||||||
return service.statDailyTrend(req);
|
return service.statDailyTrend(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
|
@PostMapping("/stat/gender")
|
||||||
|
/// 统计客户性别分布
|
||||||
|
public List<GaoCustomerGenderStatView> genderStat() {
|
||||||
|
return service.statGender();
|
||||||
|
}
|
||||||
|
|
||||||
private void fillLastSignInAt(List<GaoCustomer> customerList) {
|
private void fillLastSignInAt(List<GaoCustomer> customerList) {
|
||||||
if (customerList == null || customerList.isEmpty()) {
|
if (customerList == null || customerList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
+18
-1
@@ -1,5 +1,6 @@
|
|||||||
package com.imyeyu.api.modules.gao.controller;
|
package com.imyeyu.api.modules.gao.controller;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||||
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||||
import com.imyeyu.api.bean.RoleMatchMode;
|
import com.imyeyu.api.bean.RoleMatchMode;
|
||||||
@@ -10,7 +11,9 @@ import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService;
|
|||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq;
|
||||||
@@ -20,6 +23,7 @@ import com.imyeyu.spring.annotation.IgnoreGlobalReturn;
|
|||||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.bean.PageResult;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import com.imyeyu.spring.util.ResponseView;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@@ -49,6 +53,7 @@ public class GaoRegistrationEventRecordController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public PageResult<GaoRegistrationEventRecord> list(@RequestBody Page<GaoRegistrationEventRecord> page) {
|
public PageResult<GaoRegistrationEventRecord> list(@RequestBody Page<GaoRegistrationEventRecord> page) {
|
||||||
return service.page(page);
|
return service.page(page);
|
||||||
}
|
}
|
||||||
@@ -57,7 +62,7 @@ public class GaoRegistrationEventRecordController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
||||||
@PostMapping("/range/page")
|
@PostMapping("/range/page")
|
||||||
public PageResult<GaoRegistrationEventRecord> rangePage(@RequestBody Page<GaoRegistrationEventRecordRangeReq> page) {
|
public PageResult<GaoRegistrationEventRecordListItemView> rangePage(@RequestBody Page<GaoRegistrationEventRecordRangeReq> page) {
|
||||||
return service.pageByRange(page);
|
return service.pageByRange(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,6 +70,7 @@ public class GaoRegistrationEventRecordController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
||||||
@PostMapping("/detail")
|
@PostMapping("/detail")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoRegistrationEventRecord detail(@RequestParam String id) {
|
public GaoRegistrationEventRecord detail(@RequestParam String id) {
|
||||||
return service.get(id);
|
return service.get(id);
|
||||||
}
|
}
|
||||||
@@ -72,6 +78,7 @@ public class GaoRegistrationEventRecordController {
|
|||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoRegistrationEventRecord create(@RequestBody GaoRegistrationEventRecordCreateReq req) {
|
public GaoRegistrationEventRecord create(@RequestBody GaoRegistrationEventRecordCreateReq req) {
|
||||||
return service.createRecord(req);
|
return service.createRecord(req);
|
||||||
}
|
}
|
||||||
@@ -96,6 +103,7 @@ public class GaoRegistrationEventRecordController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
||||||
@PostMapping("/period/list")
|
@PostMapping("/period/list")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public List<GaoRegistrationEventRecord> periodList(@RequestBody GaoRegistrationEventRecordPeriodReq req) {
|
public List<GaoRegistrationEventRecord> periodList(@RequestBody GaoRegistrationEventRecordPeriodReq req) {
|
||||||
return service.listByRegistrationEventAndPeriod(req);
|
return service.listByRegistrationEventAndPeriod(req);
|
||||||
}
|
}
|
||||||
@@ -104,10 +112,19 @@ public class GaoRegistrationEventRecordController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
||||||
@PostMapping("/range/list")
|
@PostMapping("/range/list")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public List<GaoRegistrationEventRecord> rangeList(@RequestBody GaoRegistrationEventRecordRangeReq req) {
|
public List<GaoRegistrationEventRecord> rangeList(@RequestBody GaoRegistrationEventRecordRangeReq req) {
|
||||||
return service.listByRange(req);
|
return service.listByRange(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.REGISTRATION_EVENT_RECORD_READ)
|
||||||
|
@PostMapping("/range/calendar/list")
|
||||||
|
public List<GaoRegistrationEventRecordCalendarView> calendarRangeList(@RequestBody GaoRegistrationEventRecordRangeReq req) {
|
||||||
|
return service.listCalendarByRange(req);
|
||||||
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@IgnoreGlobalReturn
|
@IgnoreGlobalReturn
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.imyeyu.api.modules.gao.controller;
|
package com.imyeyu.api.modules.gao.controller;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
import com.imyeyu.api.bean.ModuleCode;
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||||
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
||||||
@@ -13,6 +14,7 @@ import com.imyeyu.spring.annotation.AOPLog;
|
|||||||
import com.imyeyu.spring.annotation.RequestRateLimit;
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.bean.PageResult;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import com.imyeyu.spring.util.ResponseView;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
@@ -40,6 +42,7 @@ public class GaoUserController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.USER_READ)
|
@RequireGaoPermission(GaoPermissionCode.USER_READ)
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public PageResult<GaoUser> list(@RequestBody Page<GaoUser> page) {
|
public PageResult<GaoUser> list(@RequestBody Page<GaoUser> page) {
|
||||||
return service.pageWithUser(page);
|
return service.pageWithUser(page);
|
||||||
}
|
}
|
||||||
@@ -48,6 +51,7 @@ public class GaoUserController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.USER_READ)
|
@RequireGaoPermission(GaoPermissionCode.USER_READ)
|
||||||
@PostMapping("/detail")
|
@PostMapping("/detail")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoUser detail(@RequestParam String id) {
|
public GaoUser detail(@RequestParam String id) {
|
||||||
return service.get(id);
|
return service.get(id);
|
||||||
}
|
}
|
||||||
@@ -56,6 +60,7 @@ public class GaoUserController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.USER_READ)
|
@RequireGaoPermission(GaoPermissionCode.USER_READ)
|
||||||
@PostMapping("/detail/user")
|
@PostMapping("/detail/user")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoUser detailByUserId(@RequestParam String userId) {
|
public GaoUser detailByUserId(@RequestParam String userId) {
|
||||||
return service.getByUserId(userId);
|
return service.getByUserId(userId);
|
||||||
}
|
}
|
||||||
@@ -64,6 +69,7 @@ public class GaoUserController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.USER_CREATE)
|
@RequireGaoPermission(GaoPermissionCode.USER_CREATE)
|
||||||
@PostMapping("/create")
|
@PostMapping("/create")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoUser create(@RequestBody GaoUser gaoUser) {
|
public GaoUser create(@RequestBody GaoUser gaoUser) {
|
||||||
service.create(gaoUser);
|
service.create(gaoUser);
|
||||||
return service.get(gaoUser.getId());
|
return service.get(gaoUser.getId());
|
||||||
@@ -73,6 +79,7 @@ public class GaoUserController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.USER_UPDATE)
|
@RequireGaoPermission(GaoPermissionCode.USER_UPDATE)
|
||||||
@PostMapping("/update")
|
@PostMapping("/update")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoUser update(@RequestBody GaoUser gaoUser) {
|
public GaoUser update(@RequestBody GaoUser gaoUser) {
|
||||||
service.update(gaoUser);
|
service.update(gaoUser);
|
||||||
return service.get(gaoUser.getId());
|
return service.get(gaoUser.getId());
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.imyeyu.api.modules.gao.entity;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.imyeyu.api.modules.common.entity.Attachment;
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.user.entity.User;
|
||||||
import com.imyeyu.api.modules.user.bean.Gender;
|
import com.imyeyu.api.modules.user.bean.Gender;
|
||||||
import com.imyeyu.spring.annotation.table.Transient;
|
import com.imyeyu.spring.annotation.table.Transient;
|
||||||
import com.imyeyu.spring.entity.UUIDEntity;
|
import com.imyeyu.spring.entity.UUIDEntity;
|
||||||
@@ -59,6 +60,9 @@ public class GaoCustomer extends UUIDEntity {
|
|||||||
/// 介绍人客户 ID
|
/// 介绍人客户 ID
|
||||||
private String introducerCustomerId;
|
private String introducerCustomerId;
|
||||||
|
|
||||||
|
/// 录入用户 ID
|
||||||
|
private String creatorUserId;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private Long lastSignInAt;
|
private Long lastSignInAt;
|
||||||
|
|
||||||
@@ -66,6 +70,8 @@ public class GaoCustomer extends UUIDEntity {
|
|||||||
private GaoCustomer introducerCustomer;
|
private GaoCustomer introducerCustomer;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
|
private User creatorUser;
|
||||||
|
|
||||||
private Long invitedCount;
|
private Long invitedCount;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
|
|||||||
@@ -16,18 +16,73 @@ import java.util.List;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class GaoRegistrationEvent extends UUIDEntity {
|
public class GaoRegistrationEvent extends UUIDEntity {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 登记事件状态
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-01
|
||||||
|
public enum Status {
|
||||||
|
|
||||||
|
/// 可登记
|
||||||
|
ACTIVE,
|
||||||
|
|
||||||
|
/// 无效,不可登记但保留统计
|
||||||
|
INACTIVE,
|
||||||
|
|
||||||
|
/// 已删除,不可登记但保留统计
|
||||||
|
DELETED
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 登记限制类型
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-01
|
||||||
|
public enum RegistrationLimitType {
|
||||||
|
|
||||||
|
/// 不限制
|
||||||
|
NONE,
|
||||||
|
|
||||||
|
/// 每天上午、下午各一次
|
||||||
|
DAILY_HALF_DAY,
|
||||||
|
|
||||||
|
/// 每个自然日一次
|
||||||
|
NATURAL_DAY,
|
||||||
|
|
||||||
|
/// 每隔 N 小时一次
|
||||||
|
INTERVAL_HOUR,
|
||||||
|
|
||||||
|
/// 每个自然月一次
|
||||||
|
NATURAL_MONTH,
|
||||||
|
|
||||||
|
/// 累计限 N 次
|
||||||
|
TOTAL_LIMIT
|
||||||
|
}
|
||||||
|
|
||||||
/// 登记事件名称
|
/// 登记事件名称
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
/// 说明
|
/// 说明
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
/// 统计图表颜色
|
||||||
|
private String color;
|
||||||
|
|
||||||
|
/// 状态
|
||||||
|
private Status status;
|
||||||
|
|
||||||
/// true 为启用
|
/// true 为启用
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
/// true 为登记时要求拍照
|
/// true 为登记时要求拍照
|
||||||
private Boolean requirePhoto;
|
private Boolean requirePhoto;
|
||||||
|
|
||||||
|
/// 登记限制类型
|
||||||
|
private RegistrationLimitType limitType;
|
||||||
|
|
||||||
|
/// 登记限制数值,按限制类型表示小时数或次数
|
||||||
|
private Integer limitValue;
|
||||||
|
|
||||||
/// 排序值
|
/// 排序值
|
||||||
private Integer sort;
|
private Integer sort;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.imyeyu.api.modules.gao.mapper;
|
|||||||
|
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
@@ -18,6 +19,11 @@ public interface GaoCustomerMapper extends BaseMapper<GaoCustomer, String> {
|
|||||||
@Select("SELECT * FROM `gao_customer` WHERE `code` = #{code} AND `deleted_at` IS NULL LIMIT 1")
|
@Select("SELECT * FROM `gao_customer` WHERE `code` = #{code} AND `deleted_at` IS NULL LIMIT 1")
|
||||||
GaoCustomer selectByCode(@Param("code") String code);
|
GaoCustomer selectByCode(@Param("code") String code);
|
||||||
|
|
||||||
|
@Select("SELECT * FROM `gao_customer` WHERE `name` = #{name} AND `deleted_at` IS NULL LIMIT 1")
|
||||||
|
GaoCustomer selectByName(@Param("name") String name);
|
||||||
|
|
||||||
|
List<GaoCustomer> selectByIdList(@Param("idList") List<String> idList);
|
||||||
|
|
||||||
List<GaoCustomer> search(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId);
|
List<GaoCustomer> search(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId);
|
||||||
|
|
||||||
Long countSearch(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId);
|
Long countSearch(@Param("keyword") String keyword, @Param("introducerCustomerId") String introducerCustomerId);
|
||||||
@@ -28,6 +34,8 @@ public interface GaoCustomerMapper extends BaseMapper<GaoCustomer, String> {
|
|||||||
|
|
||||||
Long countInvited(@Param("introducerCustomerId") String introducerCustomerId);
|
Long countInvited(@Param("introducerCustomerId") String introducerCustomerId);
|
||||||
|
|
||||||
|
void updateInvitedCountDelta(@Param("customerId") String customerId, @Param("delta") Long delta);
|
||||||
|
|
||||||
/// 统计每日新增客户数
|
/// 统计每日新增客户数
|
||||||
///
|
///
|
||||||
/// @param beginCreatedAt 开始创建时间
|
/// @param beginCreatedAt 开始创建时间
|
||||||
@@ -40,4 +48,9 @@ public interface GaoCustomerMapper extends BaseMapper<GaoCustomer, String> {
|
|||||||
/// @param beginCreatedAt 开始创建时间
|
/// @param beginCreatedAt 开始创建时间
|
||||||
/// @return 客户总数
|
/// @return 客户总数
|
||||||
Long countCreatedBefore(@Param("beginCreatedAt") Long beginCreatedAt);
|
Long countCreatedBefore(@Param("beginCreatedAt") Long beginCreatedAt);
|
||||||
|
|
||||||
|
/// 统计客户性别分布
|
||||||
|
///
|
||||||
|
/// @return 性别统计列表
|
||||||
|
List<GaoCustomerGenderStatView> statGender();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.imyeyu.api.modules.gao.mapper;
|
|||||||
|
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent;
|
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -13,6 +14,8 @@ import java.util.List;
|
|||||||
/// @since 2026-07-27
|
/// @since 2026-07-27
|
||||||
public interface GaoRegistrationEventMapper extends BaseMapper<GaoRegistrationEvent, String> {
|
public interface GaoRegistrationEventMapper extends BaseMapper<GaoRegistrationEvent, String> {
|
||||||
|
|
||||||
@Select("SELECT * FROM `gao_registration_event` WHERE `enabled` = TRUE AND `deleted_at` IS NULL ORDER BY `sort` ASC, `created_at` ASC")
|
List<GaoRegistrationEvent> selectByIdList(@Param("idList") List<String> idList);
|
||||||
|
|
||||||
|
@Select("SELECT * FROM `gao_registration_event` WHERE `enabled` = TRUE AND (`status` IS NULL OR `status` = 'ACTIVE') AND `deleted_at` IS NULL ORDER BY `sort` ASC, `created_at` ASC")
|
||||||
List<GaoRegistrationEvent> selectEnabledList();
|
List<GaoRegistrationEvent> selectEnabledList();
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-1
@@ -3,7 +3,9 @@ package com.imyeyu.api.modules.gao.mapper;
|
|||||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord;
|
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
@@ -25,6 +27,22 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper<GaoRegistra
|
|||||||
/// @return 最后登记事件记录列表
|
/// @return 最后登记事件记录列表
|
||||||
List<GaoRegistrationEventRecord> selectByRegistrationEventAndPeriod(@Param("registrationEventId") String registrationEventId, @Param("periodType") GaoRegistrationEventRecordPeriodReq.PeriodType periodType, @Param("periodValue") Integer periodValue);
|
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
|
/// @param registrationEventId 登记事件 ID
|
||||||
@@ -104,6 +122,12 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper<GaoRegistra
|
|||||||
/// @return 登记事件记录列表
|
/// @return 登记事件记录列表
|
||||||
List<GaoRegistrationEventRecord> selectByRange(@Param("req") GaoRegistrationEventRecordRangeReq req);
|
List<GaoRegistrationEventRecord> selectByRange(@Param("req") GaoRegistrationEventRecordRangeReq req);
|
||||||
|
|
||||||
|
/// 按任意时间范围查询日历轻量记录
|
||||||
|
///
|
||||||
|
/// @param req 范围查询请求
|
||||||
|
/// @return 日历轻量记录列表
|
||||||
|
List<GaoRegistrationEventRecordCalendarView> selectCalendarByRange(@Param("req") GaoRegistrationEventRecordRangeReq req);
|
||||||
|
|
||||||
/// 按任意时间范围统计登记事件记录
|
/// 按任意时间范围统计登记事件记录
|
||||||
///
|
///
|
||||||
/// @param req 范围查询请求
|
/// @param req 范围查询请求
|
||||||
@@ -116,5 +140,5 @@ public interface GaoRegistrationEventRecordMapper extends BaseMapper<GaoRegistra
|
|||||||
/// @param offset 偏移量
|
/// @param offset 偏移量
|
||||||
/// @param size 每页条数
|
/// @param size 每页条数
|
||||||
/// @return 登记事件记录列表
|
/// @return 登记事件记录列表
|
||||||
List<GaoRegistrationEventRecord> selectPageByRange(@Param("req") GaoRegistrationEventRecordRangeReq req, @Param("offset") Long offset, @Param("size") Long size);
|
List<GaoRegistrationEventRecordListItemView> selectPageByRange(@Param("req") GaoRegistrationEventRecordRangeReq req, @Param("offset") Long offset, @Param("size") Long size);
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -18,6 +18,19 @@ public interface GaoRegistrationEventRoleRelationMapper extends BaseMapper<GaoRe
|
|||||||
@Select("SELECT `role_code` FROM `gao_registration_event_role_relation` WHERE `registration_event_id` = #{registrationEventId} AND `deleted_at` IS NULL ORDER BY `created_at` ASC")
|
@Select("SELECT `role_code` FROM `gao_registration_event_role_relation` WHERE `registration_event_id` = #{registrationEventId} AND `deleted_at` IS NULL ORDER BY `created_at` ASC")
|
||||||
List<String> selectRoleCodeListByRegistrationEventId(@Param("registrationEventId") String registrationEventId);
|
List<String> selectRoleCodeListByRegistrationEventId(@Param("registrationEventId") String registrationEventId);
|
||||||
|
|
||||||
|
@Select({
|
||||||
|
"<script>",
|
||||||
|
"SELECT * FROM `gao_registration_event_role_relation`",
|
||||||
|
"WHERE `registration_event_id` IN",
|
||||||
|
"<foreach collection='registrationEventIdList' item='registrationEventId' open='(' separator=',' close=')'>",
|
||||||
|
"#{registrationEventId}",
|
||||||
|
"</foreach>",
|
||||||
|
"AND `deleted_at` IS NULL",
|
||||||
|
"ORDER BY `created_at` ASC",
|
||||||
|
"</script>"
|
||||||
|
})
|
||||||
|
List<GaoRegistrationEventRoleRelation> selectByRegistrationEventIdList(@Param("registrationEventIdList") List<String> registrationEventIdList);
|
||||||
|
|
||||||
@Update("UPDATE `gao_registration_event_role_relation` SET `deleted_at` = UNIX_TIMESTAMP() WHERE `registration_event_id` = #{registrationEventId} AND `deleted_at` IS NULL")
|
@Update("UPDATE `gao_registration_event_role_relation` SET `deleted_at` = UNIX_TIMESTAMP() WHERE `registration_event_id` = #{registrationEventId} AND `deleted_at` IS NULL")
|
||||||
void deleteByRegistrationEventId(@Param("registrationEventId") String registrationEventId);
|
void deleteByRegistrationEventId(@Param("registrationEventId") String registrationEventId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.imyeyu.api.modules.gao.service;
|
|||||||
|
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView;
|
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.GaoCustomerInviteUpdateReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq;
|
||||||
@@ -76,4 +77,9 @@ public interface GaoCustomerService extends BaseService<GaoCustomer, String> {
|
|||||||
/// @param req 趋势统计请求
|
/// @param req 趋势统计请求
|
||||||
/// @return 每日趋势列表
|
/// @return 每日趋势列表
|
||||||
List<GaoCustomerDailyStatView> statDailyTrend(GaoCustomerTrendStatReq req);
|
List<GaoCustomerDailyStatView> statDailyTrend(GaoCustomerTrendStatReq req);
|
||||||
|
|
||||||
|
/// 统计客户性别分布
|
||||||
|
///
|
||||||
|
/// @return 性别统计列表
|
||||||
|
List<GaoCustomerGenderStatView> statGender();
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-1
@@ -4,8 +4,10 @@ import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord;
|
|||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq;
|
import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq;
|
||||||
@@ -42,11 +44,17 @@ public interface GaoRegistrationEventRecordService extends BaseService<GaoRegist
|
|||||||
/// @return 登记事件记录列表
|
/// @return 登记事件记录列表
|
||||||
List<GaoRegistrationEventRecord> listByRange(GaoRegistrationEventRecordRangeReq req);
|
List<GaoRegistrationEventRecord> listByRange(GaoRegistrationEventRecordRangeReq req);
|
||||||
|
|
||||||
|
/// 按任意时间范围查询日历轻量记录
|
||||||
|
///
|
||||||
|
/// @param req 范围查询请求
|
||||||
|
/// @return 日历轻量记录列表
|
||||||
|
List<GaoRegistrationEventRecordCalendarView> listCalendarByRange(GaoRegistrationEventRecordRangeReq req);
|
||||||
|
|
||||||
/// 按任意时间范围分页查询登记事件记录
|
/// 按任意时间范围分页查询登记事件记录
|
||||||
///
|
///
|
||||||
/// @param page 分页参数
|
/// @param page 分页参数
|
||||||
/// @return 登记事件记录分页结果
|
/// @return 登记事件记录分页结果
|
||||||
PageResult<GaoRegistrationEventRecord> pageByRange(Page<GaoRegistrationEventRecordRangeReq> page);
|
PageResult<GaoRegistrationEventRecordListItemView> pageByRange(Page<GaoRegistrationEventRecordRangeReq> page);
|
||||||
|
|
||||||
/// 按任意时间范围导出登记事件记录 Excel
|
/// 按任意时间范围导出登记事件记录 Excel
|
||||||
///
|
///
|
||||||
|
|||||||
+122
-17
@@ -7,7 +7,10 @@ import com.imyeyu.api.modules.common.vo.attach.BizUpdateReq;
|
|||||||
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoCustomerMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoCustomerMapper;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
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.GaoCustomerDailyStatView;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerInviteUpdateReq;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerInviteUpdateReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerSearchReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStatReq;
|
||||||
@@ -39,6 +42,8 @@ import java.util.ArrayList;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// 客户服务实现
|
/// 客户服务实现
|
||||||
@@ -54,6 +59,8 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
|
|
||||||
private final GaoCustomerMapper mapper;
|
private final GaoCustomerMapper mapper;
|
||||||
private final AttachmentService attachmentService;
|
private final AttachmentService attachmentService;
|
||||||
|
private final UserLoginService userLoginService;
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BaseMapper<GaoCustomer, String> mapper() {
|
protected BaseMapper<GaoCustomer, String> mapper() {
|
||||||
@@ -63,22 +70,34 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
@Override
|
@Override
|
||||||
public void create(GaoCustomer entity) {
|
public void create(GaoCustomer entity) {
|
||||||
checkEntity(entity, false);
|
checkEntity(entity, false);
|
||||||
|
entity.setCreatorUserId(userLoginService.getRequireLoginUserId());
|
||||||
|
entity.setInvitedCount(0L);
|
||||||
super.create(entity);
|
super.create(entity);
|
||||||
saveAttachment(entity.getId(), resolveAttachmentList(entity));
|
saveAttachment(entity.getId(), resolveAttachmentList(entity));
|
||||||
loadTransient(entity);
|
changeInvitedCount(entity.getIntroducerCustomerId(), 1L);
|
||||||
|
loadDetailTransient(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void update(GaoCustomer entity) {
|
public void update(GaoCustomer entity) {
|
||||||
checkEntity(entity, true);
|
GaoCustomer dbCustomer = checkEntity(entity, true);
|
||||||
super.update(entity);
|
super.update(entity);
|
||||||
saveAttachment(entity.getId(), resolveAttachmentList(entity));
|
saveAttachment(entity.getId(), resolveAttachmentList(entity));
|
||||||
|
syncIntroducerInvitedCount(dbCustomer.getIntroducerCustomerId(), entity.getIntroducerCustomerId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void delete(String id) {
|
||||||
|
GaoCustomer customer = super.get(id);
|
||||||
|
super.delete(id);
|
||||||
|
changeInvitedCount(customer.getIntroducerCustomerId(), -1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GaoCustomer get(String id) {
|
public GaoCustomer get(String id) {
|
||||||
GaoCustomer customer = super.get(id);
|
GaoCustomer customer = super.get(id);
|
||||||
loadTransient(customer);
|
loadDetailTransient(customer);
|
||||||
return customer;
|
return customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +106,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
TimiException.required(code, "not found customer.code");
|
TimiException.required(code, "not found customer.code");
|
||||||
GaoCustomer customer = mapper.selectByCode(code);
|
GaoCustomer customer = mapper.selectByCode(code);
|
||||||
TimiException.required(customer, "not found customer");
|
TimiException.required(customer, "not found customer");
|
||||||
loadTransient(customer);
|
loadDetailTransient(customer);
|
||||||
return customer;
|
return customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +114,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
public GaoCustomer getNullableByCode(String code) {
|
public GaoCustomer getNullableByCode(String code) {
|
||||||
TimiException.required(code, "not found customer.code");
|
TimiException.required(code, "not found customer.code");
|
||||||
GaoCustomer customer = mapper.selectByCode(code);
|
GaoCustomer customer = mapper.selectByCode(code);
|
||||||
loadTransient(customer);
|
loadDetailTransient(customer);
|
||||||
return customer;
|
return customer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +136,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
public List<GaoCustomer> search(GaoCustomerSearchReq req) {
|
public List<GaoCustomer> search(GaoCustomerSearchReq req) {
|
||||||
req = resolveSearchReq(req);
|
req = resolveSearchReq(req);
|
||||||
List<GaoCustomer> list = mapper.search(req.getKeyword(), req.getIntroducerCustomerId());
|
List<GaoCustomer> list = mapper.search(req.getKeyword(), req.getIntroducerCustomerId());
|
||||||
list.forEach(this::loadTransient);
|
loadListTransient(list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +150,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
GaoCustomerSearchReq req = resolveSearchReq(page.getEqualsExample());
|
GaoCustomerSearchReq req = resolveSearchReq(page.getEqualsExample());
|
||||||
Long total = TimiJava.defaultIfNull(mapper.countSearch(req.getKeyword(), req.getIntroducerCustomerId()), 0L);
|
Long total = TimiJava.defaultIfNull(mapper.countSearch(req.getKeyword(), req.getIntroducerCustomerId()), 0L);
|
||||||
List<GaoCustomer> list = mapper.searchPage(req.getKeyword(), req.getIntroducerCustomerId(), page.getIndex() * page.getSize(), page.getSize());
|
List<GaoCustomer> list = mapper.searchPage(req.getKeyword(), req.getIntroducerCustomerId(), page.getIndex() * page.getSize(), page.getSize());
|
||||||
list.forEach(this::loadTransient);
|
loadListTransient(list);
|
||||||
PageResult<GaoCustomer> result = new PageResult<>();
|
PageResult<GaoCustomer> result = new PageResult<>();
|
||||||
result.setTotal(total);
|
result.setTotal(total);
|
||||||
result.setList(list);
|
result.setList(list);
|
||||||
@@ -141,6 +160,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
@Override
|
@Override
|
||||||
public byte[] exportSearchExcel(GaoCustomerSearchReq req) throws IOException {
|
public byte[] exportSearchExcel(GaoCustomerSearchReq req) throws IOException {
|
||||||
List<GaoCustomer> list = search(req);
|
List<GaoCustomer> list = search(req);
|
||||||
|
loadIntroducerCustomer(list);
|
||||||
try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||||
Sheet sheet = workbook.createSheet("客户列表");
|
Sheet sheet = workbook.createSheet("客户列表");
|
||||||
CellStyle titleStyle = workbook.createCellStyle();
|
CellStyle titleStyle = workbook.createCellStyle();
|
||||||
@@ -188,7 +208,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
public List<GaoCustomer> listInvited(String introducerCustomerId) {
|
public List<GaoCustomer> listInvited(String introducerCustomerId) {
|
||||||
TimiException.required(introducerCustomerId, "not found introducerCustomerId");
|
TimiException.required(introducerCustomerId, "not found introducerCustomerId");
|
||||||
List<GaoCustomer> list = mapper.selectInvitedList(introducerCustomerId);
|
List<GaoCustomer> list = mapper.selectInvitedList(introducerCustomerId);
|
||||||
list.forEach(this::loadTransient);
|
loadListTransient(list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,9 +218,11 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
TimiException.required(req, "not found invite req");
|
TimiException.required(req, "not found invite req");
|
||||||
TimiException.required(req.getCustomerId(), "not found invite req.customerId");
|
TimiException.required(req.getCustomerId(), "not found invite req.customerId");
|
||||||
GaoCustomer customer = super.get(req.getCustomerId());
|
GaoCustomer customer = super.get(req.getCustomerId());
|
||||||
|
String oldIntroducerCustomerId = customer.getIntroducerCustomerId();
|
||||||
customer.setIntroducerCustomerId(req.getIntroducerCustomerId());
|
customer.setIntroducerCustomerId(req.getIntroducerCustomerId());
|
||||||
checkEntity(customer, true);
|
checkEntity(customer, true);
|
||||||
super.update(customer);
|
super.update(customer);
|
||||||
|
syncIntroducerInvitedCount(oldIntroducerCustomerId, customer.getIntroducerCustomerId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@@ -208,8 +230,10 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
public void deleteInviteRelation(String customerId) {
|
public void deleteInviteRelation(String customerId) {
|
||||||
TimiException.required(customerId, "not found customerId");
|
TimiException.required(customerId, "not found customerId");
|
||||||
GaoCustomer customer = super.get(customerId);
|
GaoCustomer customer = super.get(customerId);
|
||||||
|
String oldIntroducerCustomerId = customer.getIntroducerCustomerId();
|
||||||
customer.setIntroducerCustomerId(null);
|
customer.setIntroducerCustomerId(null);
|
||||||
super.update(customer);
|
super.update(customer);
|
||||||
|
changeInvitedCount(oldIntroducerCustomerId, -1L);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -243,6 +267,11 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GaoCustomerGenderStatView> statGender() {
|
||||||
|
return mapper.statGender();
|
||||||
|
}
|
||||||
|
|
||||||
private void checkDailyStatRange(LocalDate beginDate, LocalDate endDate) {
|
private void checkDailyStatRange(LocalDate beginDate, LocalDate endDate) {
|
||||||
long days = ChronoUnit.DAYS.between(beginDate, endDate) + 1;
|
long days = ChronoUnit.DAYS.between(beginDate, endDate) + 1;
|
||||||
TimiException.requiredTrue(days <= 366, "daily stat range too large");
|
TimiException.requiredTrue(days <= 366, "daily stat range too large");
|
||||||
@@ -252,33 +281,109 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
return req == null ? new GaoCustomerSearchReq() : req;
|
return req == null ? new GaoCustomerSearchReq() : req;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkEntity(GaoCustomer entity, boolean requireId) {
|
private GaoCustomer checkEntity(GaoCustomer entity, boolean requireId) {
|
||||||
TimiException.required(entity, "not found customer");
|
TimiException.required(entity, "not found customer");
|
||||||
|
GaoCustomer dbCustomer = null;
|
||||||
|
entity.setCode(normalizeText(entity.getCode()));
|
||||||
|
entity.setIntroducerCustomerId(normalizeText(entity.getIntroducerCustomerId()));
|
||||||
if (requireId) {
|
if (requireId) {
|
||||||
TimiException.required(entity.getId(), "not found customer.id");
|
TimiException.required(entity.getId(), "not found customer.id");
|
||||||
|
dbCustomer = super.get(entity.getId());
|
||||||
|
entity.setCreatorUserId(dbCustomer.getCreatorUserId());
|
||||||
}
|
}
|
||||||
TimiException.required(entity.getName(), "not found customer.name");
|
TimiException.required(entity.getName(), "not found customer.name");
|
||||||
|
entity.setName(entity.getName().trim());
|
||||||
|
TimiException.requiredTrue(!entity.getName().isEmpty(), "not found customer.name");
|
||||||
|
GaoCustomer duplicateCustomer = mapper.selectByName(entity.getName());
|
||||||
|
if (duplicateCustomer != null && !duplicateCustomer.getId().equals(entity.getId())) {
|
||||||
|
throw new TimiException(TimiCode.ARG_BAD, "客户姓名已存在");
|
||||||
|
}
|
||||||
if (TimiJava.isNotEmpty(entity.getCode())) {
|
if (TimiJava.isNotEmpty(entity.getCode())) {
|
||||||
GaoCustomer dbCustomer = mapper.selectByCode(entity.getCode());
|
duplicateCustomer = mapper.selectByCode(entity.getCode());
|
||||||
if (dbCustomer != null && !dbCustomer.getId().equals(entity.getId())) {
|
if (duplicateCustomer != null && !duplicateCustomer.getId().equals(entity.getId())) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("客户编码已存在");
|
throw new TimiException(TimiCode.ARG_BAD, "客户编码已存在");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (TimiJava.isNotEmpty(entity.getIntroducerCustomerId())) {
|
if (TimiJava.isNotEmpty(entity.getIntroducerCustomerId())) {
|
||||||
TimiException.requiredTrue(!entity.getIntroducerCustomerId().equals(entity.getId()), "customer.introducerCustomerId invalid");
|
TimiException.requiredTrue(!entity.getIntroducerCustomerId().equals(entity.getId()), "customer.introducerCustomerId invalid");
|
||||||
TimiException.required(super.get(entity.getIntroducerCustomerId()), "not found introducer customer");
|
TimiException.required(super.get(entity.getIntroducerCustomerId()), "not found introducer customer");
|
||||||
}
|
}
|
||||||
|
return dbCustomer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadTransient(GaoCustomer customer) {
|
private void loadDetailTransient(GaoCustomer customer) {
|
||||||
if (customer == null) {
|
if (customer == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (TimiJava.isNotEmpty(customer.getIntroducerCustomerId())) {
|
loadIntroducerCustomer(List.of(customer));
|
||||||
customer.setIntroducerCustomer(super.get(customer.getIntroducerCustomerId()));
|
if (TimiJava.isNotEmpty(customer.getCreatorUserId())) {
|
||||||
|
customer.setCreatorUser(userService.get(customer.getCreatorUserId()));
|
||||||
}
|
}
|
||||||
customer.setInvitedCount(mapper.countInvited(customer.getId()));
|
loadAttachmentList(List.of(customer));
|
||||||
customer.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.GAO_CUSTOMER, customer.getId(), GaoCustomer.AttachType.PHOTO.name()));
|
}
|
||||||
|
|
||||||
|
private void loadListTransient(List<GaoCustomer> customerList) {
|
||||||
|
loadAttachmentList(customerList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadIntroducerCustomer(List<GaoCustomer> customerList) {
|
||||||
|
if (customerList == null || customerList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<String> introducerCustomerIdList = customerList.stream()
|
||||||
|
.map(GaoCustomer::getIntroducerCustomerId)
|
||||||
|
.filter(TimiJava::isNotEmpty)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
if (introducerCustomerIdList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, GaoCustomer> introducerCustomerMap = mapper.selectByIdList(new ArrayList<>(introducerCustomerIdList)).stream()
|
||||||
|
.collect(Collectors.toMap(GaoCustomer::getId, item -> item, (left, right) -> left));
|
||||||
|
for (GaoCustomer customer : customerList) {
|
||||||
|
customer.setIntroducerCustomer(introducerCustomerMap.get(customer.getIntroducerCustomerId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAttachmentList(List<GaoCustomer> customerList) {
|
||||||
|
if (customerList == null || customerList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<String> customerIdList = customerList.stream()
|
||||||
|
.map(GaoCustomer::getId)
|
||||||
|
.filter(TimiJava::isNotEmpty)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
Map<String, List<Attachment>> attachmentMap = attachmentService.mapByBizIdList(Attachment.BizType.GAO_CUSTOMER, customerIdList, GaoCustomer.AttachType.PHOTO.name());
|
||||||
|
for (GaoCustomer customer : customerList) {
|
||||||
|
customer.setAttachmentList(attachmentMap.getOrDefault(customer.getId(), List.of()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void syncIntroducerInvitedCount(String oldIntroducerCustomerId, String newIntroducerCustomerId) {
|
||||||
|
String normalizedOldIntroducerCustomerId = normalizeText(oldIntroducerCustomerId);
|
||||||
|
String normalizedNewIntroducerCustomerId = normalizeText(newIntroducerCustomerId);
|
||||||
|
if (Objects.equals(normalizedOldIntroducerCustomerId, normalizedNewIntroducerCustomerId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
changeInvitedCount(normalizedOldIntroducerCustomerId, -1L);
|
||||||
|
changeInvitedCount(normalizedNewIntroducerCustomerId, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void changeInvitedCount(String customerId, long delta) {
|
||||||
|
String normalizedCustomerId = normalizeText(customerId);
|
||||||
|
if (normalizedCustomerId == null || delta == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mapper.updateInvitedCountDelta(normalizedCustomerId, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String normalizeText(String value) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String trimmedValue = value.trim();
|
||||||
|
return trimmedValue.isEmpty() ? null : trimmedValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveAttachment(String customerId, List<Attachment> attachmentList) {
|
private void saveAttachment(String customerId, List<Attachment> attachmentList) {
|
||||||
|
|||||||
+140
-17
@@ -8,6 +8,8 @@ import com.imyeyu.api.modules.common.vo.attach.BizUpdateReq;
|
|||||||
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent;
|
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord;
|
import com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord;
|
||||||
|
import com.imyeyu.api.modules.gao.mapper.GaoCustomerMapper;
|
||||||
|
import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventMapper;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventRecordMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventRecordMapper;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService;
|
import com.imyeyu.api.modules.gao.service.GaoRegistrationEventService;
|
||||||
@@ -15,8 +17,10 @@ import com.imyeyu.api.modules.gao.service.GaoRegistrationEventRecordService;
|
|||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerRegisterStatView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq;
|
import com.imyeyu.api.modules.gao.vo.GaoQuickRegistrationEventRecordReq;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCreateReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordDailyStatView;
|
||||||
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordPeriodReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordRangeReq;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq;
|
import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordStatReq;
|
||||||
@@ -24,6 +28,7 @@ import com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordTrendStatReq;
|
|||||||
import com.imyeyu.api.modules.user.service.RoleChecker;
|
import com.imyeyu.api.modules.user.service.RoleChecker;
|
||||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||||
import com.imyeyu.api.modules.user.service.UserService;
|
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.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
@@ -55,6 +60,8 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.StringJoiner;
|
import java.util.StringJoiner;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// 登记事件记录服务实现
|
/// 登记事件记录服务实现
|
||||||
@@ -69,6 +76,9 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
|
private static final DateTimeFormatter EXPORT_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
|
||||||
|
|
||||||
private final GaoRegistrationEventRecordMapper mapper;
|
private final GaoRegistrationEventRecordMapper mapper;
|
||||||
|
private final GaoCustomerMapper customerMapper;
|
||||||
|
private final GaoRegistrationEventMapper registrationEventMapper;
|
||||||
|
private final UserMapper userMapper;
|
||||||
private final AttachmentService attachmentService;
|
private final AttachmentService attachmentService;
|
||||||
private final RoleChecker roleChecker;
|
private final RoleChecker roleChecker;
|
||||||
private final UserLoginService userLoginService;
|
private final UserLoginService userLoginService;
|
||||||
@@ -89,6 +99,8 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
String customerId = resolveCustomerId(req);
|
String customerId = resolveCustomerId(req);
|
||||||
GaoRegistrationEvent registrationEvent = registrationEventService.get(req.getRegistrationEventId());
|
GaoRegistrationEvent registrationEvent = registrationEventService.get(req.getRegistrationEventId());
|
||||||
checkRegistrationEventPermission(registrationEvent);
|
checkRegistrationEventPermission(registrationEvent);
|
||||||
|
long registeredAt = TimiJava.defaultIfNull(req.getRegisteredAt(), Time.now());
|
||||||
|
checkRegistrationEventCreatable(registrationEvent, customerId, registeredAt);
|
||||||
if (Boolean.TRUE.equals(registrationEvent.getRequirePhoto())) {
|
if (Boolean.TRUE.equals(registrationEvent.getRequirePhoto())) {
|
||||||
TimiException.requiredTrue(req.getAttachmentIdList() != null && !req.getAttachmentIdList().isEmpty(), "required record photo");
|
TimiException.requiredTrue(req.getAttachmentIdList() != null && !req.getAttachmentIdList().isEmpty(), "required record photo");
|
||||||
}
|
}
|
||||||
@@ -98,7 +110,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
record.setRegistrationEventId(req.getRegistrationEventId());
|
record.setRegistrationEventId(req.getRegistrationEventId());
|
||||||
record.setOperatorUserId(userLoginService.getRequireLoginUserId());
|
record.setOperatorUserId(userLoginService.getRequireLoginUserId());
|
||||||
record.setRemark(req.getRemark());
|
record.setRemark(req.getRemark());
|
||||||
record.setRegisteredAt(TimiJava.defaultIfNull(req.getRegisteredAt(), Time.now()));
|
record.setRegisteredAt(registeredAt);
|
||||||
super.create(record);
|
super.create(record);
|
||||||
saveAttachment(record.getId(), buildPhotoAttachmentList(req.getAttachmentIdList()));
|
saveAttachment(record.getId(), buildPhotoAttachmentList(req.getAttachmentIdList()));
|
||||||
return get(record.getId());
|
return get(record.getId());
|
||||||
@@ -137,7 +149,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
@Override
|
@Override
|
||||||
public GaoRegistrationEventRecord get(String id) {
|
public GaoRegistrationEventRecord get(String id) {
|
||||||
GaoRegistrationEventRecord record = super.get(id);
|
GaoRegistrationEventRecord record = super.get(id);
|
||||||
loadTransient(record);
|
loadTransient(List.of(record));
|
||||||
return record;
|
return record;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +160,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
TimiException.required(req.getPeriodType(), "not found req.periodType");
|
TimiException.required(req.getPeriodType(), "not found req.periodType");
|
||||||
TimiException.required(req.getPeriodValue(), "not found req.periodValue");
|
TimiException.required(req.getPeriodValue(), "not found req.periodValue");
|
||||||
List<GaoRegistrationEventRecord> list = mapper.selectByRegistrationEventAndPeriod(req.getRegistrationEventId(), req.getPeriodType(), req.getPeriodValue());
|
List<GaoRegistrationEventRecord> list = mapper.selectByRegistrationEventAndPeriod(req.getRegistrationEventId(), req.getPeriodType(), req.getPeriodValue());
|
||||||
list.forEach(this::loadTransient);
|
loadTransient(list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,12 +169,19 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
TimiException.required(req, "not found req");
|
TimiException.required(req, "not found req");
|
||||||
checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt());
|
checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt());
|
||||||
List<GaoRegistrationEventRecord> list = mapper.selectByRange(req);
|
List<GaoRegistrationEventRecord> list = mapper.selectByRange(req);
|
||||||
list.forEach(this::loadTransient);
|
loadTransient(list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<GaoRegistrationEventRecord> pageByRange(Page<GaoRegistrationEventRecordRangeReq> page) {
|
public List<GaoRegistrationEventRecordCalendarView> listCalendarByRange(GaoRegistrationEventRecordRangeReq req) {
|
||||||
|
TimiException.required(req, "not found req");
|
||||||
|
checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt());
|
||||||
|
return mapper.selectCalendarByRange(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PageResult<GaoRegistrationEventRecordListItemView> pageByRange(Page<GaoRegistrationEventRecordRangeReq> page) {
|
||||||
TimiException.required(page, "not found page");
|
TimiException.required(page, "not found page");
|
||||||
TimiException.required(page.getIndex(), "not found page.index");
|
TimiException.required(page.getIndex(), "not found page.index");
|
||||||
TimiException.required(page.getSize(), "not found page.size");
|
TimiException.required(page.getSize(), "not found page.size");
|
||||||
@@ -171,9 +190,8 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
GaoRegistrationEventRecordRangeReq req = TimiJava.defaultIfNull(page.getEqualsExample(), new GaoRegistrationEventRecordRangeReq());
|
GaoRegistrationEventRecordRangeReq req = TimiJava.defaultIfNull(page.getEqualsExample(), new GaoRegistrationEventRecordRangeReq());
|
||||||
checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt());
|
checkStatRange(req.getBeginRegisteredAt(), req.getEndRegisteredAt());
|
||||||
Long total = TimiJava.defaultIfNull(mapper.countByRange(req), 0L);
|
Long total = TimiJava.defaultIfNull(mapper.countByRange(req), 0L);
|
||||||
List<GaoRegistrationEventRecord> list = mapper.selectPageByRange(req, page.getIndex() * page.getSize(), page.getSize());
|
List<GaoRegistrationEventRecordListItemView> list = mapper.selectPageByRange(req, page.getIndex() * page.getSize(), page.getSize());
|
||||||
list.forEach(this::loadTransient);
|
PageResult<GaoRegistrationEventRecordListItemView> result = new PageResult<>();
|
||||||
PageResult<GaoRegistrationEventRecord> result = new PageResult<>();
|
|
||||||
result.setTotal(total);
|
result.setTotal(total);
|
||||||
result.setList(list);
|
result.setList(list);
|
||||||
return result;
|
return result;
|
||||||
@@ -236,7 +254,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
List<GaoRegistrationEventRecord> list = mapper.selectLatestByCustomerIdListAndRegistrationEventId(customerIdList, registrationEventId);
|
List<GaoRegistrationEventRecord> list = mapper.selectLatestByCustomerIdListAndRegistrationEventId(customerIdList, registrationEventId);
|
||||||
list.forEach(this::loadTransient);
|
loadTransient(list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -279,7 +297,7 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
public List<GaoRegistrationEventRecord> listLatestByCustomerId(String customerId) {
|
public List<GaoRegistrationEventRecord> listLatestByCustomerId(String customerId) {
|
||||||
TimiException.required(customerId, "not found customerId");
|
TimiException.required(customerId, "not found customerId");
|
||||||
List<GaoRegistrationEventRecord> list = mapper.selectLatestByCustomerId(customerId);
|
List<GaoRegistrationEventRecord> list = mapper.selectLatestByCustomerId(customerId);
|
||||||
list.forEach(this::loadTransient);
|
loadTransient(list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -300,6 +318,76 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkRegistrationEventCreatable(GaoRegistrationEvent registrationEvent, String customerId, long registeredAt) {
|
||||||
|
TimiException.requiredTrue(Boolean.TRUE.equals(registrationEvent.getEnabled()), "登记事件未启用");
|
||||||
|
TimiException.requiredTrue(registrationEvent.getStatus() == null || registrationEvent.getStatus() == GaoRegistrationEvent.Status.ACTIVE, "登记事件不可登记");
|
||||||
|
GaoRegistrationEvent.RegistrationLimitType limitType = TimiJava.defaultIfNull(registrationEvent.getLimitType(), GaoRegistrationEvent.RegistrationLimitType.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, 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 checkTotalRegistrationLimit(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 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) {
|
private void checkStatRange(Long beginRegisteredAt, Long endRegisteredAt) {
|
||||||
TimiException.required(beginRegisteredAt, "not found beginRegisteredAt");
|
TimiException.required(beginRegisteredAt, "not found beginRegisteredAt");
|
||||||
TimiException.required(endRegisteredAt, "not found endRegisteredAt");
|
TimiException.required(endRegisteredAt, "not found endRegisteredAt");
|
||||||
@@ -340,16 +428,51 @@ public class GaoRegistrationEventRecordServiceImplement extends AbstractEntitySe
|
|||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadTransient(GaoRegistrationEventRecord record) {
|
private void loadTransient(List<GaoRegistrationEventRecord> recordList) {
|
||||||
if (record == null) {
|
if (recordList == null || recordList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
record.setCustomer(customerService.get(record.getCustomerId()));
|
List<String> customerIdList = recordList.stream()
|
||||||
record.setRegistrationEvent(registrationEventService.get(record.getRegistrationEventId()));
|
.map(GaoRegistrationEventRecord::getCustomerId)
|
||||||
if (TimiJava.isNotEmpty(record.getOperatorUserId())) {
|
.filter(TimiJava::isNotEmpty)
|
||||||
record.setOperator(userService.get(record.getOperatorUserId()));
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
Map<String, GaoCustomer> customerMap = customerMapper.selectByIdList(new ArrayList<>(customerIdList)).stream()
|
||||||
|
.collect(Collectors.toMap(GaoCustomer::getId, Function.identity(), (left, right) -> left));
|
||||||
|
|
||||||
|
List<String> registrationEventIdList = recordList.stream()
|
||||||
|
.map(GaoRegistrationEventRecord::getRegistrationEventId)
|
||||||
|
.filter(TimiJava::isNotEmpty)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
Map<String, GaoRegistrationEvent> registrationEventMap = registrationEventMapper.selectByIdList(new ArrayList<>(registrationEventIdList)).stream()
|
||||||
|
.collect(Collectors.toMap(GaoRegistrationEvent::getId, Function.identity(), (left, right) -> left));
|
||||||
|
|
||||||
|
List<String> operatorUserIdList = recordList.stream()
|
||||||
|
.map(GaoRegistrationEventRecord::getOperatorUserId)
|
||||||
|
.filter(TimiJava::isNotEmpty)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
Map<String, com.imyeyu.api.modules.user.entity.User> userMap = userMapper.listByIdList(new ArrayList<>(operatorUserIdList)).stream()
|
||||||
|
.collect(Collectors.toMap(com.imyeyu.api.modules.user.entity.User::getId, Function.identity(), (left, right) -> left));
|
||||||
|
|
||||||
|
List<String> recordIdList = recordList.stream()
|
||||||
|
.map(GaoRegistrationEventRecord::getId)
|
||||||
|
.filter(TimiJava::isNotEmpty)
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
Map<String, List<Attachment>> attachmentMap = attachmentService.mapByBizIdList(
|
||||||
|
Attachment.BizType.GAO_REGISTRATION_EVENT_RECORD,
|
||||||
|
recordIdList,
|
||||||
|
GaoRegistrationEventRecord.AttachType.PHOTO.name()
|
||||||
|
);
|
||||||
|
|
||||||
|
for (GaoRegistrationEventRecord record : recordList) {
|
||||||
|
record.setCustomer(customerMap.get(record.getCustomerId()));
|
||||||
|
record.setRegistrationEvent(registrationEventMap.get(record.getRegistrationEventId()));
|
||||||
|
record.setOperator(userMap.get(record.getOperatorUserId()));
|
||||||
|
record.setAttachmentList(attachmentMap.getOrDefault(record.getId(), List.of()));
|
||||||
}
|
}
|
||||||
record.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.GAO_REGISTRATION_EVENT_RECORD, record.getId(), GaoRegistrationEventRecord.AttachType.PHOTO.name()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDailyStatRange(LocalDate beginDate, LocalDate endDate) {
|
private void checkDailyStatRange(LocalDate beginDate, LocalDate endDate) {
|
||||||
|
|||||||
+50
-6
@@ -15,9 +15,12 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// 登记事件服务实现
|
/// 登记事件服务实现
|
||||||
@@ -39,9 +42,10 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
|||||||
@Override
|
@Override
|
||||||
public PageResult<GaoRegistrationEvent> pageWithRegistrationEventLimit(Page<GaoRegistrationEvent> page) {
|
public PageResult<GaoRegistrationEvent> pageWithRegistrationEventLimit(Page<GaoRegistrationEvent> page) {
|
||||||
PageResult<GaoRegistrationEvent> result = page(page);
|
PageResult<GaoRegistrationEvent> result = page(page);
|
||||||
if (result.getList() != null) {
|
result.setList(result.getList().stream()
|
||||||
result.getList().forEach(this::loadRegistrationEventLimit);
|
.filter(item -> item.getStatus() != GaoRegistrationEvent.Status.DELETED)
|
||||||
}
|
.toList());
|
||||||
|
loadRegistrationEventLimit(result.getList());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,8 +68,10 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
|||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
public void delete(String id) {
|
public void delete(String id) {
|
||||||
roleRelationMapper.deleteByRegistrationEventId(id);
|
GaoRegistrationEvent entity = get(id);
|
||||||
super.delete(id);
|
entity.setStatus(GaoRegistrationEvent.Status.DELETED);
|
||||||
|
entity.setEnabled(false);
|
||||||
|
super.update(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,7 +84,7 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
|||||||
@Override
|
@Override
|
||||||
public List<GaoRegistrationEvent> listEnabled() {
|
public List<GaoRegistrationEvent> listEnabled() {
|
||||||
List<GaoRegistrationEvent> list = mapper.selectEnabledList();
|
List<GaoRegistrationEvent> list = mapper.selectEnabledList();
|
||||||
list.forEach(this::loadRegistrationEventLimit);
|
loadRegistrationEventLimit(list);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,17 +99,37 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
|||||||
TimiException.required(entity.getId(), "not found registrationEvent.id");
|
TimiException.required(entity.getId(), "not found registrationEvent.id");
|
||||||
}
|
}
|
||||||
TimiException.required(entity.getName(), "not found registrationEvent.name");
|
TimiException.required(entity.getName(), "not found registrationEvent.name");
|
||||||
|
if (entity.getStatus() == null) {
|
||||||
|
entity.setStatus(GaoRegistrationEvent.Status.ACTIVE);
|
||||||
|
}
|
||||||
if (entity.getEnabled() == null) {
|
if (entity.getEnabled() == null) {
|
||||||
entity.setEnabled(true);
|
entity.setEnabled(true);
|
||||||
}
|
}
|
||||||
if (entity.getRequirePhoto() == null) {
|
if (entity.getRequirePhoto() == null) {
|
||||||
entity.setRequirePhoto(false);
|
entity.setRequirePhoto(false);
|
||||||
}
|
}
|
||||||
|
if (entity.getLimitType() == null) {
|
||||||
|
entity.setLimitType(GaoRegistrationEvent.RegistrationLimitType.NONE);
|
||||||
|
}
|
||||||
|
checkRegistrationLimit(entity);
|
||||||
|
if (entity.getColor() != null) {
|
||||||
|
entity.setColor(entity.getColor().trim());
|
||||||
|
}
|
||||||
if (entity.getSort() == null) {
|
if (entity.getSort() == null) {
|
||||||
entity.setSort(0);
|
entity.setSort(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkRegistrationLimit(GaoRegistrationEvent entity) {
|
||||||
|
if (entity.getLimitType() == GaoRegistrationEvent.RegistrationLimitType.INTERVAL_HOUR
|
||||||
|
|| entity.getLimitType() == GaoRegistrationEvent.RegistrationLimitType.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 saveRoleRelation(String registrationEventId, List<String> roleCodeList) {
|
private void saveRoleRelation(String registrationEventId, List<String> roleCodeList) {
|
||||||
roleRelationMapper.deleteByRegistrationEventId(registrationEventId);
|
roleRelationMapper.deleteByRegistrationEventId(registrationEventId);
|
||||||
if (roleCodeList == null || roleCodeList.isEmpty()) {
|
if (roleCodeList == null || roleCodeList.isEmpty()) {
|
||||||
@@ -124,4 +150,22 @@ public class GaoRegistrationEventServiceImplement extends AbstractEntityService<
|
|||||||
private void loadRegistrationEventLimit(GaoRegistrationEvent registrationEvent) {
|
private void loadRegistrationEventLimit(GaoRegistrationEvent registrationEvent) {
|
||||||
registrationEvent.setRoleCodeList(roleRelationMapper.selectRoleCodeListByRegistrationEventId(registrationEvent.getId()));
|
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())
|
||||||
|
));
|
||||||
|
for (GaoRegistrationEvent registrationEvent : registrationEventList) {
|
||||||
|
registrationEvent.setRoleCodeList(roleCodeMap.getOrDefault(registrationEvent.getId(), List.of()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -18,6 +18,7 @@ import com.imyeyu.spring.bean.Page;
|
|||||||
import com.imyeyu.spring.bean.PageResult;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
|
import com.imyeyu.utils.Time;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
@@ -98,7 +99,7 @@ public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, Stri
|
|||||||
TimiException.required(userMapper.select(entity.getUserId()), "not found user");
|
TimiException.required(userMapper.select(entity.getUserId()), "not found user");
|
||||||
GaoUser dbGaoUser = mapper.selectByUserId(entity.getUserId());
|
GaoUser dbGaoUser = mapper.selectByUserId(entity.getUserId());
|
||||||
if (dbGaoUser != null && !dbGaoUser.getId().equals(entity.getId())) {
|
if (dbGaoUser != null && !dbGaoUser.getId().equals(entity.getId())) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("GAO 用户已存在");
|
throw new TimiException(TimiCode.ARG_BAD, "GAO 用户已存在");
|
||||||
}
|
}
|
||||||
if (entity.getEnabled() == null) {
|
if (entity.getEnabled() == null) {
|
||||||
entity.setEnabled(true);
|
entity.setEnabled(true);
|
||||||
@@ -112,6 +113,7 @@ public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, Stri
|
|||||||
}
|
}
|
||||||
User user = entity.getUser();
|
User user = entity.getUser();
|
||||||
TimiException.required(user, "not found gao user.user");
|
TimiException.required(user, "not found gao user.user");
|
||||||
|
user.setPhoneNoVerifyAt(TimiJava.defaultIfNull(user.getPhoneNoVerifyAt(), Time.now()));
|
||||||
userService.create(user);
|
userService.create(user);
|
||||||
entity.setUserId(user.getId());
|
entity.setUserId(user.getId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 客户性别统计视图
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-01
|
||||||
|
@Data
|
||||||
|
public class GaoCustomerGenderStatView {
|
||||||
|
|
||||||
|
/// 性别编码,未知时为 UNKNOWN
|
||||||
|
private String genderCode;
|
||||||
|
|
||||||
|
/// 客户数量
|
||||||
|
private Long count;
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 登记事件记录日历轻量视图
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-01
|
||||||
|
@Data
|
||||||
|
public class GaoRegistrationEventRecordCalendarView {
|
||||||
|
|
||||||
|
/// 记录 ID
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/// 客户 ID
|
||||||
|
private String customerId;
|
||||||
|
|
||||||
|
/// 客户编码
|
||||||
|
private String customerCode;
|
||||||
|
|
||||||
|
/// 客户姓名
|
||||||
|
private String customerName;
|
||||||
|
|
||||||
|
/// 登记事件 ID
|
||||||
|
private String registrationEventId;
|
||||||
|
|
||||||
|
/// 登记时间
|
||||||
|
private Long registeredAt;
|
||||||
|
}
|
||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 登记事件记录列表项视图
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-01
|
||||||
|
@Data
|
||||||
|
public class GaoRegistrationEventRecordListItemView {
|
||||||
|
|
||||||
|
/// 记录 ID
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
/// 客户 ID
|
||||||
|
private String customerId;
|
||||||
|
|
||||||
|
/// 客户姓名
|
||||||
|
private String customerName;
|
||||||
|
|
||||||
|
/// 客户头像附件 ID
|
||||||
|
private String customerPhotoAttachmentId;
|
||||||
|
|
||||||
|
/// 登记事件 ID
|
||||||
|
private String registrationEventId;
|
||||||
|
|
||||||
|
/// 登记事件名称
|
||||||
|
private String registrationEventName;
|
||||||
|
|
||||||
|
/// 登记时间
|
||||||
|
private Long registeredAt;
|
||||||
|
}
|
||||||
@@ -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<>();
|
|
||||||
}
|
|
||||||
@@ -45,7 +45,7 @@ public class JournalAPIInterceptor implements HandlerInterceptor {
|
|||||||
requiredUploadPermission = handlerMethod.getMethodAnnotation(RequiredUploadPermission.class) != null;
|
requiredUploadPermission = handlerMethod.getMethodAnnotation(RequiredUploadPermission.class) != null;
|
||||||
}
|
}
|
||||||
if (!canAccess()) {
|
if (!canAccess()) {
|
||||||
throw new TimiException(TimiCode.PERMISSION_MISS).msgKey("invalid.key");
|
throw new TimiException(TimiCode.PERMISSION_MISS, "invalid.key");
|
||||||
}
|
}
|
||||||
return !requiredUploadPermission || canUploadKey();
|
return !requiredUploadPermission || canUploadKey();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class LyricController {
|
|||||||
// @PostMapping("/correct")
|
// @PostMapping("/correct")
|
||||||
// public long correctRequest(CaptchaData<LyricCorrectRequest> request) {
|
// public long correctRequest(CaptchaData<LyricCorrectRequest> request) {
|
||||||
// if (IOSize.MB * 120 < request.getData().getFile().getSize()) {
|
// if (IOSize.MB * 120 < request.getData().getFile().getSize()) {
|
||||||
// throw new TimiException(TimiCode.ARG_BAD).msgKey("lyric.correct_request.too_big");
|
// throw new TimiException(TimiCode.ARG_BAD, "lyric.correct_request.too_big");
|
||||||
// }
|
// }
|
||||||
// return correctService.correctRequest(request.getData());
|
// return correctService.correctRequest(request.getData());
|
||||||
// }
|
// }
|
||||||
|
|||||||
+1
-1
@@ -135,7 +135,7 @@ public class LyricServiceImplement extends AbstractEntityService<Lyric, String>
|
|||||||
return lyric;
|
return lyric;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("fetch lyric fail", e);
|
log.error("fetch lyric fail", e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("无法获取歌词");
|
throw new TimiException(TimiCode.ERROR, "无法获取歌词");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ abstract class AbstractMirror {
|
|||||||
onException(mirror, e);
|
onException(mirror, e);
|
||||||
|
|
||||||
if (e instanceof TimiException te) {
|
if (e instanceof TimiException te) {
|
||||||
log.warn("[%s] Fail: %s".formatted(mirror.getBean(), te.getMsg()));
|
log.warn("[%s] Fail: %s".formatted(mirror.getBean(), te.getMessage()));
|
||||||
} else {
|
} else {
|
||||||
log.error("[%s] Error".formatted(mirror.getBean()), e);
|
log.error("[%s] Error".formatted(mirror.getBean()), e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ public class TerminalPipe implements TimiJava {
|
|||||||
*/
|
*/
|
||||||
public void exec(CallbackArg<String> callback, String command) {
|
public void exec(CallbackArg<String> callback, String command) {
|
||||||
if (status == Status.DIED) {
|
if (status == Status.DIED) {
|
||||||
throw new TimiException(TimiCode.RESULT_BAD).msgKey("该会话已终止");
|
throw new TimiException(TimiCode.RESULT_BAD, "该会话已终止");
|
||||||
}
|
}
|
||||||
this.status = Status.RUNNING;
|
this.status = Status.RUNNING;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public class FileController implements TimiJava, OS.FileSystem {
|
|||||||
public ServerFile object(HttpServletRequest req, HttpServletResponse resp) {
|
public ServerFile object(HttpServletRequest req, HttpServletResponse resp) {
|
||||||
String path = req.getServletPath().substring("/system/file/object".length());
|
String path = req.getServletPath().substring("/system/file/object".length());
|
||||||
if (TimiJava.isEmpty(path)) {
|
if (TimiJava.isEmpty(path)) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("TODO 缺少参数:object");
|
throw new TimiException(TimiCode.ARG_MISS, "TODO 缺少参数:object");
|
||||||
}
|
}
|
||||||
ServerFile file = new ServerFile(new File(path));
|
ServerFile file = new ServerFile(new File(path));
|
||||||
service.checkAccessPermission(file.getAbsolutePath());
|
service.checkAccessPermission(file.getAbsolutePath());
|
||||||
@@ -105,10 +105,10 @@ public class FileController implements TimiJava, OS.FileSystem {
|
|||||||
@PostMapping("/search")
|
@PostMapping("/search")
|
||||||
public List<ServerFile> search(@RequestBody Map<String, String> params) {
|
public List<ServerFile> search(@RequestBody Map<String, String> params) {
|
||||||
if (TimiJava.isEmpty(params.get("path"))) {
|
if (TimiJava.isEmpty(params.get("path"))) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:path");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:path");
|
||||||
}
|
}
|
||||||
if (TimiJava.isEmpty(params.get("keyword"))) {
|
if (TimiJava.isEmpty(params.get("keyword"))) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:keyword");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:keyword");
|
||||||
}
|
}
|
||||||
return service.doFilter(service.search(params.get("path"), params.get("keyword")));
|
return service.doFilter(service.search(params.get("path"), params.get("keyword")));
|
||||||
}
|
}
|
||||||
@@ -126,7 +126,7 @@ public class FileController implements TimiJava, OS.FileSystem {
|
|||||||
public boolean exist(HttpServletRequest req, HttpServletResponse resp) {
|
public boolean exist(HttpServletRequest req, HttpServletResponse resp) {
|
||||||
String path = req.getServletPath().substring("/system/file/exist".length());
|
String path = req.getServletPath().substring("/system/file/exist".length());
|
||||||
if (TimiJava.isEmpty(path)) {
|
if (TimiJava.isEmpty(path)) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:path");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:path");
|
||||||
}
|
}
|
||||||
return service.canAccess(path) && service.isExist(path);
|
return service.canAccess(path) && service.isExist(path);
|
||||||
}
|
}
|
||||||
@@ -237,10 +237,10 @@ public class FileController implements TimiJava, OS.FileSystem {
|
|||||||
@PostMapping("/mkdir")
|
@PostMapping("/mkdir")
|
||||||
public String mkdir(@RequestBody Map<String, String> params) {
|
public String mkdir(@RequestBody Map<String, String> params) {
|
||||||
if (TimiJava.isEmpty(params.get("path"))) {
|
if (TimiJava.isEmpty(params.get("path"))) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:path");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:path");
|
||||||
}
|
}
|
||||||
if (TimiJava.isEmpty(params.get("name"))) {
|
if (TimiJava.isEmpty(params.get("name"))) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:name");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:name");
|
||||||
}
|
}
|
||||||
return service.mkdir(params.get("path"), params.get("name")).getAbsolutePath();
|
return service.mkdir(params.get("path"), params.get("name")).getAbsolutePath();
|
||||||
}
|
}
|
||||||
@@ -256,10 +256,10 @@ public class FileController implements TimiJava, OS.FileSystem {
|
|||||||
@PostMapping("/rename")
|
@PostMapping("/rename")
|
||||||
public boolean rename(@RequestBody Map<String, String> params) {
|
public boolean rename(@RequestBody Map<String, String> params) {
|
||||||
if (TimiJava.isEmpty(params.get("from"))) {
|
if (TimiJava.isEmpty(params.get("from"))) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:from");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:from");
|
||||||
}
|
}
|
||||||
if (TimiJava.isEmpty(params.get("to"))) {
|
if (TimiJava.isEmpty(params.get("to"))) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:to");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:to");
|
||||||
}
|
}
|
||||||
return service.rename(params.get("from"), params.get("to"));
|
return service.rename(params.get("from"), params.get("to"));
|
||||||
}
|
}
|
||||||
@@ -275,10 +275,10 @@ public class FileController implements TimiJava, OS.FileSystem {
|
|||||||
@PostMapping("/zip")
|
@PostMapping("/zip")
|
||||||
public String zip(@RequestBody ListFileToRequest listFileToRequest) {
|
public String zip(@RequestBody ListFileToRequest listFileToRequest) {
|
||||||
if (TimiJava.isEmpty(listFileToRequest.getList())) {
|
if (TimiJava.isEmpty(listFileToRequest.getList())) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:list[]");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:list[]");
|
||||||
}
|
}
|
||||||
if (TimiJava.isEmpty(listFileToRequest.getTo())) {
|
if (TimiJava.isEmpty(listFileToRequest.getTo())) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:to");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:to");
|
||||||
}
|
}
|
||||||
// 异步任务
|
// 异步任务
|
||||||
FileZipAsyncTask task = new FileZipAsyncTask(listFileToRequest.getList(), listFileToRequest.getTo());
|
FileZipAsyncTask task = new FileZipAsyncTask(listFileToRequest.getList(), listFileToRequest.getTo());
|
||||||
@@ -298,14 +298,14 @@ public class FileController implements TimiJava, OS.FileSystem {
|
|||||||
public String unzip(@RequestBody Map<String, String> params) {
|
public String unzip(@RequestBody Map<String, String> params) {
|
||||||
String zipFilePath = params.get("zipFile");
|
String zipFilePath = params.get("zipFile");
|
||||||
if (TimiJava.isEmpty(zipFilePath)) {
|
if (TimiJava.isEmpty(zipFilePath)) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:zipFile");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:zipFile");
|
||||||
}
|
}
|
||||||
File zipFile = new File(zipFilePath);
|
File zipFile = new File(zipFilePath);
|
||||||
if (!zipFile.exists()) {
|
if (!zipFile.exists()) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("文件不存在:" + zipFilePath);
|
throw new TimiException(TimiCode.ARG_BAD, "文件不存在:" + zipFilePath);
|
||||||
}
|
}
|
||||||
if (TimiJava.isEmpty(params.get("to"))) {
|
if (TimiJava.isEmpty(params.get("to"))) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:to");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:to");
|
||||||
}
|
}
|
||||||
// 异步任务
|
// 异步任务
|
||||||
FileUnZipAsyncTask task = new FileUnZipAsyncTask(zipFile, params.get("to"));
|
FileUnZipAsyncTask task = new FileUnZipAsyncTask(zipFile, params.get("to"));
|
||||||
@@ -341,14 +341,14 @@ public class FileController implements TimiJava, OS.FileSystem {
|
|||||||
// TODO 具名入参
|
// TODO 具名入参
|
||||||
String tarFilePath = params.get("tarFile");
|
String tarFilePath = params.get("tarFile");
|
||||||
if (TimiJava.isEmpty(tarFilePath)) {
|
if (TimiJava.isEmpty(tarFilePath)) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:tarFile");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:tarFile");
|
||||||
}
|
}
|
||||||
File tarFile = new File(tarFilePath);
|
File tarFile = new File(tarFilePath);
|
||||||
if (!tarFile.exists()) {
|
if (!tarFile.exists()) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("文件不存在:" + tarFilePath);
|
throw new TimiException(TimiCode.ARG_BAD, "文件不存在:" + tarFilePath);
|
||||||
}
|
}
|
||||||
if (TimiJava.isEmpty(params.get("to"))) {
|
if (TimiJava.isEmpty(params.get("to"))) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:to");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:to");
|
||||||
}
|
}
|
||||||
FileUnTarAsyncTask task = new FileUnTarAsyncTask(tarFile, params.get("to"));
|
FileUnTarAsyncTask task = new FileUnTarAsyncTask(tarFile, params.get("to"));
|
||||||
asyncTaskService.addAsyncTask(task);
|
asyncTaskService.addAsyncTask(task);
|
||||||
|
|||||||
+3
-3
@@ -116,7 +116,7 @@ public abstract class AbstractAsyncTask extends AsyncTask {
|
|||||||
/** 开始 */
|
/** 开始 */
|
||||||
void start() {
|
void start() {
|
||||||
if (status != AsyncTask.Status.IDLE && status != AsyncTask.Status.PAUSE) {
|
if (status != AsyncTask.Status.IDLE && status != AsyncTask.Status.PAUSE) {
|
||||||
throw new TimiException(TimiCode.RESULT_BAD).msgKey("can not start this task");
|
throw new TimiException(TimiCode.RESULT_BAD, "can not start this task");
|
||||||
}
|
}
|
||||||
synchronized (pauseLocker) {
|
synchronized (pauseLocker) {
|
||||||
pauseLocker.notifyAll();
|
pauseLocker.notifyAll();
|
||||||
@@ -127,7 +127,7 @@ public abstract class AbstractAsyncTask extends AsyncTask {
|
|||||||
/** 暂停 */
|
/** 暂停 */
|
||||||
void pause() {
|
void pause() {
|
||||||
if (!canPause || (status != AsyncTask.Status.WAITING && status != AsyncTask.Status.RUNNING)) {
|
if (!canPause || (status != AsyncTask.Status.WAITING && status != AsyncTask.Status.RUNNING)) {
|
||||||
throw new TimiException(TimiCode.RESULT_BAD).msgKey("can not pause this task");
|
throw new TimiException(TimiCode.RESULT_BAD, "can not pause this task");
|
||||||
}
|
}
|
||||||
status = Status.PAUSE;
|
status = Status.PAUSE;
|
||||||
onPause();
|
onPause();
|
||||||
@@ -139,7 +139,7 @@ public abstract class AbstractAsyncTask extends AsyncTask {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!canInterrupt || (status != AsyncTask.Status.WAITING && status != AsyncTask.Status.RUNNING && status != AsyncTask.Status.PAUSE)) {
|
if (!canInterrupt || (status != AsyncTask.Status.WAITING && status != AsyncTask.Status.RUNNING && status != AsyncTask.Status.PAUSE)) {
|
||||||
throw new TimiException(TimiCode.RESULT_BAD).msgKey("can not interrupt this task");
|
throw new TimiException(TimiCode.RESULT_BAD, "can not interrupt this task");
|
||||||
}
|
}
|
||||||
if (status == AsyncTask.Status.PAUSE) {
|
if (status == AsyncTask.Status.PAUSE) {
|
||||||
status = AsyncTask.Status.INTERRUPT;
|
status = AsyncTask.Status.INTERRUPT;
|
||||||
|
|||||||
+1
-1
@@ -109,7 +109,7 @@ public class AsyncTaskServiceImplement implements AsyncTaskService {
|
|||||||
task.setMessage(task.logBuffer.toString());
|
task.setMessage(task.logBuffer.toString());
|
||||||
return task;
|
return task;
|
||||||
}
|
}
|
||||||
throw new TimiException(TimiCode.RESULT_NULL).msgKey("TODO not found task");
|
throw new TimiException(TimiCode.RESULT_NULL, "TODO not found task");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+10
-10
@@ -114,7 +114,7 @@ public class FileServiceImplement implements TimiJava, FileService {
|
|||||||
if (canAccess(path)) {
|
if (canAccess(path)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("TODO invalid permission");
|
throw new TimiException(TimiCode.PERMISSION_ERROR, "TODO invalid permission");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -139,7 +139,7 @@ public class FileServiceImplement implements TimiJava, FileService {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new TimiException(TimiCode.RESULT_NULL).msgKey("文件或路径不存在");
|
throw new TimiException(TimiCode.RESULT_NULL, "文件或路径不存在");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +176,7 @@ public class FileServiceImplement implements TimiJava, FileService {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
} else {
|
} else {
|
||||||
throw new TimiException(TimiCode.RESULT_NULL).msgKey("文件或路径不存在");
|
throw new TimiException(TimiCode.RESULT_NULL, "文件或路径不存在");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +186,7 @@ public class FileServiceImplement implements TimiJava, FileService {
|
|||||||
try {
|
try {
|
||||||
return IO.dir(uri);
|
return IO.dir(uri);
|
||||||
} catch (NoPermissionException e) {
|
} catch (NoPermissionException e) {
|
||||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("权限错误");
|
throw new TimiException(TimiCode.PERMISSION_ERROR, "权限错误");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,7 +205,7 @@ public class FileServiceImplement implements TimiJava, FileService {
|
|||||||
try {
|
try {
|
||||||
return IO.getInputStream(getPath(path));
|
return IO.getInputStream(getPath(path));
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
throw new TimiException(TimiCode.RESULT_NULL).msgKey("找不到文件");
|
throw new TimiException(TimiCode.RESULT_NULL, "找不到文件");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,25 +213,25 @@ public class FileServiceImplement implements TimiJava, FileService {
|
|||||||
public void upload(TransferFile file) {
|
public void upload(TransferFile file) {
|
||||||
String path = getPath(Decoder.url(file.getPath()));
|
String path = getPath(Decoder.url(file.getPath()));
|
||||||
if (file.getName() == null) {
|
if (file.getName() == null) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少参数:name");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少参数:name");
|
||||||
}
|
}
|
||||||
String fileName = Decoder.url(file.getName());
|
String fileName = Decoder.url(file.getName());
|
||||||
if (!OS.isValidFileName(path)) {
|
if (!OS.isValidFileName(path)) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("路径名称不合法:" + path);
|
throw new TimiException(TimiCode.ARG_BAD, "路径名称不合法:" + path);
|
||||||
}
|
}
|
||||||
if (!OS.isValidFileName(fileName)) {
|
if (!OS.isValidFileName(fileName)) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("文件名称不合法:" + fileName);
|
throw new TimiException(TimiCode.ARG_BAD, "文件名称不合法:" + fileName);
|
||||||
}
|
}
|
||||||
if (file.getLength() == file.getFile().getSize()) {
|
if (file.getLength() == file.getFile().getSize()) {
|
||||||
try {
|
try {
|
||||||
toFile(new File(path + fileName), file.getFile().getInputStream());
|
toFile(new File(path + fileName), file.getFile().getInputStream());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("get request input stream error", e);
|
log.error("get request input stream error", e);
|
||||||
throw new TimiException(TimiCode.ARG_BAD).msgKey("获取文件输入流失败");
|
throw new TimiException(TimiCode.ARG_BAD, "获取文件输入流失败");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log.error("request submit request size: {}, receive request size: {}", file.getLength(), file.getFile().getSize());
|
log.error("request submit request size: {}, receive request size: {}", file.getLength(), file.getFile().getSize());
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("不完整上传文件,已忽略");
|
throw new TimiException(TimiCode.ERROR, "不完整上传文件,已忽略");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class FileMoveAsyncTask extends AbstractAsyncTask {
|
|||||||
File toFile = new File(IO.fitPath(to) + item.getValue());
|
File toFile = new File(IO.fitPath(to) + item.getValue());
|
||||||
IO.dir(toFile.getParent());
|
IO.dir(toFile.getParent());
|
||||||
if (!item.getKey().renameTo(toFile)) {
|
if (!item.getKey().renameTo(toFile)) {
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("移动失败:" + item.getKey().getAbsolutePath() + " -> " + toFile.getAbsolutePath());
|
throw new TimiException(TimiCode.ERROR, "移动失败:" + item.getKey().getAbsolutePath() + " -> " + toFile.getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ public class DockerEngineClient {
|
|||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
log.error("docker engine request interrupted: {}", requestPath, e);
|
log.error("docker engine request interrupted: {}", requestPath, e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO docker engine request interrupted");
|
throw new TimiException(TimiCode.ERROR, "TODO docker engine request interrupted");
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("docker engine request error: {}", requestPath, e);
|
log.error("docker engine request error: {}", requestPath, e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("TODO docker engine request error");
|
throw new TimiException(TimiCode.ERROR, "TODO docker engine request error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ public class SystemAPIInterceptor implements HandlerInterceptor {
|
|||||||
// TimiSpring.setRequestAttr(HIGH_AUTHORITY, keyMap.get(key));
|
// TimiSpring.setRequestAttr(HIGH_AUTHORITY, keyMap.get(key));
|
||||||
// return true;
|
// return true;
|
||||||
// }
|
// }
|
||||||
// throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("TODO invalid key");
|
// throw new TimiException(TimiCode.PERMISSION_ERROR, "TODO invalid key");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,14 +43,14 @@ public class UpsStatusClient {
|
|||||||
|
|
||||||
public JsonNode getStatusJson() {
|
public JsonNode getStatusJson() {
|
||||||
if (statusUrl == null || statusUrl.isBlank()) {
|
if (statusUrl == null || statusUrl.isBlank()) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("缺少配置:ups.status-url");
|
throw new TimiException(TimiCode.ARG_MISS, "缺少配置:ups.status-url");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
String response = CommonRequest.post(statusUrl).bodyEntity(ArgMap.of("portName", "USBusbdev3").toEntity()).asString();
|
String response = CommonRequest.post(statusUrl).bodyEntity(ArgMap.of("portName", "USBusbdev3").toEntity()).asString();
|
||||||
return jackson.readTree(response);
|
return jackson.readTree(response);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
log.error("request ups status error: {}", statusUrl, e);
|
log.error("request ups status error: {}", statusUrl, e);
|
||||||
throw new TimiException(TimiCode.ERROR).msgKey("UPS 状态请求失败");
|
throw new TimiException(TimiCode.ERROR, "UPS 状态请求失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.imyeyu.api.annotation.RequireCorePermission;
|
|||||||
import com.imyeyu.api.annotation.RequireCoreRole;
|
import com.imyeyu.api.annotation.RequireCoreRole;
|
||||||
import com.imyeyu.api.bean.CorePermissionCode;
|
import com.imyeyu.api.bean.CorePermissionCode;
|
||||||
import com.imyeyu.api.bean.CoreRoleCode;
|
import com.imyeyu.api.bean.CoreRoleCode;
|
||||||
|
import com.imyeyu.api.bean.RoleMatchMode;
|
||||||
import com.imyeyu.api.modules.user.entity.Permission;
|
import com.imyeyu.api.modules.user.entity.Permission;
|
||||||
import com.imyeyu.api.modules.user.service.PermissionService;
|
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||||
import com.imyeyu.api.modules.user.vo.permission.BatchCreateReq;
|
import com.imyeyu.api.modules.user.vo.permission.BatchCreateReq;
|
||||||
@@ -32,7 +33,7 @@ public class PermissionController {
|
|||||||
|
|
||||||
private final PermissionService service;
|
private final PermissionService service;
|
||||||
|
|
||||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
||||||
@RequireCorePermission(CorePermissionCode.PERMISSION_READ)
|
@RequireCorePermission(CorePermissionCode.PERMISSION_READ)
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
public PageResult<Permission> list(@RequestBody Page<Permission> page) {
|
public PageResult<Permission> list(@RequestBody Page<Permission> page) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.imyeyu.api.annotation.RequireCoreRole;
|
|||||||
import com.imyeyu.api.bean.CorePermissionCode;
|
import com.imyeyu.api.bean.CorePermissionCode;
|
||||||
import com.imyeyu.api.bean.CoreRoleCode;
|
import com.imyeyu.api.bean.CoreRoleCode;
|
||||||
import com.imyeyu.api.bean.ModuleCode;
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
|
import com.imyeyu.api.bean.RoleMatchMode;
|
||||||
import com.imyeyu.api.modules.user.entity.Permission;
|
import com.imyeyu.api.modules.user.entity.Permission;
|
||||||
import com.imyeyu.api.modules.user.entity.Role;
|
import com.imyeyu.api.modules.user.entity.Role;
|
||||||
import com.imyeyu.api.modules.user.service.PermissionService;
|
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||||
@@ -38,7 +39,7 @@ public class RoleController {
|
|||||||
private final RoleService service;
|
private final RoleService service;
|
||||||
private final PermissionService permissionService;
|
private final PermissionService permissionService;
|
||||||
|
|
||||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
||||||
@RequireCorePermission(CorePermissionCode.ROLE_READ)
|
@RequireCorePermission(CorePermissionCode.ROLE_READ)
|
||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
public PageResult<Role> list(@RequestBody Page<Role> page) {
|
public PageResult<Role> list(@RequestBody Page<Role> page) {
|
||||||
@@ -49,7 +50,7 @@ public class RoleController {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
||||||
@RequireCorePermission(CorePermissionCode.ROLE_READ)
|
@RequireCorePermission(CorePermissionCode.ROLE_READ)
|
||||||
@PostMapping("/detail")
|
@PostMapping("/detail")
|
||||||
public Role detail(@RequestParam String id) {
|
public Role detail(@RequestParam String id) {
|
||||||
@@ -82,7 +83,7 @@ public class RoleController {
|
|||||||
service.delete(id);
|
service.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
||||||
@RequireCorePermission(CorePermissionCode.USER_ROLE_READ)
|
@RequireCorePermission(CorePermissionCode.USER_ROLE_READ)
|
||||||
@PostMapping("/authorized/list")
|
@PostMapping("/authorized/list")
|
||||||
public List<Role> listUserRole(@RequestParam String userId, @RequestParam(required = false) ModuleCode moduleCode) {
|
public List<Role> listUserRole(@RequestParam String userId, @RequestParam(required = false) ModuleCode moduleCode) {
|
||||||
@@ -93,14 +94,14 @@ public class RoleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
||||||
@RequireCorePermission(value = {CorePermissionCode.USER_ROLE_CREATE, CorePermissionCode.USER_ROLE_DELETE})
|
@RequireCorePermission(value = {CorePermissionCode.USER_ROLE_CREATE, CorePermissionCode.USER_ROLE_DELETE})
|
||||||
@PostMapping("/authorized/create")
|
@PostMapping("/authorized/create")
|
||||||
public void authorizeUserRole(@RequestBody UserRoleAuthorizeReq req) {
|
public void authorizeUserRole(@RequestBody UserRoleAuthorizeReq req) {
|
||||||
service.authorizeUserRole(req);
|
service.authorizeUserRole(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequireCoreRole(CoreRoleCode.ADMIN)
|
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
||||||
@RequireCorePermission(CorePermissionCode.USER_ROLE_READ)
|
@RequireCorePermission(CorePermissionCode.USER_ROLE_READ)
|
||||||
@PostMapping("/authorized/permission")
|
@PostMapping("/authorized/permission")
|
||||||
public List<Permission> listAuthorizedPermission(@RequestParam String userId) {
|
public List<Permission> listAuthorizedPermission(@RequestParam String userId) {
|
||||||
|
|||||||
+2
-2
@@ -53,7 +53,7 @@ public class PermissionCheckerImplement implements PermissionChecker {
|
|||||||
public void checkAll(ModuleCode moduleCode, String... permissionCodeList) {
|
public void checkAll(ModuleCode moduleCode, String... permissionCodeList) {
|
||||||
if (!hasAll(moduleCode, permissionCodeList)) {
|
if (!hasAll(moduleCode, permissionCodeList)) {
|
||||||
String codeList = buildPermissionKeys(moduleCode, permissionCodeList).toString();
|
String codeList = buildPermissionKeys(moduleCode, permissionCodeList).toString();
|
||||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("权限不足:%s".formatted(codeList));
|
throw new TimiException(TimiCode.PERMISSION_ERROR, "权限不足:%s".formatted(codeList));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ public class PermissionCheckerImplement implements PermissionChecker {
|
|||||||
public void checkAny(ModuleCode moduleCode, String... permissionCodeList) {
|
public void checkAny(ModuleCode moduleCode, String... permissionCodeList) {
|
||||||
if (!hasAny(moduleCode, permissionCodeList)) {
|
if (!hasAny(moduleCode, permissionCodeList)) {
|
||||||
String codeList = buildPermissionKeys(moduleCode, permissionCodeList).toString();
|
String codeList = buildPermissionKeys(moduleCode, permissionCodeList).toString();
|
||||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("权限不足:%s".formatted(codeList));
|
throw new TimiException(TimiCode.PERMISSION_ERROR, "权限不足:%s".formatted(codeList));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -8,8 +8,8 @@ import com.imyeyu.api.modules.user.mapper.PermissionMapper;
|
|||||||
import com.imyeyu.api.modules.user.mapper.RolePermissionMapper;
|
import com.imyeyu.api.modules.user.mapper.RolePermissionMapper;
|
||||||
import com.imyeyu.api.modules.user.service.PermissionService;
|
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||||
import com.imyeyu.api.modules.user.vo.permission.BatchCreateReq;
|
import com.imyeyu.api.modules.user.vo.permission.BatchCreateReq;
|
||||||
import com.imyeyu.api.util.RedisMultilingual;
|
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.lang.message.MessageResolver;
|
||||||
import com.imyeyu.spring.TimiSpring;
|
import com.imyeyu.spring.TimiSpring;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
@@ -35,7 +35,7 @@ public class PermissionServiceImplement extends AbstractEntityService<Permission
|
|||||||
|
|
||||||
private final MultilingualMapper multilingualMapper;
|
private final MultilingualMapper multilingualMapper;
|
||||||
private final MultilingualService multilingualService;
|
private final MultilingualService multilingualService;
|
||||||
private final RedisMultilingual multilingual;
|
private final MessageResolver messageResolver;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BaseMapper<Permission, String> mapper() {
|
protected BaseMapper<Permission, String> mapper() {
|
||||||
@@ -61,7 +61,7 @@ public class PermissionServiceImplement extends AbstractEntityService<Permission
|
|||||||
permission.setId(UUID.randomUUID().toString());
|
permission.setId(UUID.randomUUID().toString());
|
||||||
permission.setModuleCode(req.getModuleCode());
|
permission.setModuleCode(req.getModuleCode());
|
||||||
permission.setCode(req.getPrefixCode() + "_" + type.name());
|
permission.setCode(req.getPrefixCode() + "_" + type.name());
|
||||||
permission.setName(req.getPrefixName() + multilingual.map(TimiSpring.getLanguage()).text(type.name().toLowerCase()));
|
permission.setName(req.getPrefixName() + messageResolver.resolve(type.name().toLowerCase(), null, TimiSpring.getLanguage()));
|
||||||
permission.setCreatedAt(Time.now());
|
permission.setCreatedAt(Time.now());
|
||||||
permissionList.add(permission);
|
permissionList.add(permission);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -47,14 +47,14 @@ public class RoleCheckerImplement implements RoleChecker {
|
|||||||
@Override
|
@Override
|
||||||
public void checkAll(ModuleCode moduleCode, String... roleCodeList) {
|
public void checkAll(ModuleCode moduleCode, String... roleCodeList) {
|
||||||
if (!hasAll(moduleCode, roleCodeList)) {
|
if (!hasAll(moduleCode, roleCodeList)) {
|
||||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("require role: %s".formatted(buildRoleKeys(moduleCode, roleCodeList)));
|
throw new TimiException(TimiCode.PERMISSION_ERROR, "require role: %s".formatted(buildRoleKeys(moduleCode, roleCodeList)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void checkAny(ModuleCode moduleCode, String... roleCodeList) {
|
public void checkAny(ModuleCode moduleCode, String... roleCodeList) {
|
||||||
if (!hasAny(moduleCode, roleCodeList)) {
|
if (!hasAny(moduleCode, roleCodeList)) {
|
||||||
throw new TimiException(TimiCode.PERMISSION_ERROR).msgKey("require role: %s".formatted(buildRoleKeys(moduleCode, roleCodeList)));
|
throw new TimiException(TimiCode.PERMISSION_ERROR, "require role: %s".formatted(buildRoleKeys(moduleCode, roleCodeList)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -159,7 +159,7 @@ public class RoleServiceImplement extends AbstractEntityService<Role, String> im
|
|||||||
TimiException.required(req, "not found req");
|
TimiException.required(req, "not found req");
|
||||||
TimiException.required(req.getUserId(), "not found req.userId");
|
TimiException.required(req.getUserId(), "not found req.userId");
|
||||||
if (req.getModuleCode() == null) {
|
if (req.getModuleCode() == null) {
|
||||||
throw new TimiException(TimiCode.ARG_MISS).msgKey("moduleCode");
|
throw new TimiException(TimiCode.ARG_MISS, "moduleCode");
|
||||||
}
|
}
|
||||||
List<UserRole> bindingList = userRoleService.listByUserId(req.getUserId());
|
List<UserRole> bindingList = userRoleService.listByUserId(req.getUserId());
|
||||||
List<String> bindingRoleIdList = bindingList.stream().map(UserRole::getRoleId).toList();
|
List<String> bindingRoleIdList = bindingList.stream().map(UserRole::getRoleId).toList();
|
||||||
|
|||||||
@@ -65,6 +65,7 @@ public class UserServiceImplement extends AbstractEntityService<User, String> im
|
|||||||
dbUser.setPassword(Digest.argon2id(user.getPassword()));
|
dbUser.setPassword(Digest.argon2id(user.getPassword()));
|
||||||
dbUser.setEmail(user.getEmail());
|
dbUser.setEmail(user.getEmail());
|
||||||
dbUser.setPhoneNo(user.getPhoneNo());
|
dbUser.setPhoneNo(user.getPhoneNo());
|
||||||
|
dbUser.setPhoneNoVerifyAt(user.getPhoneNoVerifyAt());
|
||||||
dbUser.setExp(TimiJava.defaultIfNull(user.getExp(), 0));
|
dbUser.setExp(TimiJava.defaultIfNull(user.getExp(), 0));
|
||||||
super.create(dbUser);
|
super.create(dbUser);
|
||||||
user.setId(dbUser.getId());
|
user.setId(dbUser.getId());
|
||||||
|
|||||||
@@ -200,10 +200,10 @@ public class CaptchaManager {
|
|||||||
String cacheKey = CACHE_KEY.formatted(uniqueId);
|
String cacheKey = CACHE_KEY.formatted(uniqueId);
|
||||||
String cacheValue = redisCaptcha.get(cacheKey);
|
String cacheValue = redisCaptcha.get(cacheKey);
|
||||||
if (TimiJava.isEmpty(cacheValue)) {
|
if (TimiJava.isEmpty(cacheValue)) {
|
||||||
throw new TimiException(TimiCode.ARG_EXPIRED).msgKey("captcha.expire");
|
throw new TimiException(TimiCode.ARG_EXPIRED, "captcha.expire");
|
||||||
}
|
}
|
||||||
if (!value.trim().equalsIgnoreCase(cacheValue)) {
|
if (!value.trim().equalsIgnoreCase(cacheValue)) {
|
||||||
throw new TimiException(TimiCode.RESULT_BAD).msgKey("captcha.error");
|
throw new TimiException(TimiCode.RESULT_BAD, "captcha.error");
|
||||||
}
|
}
|
||||||
// 清除缓存
|
// 清除缓存
|
||||||
redisCaptcha.destroy(cacheKey);
|
redisCaptcha.destroy(cacheKey);
|
||||||
|
|||||||
@@ -1,9 +1,6 @@
|
|||||||
package com.imyeyu.api.util;
|
package com.imyeyu.api.util;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.common.service.SettingService;
|
import com.imyeyu.api.modules.common.service.SettingService;
|
||||||
import com.imyeyu.lang.mapper.AbstractLanguageMapper;
|
|
||||||
import com.imyeyu.spring.TimiSpring;
|
|
||||||
import com.imyeyu.spring.util.GlobalReturnHandler;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.eclipse.jgit.api.ArchiveCommand;
|
import org.eclipse.jgit.api.ArchiveCommand;
|
||||||
@@ -42,20 +39,11 @@ public class InitApplication implements ApplicationRunner {
|
|||||||
private String devLang;
|
private String devLang;
|
||||||
|
|
||||||
private final SettingService settingService;
|
private final SettingService settingService;
|
||||||
private final RedisMultilingual redisMultilingual;
|
|
||||||
private final GlobalReturnHandler globalReturnHandler;
|
|
||||||
|
|
||||||
private void initGitCommand() {
|
private void initGitCommand() {
|
||||||
ArchiveCommand.registerFormat("tar.gz", new TarFormat());
|
ArchiveCommand.registerFormat("tar.gz", new TarFormat());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initMultilingual() {
|
|
||||||
globalReturnHandler.setMultilingualHeader(mapping -> {
|
|
||||||
AbstractLanguageMapper map = redisMultilingual.map(TimiSpring.getLanguage());
|
|
||||||
return map.textArgs(mapping.getMsgKey(), mapping.getMsgArgs());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run(ApplicationArguments args) throws Exception {
|
public void run(ApplicationArguments args) throws Exception {
|
||||||
Method[] methods = getClass().getDeclaredMethods();
|
Method[] methods = getClass().getDeclaredMethods();
|
||||||
|
|||||||
@@ -1,43 +0,0 @@
|
|||||||
package com.imyeyu.api.util;
|
|
||||||
|
|
||||||
import com.imyeyu.api.TimiServerAPI;
|
|
||||||
import com.imyeyu.api.modules.common.service.MultilingualService;
|
|
||||||
import com.imyeyu.java.bean.Language;
|
|
||||||
import com.imyeyu.lang.mapper.AbstractLanguageMapper;
|
|
||||||
import com.imyeyu.utils.StringInterpolator;
|
|
||||||
import org.jcodec.api.NotSupportedException;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @version 2024-04-03 11:01
|
|
||||||
*/
|
|
||||||
public class RedisLanguage extends AbstractLanguageMapper {
|
|
||||||
|
|
||||||
private static final StringInterpolator INTERPOLATOR = new StringInterpolator(StringInterpolator.SIMPLE_OBJ);
|
|
||||||
|
|
||||||
public RedisLanguage(Language.Enum language) {
|
|
||||||
super(language);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void add(String id, String value) {
|
|
||||||
throw new NotSupportedException("not supported to add value, MultilingualService will auto cache when not found value");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean has(String id) {
|
|
||||||
return text(id).equals(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String text(String id) {
|
|
||||||
return TimiServerAPI.applicationContext.getBean(MultilingualService.class).get(id).getValue(language);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String textArgs(String id, Map<String, Object> args) {
|
|
||||||
return INTERPOLATOR.inject(text(id), args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.imyeyu.api.util;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.common.entity.Multilingual;
|
||||||
|
import com.imyeyu.api.modules.common.service.MultilingualService;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.Language;
|
||||||
|
import com.imyeyu.lang.message.MessageResolver;
|
||||||
|
import com.imyeyu.utils.StringInterpolator;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redis 消息解析器
|
||||||
|
*
|
||||||
|
* @author 夜雨
|
||||||
|
* @since 2026-08-01 00:00
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class RedisMessageResolver implements MessageResolver {
|
||||||
|
|
||||||
|
private static final StringInterpolator INTERPOLATOR = new StringInterpolator(StringInterpolator.SIMPLE_OBJ);
|
||||||
|
|
||||||
|
private final MultilingualService multilingualService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resolve(String messageCode, Map<String, Object> messageArgs, Language.Enum language) {
|
||||||
|
if (TimiJava.isEmpty(messageCode)) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
Language.Enum actualLanguage = language == null ? Language.Enum.zh_CN : language;
|
||||||
|
Multilingual multilingual = multilingualService.get(messageCode);
|
||||||
|
if (multilingual == null) {
|
||||||
|
return INTERPOLATOR.inject(messageCode, messageArgs);
|
||||||
|
}
|
||||||
|
String template = multilingual.getValue(actualLanguage);
|
||||||
|
if (TimiJava.isEmpty(template)) {
|
||||||
|
return INTERPOLATOR.inject(messageCode, messageArgs);
|
||||||
|
}
|
||||||
|
return INTERPOLATOR.inject(template, messageArgs);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package com.imyeyu.api.util;
|
|
||||||
|
|
||||||
import com.imyeyu.java.bean.Language;
|
|
||||||
import com.imyeyu.lang.multi.Multilingual;
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author 夜雨
|
|
||||||
* @version 2024-04-03 11:15
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class RedisMultilingual extends Multilingual {
|
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
private void postConstruct() {
|
|
||||||
Language.Enum[] languages = Language.Enum.values();
|
|
||||||
for (Language.Enum language : languages) {
|
|
||||||
add(language, new RedisLanguage(language));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
ALTER TABLE `gao_customer`
|
||||||
|
DROP INDEX `uk_gao_customer_code`,
|
||||||
|
ADD COLUMN `active_code` VARCHAR(64) GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL THEN `code` ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除客户编码' INVISIBLE,
|
||||||
|
ADD UNIQUE KEY `uk_gao_customer_active_code` (`active_code`);
|
||||||
|
|
||||||
|
ALTER TABLE `permission`
|
||||||
|
DROP INDEX `uk_module_code_code`,
|
||||||
|
ADD COLUMN `active_code` VARCHAR(50) GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL THEN `code` ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除权限代码' INVISIBLE,
|
||||||
|
ADD UNIQUE KEY `uk_permission_module_active_code` (`module_code`, `active_code`);
|
||||||
|
|
||||||
|
ALTER TABLE `role`
|
||||||
|
DROP INDEX `uk_module_code_code`,
|
||||||
|
ADD COLUMN `active_code` VARCHAR(50) GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL THEN `code` ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除角色代码' INVISIBLE,
|
||||||
|
ADD UNIQUE KEY `uk_role_module_active_code` (`module_code`, `active_code`);
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
ALTER TABLE `gao_customer`
|
||||||
|
ADD COLUMN `active_name` VARCHAR(64) GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL THEN NULLIF(TRIM(`name`), '') ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除客户姓名' INVISIBLE,
|
||||||
|
ADD UNIQUE KEY `uk_gao_customer_active_name` (`active_name`);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
ALTER TABLE `gao_customer`
|
||||||
|
ADD COLUMN `creator_user_id` VARCHAR(36) NULL COMMENT '录入用户 ID' AFTER `introducer_customer_id`,
|
||||||
|
ADD KEY `idx_gao_customer_creator_user_id` (`creator_user_id`);
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
ALTER TABLE `gao_customer`
|
||||||
|
ADD COLUMN `invited_count` BIGINT NOT NULL DEFAULT 0 COMMENT '邀请客户数' AFTER `introducer_customer_id`;
|
||||||
|
|
||||||
|
UPDATE `gao_customer` AS `customer`
|
||||||
|
SET `invited_count` = (
|
||||||
|
SELECT COUNT(1)
|
||||||
|
FROM `gao_customer` AS `invitee`
|
||||||
|
WHERE
|
||||||
|
`invitee`.`introducer_customer_id` = `customer`.`id`
|
||||||
|
AND `invitee`.`deleted_at` IS NULL
|
||||||
|
)
|
||||||
|
WHERE `customer`.`deleted_at` IS NULL;
|
||||||
@@ -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,29 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
<mapper namespace="com.imyeyu.api.modules.common.mapper.AttachmentMapper">
|
||||||
|
<select id="selectByBizIdList" resultType="com.imyeyu.api.modules.common.entity.Attachment">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM `attachment`
|
||||||
|
WHERE
|
||||||
|
`biz_type` = #{bizType}
|
||||||
|
<if test="bizIdList != null and !bizIdList.isEmpty()">
|
||||||
|
AND `biz_id` IN
|
||||||
|
<foreach collection="bizIdList" item="bizId" separator="," open="(" close=")">
|
||||||
|
#{bizId}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="bizIdList == null or bizIdList.isEmpty()">
|
||||||
|
AND 1 = 0
|
||||||
|
</if>
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
|
AND (`destroy_at` IS NULL OR UNIX_TIMESTAMP() < `destroy_at`)
|
||||||
|
<if test="attachTypes != null and !attachTypes.isEmpty()">
|
||||||
|
AND `attach_type` IN
|
||||||
|
<foreach collection="attachTypes" item="attachType" separator="," open="(" close=")">
|
||||||
|
#{attachType}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
ORDER BY `created_at` ASC
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
@@ -28,6 +28,18 @@
|
|||||||
ORDER BY `created_at` DESC
|
ORDER BY `created_at` DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByIdList" resultType="com.imyeyu.api.modules.gao.entity.GaoCustomer">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM `gao_customer`
|
||||||
|
WHERE
|
||||||
|
`id` IN
|
||||||
|
<foreach collection="idList" item="id" open="(" separator="," close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="countSearch" resultType="java.lang.Long">
|
<select id="countSearch" resultType="java.lang.Long">
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(1)
|
COUNT(1)
|
||||||
@@ -65,6 +77,16 @@
|
|||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<update id="updateInvitedCountDelta">
|
||||||
|
UPDATE `gao_customer`
|
||||||
|
SET
|
||||||
|
`invited_count` = GREATEST(IFNULL(`invited_count`, 0) + #{delta}, 0),
|
||||||
|
`updated_at` = UNIX_TIMESTAMP() * 1000
|
||||||
|
WHERE
|
||||||
|
`id` = #{customerId}
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
|
</update>
|
||||||
|
|
||||||
<select id="statDailyNewCustomer" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView">
|
<select id="statDailyNewCustomer" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStatView">
|
||||||
SELECT
|
SELECT
|
||||||
CAST(DATE_FORMAT(FROM_UNIXTIME(`created_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
|
CAST(DATE_FORMAT(FROM_UNIXTIME(`created_at` / 1000), '%Y%m%d') AS UNSIGNED) AS `dateValue`,
|
||||||
@@ -86,4 +108,14 @@
|
|||||||
`created_at` < #{beginCreatedAt}
|
`created_at` < #{beginCreatedAt}
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="statGender" resultType="com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView">
|
||||||
|
SELECT
|
||||||
|
IFNULL(CAST(`gender` AS CHAR), 'UNKNOWN') AS `genderCode`,
|
||||||
|
COUNT(1) AS `count`
|
||||||
|
FROM `gao_customer`
|
||||||
|
WHERE
|
||||||
|
`deleted_at` IS NULL
|
||||||
|
GROUP BY IFNULL(CAST(`gender` AS CHAR), 'UNKNOWN')
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
<mapper namespace="com.imyeyu.api.modules.gao.mapper.GaoRegistrationEventMapper">
|
||||||
|
<select id="selectByIdList" resultType="com.imyeyu.api.modules.gao.entity.GaoRegistrationEvent">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM `gao_registration_event`
|
||||||
|
WHERE
|
||||||
|
1 = 1
|
||||||
|
<if test="idList != null and !idList.isEmpty()">
|
||||||
|
AND `id` IN
|
||||||
|
<foreach collection="idList" item="id" separator="," open="(" close=")">
|
||||||
|
#{id}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="idList == null or idList.isEmpty()">
|
||||||
|
AND 1 = 0
|
||||||
|
</if>
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
@@ -20,6 +20,28 @@
|
|||||||
ORDER BY `registered_at` DESC
|
ORDER BY `registered_at` DESC
|
||||||
</select>
|
</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="statByRegistrationEventAndPeriodType" resultType="com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView">
|
<select id="statByRegistrationEventAndPeriodType" resultType="com.imyeyu.api.modules.gao.vo.GaoRegistrationEventPeriodStatView">
|
||||||
SELECT
|
SELECT
|
||||||
`registration_event_id` AS `registrationEventId`,
|
`registration_event_id` AS `registrationEventId`,
|
||||||
@@ -259,6 +281,20 @@
|
|||||||
ORDER BY r.`registered_at` DESC, r.`created_at` DESC
|
ORDER BY r.`registered_at` DESC, r.`created_at` DESC
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectCalendarByRange" resultType="com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordCalendarView">
|
||||||
|
SELECT
|
||||||
|
r.`id` AS `id`,
|
||||||
|
r.`customer_id` AS `customerId`,
|
||||||
|
c.`code` AS `customerCode`,
|
||||||
|
c.`name` AS `customerName`,
|
||||||
|
r.`registration_event_id` AS `registrationEventId`,
|
||||||
|
r.`registered_at` AS `registeredAt`
|
||||||
|
<include refid="rangeFrom"/>
|
||||||
|
WHERE
|
||||||
|
<include refid="rangeWhere"/>
|
||||||
|
ORDER BY r.`registered_at` DESC, r.`created_at` DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
<select id="countByRange" resultType="java.lang.Long">
|
<select id="countByRange" resultType="java.lang.Long">
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(1)
|
COUNT(1)
|
||||||
@@ -267,9 +303,26 @@
|
|||||||
<include refid="rangeWhere"/>
|
<include refid="rangeWhere"/>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectPageByRange" resultType="com.imyeyu.api.modules.gao.entity.GaoRegistrationEventRecord">
|
<select id="selectPageByRange" resultType="com.imyeyu.api.modules.gao.vo.GaoRegistrationEventRecordListItemView">
|
||||||
SELECT
|
SELECT
|
||||||
r.*
|
r.`id` AS `id`,
|
||||||
|
r.`customer_id` AS `customerId`,
|
||||||
|
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`,
|
||||||
|
r.`registration_event_id` AS `registrationEventId`,
|
||||||
|
e.`name` AS `registrationEventName`,
|
||||||
|
r.`registered_at` AS `registeredAt`
|
||||||
<include refid="rangeFrom"/>
|
<include refid="rangeFrom"/>
|
||||||
WHERE
|
WHERE
|
||||||
<include refid="rangeWhere"/>
|
<include refid="rangeWhere"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user