add store
This commit is contained in:
Generated
-7
@@ -1,7 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="DataSourcePerFileMappings">
|
|
||||||
<file url="file://$PROJECT_DIR$/src/main/java/com/imyeyu/api/modules/user/mapper/UserMapper.java" value="05742bdc-a11a-4147-9168-ef976a70258a" />
|
|
||||||
<file url="file://$PROJECT_DIR$/src/main/resources/mapper/timi-server/GaoCustomerMapper.xml" value="05742bdc-a11a-4147-9168-ef976a70258a" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -8,6 +8,7 @@ import com.imyeyu.java.TimiJava;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.method.HandlerMethod;
|
import org.springframework.web.method.HandlerMethod;
|
||||||
import org.springframework.web.servlet.HandlerInterceptor;
|
import org.springframework.web.servlet.HandlerInterceptor;
|
||||||
@@ -32,6 +33,9 @@ public class RequireGaoRoleInterceptor implements HandlerInterceptor {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
RequireGaoRole annotation = handlerMethod.getMethodAnnotation(RequireGaoRole.class);
|
RequireGaoRole annotation = handlerMethod.getMethodAnnotation(RequireGaoRole.class);
|
||||||
|
if (annotation == null) {
|
||||||
|
annotation = AnnotatedElementUtils.findMergedAnnotation(handlerMethod.getBeanType(), RequireGaoRole.class);
|
||||||
|
}
|
||||||
if (annotation == null || TimiJava.isEmpty(annotation.value())) {
|
if (annotation == null || TimiJava.isEmpty(annotation.value())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,16 @@ import lombok.Getter;
|
|||||||
/// @since 2026-07-26
|
/// @since 2026-07-26
|
||||||
public enum GaoPermissionCode implements BuiltinPermissionCode {
|
public enum GaoPermissionCode implements BuiltinPermissionCode {
|
||||||
|
|
||||||
|
STORE_CREATE("STORE:CREATE", "门店创建", false, true),
|
||||||
|
|
||||||
|
STORE_READ("STORE:READ", "门店读取", true, true),
|
||||||
|
|
||||||
|
STORE_EXPORT("STORE:EXPORT", "门店导出", false, true),
|
||||||
|
|
||||||
|
STORE_UPDATE("STORE:UPDATE", "门店修改", true, true),
|
||||||
|
|
||||||
|
STORE_DELETE("STORE:DELETE", "门店删除", false, true),
|
||||||
|
|
||||||
CUSTOMER_CREATE("CUSTOMER:CREATE", "客户创建"),
|
CUSTOMER_CREATE("CUSTOMER:CREATE", "客户创建"),
|
||||||
|
|
||||||
CUSTOMER_READ("CUSTOMER:READ", "客户读取"),
|
CUSTOMER_READ("CUSTOMER:READ", "客户读取"),
|
||||||
@@ -58,14 +68,23 @@ public enum GaoPermissionCode implements BuiltinPermissionCode {
|
|||||||
@Getter
|
@Getter
|
||||||
final boolean grantToStoreManager;
|
final boolean grantToStoreManager;
|
||||||
|
|
||||||
|
/// `true` 为初始化时授权给全局管理员角色
|
||||||
|
@Getter
|
||||||
|
final boolean grantToGlobalManager;
|
||||||
|
|
||||||
GaoPermissionCode(String value, String defaultName) {
|
GaoPermissionCode(String value, String defaultName) {
|
||||||
this(value, defaultName, false);
|
this(value, defaultName, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
GaoPermissionCode(String value, String defaultName, boolean grantToStoreManager) {
|
GaoPermissionCode(String value, String defaultName, boolean grantToStoreManager) {
|
||||||
|
this(value, defaultName, grantToStoreManager, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
GaoPermissionCode(String value, String defaultName, boolean grantToStoreManager, boolean grantToGlobalManager) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.defaultName = defaultName;
|
this.defaultName = defaultName;
|
||||||
this.grantToStoreManager = grantToStoreManager;
|
this.grantToStoreManager = grantToStoreManager;
|
||||||
|
this.grantToGlobalManager = grantToGlobalManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -12,12 +12,16 @@ import lombok.AllArgsConstructor;
|
|||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
public enum GaoRoleCode implements BuiltinRoleCode {
|
public enum GaoRoleCode implements BuiltinRoleCode {
|
||||||
|
|
||||||
/// 店长
|
/// 全局管理员
|
||||||
STORE_MANAGER("店长"),
|
GLOBAL_MANAGER("全局管理员", null),
|
||||||
|
|
||||||
EMPLOYEE("员工");
|
/// 店长
|
||||||
|
STORE_MANAGER("店长", GLOBAL_MANAGER.name()),
|
||||||
|
|
||||||
|
EMPLOYEE("员工", STORE_MANAGER.name());
|
||||||
|
|
||||||
final String defaultName;
|
final String defaultName;
|
||||||
|
final String parentCode;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModuleCode getModuleCode() {
|
public ModuleCode getModuleCode() {
|
||||||
@@ -36,6 +40,6 @@ public enum GaoRoleCode implements BuiltinRoleCode {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getParentCode() {
|
public String getParentCode() {
|
||||||
return null;
|
return parentCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView;
|
|||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStateReq;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStateReq;
|
||||||
import com.imyeyu.api.modules.user.service.UserService;
|
import com.imyeyu.api.modules.user.service.UserService;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.network.Network;
|
import com.imyeyu.network.Network;
|
||||||
import com.imyeyu.spring.TimiSpring;
|
import com.imyeyu.spring.TimiSpring;
|
||||||
import com.imyeyu.spring.annotation.AOPLog;
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
@@ -111,13 +112,25 @@ public class GaoCustomerController {
|
|||||||
service.delete(id);
|
service.delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
|
@PostMapping("/find/id")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
|
public GaoCustomer findById(@RequestParam String id) {
|
||||||
|
GaoCustomer customer = service.get(id);
|
||||||
|
TimiException.required(customer, "not found customer");
|
||||||
|
customer.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.GAO_CUSTOMER, customer.getId()));
|
||||||
|
return customer;
|
||||||
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/find/code")
|
@PostMapping("/find/code")
|
||||||
@JsonView(ResponseView.Public.class)
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoCustomer findByCode(@RequestParam String code) {
|
public GaoCustomer findByCode(@RequestParam String storeId, @RequestParam String code) {
|
||||||
GaoCustomer customer = service.getByCode(code);
|
GaoCustomer customer = service.getByCode(storeId, code);
|
||||||
if (customer == null) {
|
if (customer == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -130,8 +143,8 @@ public class GaoCustomerController {
|
|||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/find/name")
|
@PostMapping("/find/name")
|
||||||
@JsonView(ResponseView.Public.class)
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoCustomer findByName(@RequestParam String name) {
|
public GaoCustomer findByName(@RequestParam String storeId, @RequestParam String name) {
|
||||||
GaoCustomer customer = service.getByName(name);
|
GaoCustomer customer = service.getByName(storeId, name);
|
||||||
if (customer == null) {
|
if (customer == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -197,7 +210,7 @@ public class GaoCustomerController {
|
|||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
@RequireGaoPermission(GaoPermissionCode.CUSTOMER_READ)
|
||||||
@PostMapping("/state/gender")
|
@PostMapping("/state/gender")
|
||||||
public List<GaoCustomerGenderStatView> genderStat() {
|
public List<GaoCustomerGenderStatView> genderStat(@RequestParam String storeId) {
|
||||||
return service.stateGender();
|
return service.stateGender(storeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ public class GaoEventController {
|
|||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@PostMapping("/list/valid")
|
@PostMapping("/list/valid")
|
||||||
public List<GaoEvent> listValid() {
|
public List<GaoEvent> listValid(@RequestParam String storeId) {
|
||||||
return service.listValid();
|
return service.listValid(storeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
|
|||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.controller;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||||
|
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
||||||
|
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||||
|
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStoreBusinessDay;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoStoreBusinessDayService;
|
||||||
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/// GAO 门店营业日接口
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/gao/store/business/day")
|
||||||
|
@RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
|
||||||
|
public class GaoStoreBusinessDayController {
|
||||||
|
|
||||||
|
private final GaoStoreBusinessDayService service;
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
|
||||||
|
@PostMapping("/list")
|
||||||
|
public PageResult<GaoStoreBusinessDay> list(@RequestBody Page<GaoStoreBusinessDay> page) {
|
||||||
|
return service.page(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
|
||||||
|
@PostMapping("/calendar")
|
||||||
|
public List<GaoStoreBusinessDay> calendar(@RequestParam String storeId, @RequestParam Integer beginDateValue, @RequestParam Integer endDateValue) {
|
||||||
|
return service.listByDateRange(storeId, beginDateValue, endDateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
|
||||||
|
@PostMapping("/detail")
|
||||||
|
public GaoStoreBusinessDay detail(@RequestParam String id) {
|
||||||
|
return service.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_CREATE)
|
||||||
|
@PostMapping("/create")
|
||||||
|
public String create(@RequestBody GaoStoreBusinessDay businessDay) {
|
||||||
|
service.create(businessDay);
|
||||||
|
return businessDay.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_UPDATE)
|
||||||
|
@PostMapping("/update")
|
||||||
|
public void update(@RequestBody GaoStoreBusinessDay businessDay) {
|
||||||
|
service.update(businessDay);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_DELETE)
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public void delete(@RequestParam String id) {
|
||||||
|
service.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,103 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.controller;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.gao.annotation.RequireGaoPermission;
|
||||||
|
import com.imyeyu.api.modules.gao.annotation.RequireGaoRole;
|
||||||
|
import com.imyeyu.api.modules.gao.bean.GaoPermissionCode;
|
||||||
|
import com.imyeyu.api.modules.gao.bean.GaoRoleCode;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStore;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoStoreService;
|
||||||
|
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||||
|
import com.imyeyu.api.bean.RoleMatchMode;
|
||||||
|
import com.imyeyu.network.Network;
|
||||||
|
import com.imyeyu.spring.TimiSpring;
|
||||||
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
|
import com.imyeyu.spring.annotation.IgnoreGlobalReturn;
|
||||||
|
import com.imyeyu.spring.annotation.RequestRateLimit;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
|
import com.imyeyu.utils.Time;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/// GAO 门店接口
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
@RestController
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
@RequestMapping("/gao/store")
|
||||||
|
@RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
|
||||||
|
public class GaoStoreController {
|
||||||
|
|
||||||
|
private final GaoStoreService service;
|
||||||
|
private final UserLoginService userLoginService;
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
|
||||||
|
@PostMapping("/list")
|
||||||
|
public PageResult<GaoStore> list(@RequestBody Page<GaoStore> page) {
|
||||||
|
return service.page(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_READ)
|
||||||
|
@PostMapping("/detail")
|
||||||
|
public GaoStore detail(@RequestParam String id) {
|
||||||
|
return service.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_CREATE)
|
||||||
|
@PostMapping("/create")
|
||||||
|
public String create(@RequestBody GaoStore store) {
|
||||||
|
service.create(store);
|
||||||
|
return store.getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_UPDATE)
|
||||||
|
@PostMapping("/update")
|
||||||
|
public void update(@RequestBody GaoStore store) {
|
||||||
|
service.update(store);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_DELETE)
|
||||||
|
@PostMapping("/delete")
|
||||||
|
public void delete(@RequestParam String id) {
|
||||||
|
service.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@IgnoreGlobalReturn
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.STORE_EXPORT)
|
||||||
|
@PostMapping("/export")
|
||||||
|
public void export(@RequestBody Page<GaoStore> page) throws IOException {
|
||||||
|
HttpServletResponse resp = TimiSpring.getResponse();
|
||||||
|
String contentDisposition = Network.getFileDownloadHeader("门店列表-%s.xlsx".formatted(Time.serialize.format(Time.now())));
|
||||||
|
resp.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||||
|
resp.setHeader("Content-Disposition", contentDisposition);
|
||||||
|
resp.getOutputStream().write(service.export(page));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoRole(value = {GaoRoleCode.GLOBAL_MANAGER, GaoRoleCode.STORE_MANAGER, GaoRoleCode.EMPLOYEE}, mode = RoleMatchMode.ANY)
|
||||||
|
@PostMapping("/detail/user")
|
||||||
|
public GaoStore getByLoginUser() {
|
||||||
|
return service.getByUserId(userLoginService.getRequireLoginUserId());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,14 +2,23 @@ package com.imyeyu.api.modules.gao.controller;
|
|||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonView;
|
import com.fasterxml.jackson.annotation.JsonView;
|
||||||
import com.imyeyu.api.bean.ModuleCode;
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
|
import com.imyeyu.api.modules.common.entity.Attachment;
|
||||||
|
import com.imyeyu.api.modules.common.service.AttachmentService;
|
||||||
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;
|
||||||
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.modules.gao.entity.GaoUser;
|
import com.imyeyu.api.modules.gao.entity.GaoUser;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoStoreService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoUserService;
|
import com.imyeyu.api.modules.gao.service.GaoUserService;
|
||||||
import com.imyeyu.api.modules.user.entity.Role;
|
import com.imyeyu.api.modules.user.entity.Role;
|
||||||
|
import com.imyeyu.api.modules.user.entity.User;
|
||||||
|
import com.imyeyu.api.modules.user.service.RoleChecker;
|
||||||
import com.imyeyu.api.modules.user.service.RoleService;
|
import com.imyeyu.api.modules.user.service.RoleService;
|
||||||
|
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||||
|
import com.imyeyu.api.modules.user.service.UserRoleService;
|
||||||
|
import com.imyeyu.api.modules.user.service.UserService;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.spring.annotation.AOPLog;
|
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;
|
||||||
@@ -23,6 +32,7 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/// GAO 用户接口
|
/// GAO 用户接口
|
||||||
///
|
///
|
||||||
@@ -34,8 +44,14 @@ import java.util.List;
|
|||||||
@RequireGaoRole(GaoRoleCode.STORE_MANAGER)
|
@RequireGaoRole(GaoRoleCode.STORE_MANAGER)
|
||||||
public class GaoUserController {
|
public class GaoUserController {
|
||||||
|
|
||||||
private final GaoUserService service;
|
private final UserService userService;
|
||||||
private final RoleService roleService;
|
private final RoleService roleService;
|
||||||
|
private final RoleChecker roleChecker;
|
||||||
|
private final GaoUserService service;
|
||||||
|
private final UserRoleService userRoleService;
|
||||||
|
private final GaoStoreService gaoStoreService;
|
||||||
|
private final UserLoginService userLoginService;
|
||||||
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@@ -43,7 +59,22 @@ public class GaoUserController {
|
|||||||
@PostMapping("/list")
|
@PostMapping("/list")
|
||||||
@JsonView(ResponseView.Public.class)
|
@JsonView(ResponseView.Public.class)
|
||||||
public PageResult<GaoUser> list(@RequestBody Page<GaoUser> page) {
|
public PageResult<GaoUser> list(@RequestBody Page<GaoUser> page) {
|
||||||
return service.pageWithUser(page);
|
if (!roleChecker.hasAny(ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name())) {
|
||||||
|
// 非全局管理只能看所在店用户
|
||||||
|
page.setEqualsExample(TimiJava.defaultIfNull(page.getEqualsExample(), new GaoUser()));
|
||||||
|
page.getEqualsExample().setStoreId(gaoStoreService.getByUserId(userLoginService.getRequireLoginUserId()).getId());
|
||||||
|
}
|
||||||
|
PageResult<GaoUser> result = service.page(page);
|
||||||
|
{
|
||||||
|
List<String> userIdList = result.getList().stream().map(GaoUser::getUserId).toList();
|
||||||
|
Map<String, User> userMap = userService.mapByIdList(userIdList);
|
||||||
|
Map<String, List<Role>> roleMap = userRoleService.mapRoleListByUserIdList(userIdList);
|
||||||
|
for (GaoUser gaoUser : result.getList()) {
|
||||||
|
gaoUser.setUser(userMap.get(gaoUser.getUserId()));
|
||||||
|
gaoUser.getUser().setRoleEntityList(roleMap.get(gaoUser.getUserId()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@@ -52,16 +83,14 @@ public class GaoUserController {
|
|||||||
@PostMapping("/detail")
|
@PostMapping("/detail")
|
||||||
@JsonView(ResponseView.Public.class)
|
@JsonView(ResponseView.Public.class)
|
||||||
public GaoUser detail(@RequestParam String id) {
|
public GaoUser detail(@RequestParam String id) {
|
||||||
return service.get(id);
|
GaoUser result = service.get(id);
|
||||||
|
{
|
||||||
|
User user = userService.get(result.getUserId());
|
||||||
|
user.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.USER, user.getId()));
|
||||||
|
user.setRoleEntityList(userRoleService.listRoleByUserId(user.getId()));
|
||||||
|
result.setUser(user);
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
@AOPLog
|
|
||||||
@RequestRateLimit
|
|
||||||
@RequireGaoPermission(GaoPermissionCode.USER_READ)
|
|
||||||
@PostMapping("/detail/user")
|
|
||||||
@JsonView(ResponseView.Public.class)
|
|
||||||
public GaoUser detailByUserId(@RequestParam String userId) {
|
|
||||||
return service.getByUserId(userId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@@ -84,6 +113,17 @@ public class GaoUserController {
|
|||||||
return service.get(gaoUser.getId());
|
return service.get(gaoUser.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AOPLog
|
||||||
|
@RequestRateLimit
|
||||||
|
@RequireGaoRole(GaoRoleCode.GLOBAL_MANAGER)
|
||||||
|
@RequireGaoPermission(GaoPermissionCode.USER_UPDATE)
|
||||||
|
@PostMapping("/transfer/store")
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
|
public GaoUser transferStore(@RequestBody GaoUser gaoUser) {
|
||||||
|
service.transferStore(gaoUser);
|
||||||
|
return service.get(gaoUser.getId());
|
||||||
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequestRateLimit
|
@RequestRateLimit
|
||||||
@RequireGaoPermission(GaoPermissionCode.USER_DELETE)
|
@RequireGaoPermission(GaoPermissionCode.USER_DELETE)
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ public class GaoCustomer extends UUIDEntity {
|
|||||||
/// 客户编码
|
/// 客户编码
|
||||||
private String code;
|
private String code;
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
/// 姓名
|
/// 姓名
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,9 @@ public class GaoEvent extends UUIDEntity {
|
|||||||
/// 登记事件名称
|
/// 登记事件名称
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
/// 说明
|
/// 说明
|
||||||
private String description;
|
private String description;
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ public class GaoEventRecord extends UUIDEntity {
|
|||||||
/// 客户 ID
|
/// 客户 ID
|
||||||
private String customerId;
|
private String customerId;
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
/// 登记登记事件 ID
|
/// 登记登记事件 ID
|
||||||
private String eventId;
|
private String eventId;
|
||||||
|
|
||||||
@@ -43,6 +46,12 @@ public class GaoEventRecord extends UUIDEntity {
|
|||||||
/// 登记时间
|
/// 登记时间
|
||||||
private Long registeredAt;
|
private Long registeredAt;
|
||||||
|
|
||||||
|
/// 登记日期值,格式为 yyyyMMdd
|
||||||
|
private Integer registeredDateValue;
|
||||||
|
|
||||||
|
/// 营业日递增序号
|
||||||
|
private Long businessDayNo;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private GaoCustomer customer;
|
private GaoCustomer customer;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,57 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.entity;
|
||||||
|
|
||||||
|
import com.imyeyu.spring.entity.UUIDEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// GAO 门店
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class GaoStore extends UUIDEntity {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 门店状态
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
public enum Status {
|
||||||
|
|
||||||
|
/// 可用
|
||||||
|
ACTIVE,
|
||||||
|
|
||||||
|
/// 停用
|
||||||
|
INACTIVE,
|
||||||
|
|
||||||
|
/// 已删除
|
||||||
|
DELETED
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 门店编码
|
||||||
|
private String code;
|
||||||
|
|
||||||
|
/// 门店名称
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/// 状态
|
||||||
|
private Status status;
|
||||||
|
|
||||||
|
/// 电话
|
||||||
|
private String telephone;
|
||||||
|
|
||||||
|
/// 地址
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
/// 备注
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/// 排序值
|
||||||
|
private Integer sort;
|
||||||
|
|
||||||
|
public boolean isActivated() {
|
||||||
|
return status == Status.ACTIVE;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.entity;
|
||||||
|
|
||||||
|
import com.imyeyu.spring.entity.UUIDEntity;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// GAO 门店营业日
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
@Data
|
||||||
|
@EqualsAndHashCode(callSuper = true)
|
||||||
|
public class GaoStoreBusinessDay extends UUIDEntity {
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 营业状态
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
public enum OpenStatus {
|
||||||
|
|
||||||
|
/// 营业
|
||||||
|
OPEN,
|
||||||
|
|
||||||
|
/// 休息
|
||||||
|
CLOSED
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
|
/// 日期值,格式为 yyyyMMdd
|
||||||
|
private Integer dateValue;
|
||||||
|
|
||||||
|
/// 营业状态
|
||||||
|
private OpenStatus openStatus;
|
||||||
|
|
||||||
|
/// 营业日递增序号,仅营业日有值
|
||||||
|
private Long businessDayNo;
|
||||||
|
|
||||||
|
/// 原因
|
||||||
|
private String reason;
|
||||||
|
}
|
||||||
@@ -1,14 +1,11 @@
|
|||||||
package com.imyeyu.api.modules.gao.entity;
|
package com.imyeyu.api.modules.gao.entity;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.user.entity.User;
|
import com.imyeyu.api.modules.user.entity.User;
|
||||||
import com.imyeyu.api.modules.user.entity.Role;
|
|
||||||
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;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// GAO 用户
|
/// GAO 用户
|
||||||
///
|
///
|
||||||
@@ -21,6 +18,9 @@ public class GaoUser extends UUIDEntity {
|
|||||||
/// 用户 ID
|
/// 用户 ID
|
||||||
private String userId;
|
private String userId;
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
/// true 为启用
|
/// true 为启用
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
|
|
||||||
@@ -29,10 +29,4 @@ public class GaoUser extends UUIDEntity {
|
|||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
private User user;
|
private User user;
|
||||||
|
|
||||||
@Transient
|
|
||||||
private List<Role> roleList;
|
|
||||||
|
|
||||||
@Transient
|
|
||||||
private List<String> roleIdList;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.imyeyu.api.modules.gao.entity.GaoCustomer;
|
|||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStateView;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerDailyStateView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerGenderStatView;
|
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 java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -22,16 +23,16 @@ public interface GaoCustomerMapper extends BaseMapper<GaoCustomer, String> {
|
|||||||
/// @param beginCreatedAt 开始创建时间
|
/// @param beginCreatedAt 开始创建时间
|
||||||
/// @param endCreatedAt 结束创建时间
|
/// @param endCreatedAt 结束创建时间
|
||||||
/// @return 每日新增客户数
|
/// @return 每日新增客户数
|
||||||
List<GaoCustomerDailyStateView> stateDailyNewCustomer(Long beginCreatedAt, Long endCreatedAt);
|
List<GaoCustomerDailyStateView> stateDailyNewCustomer(@Param("storeId") String storeId, @Param("beginCreatedAt") Long beginCreatedAt, @Param("endCreatedAt") Long endCreatedAt);
|
||||||
|
|
||||||
/// 统计开始时间前客户总数
|
/// 统计开始时间前客户总数
|
||||||
///
|
///
|
||||||
/// @param beginCreatedAt 开始创建时间
|
/// @param beginCreatedAt 开始创建时间
|
||||||
/// @return 客户总数
|
/// @return 客户总数
|
||||||
Long countCreatedBefore(Long beginCreatedAt);
|
Long countCreatedBefore(@Param("storeId") String storeId, @Param("beginCreatedAt") Long beginCreatedAt);
|
||||||
|
|
||||||
/// 统计客户性别分布
|
/// 统计客户性别分布
|
||||||
///
|
///
|
||||||
/// @return 性别统计列表
|
/// @return 性别统计列表
|
||||||
List<GaoCustomerGenderStatView> stateGender();
|
List<GaoCustomerGenderStatView> stateGender(@Param("storeId") String storeId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.imyeyu.api.modules.gao.mapper;
|
|||||||
|
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoEvent;
|
import com.imyeyu.api.modules.gao.entity.GaoEvent;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -15,5 +16,5 @@ public interface GaoEventMapper extends BaseMapper<GaoEvent, String> {
|
|||||||
|
|
||||||
List<GaoEvent> selectByIdList(Collection<String> idList);
|
List<GaoEvent> selectByIdList(Collection<String> idList);
|
||||||
|
|
||||||
List<GaoEvent> selectValidList(Long now);
|
List<GaoEvent> selectValidList(@Param("storeId") String storeId, @Param("now") Long now);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.imyeyu.api.modules.gao.vo.GaoCustomerEventRankView;
|
|||||||
import com.imyeyu.api.modules.gao.vo.GaoEventRecordPage;
|
import com.imyeyu.api.modules.gao.vo.GaoEventRecordPage;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoEventRecordRankPage;
|
import com.imyeyu.api.modules.gao.vo.GaoEventRecordRankPage;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -14,7 +15,21 @@ import java.util.List;
|
|||||||
/// @since 2026-07-27 14:11
|
/// @since 2026-07-27 14:11
|
||||||
public interface GaoEventRecordMapper extends BaseMapper<GaoEventRecord, String> {
|
public interface GaoEventRecordMapper extends BaseMapper<GaoEventRecord, String> {
|
||||||
|
|
||||||
Long count(String customerId, String eventId, Long beginAt, Long endAt);
|
Long count(String storeId, String customerId, String eventId, Long beginAt, Long endAt);
|
||||||
|
|
||||||
|
/// 按门店和登记日期统计登记记录数
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param registeredDateValue 登记日期值,格式为 yyyyMMdd
|
||||||
|
/// @return 登记记录数
|
||||||
|
Long countByStoreIdAndRegisteredDateValue(@Param("storeId") String storeId, @Param("registeredDateValue") Integer registeredDateValue);
|
||||||
|
|
||||||
|
/// 同步门店指定日期的登记记录营业日序号快照
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param registeredDateValue 登记日期值,格式为 yyyyMMdd
|
||||||
|
/// @param businessDayNo 营业日序号
|
||||||
|
void updateBusinessDayNoByStoreIdAndRegisteredDateValue(@Param("storeId") String storeId, @Param("registeredDateValue") Integer registeredDateValue, @Param("businessDayNo") Long businessDayNo);
|
||||||
|
|
||||||
long countByRange(GaoEventRecordPage page);
|
long countByRange(GaoEventRecordPage page);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.mapper;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStoreBusinessDay;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// GAO 门店营业日 Mapper
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
public interface GaoStoreBusinessDayMapper extends BaseMapper<GaoStoreBusinessDay, String> {
|
||||||
|
|
||||||
|
/// 按门店和日期查询营业日
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param dateValue 日期值,格式为 yyyyMMdd
|
||||||
|
/// @return 营业日
|
||||||
|
@Select("SELECT * FROM `gao_store_business_day` WHERE `store_id` = #{storeId} AND `date_value` = #{dateValue} AND `deleted_at` IS NULL LIMIT 1")
|
||||||
|
GaoStoreBusinessDay selectByStoreIdAndDateValue(@Param("storeId") String storeId, @Param("dateValue") Integer dateValue);
|
||||||
|
|
||||||
|
/// 查询指定日期前最后一个营业日序号
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param dateValue 日期值,格式为 yyyyMMdd
|
||||||
|
/// @return 营业日序号
|
||||||
|
@Select("SELECT MAX(`business_day_no`) FROM `gao_store_business_day` WHERE `store_id` = #{storeId} AND `date_value` < #{dateValue} AND `open_status` = 'OPEN' AND `deleted_at` IS NULL")
|
||||||
|
Long selectLastBusinessDayNoBefore(@Param("storeId") String storeId, @Param("dateValue") Integer dateValue);
|
||||||
|
|
||||||
|
/// 查询指定日期及之后的营业日
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param beginDateValue 开始日期值,格式为 yyyyMMdd
|
||||||
|
/// @return 营业日列表
|
||||||
|
@Select("SELECT * FROM `gao_store_business_day` WHERE `store_id` = #{storeId} AND `date_value` >= #{beginDateValue} AND `open_status` = 'OPEN' AND `deleted_at` IS NULL ORDER BY `date_value` ASC")
|
||||||
|
List<GaoStoreBusinessDay> selectOpenListFromDate(@Param("storeId") String storeId, @Param("beginDateValue") Integer beginDateValue);
|
||||||
|
|
||||||
|
/// 查询日期范围内的营业日
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param beginDateValue 开始日期值,格式为 yyyyMMdd
|
||||||
|
/// @param endDateValue 结束日期值,格式为 yyyyMMdd
|
||||||
|
/// @return 营业日列表
|
||||||
|
@Select("SELECT * FROM `gao_store_business_day` WHERE `store_id` = #{storeId} AND `date_value` >= #{beginDateValue} AND `date_value` <= #{endDateValue} AND `deleted_at` IS NULL ORDER BY `date_value` ASC")
|
||||||
|
List<GaoStoreBusinessDay> selectByStoreIdAndDateRange(@Param("storeId") String storeId, @Param("beginDateValue") Integer beginDateValue, @Param("endDateValue") Integer endDateValue);
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.mapper;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStore;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// GAO 门店 Mapper
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
public interface GaoStoreMapper extends BaseMapper<GaoStore, String> {
|
||||||
|
|
||||||
|
/// 查询用户所属的可用门店
|
||||||
|
///
|
||||||
|
/// @param userId 用户 ID
|
||||||
|
/// @return 门店
|
||||||
|
GaoStore selectByUserId(@Param("userId") String userId);
|
||||||
|
}
|
||||||
@@ -14,4 +14,7 @@ public interface GaoUserMapper extends BaseMapper<GaoUser, String> {
|
|||||||
|
|
||||||
@Select("SELECT * FROM `gao_user` WHERE `user_id` = #{userId} AND `deleted_at` IS NULL LIMIT 1")
|
@Select("SELECT * FROM `gao_user` WHERE `user_id` = #{userId} AND `deleted_at` IS NULL LIMIT 1")
|
||||||
GaoUser selectByUserId(@Param("userId") String userId);
|
GaoUser selectByUserId(@Param("userId") String userId);
|
||||||
|
|
||||||
|
@Select("SELECT * FROM `gao_user` WHERE `store_id` = #{storeId} AND `user_id` = #{userId} AND `deleted_at` IS NULL LIMIT 1")
|
||||||
|
GaoUser selectByStoreIdAndUserId(@Param("storeId") String storeId, @Param("userId") String userId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,11 +23,17 @@ public interface GaoCustomerService extends BaseService<GaoCustomer, String> {
|
|||||||
|
|
||||||
/// 按编码查询客户
|
/// 按编码查询客户
|
||||||
///
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
/// @param code 客户编码
|
/// @param code 客户编码
|
||||||
/// @return 客户
|
/// @return 客户
|
||||||
GaoCustomer getByCode(String code);
|
GaoCustomer getByCode(String storeId, String code);
|
||||||
|
|
||||||
GaoCustomer getByName(String name);
|
/// 按姓名查询客户
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param name 姓名
|
||||||
|
/// @return 客户
|
||||||
|
GaoCustomer getByName(String storeId, String name);
|
||||||
|
|
||||||
List<GaoCustomer> listByIdList(Collection<String> idList);
|
List<GaoCustomer> listByIdList(Collection<String> idList);
|
||||||
|
|
||||||
@@ -65,6 +71,7 @@ public interface GaoCustomerService extends BaseService<GaoCustomer, String> {
|
|||||||
|
|
||||||
/// 统计客户性别分布
|
/// 统计客户性别分布
|
||||||
///
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
/// @return 性别统计列表
|
/// @return 性别统计列表
|
||||||
List<GaoCustomerGenderStatView> stateGender();
|
List<GaoCustomerGenderStatView> stateGender(String storeId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,9 @@ public interface GaoEventService extends BaseService<GaoEvent, String> {
|
|||||||
|
|
||||||
/// 查询启用的登记事件
|
/// 查询启用的登记事件
|
||||||
///
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
/// @return 登记事件列表
|
/// @return 登记事件列表
|
||||||
List<GaoEvent> listValid();
|
List<GaoEvent> listValid(String storeId);
|
||||||
|
|
||||||
/// 查询登记事件要求的角色
|
/// 查询登记事件要求的角色
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStoreBusinessDay;
|
||||||
|
import com.imyeyu.spring.service.BaseService;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// GAO 门店营业日服务
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
public interface GaoStoreBusinessDayService extends BaseService<GaoStoreBusinessDay, String> {
|
||||||
|
|
||||||
|
/// 解析营业日,不存在时按默认营业日创建
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param dateValue 日期值,格式为 yyyyMMdd
|
||||||
|
/// @return 营业日
|
||||||
|
GaoStoreBusinessDay resolveOpenBusinessDay(String storeId, Integer dateValue);
|
||||||
|
|
||||||
|
/// 重算门店营业日序号并同步登记记录快照
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param beginDateValue 开始日期值,格式为 yyyyMMdd
|
||||||
|
void rebuildBusinessDayNo(String storeId, Integer beginDateValue);
|
||||||
|
|
||||||
|
/// 查询日期范围内的营业日
|
||||||
|
///
|
||||||
|
/// @param storeId 门店 ID
|
||||||
|
/// @param beginDateValue 开始日期值,格式为 yyyyMMdd
|
||||||
|
/// @param endDateValue 结束日期值,格式为 yyyyMMdd
|
||||||
|
/// @return 营业日列表
|
||||||
|
java.util.List<GaoStoreBusinessDay> listByDateRange(String storeId, Integer beginDateValue, Integer endDateValue);
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStore;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.service.BaseService;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// GAO 门店服务
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
public interface GaoStoreService extends BaseService<GaoStore, String> {
|
||||||
|
|
||||||
|
/// 查询用户所属门店
|
||||||
|
///
|
||||||
|
/// @param userId 用户 ID
|
||||||
|
/// @return 门店
|
||||||
|
GaoStore getByUserId(String userId);
|
||||||
|
|
||||||
|
/// 导出门店列表
|
||||||
|
///
|
||||||
|
/// @param page 分页查询条件
|
||||||
|
/// @return xlsx 文件字节
|
||||||
|
byte[] export(Page<GaoStore> page) throws IOException;
|
||||||
|
}
|
||||||
@@ -1,8 +1,6 @@
|
|||||||
package com.imyeyu.api.modules.gao.service;
|
package com.imyeyu.api.modules.gao.service;
|
||||||
|
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoUser;
|
import com.imyeyu.api.modules.gao.entity.GaoUser;
|
||||||
import com.imyeyu.spring.bean.Page;
|
|
||||||
import com.imyeyu.spring.bean.PageResult;
|
|
||||||
import com.imyeyu.spring.service.BaseService;
|
import com.imyeyu.spring.service.BaseService;
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -12,15 +10,8 @@ import com.imyeyu.spring.service.BaseService;
|
|||||||
/// @since 2026-07-30
|
/// @since 2026-07-30
|
||||||
public interface GaoUserService extends BaseService<GaoUser, String> {
|
public interface GaoUserService extends BaseService<GaoUser, String> {
|
||||||
|
|
||||||
/// 按用户 ID 查询 GAO 用户
|
/// 调整 GAO 用户所属门店
|
||||||
///
|
///
|
||||||
/// @param userId 用户 ID
|
/// @param gaoUser GAO 用户,必须包含 ID 和目标门店 ID
|
||||||
/// @return GAO 用户
|
void transferStore(GaoUser gaoUser);
|
||||||
GaoUser getByUserId(String userId);
|
|
||||||
|
|
||||||
/// 分页查询并填充用户详情
|
|
||||||
///
|
|
||||||
/// @param page 分页请求
|
|
||||||
/// @return GAO 用户分页
|
|
||||||
PageResult<GaoUser> pageWithUser(Page<GaoUser> page);
|
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-14
@@ -34,8 +34,10 @@ import java.time.temporal.ChronoUnit;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/// 客户服务实现
|
/// 客户服务实现
|
||||||
///
|
///
|
||||||
@@ -66,21 +68,24 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
@Override
|
@Override
|
||||||
public void create(GaoCustomer customer) {
|
public void create(GaoCustomer customer) {
|
||||||
TimiException.required(customer.getName(), "not found customer.name");
|
TimiException.required(customer.getName(), "not found customer.name");
|
||||||
|
TimiException.required(customer.getStoreId(), "not found customer.storeId");
|
||||||
|
|
||||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_CREATE");
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_CREATE");
|
||||||
try {
|
try {
|
||||||
logger.setContent(jackson.writeValueAsString(customer));
|
logger.setContent(jackson.writeValueAsString(customer));
|
||||||
{
|
{
|
||||||
GaoCustomer byName = getByName(customer.getName());
|
GaoCustomer byName = getByName(customer.getStoreId(), customer.getName());
|
||||||
TimiException.requiredNull(byName, "该姓名客户已登记");
|
TimiException.requiredNull(byName, "该姓名客户已登记");
|
||||||
}
|
}
|
||||||
if (TimiJava.isNotEmpty(customer.getCode())) {
|
if (TimiJava.isNotEmpty(customer.getCode())) {
|
||||||
GaoCustomer byCode = getByCode(customer.getCode());
|
GaoCustomer byCode = getByCode(customer.getStoreId(), customer.getCode());
|
||||||
TimiException.requiredNull(byCode, "该编码客户已登记");
|
TimiException.requiredNull(byCode, "该编码客户已登记");
|
||||||
}
|
}
|
||||||
if (TimiJava.isNotEmpty(customer.getIntroducerCustomerId())) {
|
if (TimiJava.isNotEmpty(customer.getIntroducerCustomerId())) {
|
||||||
TimiException.requiredTrue(!customer.getIntroducerCustomerId().equals(customer.getId()), "customer.introducerCustomerId invalid");
|
TimiException.requiredTrue(!customer.getIntroducerCustomerId().equals(customer.getId()), "customer.introducerCustomerId invalid");
|
||||||
TimiException.required(super.get(customer.getIntroducerCustomerId()), "not found introducer customer");
|
GaoCustomer introducerCustomer = super.get(customer.getIntroducerCustomerId());
|
||||||
|
TimiException.required(introducerCustomer, "not found introducer customer");
|
||||||
|
TimiException.requiredTrue(customer.getStoreId().equals(introducerCustomer.getStoreId()), "介绍人和客户不属于同一门店");
|
||||||
}
|
}
|
||||||
|
|
||||||
customer.setBirthdateCalendar(TimiJava.defaultIfNull(customer.getBirthdateCalendar(), GaoCustomer.BirthdateCalendar.SOLAR));
|
customer.setBirthdateCalendar(TimiJava.defaultIfNull(customer.getBirthdateCalendar(), GaoCustomer.BirthdateCalendar.SOLAR));
|
||||||
@@ -118,19 +123,21 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
TimiException.required(customer, "not found customer");
|
TimiException.required(customer, "not found customer");
|
||||||
TimiException.required(customer.getId(), "not found customer.id");
|
TimiException.required(customer.getId(), "not found customer.id");
|
||||||
TimiException.required(customer.getName(), "not found customer.name");
|
TimiException.required(customer.getName(), "not found customer.name");
|
||||||
|
TimiException.required(customer.getStoreId(), "not found customer.storeId");
|
||||||
|
|
||||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_UPDATE");
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_UPDATE");
|
||||||
try {
|
try {
|
||||||
logger.setContent(jackson.writeValueAsString(customer));
|
logger.setContent(jackson.writeValueAsString(customer));
|
||||||
GaoCustomer dbCustomer = get(customer.getId());
|
GaoCustomer dbCustomer = get(customer.getId());
|
||||||
|
TimiException.requiredTrue(dbCustomer.getStoreId().equals(customer.getStoreId()), "customer.storeId invalid");
|
||||||
dbCustomer.setCode(TimiJava.defaultIfEmpty(customer.getCode(), null));
|
dbCustomer.setCode(TimiJava.defaultIfEmpty(customer.getCode(), null));
|
||||||
{
|
{
|
||||||
if (!dbCustomer.getCode().equals(customer.getCode())) {
|
if (!Objects.equals(dbCustomer.getCode(), customer.getCode()) && TimiJava.isNotEmpty(customer.getCode())) {
|
||||||
GaoCustomer byCode = getByCode(customer.getCode());
|
GaoCustomer byCode = getByCode(customer.getStoreId(), customer.getCode());
|
||||||
TimiException.requiredTrue(byCode == null || !byCode.getId().equals(dbCustomer.getId()), "该姓名客户已登记");
|
TimiException.requiredTrue(byCode == null || !byCode.getId().equals(dbCustomer.getId()), "该姓名客户已登记");
|
||||||
}
|
}
|
||||||
if (!dbCustomer.getName().equals(customer.getName())) {
|
if (!Objects.equals(dbCustomer.getName(), customer.getName())) {
|
||||||
GaoCustomer byName = getByName(customer.getName());
|
GaoCustomer byName = getByName(customer.getStoreId(), customer.getName());
|
||||||
TimiException.requiredTrue(byName == null || !byName.getId().equals(dbCustomer.getId()), "该姓名客户已登记");
|
TimiException.requiredTrue(byName == null || !byName.getId().equals(dbCustomer.getId()), "该姓名客户已登记");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -196,24 +203,28 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GaoCustomer getByCode(String code) {
|
public GaoCustomer getByCode(String storeId, String code) {
|
||||||
|
TimiException.required(storeId, "not found storeId");
|
||||||
TimiException.required(code, "not found code");
|
TimiException.required(code, "not found code");
|
||||||
GaoCustomer example = new GaoCustomer();
|
GaoCustomer example = new GaoCustomer();
|
||||||
|
example.setStoreId(storeId);
|
||||||
example.setCode(code);
|
example.setCode(code);
|
||||||
return mapper.selectByExample(example);
|
return mapper.selectByExample(example);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GaoCustomer getByName(String name) {
|
public GaoCustomer getByName(String storeId, String name) {
|
||||||
|
TimiException.required(storeId, "not found storeId");
|
||||||
TimiException.required(name, "not found name");
|
TimiException.required(name, "not found name");
|
||||||
GaoCustomer example = new GaoCustomer();
|
GaoCustomer example = new GaoCustomer();
|
||||||
|
example.setStoreId(storeId);
|
||||||
example.setName(name);
|
example.setName(name);
|
||||||
return mapper.selectByExample(example);
|
return mapper.selectByExample(example);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GaoCustomer> listByIdList(Collection<String> idList) {
|
public List<GaoCustomer> listByIdList(Collection<String> idList) {
|
||||||
return mapper.selectByIdList(idList);
|
return mapper.selectByIdList(new HashSet<>(idList));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -252,6 +263,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
TimiException.required(customer, "not found customer");
|
TimiException.required(customer, "not found customer");
|
||||||
GaoCustomer introducerCustomer = get(introducerCustomerId);
|
GaoCustomer introducerCustomer = get(introducerCustomerId);
|
||||||
TimiException.required(introducerCustomer, "not found introducerCustomer");
|
TimiException.required(introducerCustomer, "not found introducerCustomer");
|
||||||
|
TimiException.requiredTrue(customer.getStoreId().equals(introducerCustomer.getStoreId()), "介绍人和客户不属于同一门店");
|
||||||
if (introducerCustomer.getIntroducerCustomerId().equals(customer.getIntroducerCustomerId())) {
|
if (introducerCustomer.getIntroducerCustomerId().equals(customer.getIntroducerCustomerId())) {
|
||||||
throw new TimiException(TimiCode.ARG_BAD, "customer can not upper be introducer customer");
|
throw new TimiException(TimiCode.ARG_BAD, "customer can not upper be introducer customer");
|
||||||
}
|
}
|
||||||
@@ -312,6 +324,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
@Override
|
@Override
|
||||||
public List<GaoCustomerDailyStateView> stateDailyTrend(GaoCustomerTrendStateReq req) {
|
public List<GaoCustomerDailyStateView> stateDailyTrend(GaoCustomerTrendStateReq req) {
|
||||||
TimiException.required(req, "not found req");
|
TimiException.required(req, "not found req");
|
||||||
|
TimiException.required(req.getStoreId(), "not found req.storeId");
|
||||||
TimiException.required(req.getBeginCreatedAt(), "not found req.beginCreatedAt");
|
TimiException.required(req.getBeginCreatedAt(), "not found req.beginCreatedAt");
|
||||||
TimiException.required(req.getEndCreatedAt(), "not found req.endCreatedAt");
|
TimiException.required(req.getEndCreatedAt(), "not found req.endCreatedAt");
|
||||||
TimiException.requiredTrue(req.getEndCreatedAt() >= req.getBeginCreatedAt(), "req.endCreatedAt lt req.beginCreatedAt");
|
TimiException.requiredTrue(req.getEndCreatedAt() >= req.getBeginCreatedAt(), "req.endCreatedAt lt req.beginCreatedAt");
|
||||||
@@ -325,10 +338,10 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
long beginCreatedAt = beginDate.atStartOfDay(zoneId).toInstant().toEpochMilli();
|
long beginCreatedAt = beginDate.atStartOfDay(zoneId).toInstant().toEpochMilli();
|
||||||
long endCreatedAt = endDate.plusDays(1).atStartOfDay(zoneId).toInstant().toEpochMilli() - 1;
|
long endCreatedAt = endDate.plusDays(1).atStartOfDay(zoneId).toInstant().toEpochMilli() - 1;
|
||||||
Map<Integer, Long> newCustomerCountMap = new HashMap<>();
|
Map<Integer, Long> newCustomerCountMap = new HashMap<>();
|
||||||
for (GaoCustomerDailyStateView view : mapper.stateDailyNewCustomer(beginCreatedAt, endCreatedAt)) {
|
for (GaoCustomerDailyStateView view : mapper.stateDailyNewCustomer(req.getStoreId(), beginCreatedAt, endCreatedAt)) {
|
||||||
newCustomerCountMap.put(view.getDateValue(), TimiJava.defaultIfNull(view.getNewCustomerCount(), 0L));
|
newCustomerCountMap.put(view.getDateValue(), TimiJava.defaultIfNull(view.getNewCustomerCount(), 0L));
|
||||||
}
|
}
|
||||||
long totalCustomerCount = TimiJava.defaultIfNull(mapper.countCreatedBefore(beginCreatedAt), 0L);
|
long totalCustomerCount = TimiJava.defaultIfNull(mapper.countCreatedBefore(req.getStoreId(), beginCreatedAt), 0L);
|
||||||
List<GaoCustomerDailyStateView> list = new ArrayList<>();
|
List<GaoCustomerDailyStateView> list = new ArrayList<>();
|
||||||
for (LocalDate date = beginDate; !date.isAfter(endDate); date = date.plusDays(1)) {
|
for (LocalDate date = beginDate; !date.isAfter(endDate); date = date.plusDays(1)) {
|
||||||
int dateValue = Integer.parseInt(DAY_FORMATTER.format(date));
|
int dateValue = Integer.parseInt(DAY_FORMATTER.format(date));
|
||||||
@@ -344,8 +357,9 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GaoCustomerGenderStatView> stateGender() {
|
public List<GaoCustomerGenderStatView> stateGender(String storeId) {
|
||||||
return mapper.stateGender();
|
TimiException.required(storeId, "not found storeId");
|
||||||
|
return mapper.stateGender(storeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void changeInvitedCount(String customerId, long delta) {
|
private void changeInvitedCount(String customerId, long delta) {
|
||||||
|
|||||||
+38
-7
@@ -12,6 +12,7 @@ import com.imyeyu.api.modules.gao.mapper.GaoEventRecordMapper;
|
|||||||
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
import com.imyeyu.api.modules.gao.service.GaoCustomerService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoEventRecordService;
|
import com.imyeyu.api.modules.gao.service.GaoEventRecordService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
import com.imyeyu.api.modules.gao.service.GaoEventService;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoStoreBusinessDayService;
|
||||||
import com.imyeyu.api.modules.gao.util.EventRecordXSSFBuilder;
|
import com.imyeyu.api.modules.gao.util.EventRecordXSSFBuilder;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoCustomerEventRankView;
|
import com.imyeyu.api.modules.gao.vo.GaoCustomerEventRankView;
|
||||||
import com.imyeyu.api.modules.gao.vo.GaoEventRecordPage;
|
import com.imyeyu.api.modules.gao.vo.GaoEventRecordPage;
|
||||||
@@ -34,8 +35,10 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
import java.time.temporal.TemporalAdjusters;
|
import java.time.temporal.TemporalAdjusters;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -50,6 +53,8 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEventRecord, String> implements GaoEventRecordService {
|
public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEventRecord, String> implements GaoEventRecordService {
|
||||||
|
|
||||||
|
private static final DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||||
|
|
||||||
private final ObjectMapper jackson;
|
private final ObjectMapper jackson;
|
||||||
private final RoleChecker roleChecker;
|
private final RoleChecker roleChecker;
|
||||||
private final LoggerService loggerService;
|
private final LoggerService loggerService;
|
||||||
@@ -57,6 +62,7 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
private final UserLoginService userLoginService;
|
private final UserLoginService userLoginService;
|
||||||
private final AttachmentService attachmentService;
|
private final AttachmentService attachmentService;
|
||||||
private final GaoCustomerService customerService;
|
private final GaoCustomerService customerService;
|
||||||
|
private final GaoStoreBusinessDayService businessDayService;
|
||||||
|
|
||||||
private final GaoEventRecordMapper mapper;
|
private final GaoEventRecordMapper mapper;
|
||||||
|
|
||||||
@@ -79,8 +85,11 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
String loginUserId = userLoginService.getRequireLoginUserId();
|
String loginUserId = userLoginService.getRequireLoginUserId();
|
||||||
Long registeredAt = TimiJava.defaultIfNull(record.getRegisteredAt(), Time.now());
|
Long registeredAt = TimiJava.defaultIfNull(record.getRegisteredAt(), Time.now());
|
||||||
GaoEvent event = eventService.get(record.getEventId());
|
GaoEvent event = eventService.get(record.getEventId());
|
||||||
|
TimiException.required(event.getStoreId(), "not found event.storeId");
|
||||||
// 检查权限
|
// 检查权限
|
||||||
checkEventPermission(event);
|
checkEventPermission(event);
|
||||||
|
int registeredDateValue = dateValue(registeredAt);
|
||||||
|
long businessDayNo = businessDayService.resolveOpenBusinessDay(event.getStoreId(), registeredDateValue).getBusinessDayNo();
|
||||||
|
|
||||||
List<String> customerIdList = TimiJava.defaultIfEmpty(record.getCustomerIdList(), List.of(record.getCustomerId()));
|
List<String> customerIdList = TimiJava.defaultIfEmpty(record.getCustomerIdList(), List.of(record.getCustomerId()));
|
||||||
TimiException.required(customerIdList, "not found customerId or empty customerIdList");
|
TimiException.required(customerIdList, "not found customerId or empty customerIdList");
|
||||||
@@ -91,13 +100,19 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
String customerId = customerIdList.get(i);
|
String customerId = customerIdList.get(i);
|
||||||
// 检查事件可登记
|
// 检查事件可登记
|
||||||
checkEventCreatable(customerId, event, registeredAt);
|
checkEventCreatable(customerId, event, registeredAt);
|
||||||
|
GaoCustomer customer = customerService.get(customerId);
|
||||||
|
TimiException.required(customer, "not found customer");
|
||||||
|
TimiException.requiredTrue(event.getStoreId().equals(customer.getStoreId()), "客户和登记事件不属于同一门店");
|
||||||
|
|
||||||
GaoEventRecord dbRecord = new GaoEventRecord();
|
GaoEventRecord dbRecord = new GaoEventRecord();
|
||||||
dbRecord.setCustomerId(customerId);
|
dbRecord.setCustomerId(customerId);
|
||||||
|
dbRecord.setStoreId(event.getStoreId());
|
||||||
dbRecord.setEventId(record.getEventId());
|
dbRecord.setEventId(record.getEventId());
|
||||||
dbRecord.setOperatorUserId(loginUserId);
|
dbRecord.setOperatorUserId(loginUserId);
|
||||||
dbRecord.setRemark(record.getRemark());
|
dbRecord.setRemark(record.getRemark());
|
||||||
dbRecord.setRegisteredAt(registeredAt);
|
dbRecord.setRegisteredAt(registeredAt);
|
||||||
|
dbRecord.setRegisteredDateValue(registeredDateValue);
|
||||||
|
dbRecord.setBusinessDayNo(businessDayNo);
|
||||||
super.create(dbRecord);
|
super.create(dbRecord);
|
||||||
// 附件
|
// 附件
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
@@ -146,8 +161,16 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
record.setRegisteredAt(TimiJava.defaultIfNull(record.getRegisteredAt(), Time.now()));
|
record.setRegisteredAt(TimiJava.defaultIfNull(record.getRegisteredAt(), Time.now()));
|
||||||
|
|
||||||
GaoEvent event = eventService.get(record.getEventId());
|
GaoEvent event = eventService.get(record.getEventId());
|
||||||
|
TimiException.required(event.getStoreId(), "not found event.storeId");
|
||||||
checkEventPermission(event);
|
checkEventPermission(event);
|
||||||
checkEventCreatable(record.getCustomerId(), event, record.getRegisteredAt());
|
checkEventCreatable(record.getCustomerId(), event, record.getRegisteredAt());
|
||||||
|
GaoCustomer customer = customerService.get(record.getCustomerId());
|
||||||
|
TimiException.required(customer, "not found customer");
|
||||||
|
TimiException.requiredTrue(event.getStoreId().equals(customer.getStoreId()), "客户和登记事件不属于同一门店");
|
||||||
|
int registeredDateValue = dateValue(record.getRegisteredAt());
|
||||||
|
record.setStoreId(event.getStoreId());
|
||||||
|
record.setRegisteredDateValue(registeredDateValue);
|
||||||
|
record.setBusinessDayNo(businessDayService.resolveOpenBusinessDay(event.getStoreId(), registeredDateValue).getBusinessDayNo());
|
||||||
|
|
||||||
super.update(record);
|
super.update(record);
|
||||||
attachmentService.updateByBizId(Attachment.BizType.GAO_EVENT_RECORD, record.getId(), record.getAttachmentList());
|
attachmentService.updateByBizId(Attachment.BizType.GAO_EVENT_RECORD, record.getId(), record.getAttachmentList());
|
||||||
@@ -176,7 +199,7 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
GaoCustomer dbCustomer = customerService.get(customer.getId());
|
GaoCustomer dbCustomer = customerService.get(customer.getId());
|
||||||
TimiException.required(dbCustomer, "not found customer");
|
TimiException.required(dbCustomer, "not found customer");
|
||||||
if (TimiJava.isNotEmpty(customer.getCode())) {
|
if (TimiJava.isNotEmpty(customer.getCode())) {
|
||||||
GaoCustomer byCode = customerService.getByCode(customer.getCode());
|
GaoCustomer byCode = customerService.getByCode(dbCustomer.getStoreId(), customer.getCode());
|
||||||
TimiException.requiredTrue(byCode == null || dbCustomer.getId().equals(byCode.getId()), "该编码客户已登记");
|
TimiException.requiredTrue(byCode == null || dbCustomer.getId().equals(byCode.getId()), "该编码客户已登记");
|
||||||
dbCustomer.setCode(customer.getCode());
|
dbCustomer.setCode(customer.getCode());
|
||||||
customerService.update(dbCustomer);
|
customerService.update(dbCustomer);
|
||||||
@@ -197,6 +220,7 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<GaoEventRecord> pageByRange(GaoEventRecordPage page) {
|
public PageResult<GaoEventRecord> pageByRange(GaoEventRecordPage page) {
|
||||||
|
TimiException.required(page.getStoreId(), "not found page.storeId");
|
||||||
PageResult<GaoEventRecord> result = new PageResult<>();
|
PageResult<GaoEventRecord> result = new PageResult<>();
|
||||||
result.setTotal(mapper.countByRange(page));
|
result.setTotal(mapper.countByRange(page));
|
||||||
result.setList(mapper.selectByRange(page));
|
result.setList(mapper.selectByRange(page));
|
||||||
@@ -205,12 +229,14 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public byte[] export(GaoEventRecordPage page) throws IOException {
|
public byte[] export(GaoEventRecordPage page) throws IOException {
|
||||||
|
TimiException.required(page.getStoreId(), "not found page.storeId");
|
||||||
List<GaoEventRecord> list = mapper.selectByRange(page);
|
List<GaoEventRecord> list = mapper.selectByRange(page);
|
||||||
return xssfBuilder.build(list);
|
return xssfBuilder.build(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<GaoCustomerEventRankView> pageRankByRange(GaoEventRecordRankPage page) {
|
public PageResult<GaoCustomerEventRankView> pageRankByRange(GaoEventRecordRankPage page) {
|
||||||
|
TimiException.required(page.getStoreId(), "not found page.storeId");
|
||||||
PageResult<GaoCustomerEventRankView> result = new PageResult<>();
|
PageResult<GaoCustomerEventRankView> result = new PageResult<>();
|
||||||
result.setTotal(mapper.countRankByRange(page));
|
result.setTotal(mapper.countRankByRange(page));
|
||||||
result.setList(mapper.selectRankByRange(page));
|
result.setList(mapper.selectRankByRange(page));
|
||||||
@@ -241,18 +267,18 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
beginAt = noon;
|
beginAt = noon;
|
||||||
endAt = today + Time.D;
|
endAt = today + Time.D;
|
||||||
}
|
}
|
||||||
Long count = mapper.count(customerId, event.getId(), beginAt, endAt);
|
Long count = mapper.count(event.getStoreId(), customerId, event.getId(), beginAt, endAt);
|
||||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该客户当前半日已登记该事件");
|
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该客户当前半日已登记该事件");
|
||||||
}
|
}
|
||||||
case NATURAL_DAY -> {
|
case NATURAL_DAY -> {
|
||||||
long beginAt = Time.today(registeredAt);
|
long beginAt = Time.today(registeredAt);
|
||||||
long endAt = beginAt + Time.D;
|
long endAt = beginAt + Time.D;
|
||||||
Long count = mapper.count(customerId, event.getId(), beginAt, endAt);
|
Long count = mapper.count(event.getStoreId(), customerId, event.getId(), beginAt, endAt);
|
||||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该客户当前半日已登记该事件");
|
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该客户当前半日已登记该事件");
|
||||||
}
|
}
|
||||||
case INTERVAL_HOUR -> {
|
case INTERVAL_HOUR -> {
|
||||||
long beginAt = registeredAt - event.getLimitValue() * Time.H;
|
long beginAt = registeredAt - event.getLimitValue() * Time.H;
|
||||||
Long count = mapper.count(customerId, event.getId(), beginAt, registeredAt);
|
Long count = mapper.count(event.getStoreId(), customerId, event.getId(), beginAt, registeredAt);
|
||||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该客户登记该事件间隔不足");
|
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该客户登记该事件间隔不足");
|
||||||
}
|
}
|
||||||
case NATURAL_MONTH -> {
|
case NATURAL_MONTH -> {
|
||||||
@@ -260,17 +286,22 @@ public class GaoEventRecordServiceImplement extends AbstractEntityService<GaoEve
|
|||||||
ZonedDateTime zdt = Instant.ofEpochMilli(registeredAt).atZone(zone);
|
ZonedDateTime zdt = Instant.ofEpochMilli(registeredAt).atZone(zone);
|
||||||
long beginAt = zdt.with(TemporalAdjusters.firstDayOfMonth()).truncatedTo(ChronoUnit.DAYS).toInstant().toEpochMilli();
|
long beginAt = zdt.with(TemporalAdjusters.firstDayOfMonth()).truncatedTo(ChronoUnit.DAYS).toInstant().toEpochMilli();
|
||||||
long endAt = zdt.with(TemporalAdjusters.firstDayOfNextMonth()).truncatedTo(ChronoUnit.DAYS).toInstant().toEpochMilli();
|
long endAt = zdt.with(TemporalAdjusters.firstDayOfNextMonth()).truncatedTo(ChronoUnit.DAYS).toInstant().toEpochMilli();
|
||||||
Long count = mapper.count(customerId, event.getId(), beginAt, endAt);
|
Long count = mapper.count(event.getStoreId(), customerId, event.getId(), beginAt, endAt);
|
||||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该客户当月已登记该事件");
|
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该客户当月已登记该事件");
|
||||||
}
|
}
|
||||||
case TOTAL_LIMIT -> {
|
case TOTAL_LIMIT -> {
|
||||||
Long count = mapper.count(null, event.getId(), null, null);
|
Long count = mapper.count(event.getStoreId(), null, event.getId(), null, null);
|
||||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < event.getLimitValue(), "登记事件总次数已达上限");
|
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < event.getLimitValue(), "登记事件总次数已达上限");
|
||||||
}
|
}
|
||||||
case CUSTOMER_TOTAL_LIMIT -> {
|
case CUSTOMER_TOTAL_LIMIT -> {
|
||||||
Long count = mapper.count(customerId, event.getId(), null, null);
|
Long count = mapper.count(event.getStoreId(), customerId, event.getId(), null, null);
|
||||||
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < event.getLimitValue(), "该客户登记该事件次数已达上限");
|
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < event.getLimitValue(), "该客户登记该事件次数已达上限");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int dateValue(long time) {
|
||||||
|
LocalDate date = Instant.ofEpochMilli(time).atZone(ZoneId.systemDefault()).toLocalDate();
|
||||||
|
return Integer.parseInt(DAY_FORMATTER.format(date));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-2
@@ -56,6 +56,7 @@ public class GaoEventServiceImplement extends AbstractEntityService<GaoEvent, St
|
|||||||
@Override
|
@Override
|
||||||
public void create(GaoEvent event) {
|
public void create(GaoEvent event) {
|
||||||
TimiException.required(event, "not found event");
|
TimiException.required(event, "not found event");
|
||||||
|
TimiException.required(event.getStoreId(), "not found event.storeId");
|
||||||
TimiException.required(event.getName(), "not found event.name");
|
TimiException.required(event.getName(), "not found event.name");
|
||||||
|
|
||||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_EVENT_CREATE");
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_EVENT_CREATE");
|
||||||
@@ -98,6 +99,7 @@ public class GaoEventServiceImplement extends AbstractEntityService<GaoEvent, St
|
|||||||
try {
|
try {
|
||||||
logger.setContent(jackson.writeValueAsString(entity));
|
logger.setContent(jackson.writeValueAsString(entity));
|
||||||
GaoEvent dbEvent = get(entity.getId());
|
GaoEvent dbEvent = get(entity.getId());
|
||||||
|
TimiException.requiredTrue(dbEvent.getStoreId().equals(entity.getStoreId()), "event.storeId invalid");
|
||||||
dbEvent.setName(entity.getName());
|
dbEvent.setName(entity.getName());
|
||||||
dbEvent.setDescription(entity.getDescription());
|
dbEvent.setDescription(entity.getDescription());
|
||||||
dbEvent.setColor(entity.getColor());
|
dbEvent.setColor(entity.getColor());
|
||||||
@@ -163,8 +165,9 @@ public class GaoEventServiceImplement extends AbstractEntityService<GaoEvent, St
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<GaoEvent> listValid() {
|
public List<GaoEvent> listValid(String storeId) {
|
||||||
return mapper.selectValidList(Time.now());
|
TimiException.required(storeId, "not found storeId");
|
||||||
|
return mapper.selectValidList(storeId, Time.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+135
@@ -0,0 +1,135 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.service.implement;
|
||||||
|
|
||||||
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStoreBusinessDay;
|
||||||
|
import com.imyeyu.api.modules.gao.mapper.GaoEventRecordMapper;
|
||||||
|
import com.imyeyu.api.modules.gao.mapper.GaoStoreBusinessDayMapper;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoStoreBusinessDayService;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// GAO 门店营业日服务实现
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class GaoStoreBusinessDayServiceImplement extends AbstractEntityService<GaoStoreBusinessDay, String> implements GaoStoreBusinessDayService {
|
||||||
|
|
||||||
|
private final GaoStoreBusinessDayMapper mapper;
|
||||||
|
private final GaoEventRecordMapper eventRecordMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BaseMapper<GaoStoreBusinessDay, String> mapper() {
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
public void create(GaoStoreBusinessDay businessDay) {
|
||||||
|
prepareBusinessDay(businessDay);
|
||||||
|
super.create(businessDay);
|
||||||
|
if (businessDay.getOpenStatus() == GaoStoreBusinessDay.OpenStatus.OPEN) {
|
||||||
|
rebuildBusinessDayNo(businessDay.getStoreId(), businessDay.getDateValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
public void update(GaoStoreBusinessDay businessDay) {
|
||||||
|
TimiException.required(businessDay, "not found businessDay");
|
||||||
|
TimiException.required(businessDay.getId(), "not found businessDay.id");
|
||||||
|
GaoStoreBusinessDay dbBusinessDay = get(businessDay.getId());
|
||||||
|
TimiException.required(dbBusinessDay, "not found dbBusinessDay");
|
||||||
|
TimiException.requiredTrue(dbBusinessDay.getStoreId().equals(businessDay.getStoreId()), "businessDay.storeId invalid");
|
||||||
|
TimiException.requiredTrue(dbBusinessDay.getDateValue().equals(businessDay.getDateValue()), "businessDay.dateValue invalid");
|
||||||
|
if (businessDay.getOpenStatus() == GaoStoreBusinessDay.OpenStatus.CLOSED) {
|
||||||
|
checkNoRecord(dbBusinessDay);
|
||||||
|
}
|
||||||
|
prepareBusinessDay(businessDay);
|
||||||
|
super.update(businessDay);
|
||||||
|
rebuildBusinessDayNo(businessDay.getStoreId(), businessDay.getDateValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
public void delete(String id) {
|
||||||
|
GaoStoreBusinessDay businessDay = get(id);
|
||||||
|
TimiException.required(businessDay, "not found businessDay");
|
||||||
|
if (businessDay.getOpenStatus() == GaoStoreBusinessDay.OpenStatus.OPEN) {
|
||||||
|
checkNoRecord(businessDay);
|
||||||
|
}
|
||||||
|
super.delete(id);
|
||||||
|
rebuildBusinessDayNo(businessDay.getStoreId(), businessDay.getDateValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public GaoStoreBusinessDay resolveOpenBusinessDay(String storeId, Integer dateValue) {
|
||||||
|
TimiException.required(storeId, "not found storeId");
|
||||||
|
TimiException.required(dateValue, "not found dateValue");
|
||||||
|
GaoStoreBusinessDay businessDay = mapper.selectByStoreIdAndDateValue(storeId, dateValue);
|
||||||
|
if (businessDay != null) {
|
||||||
|
TimiException.requiredTrue(businessDay.getOpenStatus() == GaoStoreBusinessDay.OpenStatus.OPEN, "门店当日休息,不能登记");
|
||||||
|
TimiException.required(businessDay.getBusinessDayNo(), "not found businessDay.businessDayNo");
|
||||||
|
return businessDay;
|
||||||
|
}
|
||||||
|
businessDay = new GaoStoreBusinessDay();
|
||||||
|
businessDay.setStoreId(storeId);
|
||||||
|
businessDay.setDateValue(dateValue);
|
||||||
|
businessDay.setOpenStatus(GaoStoreBusinessDay.OpenStatus.OPEN);
|
||||||
|
super.create(businessDay);
|
||||||
|
rebuildBusinessDayNo(storeId, dateValue);
|
||||||
|
return mapper.selectByStoreIdAndDateValue(storeId, dateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void rebuildBusinessDayNo(String storeId, Integer beginDateValue) {
|
||||||
|
TimiException.required(storeId, "not found storeId");
|
||||||
|
TimiException.required(beginDateValue, "not found beginDateValue");
|
||||||
|
long businessDayNo = TimiJava.defaultIfNull(mapper.selectLastBusinessDayNoBefore(storeId, beginDateValue), 0L);
|
||||||
|
for (GaoStoreBusinessDay businessDay : mapper.selectOpenListFromDate(storeId, beginDateValue)) {
|
||||||
|
businessDayNo++;
|
||||||
|
if (!Long.valueOf(businessDayNo).equals(businessDay.getBusinessDayNo())) {
|
||||||
|
businessDay.setBusinessDayNo(businessDayNo);
|
||||||
|
mapper.update(businessDay);
|
||||||
|
}
|
||||||
|
eventRecordMapper.updateBusinessDayNoByStoreIdAndRegisteredDateValue(storeId, businessDay.getDateValue(), businessDayNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<GaoStoreBusinessDay> listByDateRange(String storeId, Integer beginDateValue, Integer endDateValue) {
|
||||||
|
TimiException.required(storeId, "not found storeId");
|
||||||
|
TimiException.required(beginDateValue, "not found beginDateValue");
|
||||||
|
TimiException.required(endDateValue, "not found endDateValue");
|
||||||
|
TimiException.requiredTrue(beginDateValue <= endDateValue, "endDateValue lt beginDateValue");
|
||||||
|
return mapper.selectByStoreIdAndDateRange(storeId, beginDateValue, endDateValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void prepareBusinessDay(GaoStoreBusinessDay businessDay) {
|
||||||
|
TimiException.required(businessDay, "not found businessDay");
|
||||||
|
TimiException.required(businessDay.getStoreId(), "not found businessDay.storeId");
|
||||||
|
TimiException.required(businessDay.getDateValue(), "not found businessDay.dateValue");
|
||||||
|
businessDay.setOpenStatus(TimiJava.defaultIfNull(businessDay.getOpenStatus(), GaoStoreBusinessDay.OpenStatus.OPEN));
|
||||||
|
if (businessDay.getOpenStatus() == GaoStoreBusinessDay.OpenStatus.CLOSED) {
|
||||||
|
businessDay.setBusinessDayNo(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
businessDay.setBusinessDayNo(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkNoRecord(GaoStoreBusinessDay businessDay) {
|
||||||
|
Long count = eventRecordMapper.countByStoreIdAndRegisteredDateValue(businessDay.getStoreId(), businessDay.getDateValue());
|
||||||
|
TimiException.requiredTrue(TimiJava.defaultIfNull(count, 0L) < 1, "该营业日已有登记记录,不能改为休息或删除");
|
||||||
|
}
|
||||||
|
}
|
||||||
+160
@@ -0,0 +1,160 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.service.implement;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStore;
|
||||||
|
import com.imyeyu.api.modules.gao.mapper.GaoStoreMapper;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoStoreService;
|
||||||
|
import com.imyeyu.api.modules.gao.util.StoreXSSFBuilder;
|
||||||
|
import com.imyeyu.api.modules.system.entity.Logger;
|
||||||
|
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
import com.imyeyu.spring.bean.Page;
|
||||||
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// GAO 门店服务实现
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class GaoStoreServiceImplement extends AbstractEntityService<GaoStore, String> implements GaoStoreService {
|
||||||
|
|
||||||
|
private final ObjectMapper jackson;
|
||||||
|
|
||||||
|
private final LoggerService loggerService;
|
||||||
|
|
||||||
|
private final GaoStoreMapper mapper;
|
||||||
|
private final StoreXSSFBuilder storeXSSFBuilder;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected BaseMapper<GaoStore, String> mapper() {
|
||||||
|
return mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(GaoStore store) {
|
||||||
|
TimiException.required(store, "not found store");
|
||||||
|
TimiException.required(store.getCode(), "not found store.code");
|
||||||
|
TimiException.required(store.getName(), "not found store.name");
|
||||||
|
|
||||||
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_STORE_CREATE");
|
||||||
|
try {
|
||||||
|
logger.setContent(jackson.writeValueAsString(store));
|
||||||
|
checkUnique(store);
|
||||||
|
store.setStatus(TimiJava.defaultIfNull(store.getStatus(), GaoStore.Status.ACTIVE));
|
||||||
|
store.setSort(TimiJava.defaultIfNull(store.getSort(), 0));
|
||||||
|
super.create(store);
|
||||||
|
logger.setLevel(Logger.Level.INFO);
|
||||||
|
logger.setResult(store.getId());
|
||||||
|
} catch (TimiException e) {
|
||||||
|
logger.setLevel(Logger.Level.WARN);
|
||||||
|
logger.setException(e.getMessage());
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.setLevel(Logger.Level.ERROR);
|
||||||
|
logger.setException(TimiJava.serializeThrowable(e));
|
||||||
|
log.error("新增 GAO 门店失败", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR, "新增 GAO 门店失败", e);
|
||||||
|
} finally {
|
||||||
|
loggerService.create(logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(GaoStore store) {
|
||||||
|
TimiException.required(store, "not found store");
|
||||||
|
TimiException.required(store.getId(), "not found store.id");
|
||||||
|
TimiException.required(store.getCode(), "not found store.code");
|
||||||
|
TimiException.required(store.getName(), "not found store.name");
|
||||||
|
|
||||||
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_STORE_UPDATE");
|
||||||
|
try {
|
||||||
|
logger.setContent(jackson.writeValueAsString(store));
|
||||||
|
checkUnique(store);
|
||||||
|
GaoStore dbStore = get(store.getId());
|
||||||
|
dbStore.setCode(store.getCode());
|
||||||
|
dbStore.setName(store.getName());
|
||||||
|
dbStore.setStatus(store.getStatus());
|
||||||
|
dbStore.setTelephone(store.getTelephone());
|
||||||
|
dbStore.setAddress(store.getAddress());
|
||||||
|
dbStore.setRemark(store.getRemark());
|
||||||
|
dbStore.setSort(store.getSort());
|
||||||
|
super.update(dbStore);
|
||||||
|
logger.setLevel(Logger.Level.INFO);
|
||||||
|
logger.setResult(store.getId());
|
||||||
|
} catch (TimiException e) {
|
||||||
|
logger.setLevel(Logger.Level.WARN);
|
||||||
|
logger.setException(e.getMessage());
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.setLevel(Logger.Level.ERROR);
|
||||||
|
logger.setException(TimiJava.serializeThrowable(e));
|
||||||
|
log.error("修改 GAO 门店失败", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR, "修改 GAO 门店失败", e);
|
||||||
|
} finally {
|
||||||
|
loggerService.create(logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void delete(String id) {
|
||||||
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_STORE_DELETE");
|
||||||
|
try {
|
||||||
|
logger.setContent(id);
|
||||||
|
GaoStore store = get(id);
|
||||||
|
store.setStatus(GaoStore.Status.DELETED);
|
||||||
|
super.update(store);
|
||||||
|
super.delete(id);
|
||||||
|
logger.setLevel(Logger.Level.INFO);
|
||||||
|
logger.setResult(id);
|
||||||
|
} catch (TimiException e) {
|
||||||
|
logger.setLevel(Logger.Level.WARN);
|
||||||
|
logger.setException(e.getMessage());
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.setLevel(Logger.Level.ERROR);
|
||||||
|
logger.setException(TimiJava.serializeThrowable(e));
|
||||||
|
log.error("删除 GAO 门店失败", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR, "删除 GAO 门店失败", e);
|
||||||
|
} finally {
|
||||||
|
loggerService.create(logger);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GaoStore getByUserId(String userId) {
|
||||||
|
TimiException.required(userId, "not found userId");
|
||||||
|
return mapper.selectByUserId(userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public byte[] export(Page<GaoStore> page) throws IOException {
|
||||||
|
page.setIndex(0);
|
||||||
|
page.setSize(Long.MAX_VALUE);
|
||||||
|
List<GaoStore> list = mapper.selectByPage(page);
|
||||||
|
return storeXSSFBuilder.build(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkUnique(GaoStore store) {
|
||||||
|
GaoStore codeExample = new GaoStore();
|
||||||
|
codeExample.setCode(store.getCode());
|
||||||
|
GaoStore byCode = mapper.selectByExample(codeExample);
|
||||||
|
TimiException.requiredTrue(byCode == null || byCode.getId().equals(store.getId()), "该门店编码已存在");
|
||||||
|
|
||||||
|
GaoStore nameExample = new GaoStore();
|
||||||
|
nameExample.setName(store.getName());
|
||||||
|
GaoStore byName = mapper.selectByExample(nameExample);
|
||||||
|
TimiException.requiredTrue(byName == null || byName.getId().equals(store.getId()), "该门店名称已存在");
|
||||||
|
}
|
||||||
|
}
|
||||||
+70
-132
@@ -1,39 +1,26 @@
|
|||||||
package com.imyeyu.api.modules.gao.service.implement;
|
package com.imyeyu.api.modules.gao.service.implement;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.imyeyu.api.bean.ModuleCode;
|
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStore;
|
||||||
import com.imyeyu.api.modules.gao.entity.GaoUser;
|
import com.imyeyu.api.modules.gao.entity.GaoUser;
|
||||||
import com.imyeyu.api.modules.gao.mapper.GaoUserMapper;
|
import com.imyeyu.api.modules.gao.mapper.GaoUserMapper;
|
||||||
|
import com.imyeyu.api.modules.gao.service.GaoStoreService;
|
||||||
import com.imyeyu.api.modules.gao.service.GaoUserService;
|
import com.imyeyu.api.modules.gao.service.GaoUserService;
|
||||||
import com.imyeyu.api.modules.system.entity.Logger;
|
import com.imyeyu.api.modules.system.entity.Logger;
|
||||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||||
import com.imyeyu.api.modules.user.entity.Role;
|
|
||||||
import com.imyeyu.api.modules.user.entity.User;
|
|
||||||
import com.imyeyu.api.modules.user.mapper.UserMapper;
|
|
||||||
import com.imyeyu.api.modules.user.service.RoleService;
|
import com.imyeyu.api.modules.user.service.RoleService;
|
||||||
import com.imyeyu.api.modules.user.service.UserService;
|
import com.imyeyu.api.modules.user.service.UserService;
|
||||||
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeReq;
|
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.TimiSpring;
|
|
||||||
import com.imyeyu.spring.bean.Page;
|
|
||||||
import com.imyeyu.spring.bean.PageResult;
|
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.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 lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
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.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// GAO 用户服务实现
|
/// GAO 用户服务实现
|
||||||
///
|
///
|
||||||
@@ -44,12 +31,13 @@ import java.util.stream.Collectors;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, String> implements GaoUserService {
|
public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, String> implements GaoUserService {
|
||||||
|
|
||||||
private final GaoUserMapper mapper;
|
|
||||||
private final ObjectMapper jackson;
|
private final ObjectMapper jackson;
|
||||||
private final LoggerService loggerService;
|
|
||||||
private final UserMapper userMapper;
|
|
||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final RoleService roleService;
|
private final RoleService roleService;
|
||||||
|
private final LoggerService loggerService;
|
||||||
|
private final GaoStoreService gaoStoreService;
|
||||||
|
|
||||||
|
private final GaoUserMapper mapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected BaseMapper<GaoUser, String> mapper() {
|
protected BaseMapper<GaoUser, String> mapper() {
|
||||||
@@ -58,17 +46,28 @@ public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, Stri
|
|||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
public void create(GaoUser entity) {
|
public void create(GaoUser gaoUser) {
|
||||||
|
TimiException.required(gaoUser.getStoreId(), "not found storeId");
|
||||||
|
TimiException.required(gaoUser.getUser(), "not found user");
|
||||||
|
TimiException.required(gaoUser.getUser().getName(), "not found user.name");
|
||||||
|
TimiException.required(gaoUser.getUser().getPhoneNo(), "not found user.phoneNo");
|
||||||
|
|
||||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_USER_CREATE");
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_USER_CREATE");
|
||||||
try {
|
try {
|
||||||
logger.setContent(jackson.writeValueAsString(entity));
|
logger.setContent(jackson.writeValueAsString(gaoUser));
|
||||||
prepareUser(entity);
|
|
||||||
checkEntity(entity, false);
|
GaoStore store = gaoStoreService.get(gaoUser.getStoreId());
|
||||||
super.create(entity);
|
TimiException.required(store, "not found store");
|
||||||
saveUserRole(entity);
|
TimiException.requiredTrue(store.isActivated(), "门店不可用");
|
||||||
loadUser(entity);
|
|
||||||
|
userService.create(gaoUser.getUser());
|
||||||
|
userService.verifyPhoneNo(gaoUser.getUser().getId());
|
||||||
|
gaoUser.setUserId(gaoUser.getUser().getId());
|
||||||
|
gaoUser.setEnabled(TimiJava.defaultIfNull(gaoUser.getEnabled(), true));
|
||||||
|
super.create(gaoUser);
|
||||||
|
|
||||||
logger.setLevel(Logger.Level.INFO);
|
logger.setLevel(Logger.Level.INFO);
|
||||||
logger.setResult(entity.getId());
|
logger.setResult(gaoUser.getId());
|
||||||
} catch (TimiException e) {
|
} catch (TimiException e) {
|
||||||
logger.setLevel(Logger.Level.WARN);
|
logger.setLevel(Logger.Level.WARN);
|
||||||
logger.setException(e.getMessage());
|
logger.setException(e.getMessage());
|
||||||
@@ -76,8 +75,8 @@ public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, Stri
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.setLevel(Logger.Level.ERROR);
|
logger.setLevel(Logger.Level.ERROR);
|
||||||
logger.setException(TimiJava.serializeThrowable(e));
|
logger.setException(TimiJava.serializeThrowable(e));
|
||||||
log.error("新增 GAO 用户失败", e);
|
log.error("create user error", e);
|
||||||
throw new TimiException(TimiCode.ERROR, "新增 GAO 用户失败", e);
|
throw new TimiException(TimiCode.ERROR, "create user error", e);
|
||||||
} finally {
|
} finally {
|
||||||
loggerService.create(logger);
|
loggerService.create(logger);
|
||||||
}
|
}
|
||||||
@@ -85,16 +84,23 @@ public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, Stri
|
|||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
public void update(GaoUser entity) {
|
public void update(GaoUser gaoUser) {
|
||||||
|
TimiException.required(gaoUser, "not found gao user");
|
||||||
|
TimiException.required(gaoUser.getId(), "not found gao user.id");
|
||||||
|
|
||||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_USER_UPDATE");
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_USER_UPDATE");
|
||||||
try {
|
try {
|
||||||
logger.setContent(jackson.writeValueAsString(entity));
|
logger.setContent(jackson.writeValueAsString(gaoUser));
|
||||||
checkEntity(entity, true);
|
|
||||||
updateUser(entity);
|
GaoUser dbGaoUser = super.get(gaoUser.getId());
|
||||||
super.update(entity);
|
TimiException.required(dbGaoUser, "not found gao user");
|
||||||
saveUserRole(entity);
|
|
||||||
|
dbGaoUser.setEnabled(gaoUser.getEnabled());
|
||||||
|
dbGaoUser.setRemark(gaoUser.getRemark());
|
||||||
|
super.update(dbGaoUser);
|
||||||
|
|
||||||
logger.setLevel(Logger.Level.INFO);
|
logger.setLevel(Logger.Level.INFO);
|
||||||
logger.setResult(entity.getId());
|
logger.setResult(gaoUser.getId());
|
||||||
} catch (TimiException e) {
|
} catch (TimiException e) {
|
||||||
logger.setLevel(Logger.Level.WARN);
|
logger.setLevel(Logger.Level.WARN);
|
||||||
logger.setException(e.getMessage());
|
logger.setException(e.getMessage());
|
||||||
@@ -102,115 +108,47 @@ public class GaoUserServiceImplement extends AbstractEntityService<GaoUser, Stri
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.setLevel(Logger.Level.ERROR);
|
logger.setLevel(Logger.Level.ERROR);
|
||||||
logger.setException(TimiJava.serializeThrowable(e));
|
logger.setException(TimiJava.serializeThrowable(e));
|
||||||
log.error("修改 GAO 用户失败", e);
|
log.error("update user error", e);
|
||||||
throw new TimiException(TimiCode.ERROR, "修改 GAO 用户失败", e);
|
throw new TimiException(TimiCode.ERROR, "update user error", e);
|
||||||
} finally {
|
} finally {
|
||||||
loggerService.create(logger);
|
loggerService.create(logger);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
public GaoUser get(String id) {
|
public void transferStore(GaoUser gaoUser) {
|
||||||
GaoUser gaoUser = super.get(id);
|
|
||||||
loadUser(gaoUser);
|
|
||||||
return gaoUser;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public GaoUser getByUserId(String userId) {
|
|
||||||
TimiException.required(userId, "not found userId");
|
|
||||||
GaoUser gaoUser = mapper.selectByUserId(userId);
|
|
||||||
TimiException.required(gaoUser, "not found gao user");
|
TimiException.required(gaoUser, "not found gao user");
|
||||||
loadUser(gaoUser);
|
TimiException.required(gaoUser.getId(), "not found gao user.id");
|
||||||
return gaoUser;
|
TimiException.required(gaoUser.getStoreId(), "not found gao user.storeId");
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_USER_TRANSFER_STORE");
|
||||||
public PageResult<GaoUser> pageWithUser(Page<GaoUser> page) {
|
try {
|
||||||
PageResult<GaoUser> result = page(page);
|
logger.setContent(jackson.writeValueAsString(gaoUser));
|
||||||
loadUser(result.getList());
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkEntity(GaoUser entity, boolean requireId) {
|
GaoStore store = gaoStoreService.get(gaoUser.getStoreId());
|
||||||
TimiException.required(entity, "not found gao user");
|
TimiException.required(store, "not found store");
|
||||||
if (requireId) {
|
TimiException.requiredTrue(store.isActivated(), "门店不可用");
|
||||||
TimiException.required(entity.getId(), "not found gao user.id");
|
|
||||||
}
|
|
||||||
TimiException.required(entity.getUserId(), "not found gao user.userId");
|
|
||||||
TimiException.required(userMapper.select(entity.getUserId()), "not found user");
|
|
||||||
GaoUser dbGaoUser = mapper.selectByUserId(entity.getUserId());
|
|
||||||
if (dbGaoUser != null && !dbGaoUser.getId().equals(entity.getId())) {
|
|
||||||
throw new TimiException(TimiCode.ARG_BAD, "GAO 用户已存在");
|
|
||||||
}
|
|
||||||
if (entity.getEnabled() == null) {
|
|
||||||
entity.setEnabled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void prepareUser(GaoUser entity) {
|
GaoUser dbGaoUser = super.get(gaoUser.getId());
|
||||||
TimiException.required(entity, "not found gao user");
|
TimiException.required(dbGaoUser, "not found gao user");
|
||||||
if (TimiJava.isNotEmpty(entity.getUserId())) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
User user = entity.getUser();
|
|
||||||
TimiException.required(user, "not found gao user.user");
|
|
||||||
user.setPhoneNoVerifyAt(TimiJava.defaultIfNull(user.getPhoneNoVerifyAt(), Time.now()));
|
|
||||||
userService.create(user);
|
|
||||||
entity.setUserId(user.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateUser(GaoUser entity) {
|
dbGaoUser.setStoreId(gaoUser.getStoreId());
|
||||||
User reqUser = entity.getUser();
|
super.update(dbGaoUser);
|
||||||
if (reqUser == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
User user = userService.get(entity.getUserId());
|
|
||||||
if (reqUser.getName() != null) {
|
|
||||||
user.setName(reqUser.getName());
|
|
||||||
}
|
|
||||||
if (reqUser.getNick() != null) {
|
|
||||||
user.setNick(reqUser.getNick());
|
|
||||||
}
|
|
||||||
if (reqUser.getPhoneNo() != null) {
|
|
||||||
user.setPhoneNo(reqUser.getPhoneNo());
|
|
||||||
}
|
|
||||||
if (reqUser.getEmail() != null) {
|
|
||||||
user.setEmail(reqUser.getEmail());
|
|
||||||
}
|
|
||||||
userService.update(user);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void saveUserRole(GaoUser entity) {
|
logger.setLevel(Logger.Level.INFO);
|
||||||
if (entity.getRoleIdList() == null) {
|
logger.setResult(gaoUser.getId());
|
||||||
return;
|
} catch (TimiException e) {
|
||||||
}
|
logger.setLevel(Logger.Level.WARN);
|
||||||
UserRoleAuthorizeReq req = new UserRoleAuthorizeReq();
|
logger.setException(e.getMessage());
|
||||||
req.setUserId(entity.getUserId());
|
throw e;
|
||||||
req.setModuleCode(ModuleCode.GAO);
|
} catch (Exception e) {
|
||||||
req.setRoleIdList(entity.getRoleIdList());
|
logger.setLevel(Logger.Level.ERROR);
|
||||||
roleService.authorizeUserRole(req);
|
logger.setException(TimiJava.serializeThrowable(e));
|
||||||
}
|
log.error("transfer user store error", e);
|
||||||
|
throw new TimiException(TimiCode.ERROR, "transfer user store error", e);
|
||||||
private void loadUser(GaoUser gaoUser) {
|
} finally {
|
||||||
if (gaoUser == null) {
|
loggerService.create(logger);
|
||||||
return;
|
|
||||||
}
|
|
||||||
gaoUser.setUser(userMapper.select(gaoUser.getUserId()));
|
|
||||||
gaoUser.setRoleList(roleService.listByUserId(gaoUser.getUserId(), ModuleCode.GAO));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadUser(List<GaoUser> gaoUserList) {
|
|
||||||
if (gaoUserList == null || gaoUserList.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
List<String> userIdList = gaoUserList.stream().map(GaoUser::getUserId).distinct().toList();
|
|
||||||
Map<String, User> userMap = userMapper.listByIdList(new ArrayList<>(userIdList)).stream()
|
|
||||||
.collect(Collectors.toMap(User::getId, Function.identity(), (left, right) -> left));
|
|
||||||
for (GaoUser gaoUser : gaoUserList) {
|
|
||||||
gaoUser.setUser(userMap.get(gaoUser.getUserId()));
|
|
||||||
List<Role> roleList = roleService.listByUserId(gaoUser.getUserId(), ModuleCode.GAO);
|
|
||||||
gaoUser.setRoleList(roleList);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
package com.imyeyu.api.modules.gao.util;
|
||||||
|
|
||||||
|
import com.imyeyu.api.modules.gao.entity.GaoStore;
|
||||||
|
import com.imyeyu.api.util.BaseXSSFBuilder;
|
||||||
|
import com.imyeyu.utils.Time;
|
||||||
|
import org.apache.poi.ss.usermodel.CellStyle;
|
||||||
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// 门店 Excel 构建器
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-06
|
||||||
|
@Component
|
||||||
|
public class StoreXSSFBuilder extends BaseXSSFBuilder<GaoStore> {
|
||||||
|
|
||||||
|
/// 构建门店列表 Excel
|
||||||
|
///
|
||||||
|
/// @param list 门店列表
|
||||||
|
/// @return xlsx 文件字节
|
||||||
|
/// @throws IOException 写入异常
|
||||||
|
public byte[] build(List<GaoStore> list) throws IOException {
|
||||||
|
try (Workbook workbook = new XSSFWorkbook(); ByteArrayOutputStream output = new ByteArrayOutputStream()) {
|
||||||
|
Sheet sheet = workbook.createSheet("门店列表");
|
||||||
|
CellStyle titleStyle = createTitleStyle(workbook);
|
||||||
|
CellStyle headerStyle = createHeaderStyle(workbook);
|
||||||
|
|
||||||
|
appendRow(sheet, 0, titleStyle, "门店列表导出");
|
||||||
|
appendRow(sheet, 1, null, "生成时间", Time.nowString());
|
||||||
|
appendRow(sheet, 2, null, "记录总数", String.valueOf(list.size()));
|
||||||
|
appendRow(sheet, 3, headerStyle, "门店编码", "门店名称", "状态", "电话", "地址", "备注", "排序", "创建时间");
|
||||||
|
int rowIndex = 4;
|
||||||
|
for (GaoStore store : list) {
|
||||||
|
appendRow(sheet, rowIndex, null,
|
||||||
|
text(store.getCode()),
|
||||||
|
text(store.getName()),
|
||||||
|
store.getStatus() == null ? "" : store.getStatus().name(),
|
||||||
|
text(store.getTelephone()),
|
||||||
|
text(store.getAddress()),
|
||||||
|
text(store.getRemark()),
|
||||||
|
store.getSort() == null ? "" : String.valueOf(store.getSort()),
|
||||||
|
Time.toDateTime(store.getCreatedAt())
|
||||||
|
);
|
||||||
|
rowIndex++;
|
||||||
|
}
|
||||||
|
for (int index = 0; index < 8; index++) {
|
||||||
|
sheet.autoSizeColumn(index);
|
||||||
|
sheet.setColumnWidth(index, Math.clamp(sheet.getColumnWidth(index), 10 * 256, 36 * 256));
|
||||||
|
}
|
||||||
|
workbook.write(output);
|
||||||
|
return output.toByteArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,9 @@ import lombok.Data;
|
|||||||
@Data
|
@Data
|
||||||
public class GaoCustomerTrendStateReq {
|
public class GaoCustomerTrendStateReq {
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
/// 开始创建时间
|
/// 开始创建时间
|
||||||
private Long beginCreatedAt;
|
private Long beginCreatedAt;
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ import java.util.List;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class GaoEventRecordPage extends BasePage {
|
public class GaoEventRecordPage extends BasePage {
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
/// 客户 ID,为空查询全部客户
|
/// 客户 ID,为空查询全部客户
|
||||||
private String customerId;
|
private String customerId;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,9 @@ import java.util.List;
|
|||||||
@EqualsAndHashCode(callSuper = true)
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class GaoEventRecordRankPage extends BasePage {
|
public class GaoEventRecordRankPage extends BasePage {
|
||||||
|
|
||||||
|
/// 门店 ID
|
||||||
|
private String storeId;
|
||||||
|
|
||||||
/// 客户 ID,为空查询全部客户
|
/// 客户 ID,为空查询全部客户
|
||||||
private String customerId;
|
private String customerId;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ 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;
|
||||||
import com.imyeyu.api.modules.user.service.RoleService;
|
import com.imyeyu.api.modules.user.service.RoleService;
|
||||||
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeReq;
|
import com.imyeyu.api.modules.user.service.UserRoleService;
|
||||||
|
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeRequest;
|
||||||
import com.imyeyu.spring.annotation.AOPLog;
|
import com.imyeyu.spring.annotation.AOPLog;
|
||||||
import com.imyeyu.spring.bean.Page;
|
import com.imyeyu.spring.bean.Page;
|
||||||
import com.imyeyu.spring.bean.PageResult;
|
import com.imyeyu.spring.bean.PageResult;
|
||||||
@@ -37,6 +38,7 @@ import java.util.List;
|
|||||||
public class RoleController {
|
public class RoleController {
|
||||||
|
|
||||||
private final RoleService service;
|
private final RoleService service;
|
||||||
|
private final UserRoleService userRoleService;
|
||||||
private final PermissionService permissionService;
|
private final PermissionService permissionService;
|
||||||
|
|
||||||
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
||||||
@@ -86,26 +88,26 @@ public class RoleController {
|
|||||||
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
@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(required = false) ModuleCode moduleCode, @RequestParam String userId) {
|
||||||
if (moduleCode != null) {
|
if (moduleCode != null) {
|
||||||
return service.listByUserId(userId, moduleCode);
|
return userRoleService.listRoleByUserId(moduleCode, userId);
|
||||||
}
|
}
|
||||||
return service.listByUserId(userId);
|
return userRoleService.listRoleByUserId(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AOPLog
|
@AOPLog
|
||||||
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
@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 UserRoleAuthorizeRequest req) {
|
||||||
service.authorizeUserRole(req);
|
userRoleService.authorizeUserRole(req);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequireCoreRole(value = {CoreRoleCode.ADMIN, CoreRoleCode.USER_ROLE_ADMIN}, mode = RoleMatchMode.ANY)
|
@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) {
|
||||||
return service.listAllPermissionByUserId(userId);
|
return userRoleService.listAllPermissionByUserId(userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillRoleDetail(Role role) {
|
private void fillRoleDetail(Role role) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ 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;
|
||||||
import com.imyeyu.spring.util.ResponseView;
|
import com.imyeyu.spring.util.ResponseView;
|
||||||
|
import com.imyeyu.utils.Regex;
|
||||||
import com.imyeyu.utils.Time;
|
import com.imyeyu.utils.Time;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@@ -123,6 +124,10 @@ public class User extends UUIDEntity {
|
|||||||
@JsonView(ResponseView.Public.class)
|
@JsonView(ResponseView.Public.class)
|
||||||
protected List<String> permissionList;
|
protected List<String> permissionList;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
@JsonView(ResponseView.Public.class)
|
||||||
|
protected List<Role> roleEntityList;
|
||||||
|
|
||||||
@Transient
|
@Transient
|
||||||
@JsonView(ResponseView.Public.class)
|
@JsonView(ResponseView.Public.class)
|
||||||
protected List<Attachment> attachmentList;
|
protected List<Attachment> attachmentList;
|
||||||
@@ -135,6 +140,10 @@ public class User extends UUIDEntity {
|
|||||||
@JsonView(ResponseView.Public.class)
|
@JsonView(ResponseView.Public.class)
|
||||||
protected List<String> tempFileIdList;
|
protected List<String> tempFileIdList;
|
||||||
|
|
||||||
|
public boolean isValidPhone() {
|
||||||
|
return Regex.isMatch(Regex.MOBILE_PHONE, phoneNo);
|
||||||
|
}
|
||||||
|
|
||||||
/** @return true 为禁言中 */
|
/** @return true 为禁言中 */
|
||||||
public boolean isMuting() {
|
public boolean isMuting() {
|
||||||
return unmuteAt != null && Time.now() < unmuteAt;
|
return unmuteAt != null && Time.now() < unmuteAt;
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package com.imyeyu.api.modules.user.mapper;
|
|||||||
import com.imyeyu.api.bean.ModuleCode;
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
import com.imyeyu.api.modules.user.entity.Role;
|
import com.imyeyu.api.modules.user.entity.Role;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Param;
|
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,9 +15,7 @@ import java.util.List;
|
|||||||
*/
|
*/
|
||||||
public interface RoleMapper extends BaseMapper<Role, String> {
|
public interface RoleMapper extends BaseMapper<Role, String> {
|
||||||
|
|
||||||
List<Role> selectByIdList(List<String> idList);
|
List<Role> selectByIdList(Collection<String> idList);
|
||||||
|
|
||||||
List<Role> selectByModuleCodeAndCodeList(@Param("moduleCode") ModuleCode moduleCode, @Param("codeList") List<String> codeList);
|
List<Role> selectByModuleCode(ModuleCode moduleCode);
|
||||||
|
|
||||||
List<Role> selectByModuleCode(@Param("moduleCode") ModuleCode moduleCode);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.imyeyu.api.modules.user.entity.User;
|
|||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import org.apache.ibatis.annotations.Select;
|
import org.apache.ibatis.annotations.Select;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,5 +33,5 @@ public interface UserMapper extends BaseMapper<User, String> {
|
|||||||
* @param idList 用户 ID 列表
|
* @param idList 用户 ID 列表
|
||||||
* @return 用户列表
|
* @return 用户列表
|
||||||
*/
|
*/
|
||||||
List<User> listByIdList(List<String> idList);
|
List<User> listByIdList(Collection<String> idList);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ package com.imyeyu.api.modules.user.mapper;
|
|||||||
|
|
||||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,5 +17,7 @@ public interface UserRoleMapper extends BaseMapper<UserRole, String> {
|
|||||||
|
|
||||||
void createBatch(List<UserRole> userRoleList);
|
void createBatch(List<UserRole> userRoleList);
|
||||||
|
|
||||||
|
List<UserRole> selectByUserIdList(@Param("userIdList") Collection<String> userIdList);
|
||||||
|
|
||||||
void deleteByRoleIdList(String userId, List<String> roleIdList);
|
void deleteByRoleIdList(String userId, List<String> roleIdList);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package com.imyeyu.api.modules.user.service;
|
|||||||
import com.imyeyu.api.bean.ModuleCode;
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
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.vo.role.UserRoleAuthorizeReq;
|
|
||||||
import com.imyeyu.spring.service.BaseService;
|
import com.imyeyu.spring.service.BaseService;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/// 角色服务
|
/// 角色服务
|
||||||
@@ -14,60 +14,13 @@ import java.util.List;
|
|||||||
/// @since 2026-05-13 14:46
|
/// @since 2026-05-13 14:46
|
||||||
public interface RoleService extends BaseService<Role, String> {
|
public interface RoleService extends BaseService<Role, String> {
|
||||||
|
|
||||||
/// 给用户授权角色
|
|
||||||
///
|
|
||||||
/// @param req 用户角色授权请求
|
|
||||||
void authorizeUserRole(UserRoleAuthorizeReq req);
|
|
||||||
|
|
||||||
/// 查询用户直属角色
|
|
||||||
///
|
|
||||||
/// @param userId 用户 ID
|
|
||||||
/// @return 角色列表
|
|
||||||
List<Role> listByUserId(String userId);
|
|
||||||
|
|
||||||
/// 查询用户指定模块直属角色
|
|
||||||
///
|
|
||||||
/// @param userId 用户 ID
|
|
||||||
/// @param moduleCode 模块代码
|
|
||||||
/// @return 角色列表
|
|
||||||
List<Role> listByUserId(String userId, ModuleCode moduleCode);
|
|
||||||
|
|
||||||
/// 查询模块角色
|
/// 查询模块角色
|
||||||
///
|
///
|
||||||
/// @param moduleCode 模块代码
|
/// @param moduleCode 模块代码
|
||||||
/// @return 角色列表
|
/// @return 角色列表
|
||||||
List<Role> listByModuleCode(ModuleCode moduleCode);
|
List<Role> listByModuleCode(ModuleCode moduleCode);
|
||||||
|
|
||||||
/// 查询用户直属角色编码
|
List<Role> listByIdList(Collection<String> idList);
|
||||||
///
|
|
||||||
/// @param userId 用户 ID
|
|
||||||
/// @return 角色编码列表,格式为 MODULE:ROLE
|
|
||||||
default List<String> listCodeByUserId(String userId) {
|
|
||||||
return listByUserId(userId).stream().map(role -> "%s:%s".formatted(role.getModuleCode().name(), role.getCode())).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 查询用户全部角色编码
|
|
||||||
///
|
|
||||||
/// @param userId 用户 ID
|
|
||||||
/// @return 包含子角色的角色编码列表,格式为 MODULE:ROLE
|
|
||||||
List<String> listAllCodeByUserId(String userId);
|
|
||||||
|
|
||||||
/// 查询用户全部权限
|
|
||||||
///
|
|
||||||
/// @param userId 用户 ID
|
|
||||||
/// @return 权限列表
|
|
||||||
List<Permission> listAllPermissionByUserId(String userId);
|
|
||||||
|
|
||||||
/// 查询用户全部权限编码
|
|
||||||
///
|
|
||||||
/// @param userId 用户 ID
|
|
||||||
/// @return 权限编码列表,格式为 MODULE:PERMISSION
|
|
||||||
default List<String> listAllPermissionCodeByUserId(String userId) {
|
|
||||||
return listAllPermissionByUserId(userId).stream()
|
|
||||||
.map(permission -> "%s:%s".formatted(permission.getModuleCode().name(), permission.getCode()))
|
|
||||||
.distinct()
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 查询直属子角色
|
/// 查询直属子角色
|
||||||
///
|
///
|
||||||
@@ -80,4 +33,10 @@ public interface RoleService extends BaseService<Role, String> {
|
|||||||
/// @param roleId 角色 ID
|
/// @param roleId 角色 ID
|
||||||
/// @return 权限列表
|
/// @return 权限列表
|
||||||
List<Permission> listPermissionByRoleId(String roleId);
|
List<Permission> listPermissionByRoleId(String roleId);
|
||||||
|
|
||||||
|
/// 递归获取角色及其所有子角色的 ID 列表
|
||||||
|
///
|
||||||
|
/// @param idList 角色 ID 列表
|
||||||
|
/// @return 包含所有子角色的 ID 列表
|
||||||
|
List<String> listAllRoleIdIncludingChildren(Collection<String> idList);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,15 @@
|
|||||||
package com.imyeyu.api.modules.user.service;
|
package com.imyeyu.api.modules.user.service;
|
||||||
|
|
||||||
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
|
import com.imyeyu.api.modules.user.entity.Permission;
|
||||||
|
import com.imyeyu.api.modules.user.entity.Role;
|
||||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||||
|
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeRequest;
|
||||||
import com.imyeyu.spring.service.BaseService;
|
import com.imyeyu.spring.service.BaseService;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/// 用户角色绑定服务
|
/// 用户角色绑定服务
|
||||||
///
|
///
|
||||||
@@ -16,11 +22,62 @@ public interface UserRoleService extends BaseService<UserRole, String> {
|
|||||||
/// @param list 用户角色绑定列表
|
/// @param list 用户角色绑定列表
|
||||||
void createBatch(List<UserRole> list);
|
void createBatch(List<UserRole> list);
|
||||||
|
|
||||||
/// 查询用户角色绑定
|
/// 给用户授权角色
|
||||||
|
///
|
||||||
|
/// @param req 用户角色授权请求
|
||||||
|
void authorizeUserRole(UserRoleAuthorizeRequest req);
|
||||||
|
|
||||||
|
List<UserRole> listByUserId(String userId);
|
||||||
|
|
||||||
|
/// 查询多个用户角色绑定
|
||||||
|
///
|
||||||
|
/// @param userIdList 用户 ID 列表
|
||||||
|
/// @return 用户角色绑定列表
|
||||||
|
List<UserRole> listByUserIdList(Collection<String> userIdList);
|
||||||
|
|
||||||
|
/// 查询用户直属角色
|
||||||
///
|
///
|
||||||
/// @param userId 用户 ID
|
/// @param userId 用户 ID
|
||||||
/// @return 用户角色绑定列表
|
/// @return 角色列表
|
||||||
List<UserRole> listByUserId(String userId);
|
List<Role> listRoleByUserId(String userId);
|
||||||
|
|
||||||
|
/// 查询用户指定模块直属角色
|
||||||
|
///
|
||||||
|
/// @param moduleCode 模块代码
|
||||||
|
/// @param userId 用户 ID
|
||||||
|
/// @return 角色列表
|
||||||
|
List<Role> listRoleByUserId(ModuleCode moduleCode, String userId);
|
||||||
|
|
||||||
|
/// 查询用户直属角色编码
|
||||||
|
///
|
||||||
|
/// @param userId 用户 ID
|
||||||
|
/// @return 角色编码列表,格式为 MODULE:ROLE
|
||||||
|
default List<String> listRoleCodeByUserId(String userId) {
|
||||||
|
return listRoleByUserId(userId).stream().map(role -> "%s:%s".formatted(role.getModuleCode().name(), role.getCode())).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 查询用户全部角色编码
|
||||||
|
///
|
||||||
|
/// @param userId 用户 ID
|
||||||
|
/// @return 包含子角色的角色编码列表,格式为 MODULE:ROLE
|
||||||
|
List<String> listAllRoleCodeByUserId(String userId);
|
||||||
|
|
||||||
|
/// 查询用户全部权限
|
||||||
|
///
|
||||||
|
/// @param userId 用户 ID
|
||||||
|
/// @return 权限列表
|
||||||
|
List<Permission> listAllPermissionByUserId(String userId);
|
||||||
|
|
||||||
|
/// 查询用户全部权限编码
|
||||||
|
///
|
||||||
|
/// @param userId 用户 ID
|
||||||
|
/// @return 权限编码列表,格式为 MODULE:PERMISSION
|
||||||
|
default List<String> listAllPermissionCodeByUserId(String userId) {
|
||||||
|
return listAllPermissionByUserId(userId).stream()
|
||||||
|
.map(permission -> "%s:%s".formatted(permission.getModuleCode().name(), permission.getCode()))
|
||||||
|
.distinct()
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
/// 查询用户直属角色 ID
|
/// 查询用户直属角色 ID
|
||||||
///
|
///
|
||||||
@@ -31,6 +88,12 @@ public interface UserRoleService extends BaseService<UserRole, String> {
|
|||||||
return bindingList.stream().map(UserRole::getRoleId).toList();
|
return bindingList.stream().map(UserRole::getRoleId).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 按用户 ID 分组查询直属角色
|
||||||
|
///
|
||||||
|
/// @param idList 用户 ID 列表
|
||||||
|
/// @return 用户角色映射
|
||||||
|
Map<String, List<Role>> mapRoleListByUserIdList(Collection<String> idList);
|
||||||
|
|
||||||
/// 删除用户指定角色绑定
|
/// 删除用户指定角色绑定
|
||||||
///
|
///
|
||||||
/// @param userId 用户 ID
|
/// @param userId 用户 ID
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package com.imyeyu.api.modules.user.service;
|
|||||||
import com.imyeyu.api.modules.user.entity.User;
|
import com.imyeyu.api.modules.user.entity.User;
|
||||||
import com.imyeyu.spring.service.BaseService;
|
import com.imyeyu.spring.service.BaseService;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户管理服务
|
* 用户管理服务
|
||||||
*
|
*
|
||||||
@@ -20,4 +23,10 @@ public interface UserService extends BaseService<User, String> {
|
|||||||
User getByPhoneNo(String phoneNo);
|
User getByPhoneNo(String phoneNo);
|
||||||
|
|
||||||
User getByVerifiedPhoneNo(String phoneNo);
|
User getByVerifiedPhoneNo(String phoneNo);
|
||||||
|
|
||||||
|
void verifyEmail(String id);
|
||||||
|
|
||||||
|
void verifyPhoneNo(String id);
|
||||||
|
|
||||||
|
Map<String, User> mapByIdList(Collection<String> idList);
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -4,6 +4,7 @@ import com.imyeyu.api.bean.ModuleCode;
|
|||||||
import com.imyeyu.api.modules.user.service.PermissionChecker;
|
import com.imyeyu.api.modules.user.service.PermissionChecker;
|
||||||
import com.imyeyu.api.modules.user.service.RoleService;
|
import com.imyeyu.api.modules.user.service.RoleService;
|
||||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||||
|
import com.imyeyu.api.modules.user.service.UserRoleService;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -25,7 +26,7 @@ import java.util.Set;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class PermissionCheckerImplement implements PermissionChecker {
|
public class PermissionCheckerImplement implements PermissionChecker {
|
||||||
|
|
||||||
private final RoleService roleService;
|
private final UserRoleService userRoleService;
|
||||||
private final UserLoginService userLoginService;
|
private final UserLoginService userLoginService;
|
||||||
|
|
||||||
public Set<String> codeSet() {
|
public Set<String> codeSet() {
|
||||||
@@ -34,7 +35,7 @@ public class PermissionCheckerImplement implements PermissionChecker {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> codeSet(String userId) {
|
public Set<String> codeSet(String userId) {
|
||||||
return new HashSet<>(roleService.listAllPermissionCodeByUserId(userId));
|
return new HashSet<>(userRoleService.listAllPermissionCodeByUserId(userId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+3
-3
@@ -2,8 +2,8 @@ package com.imyeyu.api.modules.user.service.implement;
|
|||||||
|
|
||||||
import com.imyeyu.api.bean.ModuleCode;
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
import com.imyeyu.api.modules.user.service.RoleChecker;
|
import com.imyeyu.api.modules.user.service.RoleChecker;
|
||||||
import com.imyeyu.api.modules.user.service.RoleService;
|
|
||||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||||
|
import com.imyeyu.api.modules.user.service.UserRoleService;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -24,12 +24,12 @@ import java.util.Set;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RoleCheckerImplement implements RoleChecker {
|
public class RoleCheckerImplement implements RoleChecker {
|
||||||
|
|
||||||
private final RoleService roleService;
|
private final UserRoleService userRoleService;
|
||||||
private final UserLoginService userLoginService;
|
private final UserLoginService userLoginService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> codeSet() {
|
public Set<String> codeSet() {
|
||||||
return new HashSet<>(roleService.listAllCodeByUserId(userLoginService.getRequireLoginUserId()));
|
return new HashSet<>(userRoleService.listAllRoleCodeByUserId(userLoginService.getRequireLoginUserId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+7
-108
@@ -2,23 +2,17 @@ package com.imyeyu.api.modules.user.service.implement;
|
|||||||
|
|
||||||
import com.imyeyu.api.bean.ModuleCode;
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
import com.imyeyu.api.modules.common.entity.Multilingual;
|
|
||||||
import com.imyeyu.api.modules.common.mapper.MultilingualMapper;
|
|
||||||
import com.imyeyu.api.modules.common.service.MultilingualService;
|
import com.imyeyu.api.modules.common.service.MultilingualService;
|
||||||
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.entity.RolePermission;
|
import com.imyeyu.api.modules.user.entity.RolePermission;
|
||||||
import com.imyeyu.api.modules.user.entity.RoleRelation;
|
import com.imyeyu.api.modules.user.entity.RoleRelation;
|
||||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
|
||||||
import com.imyeyu.api.modules.user.mapper.RoleMapper;
|
import com.imyeyu.api.modules.user.mapper.RoleMapper;
|
||||||
import com.imyeyu.api.modules.user.mapper.RolePermissionMapper;
|
import com.imyeyu.api.modules.user.mapper.RolePermissionMapper;
|
||||||
import com.imyeyu.api.modules.user.mapper.RoleRelationMapper;
|
import com.imyeyu.api.modules.user.mapper.RoleRelationMapper;
|
||||||
import com.imyeyu.api.modules.user.service.PermissionService;
|
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||||
import com.imyeyu.api.modules.user.service.RoleService;
|
import com.imyeyu.api.modules.user.service.RoleService;
|
||||||
import com.imyeyu.api.modules.user.service.UserRoleService;
|
|
||||||
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeReq;
|
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
@@ -28,6 +22,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -42,9 +37,7 @@ import java.util.stream.Collectors;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class RoleServiceImplement extends AbstractEntityService<Role, String> implements RoleService {
|
public class RoleServiceImplement extends AbstractEntityService<Role, String> implements RoleService {
|
||||||
|
|
||||||
private final UserRoleService userRoleService;
|
|
||||||
private final PermissionService permissionService;
|
private final PermissionService permissionService;
|
||||||
private final MultilingualMapper multilingualMapper;
|
|
||||||
private final MultilingualService multilingualService;
|
private final MultilingualService multilingualService;
|
||||||
|
|
||||||
private final RoleMapper mapper;
|
private final RoleMapper mapper;
|
||||||
@@ -153,67 +146,6 @@ public class RoleServiceImplement extends AbstractEntityService<Role, String> im
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
|
||||||
@Override
|
|
||||||
public void authorizeUserRole(UserRoleAuthorizeReq req) {
|
|
||||||
TimiException.required(req, "not found req");
|
|
||||||
TimiException.required(req.getUserId(), "not found req.userId");
|
|
||||||
if (req.getModuleCode() == null) {
|
|
||||||
throw new TimiException(TimiCode.ARG_MISS, "moduleCode");
|
|
||||||
}
|
|
||||||
List<UserRole> bindingList = userRoleService.listByUserId(req.getUserId());
|
|
||||||
List<String> bindingRoleIdList = bindingList.stream().map(UserRole::getRoleId).toList();
|
|
||||||
Set<String> dbIdSet = mapper.selectByIdList(bindingRoleIdList).stream()
|
|
||||||
.filter(role -> req.getModuleCode() == role.getModuleCode())
|
|
||||||
.map(Role::getId)
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
Set<String> newIdSet = new HashSet<>();
|
|
||||||
if (TimiJava.isNotEmpty(req.getRoleIdList())) {
|
|
||||||
newIdSet.addAll(mapper.selectByIdList(req.getRoleIdList()).stream()
|
|
||||||
.filter(role -> req.getModuleCode() == role.getModuleCode())
|
|
||||||
.map(Role::getId)
|
|
||||||
.toList());
|
|
||||||
}
|
|
||||||
if (TimiJava.isNotEmpty(req.getRoleCodeList())) {
|
|
||||||
newIdSet.addAll(mapper.selectByModuleCodeAndCodeList(req.getModuleCode(), req.getRoleCodeList()).stream().map(Role::getId).toList());
|
|
||||||
}
|
|
||||||
Set<String> deleteIdList = new HashSet<>(dbIdSet);
|
|
||||||
deleteIdList.removeAll(newIdSet);
|
|
||||||
|
|
||||||
Set<String> addIdList = new HashSet<>(newIdSet);
|
|
||||||
addIdList.removeAll(dbIdSet);
|
|
||||||
|
|
||||||
if (TimiJava.isNotEmpty(deleteIdList)) {
|
|
||||||
userRoleService.deleteByRoleIdList(req.getUserId(), new ArrayList<>(deleteIdList));
|
|
||||||
}
|
|
||||||
if (TimiJava.isNotEmpty(addIdList)) {
|
|
||||||
List<UserRole> roleBindingList = new ArrayList<>();
|
|
||||||
long now = Time.now();
|
|
||||||
for (String roleId : addIdList) {
|
|
||||||
UserRole roleBinding = new UserRole();
|
|
||||||
roleBinding.setId(UUID.randomUUID().toString());
|
|
||||||
roleBinding.setUserId(req.getUserId());
|
|
||||||
roleBinding.setRoleId(roleId);
|
|
||||||
roleBinding.setCreatedAt(now);
|
|
||||||
roleBindingList.add(roleBinding);
|
|
||||||
}
|
|
||||||
userRoleService.createBatch(roleBindingList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Role> listByUserId(String userId) {
|
|
||||||
return mapper.selectByIdList(userRoleService.listRoleIdByUserId(userId));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Role> listByUserId(String userId, ModuleCode moduleCode) {
|
|
||||||
TimiException.required(moduleCode, "not found moduleCode");
|
|
||||||
return listByUserId(userId).stream()
|
|
||||||
.filter(role -> moduleCode == role.getModuleCode())
|
|
||||||
.toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Role> listByModuleCode(ModuleCode moduleCode) {
|
public List<Role> listByModuleCode(ModuleCode moduleCode) {
|
||||||
TimiException.required(moduleCode, "not found moduleCode");
|
TimiException.required(moduleCode, "not found moduleCode");
|
||||||
@@ -221,20 +153,8 @@ public class RoleServiceImplement extends AbstractEntityService<Role, String> im
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> listAllCodeByUserId(String userId) {
|
public List<Role> listByIdList(Collection<String> idList) {
|
||||||
List<String> roleIdList = listByUserId(userId).stream().map(Role::getId).toList();
|
return mapper.selectByIdList(new HashSet<>(idList));
|
||||||
List<String> allRoleIdList = getAllRoleIdsIncludingChildren(roleIdList);
|
|
||||||
if (TimiJava.isEmpty(allRoleIdList)) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
return mapper.selectByIdList(allRoleIdList).stream().map(role -> "%s:%s".formatted(role.getModuleCode().name(), role.getCode())).distinct().toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Permission> listAllPermissionByUserId(String userId) {
|
|
||||||
List<String> roleIdList = listByUserId(userId).stream().map(Role::getId).toList();
|
|
||||||
List<String> allRoleIdList = getAllRoleIdsIncludingChildren(roleIdList);
|
|
||||||
return permissionService.listByRoleId(allRoleIdList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -248,20 +168,13 @@ public class RoleServiceImplement extends AbstractEntityService<Role, String> im
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Permission> listPermissionByRoleId(String roleId) {
|
public List<Permission> listPermissionByRoleId(String roleId) {
|
||||||
List<String> allRoleIdList = getAllRoleIdsIncludingChildren(List.of(roleId));
|
List<String> allRoleIdList = listAllRoleIdIncludingChildren(List.of(roleId));
|
||||||
return permissionService.listByRoleId(allRoleIdList);
|
return permissionService.listByRoleId(allRoleIdList);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 递归获取角色及其所有子角色的 ID 列表
|
public List<String> listAllRoleIdIncludingChildren(Collection<String> idList) {
|
||||||
///
|
Set<String> allRoleIdSet = new HashSet<>(idList);
|
||||||
/// @param roleIdList 角色 ID 列表
|
List<String> currentLevelRoleIdList = new ArrayList<>(idList);
|
||||||
/// @return 包含所有子角色的 ID 列表
|
|
||||||
private List<String> getAllRoleIdsIncludingChildren(List<String> roleIdList) {
|
|
||||||
if (TimiJava.isEmpty(roleIdList)) {
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
Set<String> allRoleIdSet = new HashSet<>(roleIdList);
|
|
||||||
List<String> currentLevelRoleIdList = new ArrayList<>(roleIdList);
|
|
||||||
|
|
||||||
while (TimiJava.isNotEmpty(currentLevelRoleIdList)) {
|
while (TimiJava.isNotEmpty(currentLevelRoleIdList)) {
|
||||||
List<String> childRoleIdList = roleRelationMapper.selectChildRoleIdListByParentRoleIdList(currentLevelRoleIdList);
|
List<String> childRoleIdList = roleRelationMapper.selectChildRoleIdListByParentRoleIdList(currentLevelRoleIdList);
|
||||||
@@ -277,18 +190,4 @@ public class RoleServiceImplement extends AbstractEntityService<Role, String> im
|
|||||||
}
|
}
|
||||||
return new ArrayList<>(allRoleIdSet);
|
return new ArrayList<>(allRoleIdSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String saveNameMultilingual(String langId, String name) {
|
|
||||||
if (TimiJava.isEmpty(name)) {
|
|
||||||
return langId;
|
|
||||||
}
|
|
||||||
if (TimiJava.isEmpty(langId)) {
|
|
||||||
return multilingualService.create(name);
|
|
||||||
}
|
|
||||||
Multilingual multilingual = new Multilingual();
|
|
||||||
multilingual.setId(langId);
|
|
||||||
multilingual.setZhCN(name);
|
|
||||||
multilingualMapper.updateSelective(multilingual);
|
|
||||||
return langId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -9,6 +9,7 @@ import com.imyeyu.api.modules.user.bean.BootstrapData;
|
|||||||
import com.imyeyu.api.modules.user.entity.User;
|
import com.imyeyu.api.modules.user.entity.User;
|
||||||
import com.imyeyu.api.modules.user.service.RoleService;
|
import com.imyeyu.api.modules.user.service.RoleService;
|
||||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||||
|
import com.imyeyu.api.modules.user.service.UserRoleService;
|
||||||
import com.imyeyu.api.modules.user.service.UserService;
|
import com.imyeyu.api.modules.user.service.UserService;
|
||||||
import com.imyeyu.api.modules.user.vo.LoginRequest;
|
import com.imyeyu.api.modules.user.vo.LoginRequest;
|
||||||
import com.imyeyu.api.modules.user.vo.LoginResponse;
|
import com.imyeyu.api.modules.user.vo.LoginResponse;
|
||||||
@@ -45,6 +46,7 @@ public class UserLoginServiceImplement implements UserLoginService, TimiJava {
|
|||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final RoleService roleService;
|
private final RoleService roleService;
|
||||||
private final SettingService settingService;
|
private final SettingService settingService;
|
||||||
|
private final UserRoleService userRoleService;
|
||||||
private final AttachmentService attachmentService;
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
private final Redis<String, String> redisUserToken;
|
private final Redis<String, String> redisUserToken;
|
||||||
@@ -86,8 +88,8 @@ public class UserLoginServiceImplement implements UserLoginService, TimiJava {
|
|||||||
result.setUser(userService.get(userId));
|
result.setUser(userService.get(userId));
|
||||||
|
|
||||||
User user = result.getUser();
|
User user = result.getUser();
|
||||||
user.setPermissionList(roleService.listAllPermissionCodeByUserId(user.getId()));
|
user.setPermissionList(userRoleService.listAllPermissionCodeByUserId(user.getId()));
|
||||||
user.setRoleList(roleService.listAllCodeByUserId(user.getId()));
|
user.setRoleList(userRoleService.listAllRoleCodeByUserId(user.getId()));
|
||||||
user.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.USER, user.getId()));
|
user.setAttachmentList(attachmentService.listByBizId(Attachment.BizType.USER, user.getId()));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
+117
@@ -1,14 +1,34 @@
|
|||||||
package com.imyeyu.api.modules.user.service.implement;
|
package com.imyeyu.api.modules.user.service.implement;
|
||||||
|
|
||||||
|
import com.imyeyu.api.bean.ModuleCode;
|
||||||
|
import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
|
||||||
|
import com.imyeyu.api.modules.user.entity.Permission;
|
||||||
|
import com.imyeyu.api.modules.user.entity.Role;
|
||||||
import com.imyeyu.api.modules.user.entity.UserRole;
|
import com.imyeyu.api.modules.user.entity.UserRole;
|
||||||
import com.imyeyu.api.modules.user.mapper.UserRoleMapper;
|
import com.imyeyu.api.modules.user.mapper.UserRoleMapper;
|
||||||
|
import com.imyeyu.api.modules.user.service.PermissionService;
|
||||||
|
import com.imyeyu.api.modules.user.service.RoleService;
|
||||||
import com.imyeyu.api.modules.user.service.UserRoleService;
|
import com.imyeyu.api.modules.user.service.UserRoleService;
|
||||||
|
import com.imyeyu.api.modules.user.vo.role.UserRoleAuthorizeRequest;
|
||||||
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
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 java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/// 用户角色服务实现
|
/// 用户角色服务实现
|
||||||
///
|
///
|
||||||
@@ -18,6 +38,9 @@ import java.util.List;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class UserRoleServiceImplement extends AbstractEntityService<UserRole, String> implements UserRoleService {
|
public class UserRoleServiceImplement extends AbstractEntityService<UserRole, String> implements UserRoleService {
|
||||||
|
|
||||||
|
private final RoleService roleService;
|
||||||
|
private final PermissionService permissionService;
|
||||||
|
|
||||||
private final UserRoleMapper mapper;
|
private final UserRoleMapper mapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -30,6 +53,49 @@ public class UserRoleServiceImplement extends AbstractEntityService<UserRole, St
|
|||||||
mapper.createBatch(list);
|
mapper.createBatch(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
@Override
|
||||||
|
public void authorizeUserRole(UserRoleAuthorizeRequest req) {
|
||||||
|
TimiException.required(req, "not found req");
|
||||||
|
TimiException.required(req.getUserId(), "not found req.userId");
|
||||||
|
if (req.getModuleCode() == null) {
|
||||||
|
throw new TimiException(TimiCode.ARG_MISS, "moduleCode");
|
||||||
|
}
|
||||||
|
List<UserRole> bindingList = listByUserId(req.getUserId());
|
||||||
|
List<String> bindingRoleIdList = bindingList.stream().map(UserRole::getRoleId).toList();
|
||||||
|
Set<String> dbIdSet = roleService.listByIdList(bindingRoleIdList)
|
||||||
|
.stream()
|
||||||
|
.filter(role -> req.getModuleCode() == role.getModuleCode())
|
||||||
|
.map(Role::getId)
|
||||||
|
.collect(Collectors.toSet());
|
||||||
|
Set<String> newIdSet = new HashSet<>();
|
||||||
|
if (TimiJava.isNotEmpty(req.getRoleIdList())) {
|
||||||
|
newIdSet.addAll(roleService.listByIdList(req.getRoleIdList()).stream().filter(role -> req.getModuleCode() == role.getModuleCode()).map(Role::getId).toList());
|
||||||
|
}
|
||||||
|
Set<String> deleteIdList = new HashSet<>(dbIdSet);
|
||||||
|
deleteIdList.removeAll(newIdSet);
|
||||||
|
|
||||||
|
Set<String> addIdList = new HashSet<>(newIdSet);
|
||||||
|
addIdList.removeAll(dbIdSet);
|
||||||
|
|
||||||
|
if (TimiJava.isNotEmpty(deleteIdList)) {
|
||||||
|
deleteByRoleIdList(req.getUserId(), new ArrayList<>(deleteIdList));
|
||||||
|
}
|
||||||
|
if (TimiJava.isNotEmpty(addIdList)) {
|
||||||
|
List<UserRole> roleBindingList = new ArrayList<>();
|
||||||
|
long now = Time.now();
|
||||||
|
for (String roleId : addIdList) {
|
||||||
|
UserRole roleBinding = new UserRole();
|
||||||
|
roleBinding.setId(UUID.randomUUID().toString());
|
||||||
|
roleBinding.setUserId(req.getUserId());
|
||||||
|
roleBinding.setRoleId(roleId);
|
||||||
|
roleBinding.setCreatedAt(now);
|
||||||
|
roleBindingList.add(roleBinding);
|
||||||
|
}
|
||||||
|
createBatch(roleBindingList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UserRole> listByUserId(String userId) {
|
public List<UserRole> listByUserId(String userId) {
|
||||||
UserRole example = new UserRole();
|
UserRole example = new UserRole();
|
||||||
@@ -37,6 +103,57 @@ public class UserRoleServiceImplement extends AbstractEntityService<UserRole, St
|
|||||||
return mapper.selectAllByExample(example);
|
return mapper.selectAllByExample(example);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<UserRole> listByUserIdList(Collection<String> userIdList) {
|
||||||
|
return mapper.selectByUserIdList(userIdList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Role> listRoleByUserId(String userId) {
|
||||||
|
List<UserRole> userRoleList = listByUserId(userId);
|
||||||
|
return roleService.listByIdList(userRoleList.stream().map(UserRole::getRoleId).toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Role> listRoleByUserId(ModuleCode moduleCode, String userId) {
|
||||||
|
TimiException.required(moduleCode, "not found moduleCode");
|
||||||
|
return listRoleByUserId(userId).stream().filter(role -> moduleCode == role.getModuleCode()).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> listAllRoleCodeByUserId(String userId) {
|
||||||
|
List<String> roleIdList = listRoleByUserId(userId).stream().map(Role::getId).toList();
|
||||||
|
List<String> allRoleIdList = roleService.listAllRoleIdIncludingChildren(roleIdList);
|
||||||
|
if (TimiJava.isEmpty(allRoleIdList)) {
|
||||||
|
return List.of();
|
||||||
|
}
|
||||||
|
return roleService.listByIdList(allRoleIdList).stream().map(role -> "%s:%s".formatted(role.getModuleCode().name(), role.getCode())).distinct().toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Permission> listAllPermissionByUserId(String userId) {
|
||||||
|
List<String> roleIdList = listRoleByUserId(userId).stream().map(Role::getId).toList();
|
||||||
|
List<String> allRoleIdList = roleService.listAllRoleIdIncludingChildren(roleIdList);
|
||||||
|
return permissionService.listByRoleId(allRoleIdList);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, List<Role>> mapRoleListByUserIdList(Collection<String> idList) {
|
||||||
|
if (TimiJava.isEmpty(idList)) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
List<UserRole> userRoleList = listByUserIdList(idList);
|
||||||
|
if (TimiJava.isEmpty(userRoleList)) {
|
||||||
|
return Map.of();
|
||||||
|
}
|
||||||
|
Map<String, Role> roleMap = roleService.listByIdList(userRoleList.stream().map(UserRole::getRoleId).distinct().toList())
|
||||||
|
.stream()
|
||||||
|
.collect(Collectors.toMap(Role::getId, Function.identity()));
|
||||||
|
return userRoleList.stream()
|
||||||
|
.filter(userRole -> roleMap.containsKey(userRole.getRoleId()))
|
||||||
|
.collect(Collectors.groupingBy(UserRole::getUserId, Collectors.mapping(userRole -> roleMap.get(userRole.getRoleId()), Collectors.toList())));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void deleteByRoleIdList(String userId, List<String> roleIdList) {
|
public void deleteByRoleIdList(String userId, List<String> roleIdList) {
|
||||||
mapper.deleteByRoleIdList(userId, roleIdList);
|
mapper.deleteByRoleIdList(userId, roleIdList);
|
||||||
|
|||||||
+26
-7
@@ -11,11 +11,18 @@ import com.imyeyu.spring.mapper.BaseMapper;
|
|||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
import com.imyeyu.utils.Digest;
|
import com.imyeyu.utils.Digest;
|
||||||
import com.imyeyu.utils.Regex;
|
import com.imyeyu.utils.Regex;
|
||||||
|
import com.imyeyu.utils.Time;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户管理服务实现
|
* 用户管理服务实现
|
||||||
*
|
*
|
||||||
@@ -27,8 +34,6 @@ import org.springframework.stereotype.Service;
|
|||||||
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
|
@RequiredArgsConstructor(onConstructor_ = {@Lazy})
|
||||||
public class UserServiceImplement extends AbstractEntityService<User, String> implements UserService, TimiJava {
|
public class UserServiceImplement extends AbstractEntityService<User, String> implements UserService, TimiJava {
|
||||||
|
|
||||||
private static final String REGEX_PHONE_NO = "^1\\d{10}$";
|
|
||||||
|
|
||||||
private final UserMapper mapper;
|
private final UserMapper mapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -51,7 +56,7 @@ public class UserServiceImplement extends AbstractEntityService<User, String> im
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
if (TimiJava.isNotEmpty(user.getPhoneNo())) {
|
if (TimiJava.isNotEmpty(user.getPhoneNo())) {
|
||||||
validatePhoneNo(user.getPhoneNo());
|
TimiException.requiredTrue(user.isValidPhone(), "invalid phone");
|
||||||
User byPhoneNo = getByVerifiedPhoneNo(user.getPhoneNo());
|
User byPhoneNo = getByVerifiedPhoneNo(user.getPhoneNo());
|
||||||
TimiException.requiredNull(byPhoneNo, "existed phone number");
|
TimiException.requiredNull(byPhoneNo, "existed phone number");
|
||||||
}
|
}
|
||||||
@@ -65,7 +70,6 @@ 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());
|
||||||
@@ -88,7 +92,7 @@ public class UserServiceImplement extends AbstractEntityService<User, String> im
|
|||||||
TimiException.requiredTrue(byEmail == null || byEmail.getId().equals(dbUser.getId()), "existed email");
|
TimiException.requiredTrue(byEmail == null || byEmail.getId().equals(dbUser.getId()), "existed email");
|
||||||
}
|
}
|
||||||
if (TimiJava.isNotEmpty(phoneNo)) {
|
if (TimiJava.isNotEmpty(phoneNo)) {
|
||||||
validatePhoneNo(phoneNo);
|
TimiException.requiredTrue(user.isValidPhone(), "invalid phone");
|
||||||
if (!phoneNo.equals(dbUser.getPhoneNo())) {
|
if (!phoneNo.equals(dbUser.getPhoneNo())) {
|
||||||
User byPhoneNo = getByVerifiedPhoneNo(phoneNo);
|
User byPhoneNo = getByVerifiedPhoneNo(phoneNo);
|
||||||
TimiException.requiredTrue(byPhoneNo == null || byPhoneNo.getId().equals(dbUser.getId()), "existed phone number");
|
TimiException.requiredTrue(byPhoneNo == null || byPhoneNo.getId().equals(dbUser.getId()), "existed phone number");
|
||||||
@@ -138,7 +142,22 @@ public class UserServiceImplement extends AbstractEntityService<User, String> im
|
|||||||
return mapper.selectByVerifiedPhoneNo(phoneNo);
|
return mapper.selectByVerifiedPhoneNo(phoneNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePhoneNo(String phoneNo) {
|
@Override
|
||||||
TimiException.requiredTrue(Regex.isMatch(REGEX_PHONE_NO, phoneNo), "invalid phone number");
|
public void verifyEmail(String id) {
|
||||||
|
User user = get(id);
|
||||||
|
user.setEmailVerifyAt(Time.now());
|
||||||
|
update(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void verifyPhoneNo(String id) {
|
||||||
|
User user = get(id);
|
||||||
|
user.setPhoneNoVerifyAt(Time.now());
|
||||||
|
update(user);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, User> mapByIdList(Collection<String> idList) {
|
||||||
|
return mapper.listByIdList(new HashSet<>(idList)).stream().collect(Collectors.toMap(User::getId, Function.identity()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-3
@@ -10,13 +10,11 @@ import java.util.List;
|
|||||||
/// @author 夜雨
|
/// @author 夜雨
|
||||||
/// @since 2026-07-17 14:16
|
/// @since 2026-07-17 14:16
|
||||||
@Data
|
@Data
|
||||||
public class UserRoleAuthorizeReq {
|
public class UserRoleAuthorizeRequest {
|
||||||
|
|
||||||
private String userId;
|
private String userId;
|
||||||
|
|
||||||
private ModuleCode moduleCode;
|
private ModuleCode moduleCode;
|
||||||
|
|
||||||
private List<String> roleIdList;
|
private List<String> roleIdList;
|
||||||
|
|
||||||
private List<String> roleCodeList;
|
|
||||||
}
|
}
|
||||||
@@ -192,6 +192,7 @@ public class InitBuiltinUser implements ApplicationRunner {
|
|||||||
private void bindBuiltinPermission(Map<String, Role> roleMap, Map<String, Permission> permissionMap) {
|
private void bindBuiltinPermission(Map<String, Role> roleMap, Map<String, Permission> permissionMap) {
|
||||||
Role systemRole = roleMap.get(BuiltinAuthRegistry.toRoleKey(BootstrapData.SYS_ROLE_MODULE_CODE, BootstrapData.SYS_ROLE_CODE));
|
Role systemRole = roleMap.get(BuiltinAuthRegistry.toRoleKey(BootstrapData.SYS_ROLE_MODULE_CODE, BootstrapData.SYS_ROLE_CODE));
|
||||||
Role adminRole = roleMap.get(BuiltinAuthRegistry.toRoleKey(BootstrapData.ADMIN_ROLE_MODULE_CODE, BootstrapData.ADMIN_ROLE_CODE));
|
Role adminRole = roleMap.get(BuiltinAuthRegistry.toRoleKey(BootstrapData.ADMIN_ROLE_MODULE_CODE, BootstrapData.ADMIN_ROLE_CODE));
|
||||||
|
Role gaoGlobalManagerRole = roleMap.get(BuiltinAuthRegistry.toRoleKey(ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name()));
|
||||||
Role gaoStoreManagerRole = roleMap.get(BuiltinAuthRegistry.toRoleKey(ModuleCode.GAO, GaoRoleCode.STORE_MANAGER.name()));
|
Role gaoStoreManagerRole = roleMap.get(BuiltinAuthRegistry.toRoleKey(ModuleCode.GAO, GaoRoleCode.STORE_MANAGER.name()));
|
||||||
for (BuiltinPermissionCode item : BuiltinAuthRegistry.PERMISSION_CODE_LIST) {
|
for (BuiltinPermissionCode item : BuiltinAuthRegistry.PERMISSION_CODE_LIST) {
|
||||||
Permission permission = permissionMap.get(BuiltinAuthRegistry.toPermissionKey(item.getModuleCode(), item.getValue()));
|
Permission permission = permissionMap.get(BuiltinAuthRegistry.toPermissionKey(item.getModuleCode(), item.getValue()));
|
||||||
@@ -204,6 +205,9 @@ public class InitBuiltinUser implements ApplicationRunner {
|
|||||||
if (item.isGrantToAdmin() && adminRole != null) {
|
if (item.isGrantToAdmin() && adminRole != null) {
|
||||||
createRolePermissionIfAbsent(adminRole.getId(), permission.getId());
|
createRolePermissionIfAbsent(adminRole.getId(), permission.getId());
|
||||||
}
|
}
|
||||||
|
if (item instanceof GaoPermissionCode gaoPermission && gaoPermission.isGrantToGlobalManager() && gaoGlobalManagerRole != null) {
|
||||||
|
createRolePermissionIfAbsent(gaoGlobalManagerRole.getId(), permission.getId());
|
||||||
|
}
|
||||||
if (item instanceof GaoPermissionCode gaoPermission && gaoPermission.isGrantToStoreManager() && gaoStoreManagerRole != null) {
|
if (item instanceof GaoPermissionCode gaoPermission && gaoPermission.isGrantToStoreManager() && gaoStoreManagerRole != null) {
|
||||||
createRolePermissionIfAbsent(gaoStoreManagerRole.getId(), permission.getId());
|
createRolePermissionIfAbsent(gaoStoreManagerRole.getId(), permission.getId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,192 @@
|
|||||||
|
-- 新增门店主表。active_code / active_name 沿用项目现有软删除唯一索引方案:
|
||||||
|
-- 未删除数据参与唯一约束,已删除数据生成 NULL,不阻塞后续重建同编码或同名门店。
|
||||||
|
CREATE TABLE IF NOT EXISTS `gao_store` (
|
||||||
|
`id` VARCHAR(36) NOT NULL,
|
||||||
|
`code` VARCHAR(64) NOT NULL COMMENT '门店编码',
|
||||||
|
`active_code` VARCHAR(64) GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL THEN NULLIF(TRIM(`code`), '') ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除门店编码' INVISIBLE,
|
||||||
|
`name` VARCHAR(64) NOT NULL COMMENT '门店名称',
|
||||||
|
`active_name` VARCHAR(64) GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL THEN NULLIF(TRIM(`name`), '') ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除门店名称' INVISIBLE,
|
||||||
|
`status` VARCHAR(32) NOT NULL COMMENT '门店状态',
|
||||||
|
`telephone` VARCHAR(32) NULL COMMENT '电话',
|
||||||
|
`address` VARCHAR(255) NULL COMMENT '地址',
|
||||||
|
`remark` TEXT NULL COMMENT '备注',
|
||||||
|
`sort` INT NOT NULL DEFAULT 0 COMMENT '排序值',
|
||||||
|
`created_at` BIGINT NOT NULL,
|
||||||
|
`updated_at` BIGINT NULL,
|
||||||
|
`deleted_at` BIGINT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_gao_store_active_code` (`active_code`),
|
||||||
|
UNIQUE KEY `uk_gao_store_active_name` (`active_name`),
|
||||||
|
KEY `idx_gao_store_status_sort` (`status`, `deleted_at`, `sort`, `created_at`)
|
||||||
|
) COMMENT='GAO 门店';
|
||||||
|
|
||||||
|
-- 旧数据来自单门店模型,迁移时全部归入固定默认门店。
|
||||||
|
-- 使用固定 ID 而不是 UUID(),避免迁移中断后排查或手工重跑时产生多个默认门店。
|
||||||
|
SET @gao_default_store_id = '00000000-0000-0000-0000-000000000001';
|
||||||
|
SET @gao_now = ROUND(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000);
|
||||||
|
|
||||||
|
-- Flyway 正常不会重复执行版本脚本;这里保留 ON DUPLICATE KEY,方便本地或预发排查时手工重放片段。
|
||||||
|
INSERT INTO `gao_store` (
|
||||||
|
`id`,
|
||||||
|
`code`,
|
||||||
|
`name`,
|
||||||
|
`status`,
|
||||||
|
`telephone`,
|
||||||
|
`address`,
|
||||||
|
`remark`,
|
||||||
|
`sort`,
|
||||||
|
`created_at`
|
||||||
|
) VALUES (
|
||||||
|
@gao_default_store_id,
|
||||||
|
'DEFAULT',
|
||||||
|
'默认门店',
|
||||||
|
'ACTIVE',
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
'系统迁移自动创建',
|
||||||
|
0,
|
||||||
|
@gao_now
|
||||||
|
) ON DUPLICATE KEY UPDATE
|
||||||
|
`name` = VALUES(`name`),
|
||||||
|
`status` = VALUES(`status`),
|
||||||
|
`updated_at` = @gao_now;
|
||||||
|
|
||||||
|
-- 门店营业日历是连续登记统计的事实维度。
|
||||||
|
-- business_day_no 只给营业日使用,休息日 business_day_no 为 NULL。
|
||||||
|
-- 后续统计连续登记时按 business_day_no 连续,不按自然日连续。
|
||||||
|
CREATE TABLE IF NOT EXISTS `gao_store_business_day` (
|
||||||
|
`id` VARCHAR(36) NOT NULL,
|
||||||
|
`store_id` VARCHAR(36) NOT NULL COMMENT '门店 ID',
|
||||||
|
`date_value` INT NOT NULL COMMENT '日期值,格式为 yyyyMMdd',
|
||||||
|
`active_date_value` INT GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL THEN `date_value` ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除日期值' INVISIBLE,
|
||||||
|
`open_status` VARCHAR(32) NOT NULL COMMENT '营业状态',
|
||||||
|
`business_day_no` BIGINT NULL COMMENT '营业日递增序号,仅营业日有值',
|
||||||
|
`active_business_day_no` BIGINT GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL AND `open_status` = 'OPEN' THEN `business_day_no` ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除营业日序号' INVISIBLE,
|
||||||
|
`reason` VARCHAR(255) NULL COMMENT '原因',
|
||||||
|
`created_at` BIGINT NOT NULL,
|
||||||
|
`updated_at` BIGINT NULL,
|
||||||
|
`deleted_at` BIGINT NULL,
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_gao_store_business_day_active_date` (`store_id`, `active_date_value`),
|
||||||
|
UNIQUE KEY `uk_gao_store_business_day_active_no` (`store_id`, `active_business_day_no`),
|
||||||
|
KEY `idx_gao_store_business_day_open_no` (`store_id`, `open_status`, `business_day_no`)
|
||||||
|
) COMMENT='GAO 门店营业日';
|
||||||
|
|
||||||
|
-- 客户归属门店。先允许 NULL,加字段后回填,再改 NOT NULL,避免已有数据直接违反约束。
|
||||||
|
ALTER TABLE `gao_customer`
|
||||||
|
ADD COLUMN `store_id` VARCHAR(36) NULL COMMENT '门店 ID' AFTER `id`;
|
||||||
|
|
||||||
|
UPDATE `gao_customer`
|
||||||
|
SET `store_id` = @gao_default_store_id
|
||||||
|
WHERE `store_id` IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `gao_customer`
|
||||||
|
MODIFY COLUMN `store_id` VARCHAR(36) NOT NULL COMMENT '门店 ID',
|
||||||
|
-- 客户编码、姓名从全局唯一改为门店内唯一。
|
||||||
|
DROP KEY `uk_gao_customer_active_code`,
|
||||||
|
DROP KEY `uk_gao_customer_active_name`,
|
||||||
|
ADD UNIQUE KEY `uk_gao_customer_store_active_code` (`store_id`, `active_code`),
|
||||||
|
ADD UNIQUE KEY `uk_gao_customer_store_active_name` (`store_id`, `active_name`),
|
||||||
|
ADD KEY `idx_gao_customer_store_created_at` (`store_id`, `deleted_at`, `created_at`);
|
||||||
|
|
||||||
|
-- 登记事件归属门店。历史事件统一归入默认门店。
|
||||||
|
ALTER TABLE `gao_event`
|
||||||
|
ADD COLUMN `store_id` VARCHAR(36) NULL COMMENT '门店 ID' AFTER `id`;
|
||||||
|
|
||||||
|
UPDATE `gao_event`
|
||||||
|
SET `store_id` = @gao_default_store_id
|
||||||
|
WHERE `store_id` IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `gao_event`
|
||||||
|
MODIFY COLUMN `store_id` VARCHAR(36) NOT NULL COMMENT '门店 ID',
|
||||||
|
ADD KEY `idx_gao_event_store_status` (`store_id`, `status`, `deleted_at`, `sort`, `created_at`);
|
||||||
|
|
||||||
|
-- 登记记录是事实表,需要保存门店和营业日快照。
|
||||||
|
-- store_id:优先跟随历史登记事件所属门店,找不到事件时兜底默认门店。
|
||||||
|
-- registered_date_value:由 registered_at 计算 yyyyMMdd,避免查询时反复做时间函数。
|
||||||
|
-- business_day_no:按门店营业日历回填,用于连续登记统计。
|
||||||
|
ALTER TABLE `gao_event_record`
|
||||||
|
ADD COLUMN `store_id` VARCHAR(36) NULL COMMENT '门店 ID' AFTER `customer_id`,
|
||||||
|
ADD COLUMN `registered_date_value` INT NULL COMMENT '登记日期值,格式为 yyyyMMdd' AFTER `registered_at`,
|
||||||
|
ADD COLUMN `business_day_no` BIGINT NULL COMMENT '营业日递增序号' AFTER `registered_date_value`;
|
||||||
|
|
||||||
|
UPDATE `gao_event_record` r
|
||||||
|
LEFT JOIN `gao_event` e ON r.`event_id` = e.`id`
|
||||||
|
SET
|
||||||
|
r.`store_id` = COALESCE(e.`store_id`, @gao_default_store_id),
|
||||||
|
r.`registered_date_value` = CAST(DATE_FORMAT(FROM_UNIXTIME(r.`registered_at` / 1000), '%Y%m%d') AS UNSIGNED)
|
||||||
|
WHERE
|
||||||
|
r.`store_id` IS NULL
|
||||||
|
OR r.`registered_date_value` IS NULL;
|
||||||
|
|
||||||
|
-- 以历史登记记录中实际发生过登记的日期生成营业日。
|
||||||
|
-- 这是最平滑的迁移口径:有登记的日期一定视为营业日;没有登记的历史日期不主动生成休息日或营业日。
|
||||||
|
-- 如果门店历史休息日需要展示,可在迁移后通过营业日接口补录 CLOSED 数据,不影响已有登记记录。
|
||||||
|
INSERT INTO `gao_store_business_day` (
|
||||||
|
`id`,
|
||||||
|
`store_id`,
|
||||||
|
`date_value`,
|
||||||
|
`open_status`,
|
||||||
|
`business_day_no`,
|
||||||
|
`reason`,
|
||||||
|
`created_at`
|
||||||
|
)
|
||||||
|
SELECT
|
||||||
|
UUID(),
|
||||||
|
d.`store_id`,
|
||||||
|
d.`registered_date_value`,
|
||||||
|
'OPEN',
|
||||||
|
ROW_NUMBER() OVER (PARTITION BY d.`store_id` ORDER BY d.`registered_date_value`),
|
||||||
|
'系统迁移按历史登记日期生成',
|
||||||
|
@gao_now
|
||||||
|
FROM (
|
||||||
|
SELECT DISTINCT
|
||||||
|
`store_id`,
|
||||||
|
`registered_date_value`
|
||||||
|
FROM `gao_event_record`
|
||||||
|
WHERE
|
||||||
|
`store_id` IS NOT NULL
|
||||||
|
AND `registered_date_value` IS NOT NULL
|
||||||
|
) d;
|
||||||
|
|
||||||
|
-- 把营业日序号快照回填到历史登记记录。
|
||||||
|
-- 后续即使营业日历被调整,历史记录仍保留迁移时的事实快照;如需重算,应做显式重算脚本。
|
||||||
|
UPDATE `gao_event_record` r
|
||||||
|
LEFT JOIN `gao_store_business_day` d ON r.`store_id` = d.`store_id` AND r.`registered_date_value` = d.`date_value` AND d.`deleted_at` IS NULL
|
||||||
|
SET r.`business_day_no` = d.`business_day_no`
|
||||||
|
WHERE r.`business_day_no` IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `gao_event_record`
|
||||||
|
MODIFY COLUMN `store_id` VARCHAR(36) NOT NULL COMMENT '门店 ID',
|
||||||
|
MODIFY COLUMN `registered_date_value` INT NOT NULL COMMENT '登记日期值,格式为 yyyyMMdd',
|
||||||
|
MODIFY COLUMN `business_day_no` BIGINT NOT NULL COMMENT '营业日递增序号',
|
||||||
|
ADD KEY `idx_gao_event_record_store_registered_at` (`store_id`, `deleted_at`, `registered_at`),
|
||||||
|
ADD KEY `idx_gao_event_record_store_date` (`store_id`, `registered_date_value`, `deleted_at`),
|
||||||
|
ADD KEY `idx_gao_event_record_store_customer_time` (`store_id`, `customer_id`, `deleted_at`, `registered_at`),
|
||||||
|
ADD KEY `idx_gao_event_record_store_event_time` (`store_id`, `event_id`, `deleted_at`, `registered_at`),
|
||||||
|
ADD KEY `idx_gao_event_record_store_customer_day` (`store_id`, `customer_id`, `business_day_no`);
|
||||||
|
|
||||||
|
-- GAO 用户归属门店。用户可在不同门店分别存在一条 GAO 用户记录。
|
||||||
|
-- 注意:当前用户角色关系仍是用户维度,不是门店维度;不同门店不同角色需要后续扩展 user_role 作用域。
|
||||||
|
ALTER TABLE `gao_user`
|
||||||
|
ADD COLUMN `store_id` VARCHAR(36) NULL COMMENT '门店 ID' AFTER `id`,
|
||||||
|
ADD COLUMN `active_user_id` VARCHAR(36) GENERATED ALWAYS AS (
|
||||||
|
CASE WHEN `deleted_at` IS NULL THEN `user_id` ELSE NULL END
|
||||||
|
) STORED COMMENT '未删除用户 ID' INVISIBLE;
|
||||||
|
|
||||||
|
UPDATE `gao_user`
|
||||||
|
SET `store_id` = @gao_default_store_id
|
||||||
|
WHERE `store_id` IS NULL;
|
||||||
|
|
||||||
|
ALTER TABLE `gao_user`
|
||||||
|
MODIFY COLUMN `store_id` VARCHAR(36) NOT NULL COMMENT '门店 ID',
|
||||||
|
ADD UNIQUE KEY `uk_gao_user_store_active_user` (`store_id`, `active_user_id`),
|
||||||
|
ADD KEY `idx_gao_user_store_enabled` (`store_id`, `enabled`, `deleted_at`, `created_at`);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- V24 已经上线为“用户可在多个门店分别存在 GAO 用户记录”。
|
||||||
|
-- 现在业务改为一个用户只能归属一个门店,所以不能再改 V24,必须通过 V25 切换唯一约束。
|
||||||
|
|
||||||
|
-- 如果线上已经存在同一 user_id 绑定多个未删除门店的数据,下面新增唯一索引会失败。
|
||||||
|
-- 这是正确行为:这种数据无法自动判断保留哪个门店,必须人工先清理重复 GAO 用户记录。
|
||||||
|
ALTER TABLE `gao_user`
|
||||||
|
DROP KEY `uk_gao_user_store_active_user`,
|
||||||
|
ADD UNIQUE KEY `uk_gao_user_active_user` (`active_user_id`);
|
||||||
@@ -6,10 +6,16 @@
|
|||||||
*
|
*
|
||||||
FROM `gao_customer`
|
FROM `gao_customer`
|
||||||
WHERE
|
WHERE
|
||||||
`id` IN
|
TRUE
|
||||||
<foreach collection="idList" item="id" open="(" separator="," close=")">
|
<if test="idList != null and !idList.isEmpty()">
|
||||||
|
AND `id` IN
|
||||||
|
<foreach collection="idList" item="id" separator="," open="(" close=")">
|
||||||
#{id}
|
#{id}
|
||||||
</foreach>
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="idList == null or idList.isEmpty()">
|
||||||
|
AND FALSE
|
||||||
|
</if>
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -19,7 +25,8 @@
|
|||||||
COUNT(1) AS `newCustomerCount`
|
COUNT(1) AS `newCustomerCount`
|
||||||
FROM `gao_customer`
|
FROM `gao_customer`
|
||||||
WHERE
|
WHERE
|
||||||
`created_at` >= #{beginCreatedAt}
|
`store_id` = #{storeId}
|
||||||
|
AND `created_at` >= #{beginCreatedAt}
|
||||||
AND `created_at` <= #{endCreatedAt}
|
AND `created_at` <= #{endCreatedAt}
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
GROUP BY DATE_FORMAT(FROM_UNIXTIME(`created_at` / 1000), '%Y%m%d')
|
GROUP BY DATE_FORMAT(FROM_UNIXTIME(`created_at` / 1000), '%Y%m%d')
|
||||||
@@ -31,7 +38,8 @@
|
|||||||
COUNT(1)
|
COUNT(1)
|
||||||
FROM `gao_customer`
|
FROM `gao_customer`
|
||||||
WHERE
|
WHERE
|
||||||
`created_at` < #{beginCreatedAt}
|
`store_id` = #{storeId}
|
||||||
|
AND `created_at` < #{beginCreatedAt}
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -41,7 +49,8 @@
|
|||||||
COUNT(1) AS `count`
|
COUNT(1) AS `count`
|
||||||
FROM `gao_customer`
|
FROM `gao_customer`
|
||||||
WHERE
|
WHERE
|
||||||
`deleted_at` IS NULL
|
`store_id` = #{storeId}
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
GROUP BY IFNULL(CAST(`gender` AS CHAR), 'UNKNOWN')
|
GROUP BY IFNULL(CAST(`gender` AS CHAR), 'UNKNOWN')
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -24,7 +24,8 @@
|
|||||||
*
|
*
|
||||||
FROM `gao_event`
|
FROM `gao_event`
|
||||||
WHERE
|
WHERE
|
||||||
`status` = '${@com.imyeyu.api.modules.gao.entity.GaoEvent$Status@ACTIVE.name()}'
|
`store_id` = #{storeId}
|
||||||
|
AND `status` = '${@com.imyeyu.api.modules.gao.entity.GaoEvent$Status@ACTIVE.name()}'
|
||||||
AND (`begin_at` IS NULL OR `begin_at` <= #{now})
|
AND (`begin_at` IS NULL OR `begin_at` <= #{now})
|
||||||
AND (`end_at` IS NULL OR #{now} <= `end_at`)
|
AND (`end_at` IS NULL OR #{now} <= `end_at`)
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
`gao_event_record`
|
`gao_event_record`
|
||||||
WHERE
|
WHERE
|
||||||
TRUE
|
TRUE
|
||||||
|
<if test="storeId != null">
|
||||||
|
AND `store_id` = #{storeId}
|
||||||
|
</if>
|
||||||
<if test="customerId != null">
|
<if test="customerId != null">
|
||||||
AND `customer_id` = #{customerId}
|
AND `customer_id` = #{customerId}
|
||||||
</if>
|
</if>
|
||||||
@@ -18,19 +21,48 @@
|
|||||||
AND `registered_at` >= #{beginAt}
|
AND `registered_at` >= #{beginAt}
|
||||||
</if>
|
</if>
|
||||||
<if test="endAt != null">
|
<if test="endAt != null">
|
||||||
AND `registered_at` >= #{endAt}
|
AND `registered_at` <= #{endAt}
|
||||||
</if>
|
</if>
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="countByStoreIdAndRegisteredDateValue" resultType="java.lang.Long">
|
||||||
|
SELECT
|
||||||
|
COUNT(1)
|
||||||
|
FROM `gao_event_record`
|
||||||
|
WHERE
|
||||||
|
`store_id` = #{storeId}
|
||||||
|
AND `registered_date_value` = #{registeredDateValue}
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="updateBusinessDayNoByStoreIdAndRegisteredDateValue">
|
||||||
|
UPDATE `gao_event_record`
|
||||||
|
SET
|
||||||
|
`business_day_no` = #{businessDayNo},
|
||||||
|
`updated_at` = ROUND(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000)
|
||||||
|
WHERE
|
||||||
|
`store_id` = #{storeId}
|
||||||
|
AND `registered_date_value` = #{registeredDateValue}
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
|
</update>
|
||||||
|
|
||||||
<sql id="rangeFrom">
|
<sql id="rangeFrom">
|
||||||
FROM `gao_event_record` r
|
FROM `gao_event_record` r
|
||||||
LEFT JOIN `gao_customer` c ON r.`customer_id` = c.`id`
|
LEFT JOIN `gao_customer` c ON r.`customer_id` = c.`id`
|
||||||
</sql>
|
</sql>
|
||||||
<sql id="rangeWhere">
|
<sql id="rangeWhere">
|
||||||
r.`registered_at` >= #{beginAt}
|
TRUE
|
||||||
|
<if test="beginAt != null">
|
||||||
|
AND r.`registered_at` >= #{beginAt}
|
||||||
|
</if>
|
||||||
|
<if test="endAt != null">
|
||||||
AND r.`registered_at` <= #{endAt}
|
AND r.`registered_at` <= #{endAt}
|
||||||
|
</if>
|
||||||
AND r.`deleted_at` IS NULL
|
AND r.`deleted_at` IS NULL
|
||||||
|
<if test="storeId != null and storeId != ''">
|
||||||
|
AND r.`store_id` = #{storeId}
|
||||||
|
</if>
|
||||||
<if test="customerId != null">
|
<if test="customerId != null">
|
||||||
AND r.`customer_id` = #{customerId}
|
AND r.`customer_id` = #{customerId}
|
||||||
</if>
|
</if>
|
||||||
@@ -69,6 +101,9 @@
|
|||||||
<sql id="rankWhere">
|
<sql id="rankWhere">
|
||||||
r.`deleted_at` IS NULL
|
r.`deleted_at` IS NULL
|
||||||
AND c.`deleted_at` IS NULL
|
AND c.`deleted_at` IS NULL
|
||||||
|
<if test="storeId != null and storeId != ''">
|
||||||
|
AND r.`store_id` = #{storeId}
|
||||||
|
</if>
|
||||||
<if test="customerId != null and customerId != ''">
|
<if test="customerId != null and customerId != ''">
|
||||||
AND r.`customer_id` = #{customerId}
|
AND r.`customer_id` = #{customerId}
|
||||||
</if>
|
</if>
|
||||||
@@ -97,7 +132,7 @@
|
|||||||
WITH `daily_stat` AS (
|
WITH `daily_stat` AS (
|
||||||
SELECT
|
SELECT
|
||||||
r.`customer_id` AS `customerId`,
|
r.`customer_id` AS `customerId`,
|
||||||
DATE(FROM_UNIXTIME(r.`registered_at` / 1000)) AS `eventDate`,
|
r.`business_day_no` AS `businessDayNo`,
|
||||||
COUNT(1) AS `dailyCount`,
|
COUNT(1) AS `dailyCount`,
|
||||||
MAX(r.`registered_at`) AS `latestRegisteredAt`
|
MAX(r.`registered_at`) AS `latestRegisteredAt`
|
||||||
FROM `gao_event_record` r
|
FROM `gao_event_record` r
|
||||||
@@ -106,7 +141,7 @@
|
|||||||
<include refid="rankWhere"/>
|
<include refid="rankWhere"/>
|
||||||
GROUP BY
|
GROUP BY
|
||||||
r.`customer_id`,
|
r.`customer_id`,
|
||||||
DATE(FROM_UNIXTIME(r.`registered_at` / 1000))
|
r.`business_day_no`
|
||||||
),
|
),
|
||||||
`rank_stat` AS (
|
`rank_stat` AS (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -120,14 +155,14 @@
|
|||||||
`continuous_ordered` AS (
|
`continuous_ordered` AS (
|
||||||
SELECT
|
SELECT
|
||||||
`customerId`,
|
`customerId`,
|
||||||
`eventDate`,
|
`businessDayNo`,
|
||||||
ROW_NUMBER() OVER (PARTITION BY `customerId` ORDER BY `eventDate` DESC) AS `dayIndex`
|
ROW_NUMBER() OVER (PARTITION BY `customerId` ORDER BY `businessDayNo` DESC) AS `dayIndex`
|
||||||
FROM `daily_stat`
|
FROM `daily_stat`
|
||||||
),
|
),
|
||||||
`latest_date` AS (
|
`latest_date` AS (
|
||||||
SELECT
|
SELECT
|
||||||
`customerId`,
|
`customerId`,
|
||||||
MAX(`eventDate`) AS `latestEventDate`
|
MAX(`businessDayNo`) AS `latestBusinessDayNo`
|
||||||
FROM `daily_stat`
|
FROM `daily_stat`
|
||||||
GROUP BY `customerId`
|
GROUP BY `customerId`
|
||||||
),
|
),
|
||||||
@@ -137,7 +172,7 @@
|
|||||||
COUNT(1) AS `recentContinuousEventDays`
|
COUNT(1) AS `recentContinuousEventDays`
|
||||||
FROM `continuous_ordered` o
|
FROM `continuous_ordered` o
|
||||||
LEFT JOIN `latest_date` l ON o.`customerId` = l.`customerId`
|
LEFT JOIN `latest_date` l ON o.`customerId` = l.`customerId`
|
||||||
WHERE DATE_ADD(o.`eventDate`, INTERVAL o.`dayIndex` DAY) = DATE_ADD(l.`latestEventDate`, INTERVAL 1 DAY)
|
WHERE o.`businessDayNo` + o.`dayIndex` = l.`latestBusinessDayNo` + 1
|
||||||
GROUP BY o.`customerId`
|
GROUP BY o.`customerId`
|
||||||
),
|
),
|
||||||
`ranked` AS (
|
`ranked` AS (
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
<?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.GaoStoreMapper">
|
||||||
|
<select id="selectByUserId" resultType="com.imyeyu.api.modules.gao.entity.GaoStore">
|
||||||
|
SELECT
|
||||||
|
s.*
|
||||||
|
FROM `gao_user` u
|
||||||
|
INNER JOIN `gao_store` s ON u.`store_id` = s.`id`
|
||||||
|
WHERE
|
||||||
|
u.`user_id` = #{userId}
|
||||||
|
AND u.`enabled` = TRUE
|
||||||
|
AND u.`deleted_at` IS NULL
|
||||||
|
AND s.`status` = 'ACTIVE'
|
||||||
|
AND s.`deleted_at` IS NULL
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
</mapper>
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
*
|
*
|
||||||
FROM `role`
|
FROM `role`
|
||||||
WHERE
|
WHERE
|
||||||
1 = 1
|
TRUE
|
||||||
<if test="idList != null and !idList.isEmpty()">
|
<if test="idList != null and !idList.isEmpty()">
|
||||||
AND `id` IN
|
AND `id` IN
|
||||||
<foreach collection="idList" item="item" separator="," open="(" close=")">
|
<foreach collection="idList" item="item" separator="," open="(" close=")">
|
||||||
@@ -14,29 +14,10 @@
|
|||||||
</foreach>
|
</foreach>
|
||||||
</if>
|
</if>
|
||||||
<if test="idList == null or idList.isEmpty()">
|
<if test="idList == null or idList.isEmpty()">
|
||||||
AND 1 = 0
|
AND FALSE
|
||||||
</if>
|
</if>
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
</select>
|
</select>
|
||||||
<select id="selectByModuleCodeAndCodeList" resultType="com.imyeyu.api.modules.user.entity.Role">
|
|
||||||
SELECT
|
|
||||||
*
|
|
||||||
FROM `role`
|
|
||||||
WHERE
|
|
||||||
1 = 1
|
|
||||||
AND `module_code` = #{moduleCode}
|
|
||||||
<if test="codeList != null and !codeList.isEmpty()">
|
|
||||||
AND `code` IN
|
|
||||||
<foreach collection="codeList" item="item" separator="," open="(" close=")">
|
|
||||||
#{item}
|
|
||||||
</foreach>
|
|
||||||
</if>
|
|
||||||
<if test="codeList == null or codeList.isEmpty()">
|
|
||||||
AND 1 = 0
|
|
||||||
</if>
|
|
||||||
AND `deleted_at` IS NULL
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<select id="selectByModuleCode" resultType="com.imyeyu.api.modules.user.entity.Role">
|
<select id="selectByModuleCode" resultType="com.imyeyu.api.modules.user.entity.Role">
|
||||||
SELECT
|
SELECT
|
||||||
*
|
*
|
||||||
@@ -44,6 +25,6 @@
|
|||||||
WHERE
|
WHERE
|
||||||
`module_code` = #{moduleCode}
|
`module_code` = #{moduleCode}
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
ORDER BY `created_at` ASC
|
ORDER BY `created_at`
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -12,6 +12,23 @@
|
|||||||
(#{item.id}, #{item.userId}, #{item.roleId}, #{item.createdAt})
|
(#{item.id}, #{item.userId}, #{item.roleId}, #{item.createdAt})
|
||||||
</foreach>
|
</foreach>
|
||||||
</insert>
|
</insert>
|
||||||
|
<select id="selectByUserIdList" resultType="com.imyeyu.api.modules.user.entity.UserRole">
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM `user_role`
|
||||||
|
WHERE
|
||||||
|
TRUE
|
||||||
|
<if test="userIdList != null and !userIdList.isEmpty()">
|
||||||
|
AND `user_id` IN
|
||||||
|
<foreach collection="userIdList" item="item" separator="," open="(" close=")">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="userIdList == null or userIdList.isEmpty()">
|
||||||
|
AND FALSE
|
||||||
|
</if>
|
||||||
|
AND `deleted_at` IS NULL
|
||||||
|
</select>
|
||||||
<update id="deleteByRoleIdList">
|
<update id="deleteByRoleIdList">
|
||||||
UPDATE `user_role`
|
UPDATE `user_role`
|
||||||
SET `deleted_at` = UNIX_TIMESTAMP()
|
SET `deleted_at` = UNIX_TIMESTAMP()
|
||||||
|
|||||||
Reference in New Issue
Block a user