diff --git a/pom.xml b/pom.xml index ab1ae6b..28f0542 100644 --- a/pom.xml +++ b/pom.xml @@ -17,25 +17,7 @@ 25 - - - - - - org.springframework.cloud - spring-cloud-dependencies - 2025.0.1 - pom - import - - - - - - org.springframework.cloud - spring-cloud-starter-openfeign - org.springframework.boot spring-boot-starter-web @@ -94,22 +76,6 @@ commons-lang3 3.18.0 - - - com.tencentcloudapi - tencentcloud-sdk-java - 3.1.1396 - - - com.qcloud - cos_api - 5.6.246 - - - org.apache.tika - tika-core - 3.2.3 - diff --git a/src/main/java/com/xjhs/findmemerchant/common/jpa/AbstractBaseEntity.java b/src/main/java/com/xjhs/findmemerchant/common/jpa/AbstractBaseEntity.java index d91a194..0d16da2 100644 --- a/src/main/java/com/xjhs/findmemerchant/common/jpa/AbstractBaseEntity.java +++ b/src/main/java/com/xjhs/findmemerchant/common/jpa/AbstractBaseEntity.java @@ -34,7 +34,7 @@ public class AbstractBaseEntity { @CreatedDate @Column(name = "created_at", nullable = false, updatable = false) @Comment("创建时间") - private LocalDateTime createTime; + private LocalDateTime createdAt; /** * 创建人 */ @@ -49,7 +49,7 @@ public class AbstractBaseEntity { @LastModifiedDate @Column(name = "updated_at", nullable = false) @Comment("更新时间") - private LocalDateTime updateTime; + private LocalDateTime updatedAt; /** * 更新人 */ @@ -62,20 +62,20 @@ public class AbstractBaseEntity { */ @Column(name = "deleted_at") @Comment("软删除时间") - private LocalDateTime deleteTime; + private LocalDateTime deletedAt; /** * 是否已删除 */ public boolean isDeleted() { - return deleteTime != null; + return deletedAt != null; } /** * 标记删除 */ public void markDeleted() { - this.deleteTime = LocalDateTime.now(); + this.deletedAt = LocalDateTime.now(); } } diff --git a/src/main/java/com/xjhs/findmemerchant/common/openapi/TencentCOSService.java b/src/main/java/com/xjhs/findmemerchant/common/openapi/TencentCOSService.java deleted file mode 100644 index 63ae89c..0000000 --- a/src/main/java/com/xjhs/findmemerchant/common/openapi/TencentCOSService.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.xjhs.findmemerchant.common.openapi; - -import com.qcloud.cos.COSClient; -import com.qcloud.cos.exception.CosClientException; -import com.qcloud.cos.model.GetObjectRequest; -import com.qcloud.cos.model.PutObjectRequest; -import com.xjhs.findmemerchant.common.openapi.dto.CosPutObjectResult; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -import java.io.File; -import java.io.InputStream; -import java.util.UUID; - -@Slf4j -@Service -@RequiredArgsConstructor -public class TencentCOSService { - @Value("${appconfig.tencentCos.bucketName}") - private String bucketName; - private final COSClient tencentCosClient; - - /** - * 文件上传到Cos存储桶 - * - * @param file 文件 - * @return 存储对象信息 - */ - public CosPutObjectResult putObject(File file) throws Exception { - try { - var key = UUID.randomUUID().toString(); - var req = new PutObjectRequest(this.bucketName, key, file); - var result = tencentCosClient.putObject(req); - return new CosPutObjectResult(key, result.getETag()); - } catch (CosClientException e) { - log.error("文件上传到对象存储失败", e); - throw new Exception("文件上传到对象存储失败"); - } - } - - /** - * 获取文件输入流(下载文件) - * @param key 对象key - * @return 输入流 - * @throws Exception 下载失败 - */ - public InputStream getObject(String key) throws Exception{ - try { - var req = new GetObjectRequest(this.bucketName, key); - var cosObject = this.tencentCosClient.getObject(req); - return cosObject.getObjectContent(); - } catch (CosClientException e) { - log.error("从对象存储下载文件失败",e); - throw new Exception("从对象存储下载文件失败"); - } - } - - - /** - * 删除存储对象 - * - * @param key 对象key - * @throws Exception 删除失败 - */ - public void deleteObject(String key) throws Exception { - try { - this.tencentCosClient.deleteObject(this.bucketName, key); - } catch (CosClientException e) { - log.error("文件上传到对象存储失败", e); - throw new Exception("文件上传到对象存储失败"); - } - } -} diff --git a/src/main/java/com/xjhs/findmemerchant/common/openapi/TencentCloudSMSService.java b/src/main/java/com/xjhs/findmemerchant/common/openapi/TencentCloudSMSService.java deleted file mode 100644 index 8c4c583..0000000 --- a/src/main/java/com/xjhs/findmemerchant/common/openapi/TencentCloudSMSService.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.xjhs.findmemerchant.common.openapi; - - -import com.tencentcloudapi.common.exception.TencentCloudSDKException; -import com.tencentcloudapi.sms.v20190711.models.SendSmsRequest; -import com.tencentcloudapi.sms.v20190711.SmsClient; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@RequiredArgsConstructor() -public class TencentCloudSMSService { - @Value("${appconfig.tencentSms.sdkAppId}") - private String sdkAppid; - @Value("${appconfig.tencentSms.templateId}") - private String templateId; - @Value("${appconfig.tencentSms.signName}") - private String signName; - private final SmsClient tencentSmsClient; - - - /** - * 发送短信验证码 - * - * @param phone 11位国内手机号码 - * @param code 验证码 - * @return 验证码值 - * @throws Exception 发送失败 - */ - public String sendVerifyCode(String phone, String code) throws Exception { - try { - if (!phone.startsWith("+86")) { - phone = "+86" + phone; - } - var req = new SendSmsRequest(); - req.setSmsSdkAppid(this.sdkAppid); - req.setTemplateID(this.templateId); - req.setSign(this.signName); - req.setPhoneNumberSet(new String[]{phone}); - req.setTemplateParamSet(new String[]{code}); - var resp = this.tencentSmsClient.SendSms(req); - if (resp.getSendStatusSet().length == 0){ - throw new Exception("取回短信发送结果失败"); - } - if (!"ok".equalsIgnoreCase(resp.getSendStatusSet()[0].getCode())){ - throw new Exception(resp.getSendStatusSet()[0].getMessage()); - } - return code; - } catch (TencentCloudSDKException e) { - log.error("验证码发送失败", e); - throw new Exception("系统错误,验证码发送失败"); - } - } -} diff --git a/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/AmapFeignClient.java b/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/AmapFeignClient.java deleted file mode 100644 index a98d2bf..0000000 --- a/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/AmapFeignClient.java +++ /dev/null @@ -1,35 +0,0 @@ -package com.xjhs.findmemerchant.common.openapi.amap; - - -import com.xjhs.findmemerchant.common.openapi.amap.response.AmapGeocodeResponse; -import com.xjhs.findmemerchant.common.openapi.amap.response.AmapReGeocodeResponse; -import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestParam; - -/** - * 高德地图服务接口 - */ -@FeignClient(name = "amapFeignClient", url = "https://restapi.amap.com") -public interface AmapFeignClient { - - /** - * 地理编码 API 服务 - * @param key 高德Key - * @param address 结构化地址信息,规则遵循:国家、省份、城市、区县、城镇、乡村、街道、门牌号码、屋邨、大厦,如:北京市朝阳区阜通东大街6号。 - * @return 响应信息 - */ - @GetMapping("/v3/geocode/geo") - AmapGeocodeResponse getGeo(@RequestParam(name = "key") String key, - @RequestParam(name = "address") String address); - - - /** - * 逆地理编码 API 服务地址 - * @param key 高德Key - * @param location 经纬度坐标 传入内容规则:经度在前,纬度在后,经纬度间以“,”分割,经纬度小数点后不要超过 6 位。 - */ - @GetMapping("/v3/geocode/regeo") - AmapReGeocodeResponse getReGeo(@RequestParam(name = "key") String key, - @RequestParam(name = "location") String location); -} diff --git a/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/AmapService.java b/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/AmapService.java deleted file mode 100644 index a9583fb..0000000 --- a/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/AmapService.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.xjhs.findmemerchant.common.openapi.amap; - -import com.xjhs.findmemerchant.common.openapi.amap.response.AmapGeocodeResponse; -import com.xjhs.findmemerchant.common.openapi.amap.response.AmapReGeocodeResponse; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@RequiredArgsConstructor -public class AmapService { - - @Value("${appconfig.amapKey}") - private String amapKey = "c618de6e686c43095a8593db836c7de2"; - private final AmapFeignClient amapFeignClient; - - /** - * 地址转经纬度 - * - * @param address 地址信息 - * @return 经纬度信息结果 - */ - public AmapGeocodeResponse getGeo(String address) { - return this.amapFeignClient.getGeo(this.amapKey, address); - } - - /** - * 经纬度转地理位置信息 - * - * @param lng 经度 - * @param lat 纬度 - * @return 位置信息 - */ - public AmapReGeocodeResponse getRegeo(double lng, double lat) { - return this.amapFeignClient.getReGeo(this.amapKey, lng + "," + lat); - } -} diff --git a/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/response/AmapGeocodeResponse.java b/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/response/AmapGeocodeResponse.java deleted file mode 100644 index 0969541..0000000 --- a/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/response/AmapGeocodeResponse.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.xjhs.findmemerchant.common.openapi.amap.response; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; - -/** - * 地理编码 API 服务响应内容 - */ -@Data -public class AmapGeocodeResponse { - /** - * 请求状态值,0 表示请求失败,1 表示请求成功 - */ - private int status; - - /** - * 返回结果的数量 - */ - private int count; - - /** - * 返回结果的详细说明,当 status 为 0 时,info 会包含错误原因;否则返回 "OK" - */ - private String info; - - /** - * 地理编码信息列表,包含多个地址组件 - */ - private List geocodes = new ArrayList<>(); - - /** - * 地理编码信息的详细字段 - */ - @Data - public static class GeocodeDetails { - - @JsonProperty("formatted_address") - private String address; - - /** - * 国家,默认返回中国 - */ - private String country; - - /** - * 省份名称,例如:北京市 - */ - private String province; - - /** - * 城市名称,例如:北京市 - */ - private String city; - - /** - * 城市编码,例如:010 - */ - private String citycode; - - /** - * 区域名称,例如:朝阳区 - */ - private String district; - - /** - * 街道名称,例如:单通东大街 - */ - private String street; - - /** - * 门牌号,例如:6号 - */ - private String number; - - /** - * 区域编码,例如:110101 - */ - private String adcode; - - /** - * 经纬度坐标,逗号分隔 - */ - private String location; - - /** - * 匹配级别,用于地理匹配的精确度 - */ - private String level; - } - - -} diff --git a/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/response/AmapReGeocodeResponse.java b/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/response/AmapReGeocodeResponse.java deleted file mode 100644 index 11d01dd..0000000 --- a/src/main/java/com/xjhs/findmemerchant/common/openapi/amap/response/AmapReGeocodeResponse.java +++ /dev/null @@ -1,207 +0,0 @@ -package com.xjhs.findmemerchant.common.openapi.amap.response; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; - -import java.util.ArrayList; -import java.util.List; - -/** - * 逆地理位置服务响应内容 - */ -@Data -public class AmapReGeocodeResponse { - - /** - * 请求状态,1 表示请求成功 - */ - private String status; - - /** - * 地址组件信息 - */ - private Regeocode regeocode; - - /** - * 返回的状态信息 - */ - private String info; - - /** - * 状态码,10000 表示成功 - */ - private String infocode; - - /** - * 地址组件类,包含具体的地理信息 - */ - @Data - public static class Regeocode { - - /** - * 地址组件,包含城市、区、街道等信息 - */ - private AddressComponent addressComponent; - - /** - * 格式化后的地址,整合了详细信息 - */ - @JsonProperty("formatted_address") - private String address; - } - - /** - * 地址组件,包含详细的地理信息 - */ - @Data - public static class AddressComponent { - - /** - * 城市名称,可能为空 - */ - private List city = new ArrayList<>(); - - /** - * 省份名称 - */ - private String province; - - /** - * 区域编码 - */ - private String adcode; - - /** - * 区域名称 - */ - private String district; - - /** - * 城镇编码 - */ - private String towncode; - - /** - * 街道信息 - */ - private StreetNumber streetNumber; - - /** - * 国家名称 - */ - private String country; - - /** - * 街道所属乡镇名称 - */ - private String township; - - /** - * 商圈信息,包含多个商圈 - */ - private List businessAreas; - - /** - * 建筑信息 - */ - private Building building; - - /** - * 邻里信息 - */ - private Neighborhood neighborhood; - - /** - * 城市编码 - */ - private String citycode; - } - - /** - * 街道信息,包括街道名称、位置、方向等 - */ - @Data - public static class StreetNumber { - - /** - * 门牌号 - */ - private String number; - - /** - * 经纬度位置 - */ - private String location; - - /** - * 方向 - */ - private String direction; - - /** - * 距离 - */ - private String distance; - - /** - * 街道名称 - */ - private String street; - } - - /** - * 商圈信息 - */ - @Data - public static class BusinessArea { - - /** - * 商圈位置(经纬度) - */ - private String location; - - /** - * 商圈名称 - */ - private String name; - - /** - * 商圈ID - */ - private String id; - } - - /** - * 建筑信息,包括建筑名称和类型 - */ - @Data - public static class Building { - - /** - * 建筑名称 - */ - private String name; - - /** - * 建筑类型 - */ - private String type; - } - - /** - * 邻里信息 - */ - @Data - public static class Neighborhood { - - /** - * 邻里名称 - */ - private String name; - - /** - * 邻里类型 - */ - private String type; - } -} diff --git a/src/main/java/com/xjhs/findmemerchant/common/openapi/dto/CosPutObjectResult.java b/src/main/java/com/xjhs/findmemerchant/common/openapi/dto/CosPutObjectResult.java deleted file mode 100644 index 4ff570a..0000000 --- a/src/main/java/com/xjhs/findmemerchant/common/openapi/dto/CosPutObjectResult.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.xjhs.findmemerchant.common.openapi.dto; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@AllArgsConstructor -@NoArgsConstructor -public class CosPutObjectResult { - private String key; - private String eTag; -} diff --git a/src/main/java/com/xjhs/findmemerchant/config/FeignConfig.java b/src/main/java/com/xjhs/findmemerchant/config/FeignConfig.java deleted file mode 100644 index d3790a1..0000000 --- a/src/main/java/com/xjhs/findmemerchant/config/FeignConfig.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.xjhs.findmemerchant.config; - -import com.xjhs.findmemerchant.common.openapi.amap.AmapFeignClient; -import org.springframework.cloud.openfeign.EnableFeignClients; -import org.springframework.context.annotation.Configuration; - -@Configuration -@EnableFeignClients(basePackageClasses = { - AmapFeignClient.class, -}) -public class FeignConfig { - -} diff --git a/src/main/java/com/xjhs/findmemerchant/config/JpaConfig.java b/src/main/java/com/xjhs/findmemerchant/config/JpaConfig.java index a64a9ec..18bf7fa 100644 --- a/src/main/java/com/xjhs/findmemerchant/config/JpaConfig.java +++ b/src/main/java/com/xjhs/findmemerchant/config/JpaConfig.java @@ -1,6 +1,6 @@ package com.xjhs.findmemerchant.config; -import com.xjhs.findmemerchant.security.LoginUser; +import com.xjhs.findmemerchant.entity.Merchant; import com.xjhs.findmemerchant.security.sms.SmsAuthenticationToken; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -20,8 +20,8 @@ public class JpaConfig { var auth = SecurityContextHolder.getContext().getAuthentication(); if (auth instanceof SmsAuthenticationToken){ var principal = auth.getPrincipal(); - if (principal instanceof LoginUser loginUser){ - return Optional.of(loginUser.getUserId()); + if (principal instanceof Merchant merchant){ + return Optional.of(merchant.getId()); } } return Optional.of(0L); diff --git a/src/main/java/com/xjhs/findmemerchant/config/ThirdOpenApiConfig.java b/src/main/java/com/xjhs/findmemerchant/config/ThirdOpenApiConfig.java deleted file mode 100644 index 6c66601..0000000 --- a/src/main/java/com/xjhs/findmemerchant/config/ThirdOpenApiConfig.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.xjhs.findmemerchant.config; - -import com.qcloud.cos.COSClient; -import com.qcloud.cos.ClientConfig; -import com.qcloud.cos.auth.BasicCOSCredentials; -import com.tencentcloudapi.common.Credential; -import com.tencentcloudapi.common.profile.ClientProfile; -import com.tencentcloudapi.common.profile.HttpProfile; -import com.tencentcloudapi.common.profile.Region; -import com.tencentcloudapi.sms.v20190711.SmsClient; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class ThirdOpenApiConfig { - - @Bean - public SmsClient tencentSmsClient(@Value("${appconfig.tencentSms.secretId}") String secretId, - @Value("${appconfig.tencentSms.secretKey}") String secretKey) { - var cred = new Credential(secretId, secretKey); - var httpProfile = new HttpProfile(); - httpProfile.setEndpoint("sms.tencentcloudapi.com"); - var clientProfile = new ClientProfile(); - clientProfile.setHttpProfile(httpProfile); - return new SmsClient(cred, "ap-guangzhou", clientProfile); - } - - @Bean - public COSClient tencentCosClient(@Value("${appconfig.tencentCos.secretId}") String secretId, - @Value("${appconfig.tencentCos.secretKey}") String secretKey){ - var cred = new BasicCOSCredentials(secretId,secretKey); - ClientConfig clientConfig = new ClientConfig(new com.qcloud.cos.region.Region("ap-guangzhou")); - return new COSClient(cred, clientConfig); - } -} diff --git a/src/main/java/com/xjhs/findmemerchant/controller/AuthController.java b/src/main/java/com/xjhs/findmemerchant/controller/AuthController.java index c854ced..745053d 100644 --- a/src/main/java/com/xjhs/findmemerchant/controller/AuthController.java +++ b/src/main/java/com/xjhs/findmemerchant/controller/AuthController.java @@ -1,22 +1,20 @@ package com.xjhs.findmemerchant.controller; import com.xjhs.findmemerchant.common.ApiResult; +import com.xjhs.findmemerchant.dto.MerchantDto; import com.xjhs.findmemerchant.dto.auth.RegisterDto; -import com.xjhs.findmemerchant.dto.merchant.MerchantDto; import com.xjhs.findmemerchant.entity.Merchant; -import com.xjhs.findmemerchant.mapper.MerchantMapper; import com.xjhs.findmemerchant.redis.TokenBlacklistRedisService; import com.xjhs.findmemerchant.repository.MerchantRepository; import com.xjhs.findmemerchant.security.JwtTokenService; -import com.xjhs.findmemerchant.security.LoginUser; import com.xjhs.findmemerchant.security.RefreshTokenService; import com.xjhs.findmemerchant.security.sms.SmsAuthenticationToken; import com.xjhs.findmemerchant.security.sms.SmsCodeService; -import com.xjhs.findmemerchant.system.SystemUserService; import com.xjhs.findmemerchant.vo.auth.SmsLoginVo; import com.xjhs.findmemerchant.vo.auth.SmsSendVo; -import com.xjhs.findmemerchant.vo.auth.RegisterVo; +import com.xjhs.findmemerchant.service.MerchantService; import com.xjhs.findmemerchant.vo.merchant.MerchantUpdateVo; +import com.xjhs.findmemerchant.vo.auth.RegisterVo; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -24,7 +22,6 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpHeaders; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.annotation.AuthenticationPrincipal; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import java.util.Map; @@ -43,8 +40,7 @@ public class AuthController { private final RefreshTokenService refreshTokenService; private final MerchantRepository merchantRepository; private final TokenBlacklistRedisService tokenBlacklistRedisService; - private final SystemUserService systemUserService; - private final MerchantMapper merchantMapper; + private final MerchantService merchantService; /** * 发送短信验证码 @@ -126,46 +122,41 @@ public class AuthController { * @return 注册成功返回登录令牌信息 */ @PostMapping("/register") - @Transactional - public ApiResult register(@Valid @RequestBody RegisterVo registerVo) throws Exception { + public ApiResult register(@Valid @RequestBody RegisterVo registerVo) { try { this.smsCodeService.verifyCode(registerVo.getPhone(), "register", registerVo.getCode()); - var systemUser = this.systemUserService.getAndRegisterByPhone(registerVo.getPhone()); - if (systemUser.getMerchant() != null){ - throw new Exception("手机号已被注册"); + var exists = merchantRepository.existsByPhone(registerVo.getPhone()); + if (exists) { + return ApiResult.fail("手机号已被注册"); } - var merchant = new Merchant(); - merchant.setSystemUser(systemUser); - systemUser.setMerchant(merchant); + merchant.setPhone(registerVo.getPhone()); this.merchantRepository.save(merchant); return ApiResult.data( - new RegisterDto( - merchant.getId().toString(), - this.jwtTokenService.generateToken(registerVo.getPhone()), - this.refreshTokenService.create(registerVo.getPhone()) - ) + new RegisterDto( + merchant.getId(), + this.jwtTokenService.generateToken(registerVo.getPhone()), + this.refreshTokenService.create(registerVo.getPhone()) + ) ); } catch (Exception e) { log.error("注册失败", e); - throw e; + return ApiResult.fail("注册失败:" + e.getMessage()); } } /** * 获取当前登录的商家基本信息 * - * @param loginUser @ignore 当前登录用户 + * @param merchant @ignore 当前商家 * @return 商家信息 */ @GetMapping("/profile") - @Transactional(readOnly = true) - public ApiResult getProfile(@AuthenticationPrincipal LoginUser loginUser) { - if (loginUser.getMerchantId() == null) { + public ApiResult getProfile(@AuthenticationPrincipal Merchant merchant) { + if (merchant == null) { return ApiResult.fail("商家信息不存在"); } - return this.merchantRepository.findById(loginUser.getMerchantId()) - .map(this.merchantMapper::toDto) + return this.merchantService.getById(merchant.getId()) .map(ApiResult::data) .orElse(ApiResult.fail("商家信息不存在")); } @@ -181,8 +172,8 @@ public class AuthController { public ApiResult updateProfile(@AuthenticationPrincipal Merchant merchant, @Valid @RequestBody MerchantUpdateVo merchantUpdateVo) { try { - // TODO : 待完成 - return ApiResult.data(null); + var result = this.merchantService.updateMerchant(merchant.getId(), merchantUpdateVo); + return ApiResult.data(result); } catch (Exception e) { return ApiResult.fail(e.getMessage()); } diff --git a/src/main/java/com/xjhs/findmemerchant/controller/MerchantController.java b/src/main/java/com/xjhs/findmemerchant/controller/MerchantController.java new file mode 100644 index 0000000..332bc93 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/controller/MerchantController.java @@ -0,0 +1,75 @@ +package com.xjhs.findmemerchant.controller; + +import com.xjhs.findmemerchant.common.ApiResult; +import com.xjhs.findmemerchant.dto.MerchantDto; +import com.xjhs.findmemerchant.entity.Merchant; +import com.xjhs.findmemerchant.service.MerchantService; +import com.xjhs.findmemerchant.vo.merchant.MerchantUpdateVo; +import com.xjhs.findmemerchant.vo.merchant.MerchantVerifyVo; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.web.bind.annotation.*; + +import java.security.Principal; + +/** + * 商家管理接口 + */ +@Slf4j +@RestController +@RequestMapping("/merchant") +@RequiredArgsConstructor +public class MerchantController { + private final MerchantService merchantService; + + /** + * 查询当前登录商家详情 + * + * @param merchant @ignore 当前商家 + * @return 商家详情信息 + */ + @GetMapping + public ApiResult getMerchant(@AuthenticationPrincipal Merchant merchant) { + return this.merchantService.getById(merchant.getId()) + .map(ApiResult::data) + .orElse(ApiResult.fail("商家信息不存在")); + } + + /** + * 更新当前登录商家信息 + * + * @param merchant @ignore 当前商家 + * @param merchantUpdateVo 更新参数 + * @return 商家信息 + */ + @PutMapping + public ApiResult updateMerchant(@AuthenticationPrincipal Merchant merchant, + @Valid @RequestBody MerchantUpdateVo merchantUpdateVo) { + try { + var dto = this.merchantService.updateMerchant(merchant.getId(), merchantUpdateVo); + return ApiResult.data(dto); + } catch (Exception e) { + return ApiResult.fail(e.getMessage()); + } + } + + /** + * 当前商家验证 + * + * @param merchant @ignore 当前商家 + * @param merchantVerifyVo 验证参数 + * @return 商家信息 + */ + @PostMapping("/verify") + public ApiResult verifyMerchant(@AuthenticationPrincipal Merchant merchant, + @Valid @RequestBody MerchantVerifyVo merchantVerifyVo) { + try { + var dto = this.merchantService.verifyMerchant(merchant.getId(), merchantVerifyVo.getIdCardNo(), merchantVerifyVo.getRealName()); + return ApiResult.data(dto); + } catch (Exception e) { + return ApiResult.fail(e.getMessage()); + } + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/controller/StoreController.java b/src/main/java/com/xjhs/findmemerchant/controller/StoreController.java new file mode 100644 index 0000000..e2bbe03 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/controller/StoreController.java @@ -0,0 +1,237 @@ +package com.xjhs.findmemerchant.controller; + +import com.xjhs.findmemerchant.common.ApiResult; +import com.xjhs.findmemerchant.common.PageData; +import com.xjhs.findmemerchant.common.jpa.query.JpaSpecs; +import com.xjhs.findmemerchant.common.mvc.PageVo; +import com.xjhs.findmemerchant.dto.store.BusinessPeriodDto; +import com.xjhs.findmemerchant.dto.store.StoreBusinessStatusDto; +import com.xjhs.findmemerchant.dto.store.StoreDto; +import com.xjhs.findmemerchant.entity.BusinessPeriod; +import com.xjhs.findmemerchant.entity.Merchant; +import com.xjhs.findmemerchant.entity.Store; +import com.xjhs.findmemerchant.mapper.StoreMapper; +import com.xjhs.findmemerchant.repository.BusinessPeriodRepository; +import com.xjhs.findmemerchant.repository.MerchantRepository; +import com.xjhs.findmemerchant.repository.StoreRepository; +import com.xjhs.findmemerchant.vo.store.BusinessPeriodVo; +import com.xjhs.findmemerchant.vo.store.StoreBusinessStatusUpdateVo; +import com.xjhs.findmemerchant.vo.store.StoreCreateVo; +import com.xjhs.findmemerchant.vo.store.StoreUpdateVo; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.security.Principal; +import java.util.List; +import java.util.Objects; + +/** + * 门店管理接口 + */ +@Slf4j +@RestController +@RequestMapping("/stores") +@RequiredArgsConstructor +public class StoreController { + private final MerchantRepository merchantRepository; + private final StoreRepository storeRepository; + private final StoreMapper storeMapper; + private final BusinessPeriodRepository businessPeriodRepository; + + + /** + * 门店信息(分页查询) + * + * @param pageVo 分页参数 + * @param merchant @ignore 当前登录商家 + * @return 分页数据信息 + */ + @GetMapping + @Transactional(readOnly = true) + public ApiResult> findPage(@AuthenticationPrincipal Merchant merchant, PageVo pageVo) { + var pageData = this.storeRepository.findAll(Specification.allOf( + JpaSpecs.eq("merchant.id", merchant.getId()) + ), pageVo.getPageable()).map(this.storeMapper::toDto); + return ApiResult.page(pageData.getTotalElements(), pageData.getContent()); + } + + /** + * 创建商家的门店 + * + * @param vo 门店信息 + * @param merchant @ignore 当前登录的商家 + * @return 门店信息 + */ + @PostMapping + @Transactional(rollbackFor = Exception.class) + public ApiResult create(@AuthenticationPrincipal Merchant merchant, + @Valid @RequestBody StoreCreateVo vo) { + var store = this.storeMapper.toEntity(vo); + merchant.addStore(store); + this.storeRepository.save(store); + var dto = this.storeMapper.toDto(store); + return ApiResult.data(dto); + } + + /** + * 查询门店详情 + * + * @param storeId 门店id + * @param merchant @ignore 当前登录的商家 + * @return 门店详情 + */ + @GetMapping("/{storeId}") + @Transactional(readOnly = true) + public ApiResult findById(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") String storeId) { + var storeIdLong = Long.parseLong(storeId); + return merchant.getStores().stream() + .filter(x -> Objects.equals(x.getId(), storeIdLong)) + .map(this.storeMapper::toDto) + .map(ApiResult::data) + .findFirst() + .orElse(ApiResult.fail("门店信息不存在")); + } + + /** + * 更新门店信息 + * + * @param storeId 门店id + * @param merchant @ignore 当前登录的商家 + * @param vo 更新对象 + * @return 门店信息 + */ + @PutMapping("/{storeId}") + @Transactional(rollbackFor = Exception.class) + public ApiResult updateById(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") String storeId, + @Valid @RequestBody StoreUpdateVo vo) { + var storeIdLong = Long.parseLong(storeId); + for (Store store : merchant.getStores()) { + if (Objects.equals(storeIdLong, store.getId())) { + this.storeMapper.updateFromVo(vo, store); + this.storeRepository.save(store); + return ApiResult.data(this.storeMapper.toDto(store)); + } + } + return ApiResult.fail("门店信息不存在"); + } + + /** + * 删除门店 + * + * @param storeId 门店id + * @param merchant @ignore 当前登录的商家 + */ + @DeleteMapping("/{storeId}") + @Transactional(rollbackFor = Exception.class) + public ApiResult delteById(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") String storeId) { + var storeIdLong = Long.parseLong(storeId); + merchant.getStores().removeIf(x -> Objects.equals(storeIdLong, x.getId())); + this.merchantRepository.save(merchant); + return ApiResult.success("删除成功"); + } + + /** + * 获取门店营业状态 + * + * @param storeId 门店id + * @param merchant @ignore 当前商户 + * @return 门店营业状态信息 + */ + @GetMapping("/{storeId}/business-status") + @Transactional(readOnly = true) + public ApiResult getStoreBusinessStatus(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") String storeId) { + var storeIdLong = Long.parseLong(storeId); + return merchant.getStores().stream() + .filter(x -> Objects.equals(x.getId(), storeIdLong)) + .map(this.storeMapper::toBusinessStatusDto) + .map(ApiResult::data) + .findFirst() + .orElse(ApiResult.fail("门店信息不存在")); + } + + /** + * 设置门店营业状态 + * + * @param storeId 门店id + * @param merchant @ignore 当前商家 + * @param updateVo 更新参数 + * @return 门店营业状态信息 + */ + @PutMapping("/{storeId}/business-status") + @Transactional(rollbackFor = Exception.class) + public ApiResult putStoreBusinessStatus(@PathVariable("storeId") String storeId, + @AuthenticationPrincipal Merchant merchant, + @Validated @RequestBody StoreBusinessStatusUpdateVo updateVo) { + var storeIdLong = Long.parseLong(storeId); + return merchant.getStores().stream() + .filter(x -> Objects.equals(x.getId(), storeIdLong)) + .findFirst() + .map(x -> { + this.storeMapper.updateFromBusinessUpdateVo(updateVo, x); + this.storeRepository.save(x); + return this.storeMapper.toBusinessStatusDto(x); + }) + .map(ApiResult::data) + .orElse(ApiResult.fail("门店信息不存在")); + + } + + /** + * 获取门店营业时间段 + * + * @param storeId 门店id + * @param merchant @ignore 当前商家 + * @return 门店营业时间段 列表 + */ + @GetMapping("/{storeId}/business-periods") + public ApiResult> getStoreBusinessPeriodList(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") String storeId) { + var storeIdLong = Long.parseLong(storeId); + return merchant.getStores().stream() + .filter(x -> Objects.equals(x.getId(), storeIdLong)) + .findFirst() + .map(x -> this.storeMapper.toDtoList(x.getBusinessPeriods())) + .map(ApiResult::data) + .orElse(ApiResult.fail("门店信息不存在")); + } + + /** + * 设置门店营业时间段 + * + * @param storeId 门店id + * @param merchant @ignore 当前商家 + * @param updateVoList 门店营业时间段更新参数列表 + * @return 门店营业时间段 列表 + */ + @PutMapping("/{storeId}/business-periods") + public ApiResult> putStoreBusinessPeriodList(@PathVariable("storeId") String storeId, + @AuthenticationPrincipal Merchant merchant, + @Validated @RequestBody List updateVoList) { + var storeIdLong = Long.parseLong(storeId); + return merchant.getStores().stream() + .filter(x -> Objects.equals(x.getId(), storeIdLong)) + .findFirst() + .map(store -> { + store.getBusinessPeriods().clear(); + for (BusinessPeriodVo businessPeriodVo : updateVoList) { + var entity = this.storeMapper.toEntity(businessPeriodVo); + store.addBusinessPeriods(entity); + this.businessPeriodRepository.save(entity); + } + return this.storeMapper.toDtoList(store.getBusinessPeriods()); + }) + .map(ApiResult::data) + .orElse(ApiResult.fail("门店信息不存在")); + + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/controller/StoreEmployeeController.java b/src/main/java/com/xjhs/findmemerchant/controller/StoreEmployeeController.java new file mode 100644 index 0000000..00d452e --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/controller/StoreEmployeeController.java @@ -0,0 +1,157 @@ +package com.xjhs.findmemerchant.controller; + +import com.xjhs.findmemerchant.common.ApiResult; +import com.xjhs.findmemerchant.dto.member.EmployeeDto; +import com.xjhs.findmemerchant.entity.Merchant; +import com.xjhs.findmemerchant.mapper.EmployeeMapper; +import com.xjhs.findmemerchant.repository.EmployeeRepository; +import com.xjhs.findmemerchant.vo.member.EmployeeCreateVo; +import com.xjhs.findmemerchant.vo.member.EmployeeUpdateVo; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.annotation.AuthenticationPrincipal; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; +import java.util.Objects; + +/** + * 门店员工管理接口 + */ +@Slf4j +@RestController +@RequestMapping("/stores/{storeId}/employees") +@RequiredArgsConstructor +public class StoreEmployeeController { + private final EmployeeRepository employeeRepository; + private final EmployeeMapper employeeMapper; + + /** + * 查询门店员工列表 + * @param merchant @ignore 当前商户 + * @param storeId 门店id + * @return 员工列表信息 + */ + @GetMapping + @Transactional(readOnly = true) + public ApiResult> getList(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") Long storeId) { + var list = this.employeeRepository.findByStoreId(storeId) + .stream().map(this.employeeMapper::toDto) + .toList(); + return ApiResult.data(list); + } + + /** + * 新建门店员工 + * @param merchant @ignore 当前商户 + * @param storeId 门店id + * @param createVo 员工信息参数 + * @return 门店员工信息 + */ + @PostMapping + @Transactional + public ApiResult create(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") Long storeId, + @Validated @RequestBody EmployeeCreateVo createVo) throws Exception { + try { + var store = merchant.getStores().stream() + .filter(x -> Objects.equals(storeId, x.getId())) + .findFirst() + .orElseThrow(() -> new Exception("门店信息不存在")); + var phoneExists = store.getEmployees().stream() + .anyMatch(x -> Objects.equals(x.getPhone(), createVo.getPhone())); + if (phoneExists) { + throw new Exception("手机号码已被使用"); + } + var employee = this.employeeMapper.toEntity(createVo); + store.addEmployee(employee); + this.employeeRepository.save(employee); + var dto = this.employeeMapper.toDto(employee); + return ApiResult.data(dto); + } catch (Exception e) { + log.error("员工信息注册失败", e); + throw e; + } + } + + /** + * 查询门店员工详情 + * @param merchant @ignore 当前商户 + * @param storeId 门店id + * @param employeeId 门店员工id + * @return 员工详情 + */ + @GetMapping("/{employeeId}") + @Transactional(readOnly = true) + public ApiResult findById(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") Long storeId, + @PathVariable("employeeId") Long employeeId) { + return merchant.getStores().stream() + .filter(x -> Objects.equals(storeId, x.getId())) + .flatMap(x -> x.getEmployees().stream()) + .filter(x -> Objects.equals(employeeId, x.getId())) + .findFirst() + .map(this.employeeMapper::toDto) + .map(ApiResult::data) + .orElse(ApiResult.fail("员工信息不存在")); + + } + + /** + * 根据员工id更新员工信息 + * @param merchant @ignore 当前商户 + * @param storeId 门店id + * @param employeeId 员工id + * @param updateVo 更新参数 + * @return 员工详情 + */ + @PutMapping("/{employeeId}") + @Transactional + public ApiResult updateById(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") Long storeId, + @PathVariable("employeeId") Long employeeId, + @Validated @RequestBody EmployeeUpdateVo updateVo) { + return merchant.getStores().stream() + .filter(x -> Objects.equals(storeId, x.getId())) + .flatMap(x -> x.getEmployees().stream()) + .filter(x -> Objects.equals(employeeId, x.getId())) + .findFirst() + .map(employee -> { + this.employeeMapper.updateEntityFormUpdateVo(updateVo, employee); + this.employeeRepository.save(employee); + return ApiResult.data( + this.employeeMapper.toDto(employee) + ); + }) + .orElse(ApiResult.fail("员工信息不存在")); + } + + /** + * 根据id删除员工信息 + * @param merchant @ignore 当前商户 + * @param storeId 门店id + * @param employeeId 员工id + * @return 删除结果 + */ + @DeleteMapping("/{employeeId}") + @Transactional + public ApiResult deleteById(@AuthenticationPrincipal Merchant merchant, + @PathVariable("storeId") Long storeId, + @PathVariable("employeeId") Long employeeId) throws Exception { + try { + var store = merchant.getStores().stream() + .filter(x -> Objects.equals(storeId, x.getId())) + .findFirst() + .orElseThrow(()->new Exception("门店信息不存在")); + store.getEmployees().removeIf(x->Objects.equals(employeeId,x.getId())); + return ApiResult.success(); + } catch (Exception e) { + log.error("删除员工失败",e); + throw e; + } + } + +} diff --git a/src/main/java/com/xjhs/findmemerchant/dto/MerchantDto.java b/src/main/java/com/xjhs/findmemerchant/dto/MerchantDto.java new file mode 100644 index 0000000..1c235c3 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/dto/MerchantDto.java @@ -0,0 +1,45 @@ +package com.xjhs.findmemerchant.dto; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.xjhs.findmemerchant.types.AuthStatus; +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 商家信息 + */ +@Data +public class MerchantDto { + /** + * 商家id + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + /** + * 手机号码 + * TODO: 手机号码需要脱敏 + */ + private String phone; + /** + * 真实姓名 + */ + private String realName; + /** + * 身份证号(明文) + */ + private String idCardNo; + /** + * 认证状态 + */ + private AuthStatus authStatus; + /** + * 认证状态(说明) + */ + private String authStatusDesc; + /** + * 创建时间 + */ + private LocalDateTime createdAt; +} diff --git a/src/main/java/com/xjhs/findmemerchant/dto/auth/RegisterDto.java b/src/main/java/com/xjhs/findmemerchant/dto/auth/RegisterDto.java index 8c2ee41..6a415d8 100644 --- a/src/main/java/com/xjhs/findmemerchant/dto/auth/RegisterDto.java +++ b/src/main/java/com/xjhs/findmemerchant/dto/auth/RegisterDto.java @@ -16,7 +16,8 @@ public class RegisterDto { /** * 商家id */ - private String merchantId; + @JsonSerialize(using = ToStringSerializer.class) + private Long merchantId; /** * 访问令牌 */ diff --git a/src/main/java/com/xjhs/findmemerchant/dto/member/EmployeeDto.java b/src/main/java/com/xjhs/findmemerchant/dto/member/EmployeeDto.java new file mode 100644 index 0000000..d592180 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/dto/member/EmployeeDto.java @@ -0,0 +1,40 @@ +package com.xjhs.findmemerchant.dto.member; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.time.LocalDateTime; + +@Data +public class EmployeeDto { + + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + /** + * 员工姓名 + */ + private String name; + /** + * 手机号码 + */ + private String phone; + /** + * 关联角色id + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long roleId; + /** + * 关联门店id + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long storeId; + /** + * 员工状态 + */ + private Integer status; + /** + * 创建时间 + */ + private LocalDateTime createdAt; +} diff --git a/src/main/java/com/xjhs/findmemerchant/dto/merchant/MerchantDto.java b/src/main/java/com/xjhs/findmemerchant/dto/merchant/MerchantDto.java deleted file mode 100644 index 5742c20..0000000 --- a/src/main/java/com/xjhs/findmemerchant/dto/merchant/MerchantDto.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.xjhs.findmemerchant.dto.merchant; - -import lombok.Data; - -@Data -public class MerchantDto { - private String id; - private String merchantName; -} diff --git a/src/main/java/com/xjhs/findmemerchant/dto/store/BusinessPeriodDto.java b/src/main/java/com/xjhs/findmemerchant/dto/store/BusinessPeriodDto.java new file mode 100644 index 0000000..c7201d8 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/dto/store/BusinessPeriodDto.java @@ -0,0 +1,30 @@ +package com.xjhs.findmemerchant.dto.store; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +@Data +public class BusinessPeriodDto { + /** + * 门店id + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long storeId; + /** + * 周几,周天0,... + */ + private Integer dayOfWeek; + /** + * 开始营业时间 HH:mm 格式 + */ + private String startTime; + /** + * 结束营业时间 HH:mm 格式 + */ + private String endTime; + /** + * 是否启用 + */ + private Boolean enabled; +} diff --git a/src/main/java/com/xjhs/findmemerchant/dto/store/StoreBusinessStatusDto.java b/src/main/java/com/xjhs/findmemerchant/dto/store/StoreBusinessStatusDto.java new file mode 100644 index 0000000..67c1533 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/dto/store/StoreBusinessStatusDto.java @@ -0,0 +1,36 @@ +package com.xjhs.findmemerchant.dto.store; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 门店营业状态 + */ +@Data +public class StoreBusinessStatusDto { + /** + * 业务状态值 + */ + private Integer status; + + /** + * 业务状态文案 + */ + private String statusText; + + /** + * 临时关闭原因(可为空) + */ + private String tempCloseReason; + + /** + * 临时关闭截止时间(可为空) + */ + private LocalDateTime tempCloseUntil; + + /** + * 是否营业 + */ + private Boolean isOpen; +} diff --git a/src/main/java/com/xjhs/findmemerchant/dto/store/StoreDto.java b/src/main/java/com/xjhs/findmemerchant/dto/store/StoreDto.java new file mode 100644 index 0000000..563a993 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/dto/store/StoreDto.java @@ -0,0 +1,110 @@ +package com.xjhs.findmemerchant.dto.store; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import com.xjhs.findmemerchant.types.BusinessStatus; +import com.xjhs.findmemerchant.types.CommonStatus; +import com.xjhs.findmemerchant.types.StoreAuditStatus; +import lombok.Data; + +import java.math.BigDecimal; + +@Data +public class StoreDto { + /** + * 门店id + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long id; + /** + * 商家id + */ + @JsonSerialize(using = ToStringSerializer.class) + private Long merchantId; + /** + * 门店名称 + */ + private String name; + /** + * 门店logo + */ + private String logo; + /** + * 联系电话 + */ + private String phone; + /** + * 省 + */ + private String province; + /** + * 市 + */ + private String city; + /** + * 区/县 + */ + private String district; + /** + * 详细地址 + */ + private String address; + /** + * 完整地址 + */ + private String fullAddress; + + // TODO: 后续改为 Point location + /** + * 经度 + */ + private BigDecimal longitude; + /** + * 纬度 + */ + private BigDecimal latitude; + /** + * 营业时间描述 + */ + private String businessHours; + /** + * 营业状态 + */ + private BusinessStatus businessStatus; + /** + * 营业状态(说明) + */ + private String businessStatusDesc; + /** + * 临时打烊原因 + */ + private String tempCloseReason; + /** + * 临时打烊结束时间 + */ + private String tempCloseUntil; + /** + * 审核状态 + */ + private StoreAuditStatus auditStatus; + /** + * 审核状态(说明) + */ + private String auditStatusDesc; + /** + * 审核备注 + */ + private String auditRemark; + /** + * 启用状态 + */ + private CommonStatus status; + /** + * 启用状态(说明) + */ + private String statusDesc; + /** + * 创建时间 + */ + private String createdAt; +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Activity.java b/src/main/java/com/xjhs/findmemerchant/entity/Activity.java new file mode 100644 index 0000000..746fc32 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Activity.java @@ -0,0 +1,137 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.ActivityStatus; +import com.xjhs.findmemerchant.types.ActivityType; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.time.LocalDateTime; + +/** + * 活动 / 营销活动实体 + * 对应表:activities + */ +@Getter +@Setter +@Entity +@Table( + name = "activities", + indexes = { + @Index(name = "idx_activities_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_activities_time", columnList = "start_time,end_time"), + @Index(name = "idx_activities_status", columnList = "status") + } +) +public class Activity extends AbstractBaseEntity { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id") + private Merchant merchant; + + /** + * 活动名称 + */ + @Column(name = "name", length = 100) + @Comment("活动名称") + private String name; + + /** + * 活动类型 (1团购 2折扣 3限时优惠) + */ + @Column(name = "type", length = 15, columnDefinition = "VARCHAR(15)") + @Enumerated(EnumType.STRING) + @Comment("活动类型") + private ActivityType type; + + /** + * 开始时间 + */ + @Column(name = "start_time") + @Comment("开始时间") + private LocalDateTime startTime; + + /** + * 结束时间 + */ + @Column(name = "end_time") + @Comment("结束时间") + private LocalDateTime endTime; + + /** + * 库存 + */ + @Column(name = "stock") + @Comment("库存总数") + private Integer stock = 0; + + /** + * 已售数量 + */ + @Column(name = "sold_count") + @Comment("已售数量") + private Integer soldCount = 0; + + /** + * 库存告警阈值 + */ + @Column(name = "alert_threshold") + @Comment("库存告警阈值") + private Integer alertThreshold; + + /** + * 活动状态 + */ + @Column(name = "status", columnDefinition = "VARCHAR(20)") + @Enumerated(EnumType.STRING) + @Comment("活动状态:0未开始 1进行中 2已结束 3已下架") + private ActivityStatus status = ActivityStatus.NOT_STARTED; + + + + + // ================= 业务逻辑 ================= + + public boolean isOngoing() { + var now = LocalDateTime.now(); + return this.status == ActivityStatus.ONGOING + && now.isAfter(startTime) + && now.isBefore(endTime); + } + + public boolean hasStock() { + return stock != null && soldCount != null && soldCount < stock; + } + + public int remainingStock() { + if (stock == null || soldCount == null) return 0; + return stock - soldCount; + } + + public boolean isLowStock() { + return alertThreshold != null && remainingStock() <= alertThreshold; + } + + public String getTypeText() { + var e = this.type; + return e != null ? e.getDesc() : "未知"; + } + + public String getStatusText() { + var e = this.status; + return e != null ? e.getDesc() : "未知"; + } + + public boolean canEdit() { + return this.status == ActivityStatus.NOT_STARTED; + } + + public boolean canOffline() { + var s = this.status; + return s == ActivityStatus.NOT_STARTED || s == ActivityStatus.ONGOING; + } + + +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/BankCard.java b/src/main/java/com/xjhs/findmemerchant/entity/BankCard.java new file mode 100644 index 0000000..1f26233 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/BankCard.java @@ -0,0 +1,109 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.CommonStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +/** + * 商家提现银行卡 + * 对应表:bank_cards + */ +@Getter +@Setter +@Entity +@Table( + name = "bank_cards", + indexes = { + @Index(name = "idx_bank_cards_merchant_id", columnList = "merchant_id") + } +) +public class BankCard extends AbstractBaseEntity { + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + /** + * 银行名称 + */ + @Column(name = "bank_name", length = 50) + @Comment("银行名称") + private String bankName; + + /** + * 银行代码 + */ + @Column(name = "bank_code", length = 20) + @Comment("银行代码") + private String bankCode; + + /** + * 支行名称 + */ + @Column(name = "branch_name", length = 100) + @Comment("支行名称") + private String branchName; + + /** + * 银行账号(建议加密存储) + */ + @Column(name = "account_no", length = 30) + @Comment("银行卡号(加密存储)") + private String accountNo; + + /** + * 开户名 + */ + @Column(name = "account_name", length = 50) + @Comment("开户名") + private String accountName; + + /** + * 是否默认卡 + */ + @Column(name = "is_default") + @Comment("是否默认卡") + private Boolean isDefault = false; + + /** + * 状态:0-禁用 1-启用 + */ + @Column(name = "status",columnDefinition = "VARCHAR(15)",length = 15) + @Enumerated(EnumType.STRING) + @Comment("状态:0禁用 1启用") + private CommonStatus status = CommonStatus.ENABLED; + + + + // ========== 业务方法 ========== + + /** + * 脱敏账号,例如:6222****1234 + */ + public String maskAccountNo() { + if (accountNo == null || accountNo.length() <= 8) { + return accountNo; + } + return accountNo.substring(0, 4) + + "****" + + accountNo.substring(accountNo.length() - 4); + } + + /** + * 是否启用 + */ + public boolean isActive() { + return this.status == CommonStatus.ENABLED; + } + + public String getStatusText() { + CommonStatus e = this.status; + return e != null ? e.getDesc() : "未知"; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/BusinessLicense.java b/src/main/java/com/xjhs/findmemerchant/entity/BusinessLicense.java new file mode 100644 index 0000000..03b579e --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/BusinessLicense.java @@ -0,0 +1,67 @@ +package com.xjhs.findmemerchant.entity; + + +import com.xjhs.findmemerchant.common.jpa.json.HashMapJsonConverter; +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.BusinessLicenseStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.util.HashMap; + +/** + * 营业执照资质 + * 对应表:business_licenses + */ +@Getter +@Setter +@Entity +@Table( + name = "business_licenses", + indexes = { + @Index(name = "idx_business_licenses_merchant_id", columnList = "merchant_id") + } +) +public class BusinessLicense extends AbstractBaseEntity { + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + @Column(name = "image_url", length = 500) + @Comment("营业执照图片URL") + private String imageUrl; + + @Column(name = "company_name", length = 200) + @Comment("公司名称(OCR识别)") + private String companyName; + + @Column(name = "license_no", length = 50) + @Comment("营业执照号(OCR识别)") + private String licenseNo; + + @Convert(converter = HashMapJsonConverter.class) + @Column(name = "ocr_raw", columnDefinition = "json") + @Comment("OCR原始结果") + private HashMap ocrRaw; + + @Column(name = "status",length = 15,columnDefinition = "VARCHAR(15)") + @Enumerated(EnumType.STRING) + @Comment("状态:0待审核 1已通过 2已拒绝") + private BusinessLicenseStatus status = BusinessLicenseStatus.PENDING; + + + // ===== 业务方法 ===== + + public boolean isApproved() { + return this.status == BusinessLicenseStatus.APPROVED; + } + + + public String getStatusText() { + var e = this.status; + return e != null ? e.getDesc() : "未知"; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/BusinessPeriod.java b/src/main/java/com/xjhs/findmemerchant/entity/BusinessPeriod.java new file mode 100644 index 0000000..489b74f --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/BusinessPeriod.java @@ -0,0 +1,81 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +/** + * 门店营业时间段 + * 对应表:business_periods + */ +@Getter +@Setter +@Entity +@Table( + name = "business_periods", + indexes = { + @Index(name = "idx_business_periods_store_id", columnList = "store_id") + } +) +public class BusinessPeriod extends AbstractBaseEntity { + + /** + * 门店 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id", insertable = false, updatable = false) + @Comment("门店Id") + private Store store; + + /** + * 周几:0=周日 ... 6=周六 + */ + @Column(name = "day_of_week") + @Comment("周几:0周日 1周一 ... 6周六") + private Integer dayOfWeek; + + /** + * 开始时间,HH:MM + */ + @Column(name = "start_time", length = 5) + @Comment("开始时间,HH:MM") + private String startTime; + + /** + * 结束时间,HH:MM + */ + @Column(name = "end_time", length = 5) + @Comment("结束时间,HH:MM") + private String endTime; + + /** + * 是否启用 + */ + @Column(name = "is_enabled") + @Comment("是否启用") + private Boolean isEnabled = Boolean.TRUE; + + + // ========== 业务方法 ========== + + /** + * 中文周几,比如:周一 + */ + public String getDayName() { + if (dayOfWeek == null) { + return "未知"; + } + return switch (dayOfWeek) { + case 0 -> "周日"; + case 1 -> "周一"; + case 2 -> "周二"; + case 3 -> "周三"; + case 4 -> "周四"; + case 5 -> "周五"; + case 6 -> "周六"; + default -> "未知"; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Coupon.java b/src/main/java/com/xjhs/findmemerchant/entity/Coupon.java new file mode 100644 index 0000000..5f8b1d7 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Coupon.java @@ -0,0 +1,211 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.CouponStatus; +import com.xjhs.findmemerchant.types.CouponType; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 优惠券模板实体 + * 对应表:coupons + */ +@Getter +@Setter +@Entity +@Table( + name = "coupons", + indexes = { + @Index(name = "idx_coupons_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_coupons_status", columnList = "status"), + @Index(name = "idx_coupons_gift_product_id", columnList = "gift_product_id") + } +) +public class Coupon extends AbstractBaseEntity { + + /** + * 优惠券名称 + */ + @Column(name = "name", length = 100) + @Comment("优惠券名称") + private String name; + + /** + * 优惠券类型:1-折扣券 2-满减券 3-现金券 4-赠品券 + */ + @Column(name = "type",length = 15,columnDefinition = "VARCHAR(15)") + @Comment("优惠券类型:1折扣券 2满减券 3现金券 4赠品券") + private CouponType type; + + /** + * 折扣率 0.01-0.99,decimal(3,2) + */ + @Column(name = "discount_rate", precision = 3, scale = 2) + @Comment("折扣率 0.01-0.99") + private BigDecimal discountRate; + + /** + * 满减门槛,decimal(10,2) + */ + @Column(name = "min_amount", precision = 10, scale = 2) + @Comment("满减门槛") + private BigDecimal minAmount; + + /** + * 减免金额,decimal(10,2) + */ + @Column(name = "reduce_amount", precision = 10, scale = 2) + @Comment("减免金额") + private BigDecimal reduceAmount; + + /** + * 赠品商品ID + */ + @Column(name = "gift_product_id") + @Comment("赠品商品ID") + private Long giftProductId; + + /** + * 赠品数量,默认 1 + */ + @Column(name = "gift_quantity") + @Comment("赠品数量") + private Integer giftQuantity = 1; + + /** + * 发放总量 + */ + @Column(name = "total_count") + @Comment("发放总量") + private Integer totalCount; + + /** + * 已领取数量 + */ + @Column(name = "claimed_count") + @Comment("已领取数量") + private Integer claimedCount = 0; + + /** + * 每人限领数量,0 表示不限 + */ + @Column(name = "per_user_limit") + @Comment("每人限领数量,0表示不限") + private Integer perUserLimit = 1; + + /** + * 领取后有效天数 + */ + @Column(name = "valid_days") + @Comment("领取后有效天数") + private Integer validDays; + + /** + * 活动开始时间 + */ + @Column(name = "start_time") + @Comment("活动开始时间") + private LocalDateTime startTime; + + /** + * 活动结束时间 + */ + @Column(name = "end_time") + @Comment("活动结束时间") + private LocalDateTime endTime; + + /** + * 使用规则 + */ + @Column(name = "rules", columnDefinition = "text") + @Comment("使用规则") + private String rules; + + /** + * 状态:0-下架 1-进行中 2-已结束 + */ + @Column(name = "status",columnDefinition = "VARCHAR(15)",length = 15) + @Comment("状态:0下架 1进行中 2已结束") + private CouponStatus status = CouponStatus.ONLINE; + + + // ================= 关联关系 ================= + + /** + * 所属商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + /** + * 可用门店关联 + */ + @OneToMany(mappedBy = "coupon", fetch = FetchType.LAZY) + private List stores; + + /** + * 所有券码 + */ + @OneToMany(mappedBy = "coupon", fetch = FetchType.LAZY) + private List codes; + + /** + * 赠品商品 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "gift_product_id", insertable = false, updatable = false) + private Product giftProduct; + + // ================= 业务方法 ================= + + /** + * 是否当前有效(进行中 + 时间范围内) + */ + public boolean isActive() { + LocalDateTime now = LocalDateTime.now(); + return this.status == CouponStatus.ONLINE + && now.isAfter(startTime) + && now.isBefore(endTime); + } + + /** + * 是否还有库存可领取 + */ + public boolean hasStock() { + return claimedCount != null && totalCount != null && claimedCount < totalCount; + } + + /** + * 剩余可领取数量 + */ + public int remainingCount() { + if (totalCount == null || claimedCount == null) { + return 0; + } + return totalCount - claimedCount; + } + + /** + * 优惠券类型文案 + */ + public String getTypeText() { + CouponType typeEnum = this.type; + return typeEnum != null ? typeEnum.getDesc() : "未知"; + } + + /** + * 是否为赠品券 + */ + public boolean isGiftCoupon() { + return this.type == CouponType.GIFT; + } + + +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/CouponCode.java b/src/main/java/com/xjhs/findmemerchant/entity/CouponCode.java new file mode 100644 index 0000000..fe78cc2 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/CouponCode.java @@ -0,0 +1,172 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.CouponCodeStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.time.LocalDateTime; + +/** + * 优惠券码实例 + * 对应表:coupon_codes + */ +@Getter +@Setter +@Entity +@Table( + name = "coupon_codes", + indexes = { + @Index(name = "idx_coupon_codes_coupon_id", columnList = "coupon_id"), + @Index(name = "idx_coupon_codes_member_id", columnList = "member_id"), + @Index(name = "idx_coupon_codes_status", columnList = "status") + }, + uniqueConstraints = { + @UniqueConstraint(name = "uk_coupon_codes_code", columnNames = "code") + } +) +public class CouponCode extends AbstractBaseEntity { + + + /** + * 券码 + */ + @Column(name = "code", length = 32) + @Comment("优惠券码") + private String code; + + /** + * 状态:0-未领取 1-已领取 2-已核销 3-已过期 + */ + @Column(name = "status",columnDefinition = "VARCHAR(20)",length = 20) + @Comment("状态:0未领取 1已领取 2已核销 3已过期") + private CouponCodeStatus status = CouponCodeStatus.UNCLAIMED; + + /** + * 领取时间 + */ + @Column(name = "claimed_at") + @Comment("领取时间") + private LocalDateTime claimedAt; + + /** + * 有效期至 + */ + @Column(name = "valid_until") + @Comment("有效期至") + private LocalDateTime validUntil; + + /** + * 核销时间 + */ + @Column(name = "verified_at") + @Comment("核销时间") + private LocalDateTime verifiedAt; + + /** + * 核销人ID(员工) + */ + @Column(name = "verified_by") + @Comment("核销人ID(员工)") + private Long verifiedBy; + + /** + * 核销门店ID + */ + @Column(name = "verify_store_id") + @Comment("核销门店ID") + private Long verifyStoreId; + + + // =============== 关联关系 =============== + + /** + * 所属优惠券模板 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "coupon_id", insertable = false, updatable = false) + private Coupon coupon; + + /** + * 会员 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", insertable = false, updatable = false) + private Member member; + + /** + * 核销员工 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "verified_by", insertable = false, updatable = false) + private Employee verifier; + + /** + * 核销门店 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "verify_store_id", insertable = false, updatable = false) + private Store verifyStore; + + // =============== 业务方法 =============== + + /** + * 是否已领取 + */ + public boolean isClaimed() { + return this.status != null && + this.status.ordinal() >= CouponCodeStatus.CLAIMED.ordinal(); + } + + /** + * 是否已核销 + */ + public boolean isVerified() { + return this.status == CouponCodeStatus.VERIFIED; + } + + /** + * 是否已过期 + */ + public boolean isExpired() { + CouponCodeStatus statusEnum = this.status; + if (statusEnum == CouponCodeStatus.EXPIRED) { + return true; + } + if (validUntil != null && LocalDateTime.now().isAfter(validUntil)) { + return true; + } + return false; + } + + /** + * 是否可核销 + */ + public boolean canVerify() { + return this.status == CouponCodeStatus.CLAIMED && !isExpired(); + } + + /** + * 状态文案 + */ + public String getStatusText() { + CouponCodeStatus statusEnum = this.status; + return statusEnum != null ? statusEnum.getDesc() : "未知"; + } + + /** + * 脱敏券码,例如:ABC***XYZ + */ + public String maskCode() { + if (code == null) { + return null; + } + if (code.length() <= 6) { + return code; + } + return code.substring(0, 3) + "***" + code.substring(code.length() - 3); + } + +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/CouponStore.java b/src/main/java/com/xjhs/findmemerchant/entity/CouponStore.java new file mode 100644 index 0000000..2031490 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/CouponStore.java @@ -0,0 +1,40 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; + +/** + * 优惠券与门店的关联关系 + * 对应表:coupon_stores + */ +@Getter +@Setter +@Entity +@Table( + name = "coupon_stores", + uniqueConstraints = { + @UniqueConstraint( + name = "idx_coupon_store", + columnNames = {"coupon_id", "store_id"} + ) + } +) +public class CouponStore extends AbstractBaseEntity { + + + /** + * 优惠券 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "coupon_id", insertable = false, updatable = false) + private Coupon coupon; + + /** + * 门店 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id", insertable = false, updatable = false) + private Store store; +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Employee.java b/src/main/java/com/xjhs/findmemerchant/entity/Employee.java new file mode 100644 index 0000000..9350ab8 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Employee.java @@ -0,0 +1,95 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.CommonStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +/** + * 员工实体 + * 对应表:employees + */ +@Getter +@Setter +@Entity +@Table( + name = "employees", + indexes = { + @Index(name = "idx_employees_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_employees_store_id", columnList = "store_id"), + @Index(name = "idx_employees_role_id", columnList = "role_id"), + @Index(name = "idx_employees_phone", columnList = "phone") + } +) +public class Employee extends AbstractBaseEntity { + + + /** + * 手机号 + */ + @Column(name = "phone", length = 11) + @Comment("手机号") + private String phone; + + /** + * 员工姓名 + */ + @Column(name = "name", length = 50) + @Comment("员工姓名") + private String name; + + /** + * 状态:0-禁用 1-启用 + */ + @Column(name = "status",columnDefinition = "VARCHAR(15)",length = 15) + @Comment("状态") + private CommonStatus status = CommonStatus.ENABLED; + + + + // ===== 关联关系 ===== + /** + * 门店 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id", insertable = false, updatable = false) + private Store store; + + /** + * 角色 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "role_id", insertable = false, updatable = false) + private Role role; + + // ===== 业务方法 ===== + + /** + * 是否为启用状态 + */ + public boolean isActive() { + return this.status == CommonStatus.ENABLED; + } + + + + /** + * 状态文案 + */ + public String getStatusText() { + CommonStatus e = this.status; + return e != null ? e.getDesc() : "未知"; + } + + /** + * 返回脱敏手机号,例如:138****1234 + */ + public String maskPhone() { + if (phone == null || phone.length() != 11) { + return phone; + } + return phone.substring(0, 3) + "****" + phone.substring(7); + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/HealthCertificate.java b/src/main/java/com/xjhs/findmemerchant/entity/HealthCertificate.java new file mode 100644 index 0000000..b0111a9 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/HealthCertificate.java @@ -0,0 +1,90 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.json.HashMapJsonConverter; +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.HealthCertificateStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.time.LocalDateTime; +import java.util.HashMap; + +/** + * 健康证资质 + * 对应表:health_certificates + */ +@Getter +@Setter +@Entity +@Table( + name = "health_certificates", + indexes = { + @Index(name = "idx_health_certificates_store_id", columnList = "store_id"), + @Index(name = "idx_health_certificates_employee_id", columnList = "employee_id") + } +) +public class HealthCertificate extends AbstractBaseEntity { + + @Column(name = "image_url", length = 500) + @Comment("健康证图片URL") + private String imageUrl; + + @Column(name = "holder_name", length = 50) + @Comment("持证人姓名(OCR识别)") + private String holderName; + + @Column(name = "valid_until") + @Comment("证件有效期至(OCR识别)") + private LocalDateTime validUntil; + + @Column(name = "issuer", length = 100) + @Comment("签发机构(OCR识别)") + private String issuer; + + @Convert(converter = HashMapJsonConverter.class) + @Column(name = "ocr_raw", columnDefinition = "json") + @Comment("OCR原始结果") + private HashMap ocrRaw; + + @Column(name = "status",columnDefinition = "VARCHAR(20)",length = 20) + @Comment("状态:0待审核 1有效 2过期") + private HealthCertificateStatus status = HealthCertificateStatus.PENDING; + + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id", insertable = false, updatable = false) + private Store store; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "employee_id", insertable = false, updatable = false) + private Employee employee; + + // ===== 业务方法 ===== + + public boolean isValid() { + if (getStatusEnum() != HealthCertificateStatus.VALID) { + return false; + } + if (validUntil != null && LocalDateTime.now().isAfter(validUntil)) { + return false; + } + return true; + } + + public boolean isExpired() { + if (validUntil == null) return false; + return LocalDateTime.now().isAfter(validUntil); + } + + public HealthCertificateStatus getStatusEnum() { + return this.status; + } + + + public String getStatusText() { + var e = getStatusEnum(); + return e != null ? e.getDesc() : "未知"; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Member.java b/src/main/java/com/xjhs/findmemerchant/entity/Member.java new file mode 100644 index 0000000..994abee --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Member.java @@ -0,0 +1,127 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 会员实体(C 端用户) + * 对应表:members + */ +@Getter +@Setter +@Entity +@Table( + name = "members", + indexes = { + @Index(name = "idx_members_phone", columnList = "phone") + }, + uniqueConstraints = { + @UniqueConstraint( + name = "idx_merchant_phone", + columnNames = {"merchant_id", "phone"} + ) + } +) +public class Member extends AbstractBaseEntity { + + /** + * 手机号 + */ + @Column(name = "phone", length = 11) + @Comment("手机号") + private String phone; + + /** + * 昵称 + */ + @Column(name = "nickname", length = 50) + @Comment("昵称") + private String nickname; + + /** + * 头像地址 + */ + @Column(name = "avatar", length = 500) + @Comment("头像URL") + private String avatar; + + /** + * 累计订单数 + */ + @Column(name = "total_orders") + @Comment("累计订单数") + private Integer totalOrders = 0; + + /** + * 累计消费金额 + */ + @Column(name = "total_amount", precision = 12, scale = 2) + @Comment("累计消费金额") + private BigDecimal totalAmount = BigDecimal.ZERO; + + /** + * 最后一次下单时间 + */ + @Column(name = "last_order_at") + @Comment("最后下单时间") + private LocalDateTime lastOrderAt; + + // ============ 关联关系 ============ + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + /** + * 拥有的券码 + */ + @OneToMany(mappedBy = "member", fetch = FetchType.LAZY) + private List couponCodes; + + /** + * 订单列表 + */ + @OneToMany(mappedBy = "member", fetch = FetchType.LAZY) + private List orders; + + // ============ 业务方法 ============ + + /** + * 返回脱敏手机号,例如:138****1234 + */ + public String maskPhone() { + if (phone == null || phone.length() != 11) { + return phone; + } + return phone.substring(0, 3) + "****" + phone.substring(7); + } + + /** + * 展示用名称:优先昵称,否则使用脱敏手机号 + */ + public String getDisplayName() { + if (nickname != null && !nickname.isBlank()) { + return nickname; + } + return maskPhone(); + } + + /** + * 返回头像URL,若为空则返回默认头像 + */ + public String getAvatarOrDefault() { + if (avatar != null && !avatar.isBlank()) { + return avatar; + } + return "/static/default-avatar.png"; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Merchant.java b/src/main/java/com/xjhs/findmemerchant/entity/Merchant.java index e10539a..15a4bc2 100644 --- a/src/main/java/com/xjhs/findmemerchant/entity/Merchant.java +++ b/src/main/java/com/xjhs/findmemerchant/entity/Merchant.java @@ -1,27 +1,147 @@ package com.xjhs.findmemerchant.entity; + import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; -import com.xjhs.findmemerchant.system.entity.SystemUser; -import jakarta.persistence.Entity; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.OneToOne; -import jakarta.persistence.Table; -import lombok.Data; -import lombok.EqualsAndHashCode; +import com.xjhs.findmemerchant.types.AuthStatus; +import com.xjhs.findmemerchant.types.CommonStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; import org.hibernate.annotations.Comment; -@EqualsAndHashCode(callSuper = true) -@Data -@Entity -@Table -@Comment("商户信息表") -public class Merchant extends AbstractBaseEntity { - /** - * 用户信息 - */ - @OneToOne - @JoinColumn(name = "user_id") - @Comment("关联的用户信息") - private SystemUser systemUser; +import java.util.List; +/** + * 商家实体 + * 对应表:merchants + */ +@Getter +@Setter +@Entity +@Table( + name = "merchants", + indexes = { + @Index(name = "idx_merchants_auth_status", columnList = "auth_status"), + @Index(name = "idx_merchants_status", columnList = "status") + }, + uniqueConstraints = { + @UniqueConstraint(name = "uk_merchant_phone", columnNames = "phone") + } +) +public class Merchant extends AbstractBaseEntity { + + + /** + * 登录手机号 + */ + @Column(name = "phone", length = 11) + @Comment("手机号") + private String phone; + + /** + * 登录密码Hash + */ + @Column(name = "password_hash", length = 255) + @Comment("密码Hash") + private String passwordHash; + + /** + * 真实姓名 + */ + @Column(name = "real_name", length = 50) + @Comment("真实姓名") + private String realName; + + /** + * 身份证号(明文)——不入库 + */ + @Transient + private String idCardNo; + + /** + * 身份证加密存储 + */ + @Column(name = "id_card_encrypted", length = 255) + @Comment("身份证加密存储") + private String idCardEncrypted; + + /** + * 认证状态 + */ + @Column(name = "auth_status",length = 20,columnDefinition = "VARCHAR(20)") + @Comment("认证状态") + @Enumerated(EnumType.STRING) + private AuthStatus authStatus = AuthStatus.NOT_VERIFIED; + + /** + * 账户状态 + */ + @Column(name = "status",length = 20,columnDefinition = "VARCHAR(20)") + @Comment("账户状态") + @Enumerated(EnumType.STRING) + private CommonStatus status = CommonStatus.ENABLED; + + // ========== 关联关系 ========== + + /** + * 门店列表 + */ + @OneToMany(mappedBy = "merchant", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true) + private List stores; + + /** + * 添加一个门店 + * @param store 门店信息 + */ + public void addStore(Store store) { + store.setMerchant(this); + this.stores.add(store); + } + + + /** + * 营业执照 + */ + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "id", referencedColumnName = "merchant_id", insertable = false, updatable = false) + private BusinessLicense businessLicense; + + // ========== 业务方法 ========== + + /** + * 是否已完成实名认证 + */ + public boolean isAuthenticated() { + return getAuthStatusEnum() == AuthStatus.VERIFIED; + } + + public AuthStatus getAuthStatusEnum() { + return this.authStatus; + } + /** + * 是否启用 + */ + public boolean isActive() { + return getStatusEnum() == CommonStatus.ENABLED; + } + + public CommonStatus getStatusEnum() { + return this.status; + } + + /** + * 手机脱敏 + */ + public String maskPhone() { + if (phone == null || phone.length() != 11) return phone; + return phone.substring(0, 3) + "****" + phone.substring(7); + } + + /** + * 身份证脱敏 + */ + public String maskIdCard() { + if (idCardNo == null || idCardNo.length() != 18) return idCardNo; + return idCardNo.substring(0, 3) + "***********" + idCardNo.substring(14); + } } diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Message.java b/src/main/java/com/xjhs/findmemerchant/entity/Message.java new file mode 100644 index 0000000..baf6965 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Message.java @@ -0,0 +1,122 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.MessageType; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.time.LocalDateTime; + +/** + * 消息实体 + * 对应表:messages + */ +@Getter +@Setter +@Entity +@Table( + name = "messages", + indexes = { + @Index(name = "idx_messages_merchant", columnList = "merchant_id"), + @Index(name = "idx_messages_type_read", columnList = "merchant_id,type,is_read") + } +) +public class Message extends AbstractBaseEntity { + + /** + * 消息类型:1-系统通知 2-活动提醒 3-私信 + */ + @Column(name = "type",columnDefinition = "VARCHAR(20)",length = 20) + @Enumerated(EnumType.STRING) + @Comment("消息类型:1系统通知 2活动提醒 3私信") + private MessageType type; + + /** + * 标题 + */ + @Column(name = "title", length = 200) + @Comment("消息标题") + private String title; + + /** + * 内容 + */ + @Column(name = "content", columnDefinition = "text") + @Comment("消息内容") + private String content; + + /** + * 是否已读:0-未读 1-已读 + */ + @Column(name = "is_read") + @Comment("是否已读:0未读 1已读") + private Boolean isRead = false; + + /** + * 创建时间 + */ + @Column(name = "created_at") + @Comment("创建时间") + private LocalDateTime createdAt; + + /** + * 阅读时间 + */ + @Column(name = "read_at") + @Comment("阅读时间") + private LocalDateTime readAt; + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + // ========== 业务方法 ========== + + /** + * 标记为已读 + */ + public void markAsRead() { + this.isRead = true; + this.readAt = LocalDateTime.now(); + } + + /** + * 是否未读 + */ + public boolean isUnread() { + return this.isRead != null && !this.isRead; + } + + /** + * 消息类型文案 + */ + public String getTypeText() { + MessageType t = getTypeEnum(); + return t != null ? t.getDesc() : "未知"; + } + + /** + * 内容摘要,最多100字符 + */ + public String getSummary() { + if (content == null) { + return ""; + } + if (content.length() <= 100) { + return content; + } + return content.substring(0, 100) + "..."; + } + + // ========== 枚举转换辅助 ========== + + public MessageType getTypeEnum() { + return this.type; + } + +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Order.java b/src/main/java/com/xjhs/findmemerchant/entity/Order.java new file mode 100644 index 0000000..f690469 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Order.java @@ -0,0 +1,168 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.OrderStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * 订单实体 + * 对应表:orders + */ +@Getter +@Setter +@Entity +@Table( + name = "orders", + indexes = { + @Index(name = "idx_orders_store_id", columnList = "store_id"), + @Index(name = "idx_orders_member_id", columnList = "member_id"), + @Index(name = "idx_orders_status", columnList = "status") + }, + uniqueConstraints = { + @UniqueConstraint(name = "uk_orders_order_no", columnNames = "order_no") + } +) +public class Order extends AbstractBaseEntity { + /** + * 订单号 + */ + @Column(name = "order_no", length = 32) + @Comment("订单号") + private String orderNo; + + + /** + * 订单总金额 + */ + @Column(name = "total_amount", precision = 10, scale = 2) + @Comment("订单总金额") + private BigDecimal totalAmount; + + /** + * 优惠金额 + */ + @Column(name = "discount_amount", precision = 10, scale = 2) + @Comment("优惠金额") + private BigDecimal discountAmount = BigDecimal.ZERO; + + /** + * 实付金额 + */ + @Column(name = "pay_amount", precision = 10, scale = 2) + @Comment("实付金额") + private BigDecimal payAmount; + + /** + * 使用的券码ID(可为空) + */ + @Column(name = "coupon_code_id") + @Comment("优惠券码ID") + private Long couponCodeId; + + /** + * 订单状态:1-待支付 2-已支付 3-已完成 4-已退款 5-已取消 + */ + @Column(name = "status") + @Comment("订单状态:1待支付 2已支付 3已完成 4已退款 5已取消") + private OrderStatus status; + + /** + * 支付时间 + */ + @Column(name = "paid_at") + @Comment("支付时间") + private LocalDateTime paidAt; + + + // ========== 关联关系 ========== + + /** + * 门店 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id", insertable = false, updatable = false) + private Store store; + + /** + * 会员 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", insertable = false, updatable = false) + private Member member; + + /** + * 优惠券码 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "coupon_code_id", insertable = false, updatable = false) + private CouponCode couponCode; + + /** + * 订单明细 + */ + @OneToMany(mappedBy = "order", fetch = FetchType.LAZY) + private List items; + + // ========== 业务方法 ========== + + /** + * 是否已支付(状态>=已支付且非已取消) + */ + public boolean isPaid() { + OrderStatus s = getStatusEnum(); + if (s == null) return false; + return s.getCodeValue() >= OrderStatus.PAID.getCodeValue() + && s != OrderStatus.CANCELLED; + } + + /** + * 是否已完成 + */ + public boolean isCompleted() { + return getStatusEnum() == OrderStatus.COMPLETED; + } + + /** + * 是否可退款(已支付或已完成) + */ + public boolean canRefund() { + OrderStatus s = getStatusEnum(); + return s == OrderStatus.PAID || s == OrderStatus.COMPLETED; + } + + /** + * 是否可取消(待支付) + */ + public boolean canCancel() { + return getStatusEnum() == OrderStatus.PENDING; + } + + /** + * 状态文案 + */ + public String getStatusText() { + OrderStatus s = getStatusEnum(); + return s != null ? s.getDesc() : "未知"; + } + + /** + * 是否有优惠 + */ + public boolean hasDiscount() { + return discountAmount != null && discountAmount.compareTo(BigDecimal.ZERO) > 0; + } + + // ========== 枚举转换辅助 ========== + + public OrderStatus getStatusEnum() { + return this.status; + } + +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/OrderItem.java b/src/main/java/com/xjhs/findmemerchant/entity/OrderItem.java new file mode 100644 index 0000000..640d5f2 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/OrderItem.java @@ -0,0 +1,123 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.id.SnowflakeGenerated; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 订单明细 + * 对应表:order_items + */ +@Getter +@Setter +@Entity +@Table( + name = "order_items", + indexes = { + @Index(name = "idx_order_items_order_id", columnList = "order_id"), + @Index(name = "idx_order_items_product_id", columnList = "product_id"), + @Index(name = "idx_order_items_sku_id", columnList = "sku_id") + } +) +public class OrderItem { + + /** + * 主键(雪花ID) + */ + @Id + @GeneratedValue + @SnowflakeGenerated + @Comment("主键ID") + private Long id; + + + + /** + * 商品ID(可能被删除所以可空) + */ + @Column(name = "product_id") + @Comment("商品ID(可空)") + private Long productId; + + /** + * 商品名称(快照) + */ + @Column(name = "product_name", length = 100) + @Comment("商品名称(快照)") + private String productName; + + /** + * SKU ID(可能被删除所以可空) + */ + @Column(name = "sku_id") + @Comment("SKU ID(可空)") + private Long skuId; + + /** + * SKU 名称(快照) + */ + @Column(name = "sku_name", length = 100) + @Comment("SKU名称(快照)") + private String skuName; + + /** + * 商品图片(快照) + */ + @Column(name = "image", length = 255) + @Comment("商品图片(快照)") + private String image; + + /** + * 商品单价 + */ + @Column(name = "unit_price", precision = 10, scale = 2) + @Comment("商品单价") + private BigDecimal unitPrice; + + /** + * 购买数量 + */ + @Column(name = "quantity") + @Comment("购买数量") + private Integer quantity = 1; + + /** + * 小计金额 + */ + @Column(name = "total_price", precision = 10, scale = 2) + @Comment("小计金额") + private BigDecimal totalPrice; + + /** + * 创建时间 + */ + @Column(name = "created_at") + @Comment("创建时间") + private LocalDateTime createdAt; + + // ========== 关联关系 ========== + + /** + * 所属订单 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "order_id") + private Order order; + + // ========== 业务方法 ========== + + /** + * 根据单价 * 数量计算小计 + */ + public BigDecimal getSubtotal() { + if (unitPrice == null || quantity == null) { + return BigDecimal.ZERO; + } + return unitPrice.multiply(BigDecimal.valueOf(quantity)); + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Product.java b/src/main/java/com/xjhs/findmemerchant/entity/Product.java new file mode 100644 index 0000000..ca1cd2b --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Product.java @@ -0,0 +1,190 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.ProductStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.List; + +/** + * 商品实体 + * 对应表:products + */ +@Getter +@Setter +@Entity +@Table( + name = "products", + indexes = { + @Index(name = "idx_products_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_products_store_id", columnList = "store_id"), + @Index(name = "idx_products_category_id", columnList = "category_id"), + @Index(name = "idx_products_status", columnList = "status") + } +) +public class Product extends AbstractBaseEntity { + + /** + * 商品名称 + */ + @Column(name = "name", length = 100) + @Comment("商品名称") + private String name; + + /** + * 商品描述 + */ + @Column(name = "description", columnDefinition = "text") + @Comment("商品描述") + private String description; + + /** + * 商品图片列表(JSON数组字符串) + */ + @Column(name = "images", columnDefinition = "text") + @Comment("商品图片(JSON数组)") + private String images; + + /** + * 原价 + */ + @Column(name = "original_price", precision = 10, scale = 2) + @Comment("原价") + private BigDecimal originalPrice; + + /** + * 售价 + */ + @Column(name = "sale_price", precision = 10, scale = 2) + @Comment("售价") + private BigDecimal salePrice; + + /** + * 库存,-1 表示无限库存 + */ + @Column(name = "stock") + @Comment("库存,-1表示无限库存") + private Integer stock = -1; + + /** + * 已售数量 + */ + @Column(name = "sold_count") + @Comment("已售数量") + private Integer soldCount = 0; + + /** + * 排序值 + */ + @Column(name = "sort_order") + @Comment("排序值") + private Integer sortOrder = 0; + + /** + * 商品状态:0-下架 1-上架 + */ + @Column(name = "status",columnDefinition = "VARCHAR(20)",length = 20) + @Enumerated(EnumType.STRING) + @Comment("商品状态:0下架 1上架") + private ProductStatus status = ProductStatus.OFF_SALE; + + // ========== 关联关系 ========== + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + /** + * 门店 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id", insertable = false, updatable = false) + private Store store; + + /** + * 商品分类 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id", insertable = false, updatable = false) + private ProductCategory category; + + /** + * SKU 列表 + */ + @OneToMany(mappedBy = "product", fetch = FetchType.LAZY) + private List skus; + + // ========== 业务方法 ========== + + /** + * 是否上架中 + */ + public boolean isOnSale() { + return getStatusEnum() == ProductStatus.ON_SALE; + } + + /** + * 是否有库存 + */ + public boolean hasStock() { + if (stock == null) return false; + return stock == -1 || stock > 0; + } + + /** + * 是否有折扣(售价 < 原价) + */ + public boolean hasDiscount() { + if (salePrice == null || originalPrice == null) return false; + return salePrice.compareTo(originalPrice) < 0; + } + + /** + * 折扣率 (0-100),整数部分 + */ + public int getDiscountRate() { + if (originalPrice == null || originalPrice.compareTo(BigDecimal.ZERO) == 0 + || salePrice == null) { + return 0; + } + BigDecimal rate = salePrice + .divide(originalPrice, 2, RoundingMode.HALF_UP) + .multiply(BigDecimal.valueOf(100)); + return rate.intValue(); + } + + /** + * 状态文案 + */ + public String getStatusText() { + ProductStatus s = getStatusEnum(); + return s != null ? s.getDesc() : "未知"; + } + + /** + * 是否可扣减库存 + */ + public boolean canDeductStock(int quantity) { + if (stock == null || quantity <= 0) { + return false; + } + if (stock == -1) { + return true; // 无限库存 + } + return stock >= quantity; + } + + // ========== 枚举转换辅助 ========== + + public ProductStatus getStatusEnum() { + return this.status; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/ProductCategory.java b/src/main/java/com/xjhs/findmemerchant/entity/ProductCategory.java new file mode 100644 index 0000000..c0aca82 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/ProductCategory.java @@ -0,0 +1,109 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.CommonStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.util.List; + +/** + * 商品分类实体 + * 对应表:product_categories + */ +@Getter +@Setter +@Entity +@Table( + name = "product_categories", + indexes = { + @Index(name = "idx_product_categories_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_product_categories_parent_id", columnList = "parent_id"), + @Index(name = "idx_product_categories_status", columnList = "status") + } +) +public class ProductCategory extends AbstractBaseEntity { + + /** + * 分类名称 + */ + @Column(name = "name", length = 50) + @Comment("分类名称") + private String name; + + /** + * 父分类ID,支持二级分类 + */ + @Column(name = "parent_id") + @Comment("父分类ID,支持二级分类") + private Long parentId; + + /** + * 排序值 + */ + @Column(name = "sort_order") + @Comment("排序值") + private Integer sortOrder = 0; + + /** + * 状态:0-禁用 1-启用 + */ + @Column(name = "status") + @Comment("状态:0禁用 1启用") + private CommonStatus status = CommonStatus.ENABLED; + + // ========== 关联关系 ========== + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + /** + * 父分类 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id", insertable = false, updatable = false) + private ProductCategory parent; + + /** + * 子分类列表 + */ + @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY) + private List children; + + /** + * 分类下商品 + */ + @OneToMany(mappedBy = "category", fetch = FetchType.LAZY) + private List products; + + // ========== 业务方法 ========== + + /** + * 是否启用 + */ + public boolean isEnabled() { + return getStatusEnum() == CommonStatus.ENABLED; + } + + /** + * 是否为一级分类(无父分类) + */ + public boolean isTopLevel() { + return parentId == null; + } + + public CommonStatus getStatusEnum() { + return this.status; + } + + public String getStatusText() { + CommonStatus e = getStatusEnum(); + return e != null ? e.getDesc() : "未知"; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/ProductSKU.java b/src/main/java/com/xjhs/findmemerchant/entity/ProductSKU.java new file mode 100644 index 0000000..aa78e36 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/ProductSKU.java @@ -0,0 +1,126 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.id.SnowflakeGenerated; +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.CommonStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; + +/** + * 商品SKU(规格)实体 + * 对应表:product_skus + */ +@Getter +@Setter +@Entity +@Table( + name = "product_skus", + indexes = { + @Index(name = "idx_product_skus_product_id", columnList = "product_id"), + @Index(name = "idx_product_skus_sku_code", columnList = "sku_code") + } +) +public class ProductSKU extends AbstractBaseEntity { + + /** + * 主键(雪花ID) + */ + @Id + @GeneratedValue + @SnowflakeGenerated + @Comment("主键ID") + private Long id; + + /** + * 规格名称(如:大杯/加冰) + */ + @Column(name = "sku_name", length = 100) + @Comment("规格名称") + private String skuName; + + /** + * SKU 编码 + */ + @Column(name = "sku_code", length = 50) + @Comment("SKU编码") + private String skuCode; + + /** + * 售价 + */ + @Column(name = "price", precision = 10, scale = 2) + @Comment("规格价格") + private BigDecimal price; + + /** + * 库存,-1 表示无限库存 + */ + @Column(name = "stock") + @Comment("库存,-1表示无限库存") + private Integer stock = -1; + + /** + * 已售数量 + */ + @Column(name = "sold_count") + @Comment("已售数量") + private Integer soldCount = 0; + + /** + * 状态:0-禁用 1-启用 + */ + @Column(name = "status",columnDefinition = "VARCHAR(20)",length = 20) + @Comment("状态:0禁用 1启用") + private CommonStatus status = CommonStatus.ENABLED; + + + /** + * 所属商品 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "product_id", insertable = false, updatable = false) + private Product product; + + // ===== 业务方法 ===== + + /** + * 是否启用 + */ + public boolean isEnabled() { + return getStatusEnum() == CommonStatus.ENABLED; + } + + /** + * 是否有库存 + */ + public boolean hasStock() { + if (stock == null) return false; + return stock == -1 || stock > 0; + } + + /** + * 是否可扣减库存 + */ + public boolean canDeductStock(int quantity) { + if (stock == null || quantity <= 0) { + return false; + } + if (stock == -1) { + return true; + } + return stock >= quantity; + } + + public CommonStatus getStatusEnum() { + return this.status; + } + + public String getStatusText() { + CommonStatus e = getStatusEnum(); + return e != null ? e.getDesc() : "未知"; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Review.java b/src/main/java/com/xjhs/findmemerchant/entity/Review.java new file mode 100644 index 0000000..6928222 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Review.java @@ -0,0 +1,170 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.ReviewStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +/** + * 用户评价(C端共享) + * 对应表:reviews + */ +@Getter +@Setter +@Entity +@Table( + name = "reviews", + indexes = { + @Index(name = "idx_reviews_order_id", columnList = "order_id"), + @Index(name = "idx_reviews_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_reviews_store_id", columnList = "store_id"), + @Index(name = "idx_reviews_user_id", columnList = "user_id"), + @Index(name = "idx_reviews_created_at", columnList = "created_at") + } +) +public class Review extends AbstractBaseEntity { + + + + + /** + * C端用户ID + */ + @Column(name = "user_id") + @Comment("C端用户ID") + private Long userId; + + /** + * 用户昵称 + */ + @Column(name = "user_name", length = 50) + @Comment("用户昵称") + private String userName; + + /** + * 用户头像 + */ + @Column(name = "user_avatar", length = 255) + @Comment("用户头像URL") + private String userAvatar; + + /** + * 评分 1-5 + */ + @Column(name = "rating") + @Comment("评分 1-5") + private Integer rating; + + /** + * 评价内容 + */ + @Column(name = "content", columnDefinition = "text") + @Comment("评价内容") + private String content; + + /** + * 图片URL,逗号分隔 + */ + @Column(name = "images", length = 1000) + @Comment("评价图片URL,逗号分隔") + private String images; + + /** + * 是否匿名 + */ + @Column(name = "is_anonymous") + @Comment("是否匿名") + private Boolean isAnonymous = Boolean.FALSE; + + /** + * 状态:1-正常 0-隐藏 + */ + @Column(name = "status",columnDefinition = "VARCHAR(20)",length = 20) + @Comment("状态:1正常 0隐藏") + private ReviewStatus status = ReviewStatus.NORMAL; + + // ========== 关联关系 ========== + + /** + * 回复 + */ + @OneToOne(mappedBy = "review", fetch = FetchType.LAZY) + private ReviewReply reply; + + /** + * 门店 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id") + private Merchant merchant; + /** + * 门店 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "store_id") + private Store store; + + /** + * 订单 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "order_id") + private Order order; + + + + + // ========== 业务方法 ========== + + /** + * 评分文案 + */ + public String getRatingText() { + if (rating == null) { + return "未知"; + } + return switch (rating) { + case 5 -> "非常满意"; + case 4 -> "满意"; + case 3 -> "一般"; + case 2 -> "不满意"; + case 1 -> "非常不满意"; + default -> "未知"; + }; + } + + /** + * 是否好评(4-5星) + */ + public boolean isPositive() { + return rating != null && rating >= 4; + } + + /** + * 是否差评(1-2星) + */ + public boolean isNegative() { + return rating != null && rating <= 2; + } + + /** + * 展示用昵称(匿名/真实) + */ + public String getDisplayName() { + if (Boolean.TRUE.equals(isAnonymous)) { + return "匿名用户"; + } + return userName; + } + + public ReviewStatus getStatusEnum() { + return this.status; + } + + public String getStatusText() { + ReviewStatus e = getStatusEnum(); + return e != null ? e.getDesc() : "未知"; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/ReviewReply.java b/src/main/java/com/xjhs/findmemerchant/entity/ReviewReply.java new file mode 100644 index 0000000..3a3b223 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/ReviewReply.java @@ -0,0 +1,77 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.id.SnowflakeGenerated; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +/** + * 商家对评价的回复 + * 对应表:review_replies + */ +@Getter +@Setter +@Entity +@Table( + name = "review_replies", + uniqueConstraints = { + @UniqueConstraint(name = "uk_review_replies_review_id", columnNames = "review_id") + }, + indexes = { + @Index(name = "idx_review_replies_merchant_id", columnList = "merchant_id") + } +) +public class ReviewReply{ + + /** + * 主键(雪花ID) + */ + @Id + @GeneratedValue + @SnowflakeGenerated + @Comment("主键ID") + private Long id; + + /** + * 评价ID(唯一,一个评价一条回复) + */ + @Column(name = "review_id") + @Comment("评价ID") + private Long reviewId; + + /** + * 商家ID + */ + @Column(name = "merchant_id") + @Comment("商家ID") + private Long merchantId; + + /** + * 回复内容 + */ + @Column(name = "content", columnDefinition = "text") + @Comment("回复内容") + private String content; + + /** + * 回复人ID(商家或员工) + */ + @Column(name = "replier_id") + @Comment("回复人ID(商家或员工)") + private Long replierId; + + /** + * 回复人名称 + */ + @Column(name = "replier_name", length = 50) + @Comment("回复人名称") + private String replierName; + + /** + * 所属评价 + */ + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "review_id", insertable = false, updatable = false) + private Review review; +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Role.java b/src/main/java/com/xjhs/findmemerchant/entity/Role.java new file mode 100644 index 0000000..e9f9004 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Role.java @@ -0,0 +1,162 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.json.StringListJsonConverter; +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.util.ArrayList; +import java.util.List; + +import static com.xjhs.findmemerchant.constants.RoleConstants.*; + + +/** + * 角色实体 + * 对应表:roles + */ +@Getter +@Setter +@Entity +@Table( + name = "roles", + uniqueConstraints = { + @UniqueConstraint(name = "uk_roles_code", columnNames = "code") + } +) +public class Role extends AbstractBaseEntity { + + + /** + * 角色名称 + */ + @Column(name = "name", length = 50) + @Comment("角色名称") + private String name; + + /** + * 角色编码(唯一) + */ + @Column(name = "code", length = 50) + @Comment("角色编码") + private String code; + + /** + * 描述 + */ + @Column(name = "description", length = 200) + @Comment("角色描述") + private String description; + + /** + * 权限列表(JSON数组) + */ + @Convert(converter = StringListJsonConverter.class) + @Column(name = "permissions", columnDefinition = "json") + @Comment("权限列表(JSON数组)") + private List permissions = new ArrayList<>(); + + /** + * 是否系统内置角色:1-是 0-否 + */ + @Column(name = "is_system") + @Comment("是否系统内置角色:1是 0否") + private Byte isSystem = 0; + + // ========== 业务方法 ========== + + /** + * 是否系统预置角色 + */ + public boolean isSystemRole() { + return Byte.valueOf((byte) 1).equals(isSystem); + } + + /** + * 是否拥有指定权限(支持 *) + */ + public boolean hasPermission(String permission) { + if (permission == null || permissions == null || permissions.isEmpty()) { + return false; + } + for (String p : permissions) { + if (PERMISSION_ALL.equals(p) || permission.equals(p)) { + return true; + } + } + return false; + } + + /** + * 返回权限列表,避免 null + */ + public List getPermissionsSafe() { + return permissions != null ? permissions : new ArrayList<>(); + } + + /** + * 系统内置默认角色(不带ID、时间,用于初始化) + */ + public static List getDefaultRoles() { + List roles = new ArrayList<>(); + + // 店长:全部权限 + Role owner = new Role(); + owner.setCode(ROLE_CODE_OWNER); + owner.setName("店长"); + owner.setPermissions(List.of(PERMISSION_ALL)); + owner.setIsSystem((byte) 1); + roles.add(owner); + + // 运营 + Role operator = new Role(); + operator.setCode(ROLE_CODE_OPERATOR); + operator.setName("运营"); + operator.setPermissions(List.of( + PERMISSION_STORE_VIEW, + PERMISSION_COUPON_MANAGE, + PERMISSION_COUPON_VIEW, + PERMISSION_COUPON_VERIFY, + PERMISSION_ORDER_VIEW, + PERMISSION_ACTIVITY_MANAGE, + PERMISSION_ACTIVITY_VIEW, + PERMISSION_ANALYTICS_VIEW, + PERMISSION_MEMBER_VIEW + )); + operator.setIsSystem((byte) 1); + roles.add(operator); + + // 客服 + Role service = new Role(); + service.setCode(ROLE_CODE_SERVICE); + service.setName("客服"); + service.setPermissions(List.of( + PERMISSION_STORE_VIEW, + PERMISSION_COUPON_VIEW, + PERMISSION_COUPON_VERIFY, + PERMISSION_ORDER_VIEW, + PERMISSION_MEMBER_VIEW, + PERMISSION_MESSAGE_VIEW + )); + service.setIsSystem((byte) 1); + roles.add(service); + + // 营销管理员 + Role marketing = new Role(); + marketing.setCode(ROLE_CODE_MARKETING); + marketing.setName("营销管理员"); + marketing.setPermissions(List.of( + PERMISSION_COUPON_MANAGE, + PERMISSION_COUPON_VIEW, + PERMISSION_ACTIVITY_MANAGE, + PERMISSION_ACTIVITY_VIEW, + PERMISSION_ANALYTICS_VIEW + )); + marketing.setIsSystem((byte) 1); + roles.add(marketing); + + return roles; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Settlement.java b/src/main/java/com/xjhs/findmemerchant/entity/Settlement.java new file mode 100644 index 0000000..9e0f89c --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Settlement.java @@ -0,0 +1,167 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.SettlementStatus; +import com.xjhs.findmemerchant.types.SettlementType; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +/** + * 结算记录(按日/按周) + * 对应表:settlements + */ +@Getter +@Setter +@Entity +@Table( + name = "settlements", + indexes = { + @Index(name = "idx_settlements_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_settlements_status", columnList = "status") + }, + uniqueConstraints = { + @UniqueConstraint(name = "uk_settlements_no", columnNames = "settlement_no") + } +) +public class Settlement extends AbstractBaseEntity { + + private static final DateTimeFormatter PERIOD_DATE_FORMATTER = + DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + + /** + * 结算单号 + */ + @Column(name = "settlement_no", length = 32) + @Comment("结算单号") + private String settlementNo; + + /** + * 结算类型:1-日结 2-周结 + */ + @Column(name = "type") + @Comment("结算类型:1日结 2周结") + private SettlementType type; + + /** + * 结算周期开始时间 + */ + @Column(name = "period_start") + @Comment("结算周期开始时间") + private LocalDateTime periodStart; + + /** + * 结算周期结束时间 + */ + @Column(name = "period_end") + @Comment("结算周期结束时间") + private LocalDateTime periodEnd; + + /** + * 订单数量 + */ + @Column(name = "order_count") + @Comment("订单数量") + private Integer orderCount = 0; + + /** + * 订单总额 + */ + @Column(name = "total_amount", precision = 12, scale = 2) + @Comment("订单总额") + private BigDecimal totalAmount; + + /** + * 退款金额 + */ + @Column(name = "refund_amount", precision = 12, scale = 2) + @Comment("退款金额") + private BigDecimal refundAmount = BigDecimal.ZERO; + + /** + * 平台服务费 + */ + @Column(name = "platform_fee", precision = 10, scale = 2) + @Comment("平台服务费") + private BigDecimal platformFee = BigDecimal.ZERO; + + /** + * 结算金额 + */ + @Column(name = "settlement_amount", precision = 12, scale = 2) + @Comment("结算金额") + private BigDecimal settlementAmount; + + /** + * 结算状态:0-待结算 1-已结算 + */ + @Column(name = "status") + @Comment("结算状态:0待结算 1已结算") + private SettlementStatus status = SettlementStatus.PENDING; + + /** + * 实际结算时间 + */ + @Column(name = "settled_at") + @Comment("实际结算时间") + private LocalDateTime settledAt; + + + + // ========== 业务方法 ========== + + public SettlementType getTypeEnum() { + return this.type; + } + + public SettlementStatus getStatusEnum() { + return this.status; + } + /** + * 结算类型文案 + */ + public String getTypeText() { + SettlementType e = getTypeEnum(); + return e != null ? e.getDesc() : "未知"; + } + + /** + * 状态文案 + */ + public String getStatusText() { + SettlementStatus e = getStatusEnum(); + return e != null ? e.getDesc() : "未知"; + } + + /** + * 是否已结算 + */ + public boolean isSettled() { + return getStatusEnum() == SettlementStatus.SETTLED; + } + + /** + * 周期文案,例如:2024-01-01 ~ 2024-01-07 + */ + public String getPeriodText() { + if (periodStart == null || periodEnd == null) { + return ""; + } + return periodStart.format(PERIOD_DATE_FORMATTER) + + " ~ " + + periodEnd.format(PERIOD_DATE_FORMATTER); + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Store.java b/src/main/java/com/xjhs/findmemerchant/entity/Store.java new file mode 100644 index 0000000..550d0d6 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Store.java @@ -0,0 +1,258 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.BusinessStatus; +import com.xjhs.findmemerchant.types.CommonStatus; +import com.xjhs.findmemerchant.types.StoreAuditStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; + +/** + * 门店实体 + * 对应表:stores + */ +@Getter +@Setter +@Entity +@Table( + name = "stores", + indexes = { + @Index(name = "idx_stores_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_stores_audit_status", columnList = "audit_status") + } +) +public class Store extends AbstractBaseEntity { + /** + * 门店名称 + */ + @Column(name = "name", length = 100) + @Comment("门店名称") + private String name; + + /** + * 门店Logo + */ + @Column(name = "logo", length = 500) + @Comment("门店Logo") + private String logo; + + /** + * 联系电话 + */ + @Column(name = "phone", length = 11) + @Comment("联系电话") + private String phone; + + /** + * 省 + */ + @Column(name = "province", length = 50) + @Comment("省") + private String province; + + /** + * 市 + */ + @Column(name = "city", length = 50) + @Comment("市") + private String city; + + /** + * 区/县 + */ + @Column(name = "district", length = 50) + @Comment("区/县") + private String district; + + /** + * 详细地址 + */ + @Column(name = "address", length = 200) + @Comment("详细地址") + private String address; + + /** + * 经度 + */ + @Column(name = "longitude", precision = 10, scale = 7) + @Comment("经度") + private BigDecimal longitude; + + /** + * 纬度 + */ + @Column(name = "latitude", precision = 10, scale = 7) + @Comment("纬度") + private BigDecimal latitude; + + /** + * 营业时间描述 + */ + @Column(name = "business_hours", length = 100) + @Comment("营业时间描述") + private String businessHours; + + /** + * 营业状态:0-已打烊 1-营业中 2-临时打烊 + */ + @Column(name = "business_status",columnDefinition = "VARCHAR(20)", length = 20) + @Enumerated(EnumType.STRING) + @Comment("营业状态:0已打烊 1营业中 2临时打烊") + private BusinessStatus businessStatus = BusinessStatus.OPEN; + + /** + * 临时打烊原因 + */ + @Column(name = "temp_close_reason", length = 200) + @Comment("临时打烊原因") + private String tempCloseReason; + + /** + * 临时打烊结束时间 + */ + @Column(name = "temp_close_until") + @Comment("临时打烊结束时间") + private LocalDateTime tempCloseUntil; + + /** + * 审核状态 + */ + @Column(name = "audit_status",columnDefinition = "VARCHAR(20)", length = 20) + @Comment("审核状态:0待审核 1已通过 2已拒绝") + private StoreAuditStatus auditStatus = StoreAuditStatus.PENDING; + + /** + * 审核备注 + */ + @Column(name = "audit_remark", length = 500) + @Comment("审核备注") + private String auditRemark; + + /** + * 启用状态:0-禁用 1-启用 + */ + @Column(name = "status",columnDefinition = "VARCHAR(20)", length = 20) + @Comment("启用状态:0禁用 1启用") + private CommonStatus status = CommonStatus.ENABLED; + + // ========== 关联关系 ========== + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id") + private Merchant merchant; + + /** + * 员工列表 + */ + @OneToMany(mappedBy = "store", fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true) + private List employees = new ArrayList<>(); + + public void addEmployee(Employee employee){ + employee.setStore(this); + this.employees.add(employee); + } + + /** + * 营业时间段 + */ + @OneToMany(mappedBy = "store", fetch = FetchType.LAZY,cascade = CascadeType.ALL,orphanRemoval = true) + private List businessPeriods = new ArrayList<>(); + + public void addBusinessPeriods(BusinessPeriod businessPeriod){ + businessPeriod.setStore(this); + this.businessPeriods.add(businessPeriod); + } + + + // ========== 业务方法 ========== + + /** + * 完整地址 + */ + public String getFullAddress() { + return (province == null ? "" : province) + + (city == null ? "" : city) + + (district == null ? "" : district) + + (address == null ? "" : address); + } + + /** + * 是否审核通过 + */ + public boolean isApproved() { + return getAuditStatusEnum() == StoreAuditStatus.APPROVED; + } + + /** + * 是否启用 + */ + public boolean isActive() { + return getStatusEnum() == CommonStatus.ENABLED; + } + + /** + * 是否有地理位置 + */ + public boolean hasLocation() { + return longitude != null && latitude != null; + } + + /** + * 当前是否营业 + */ + public boolean isBusinessOpen() { + BusinessStatus bs = getBusinessStatusEnum(); + if (bs == null) { + return false; + } + if (bs == BusinessStatus.TEMP_CLOSED) { + // 如果设置了临时打烊结束时间且已过期,则视作应恢复营业 + if (tempCloseUntil != null && LocalDateTime.now().isAfter(tempCloseUntil)) { + return true; + } + return false; + } + return bs == BusinessStatus.OPEN; + } + + /** + * 营业状态文案 + */ + public String getBusinessStatusText() { + BusinessStatus bs = getBusinessStatusEnum(); + return bs != null ? bs.getDesc() : "未知"; + } + + public BusinessStatus getBusinessStatusEnum() { + return this.businessStatus; + } + + + public StoreAuditStatus getAuditStatusEnum() { + return this.auditStatus; + } + + public CommonStatus getStatusEnum() { + return this.status; + } + + public String getAuditStatusText() { + StoreAuditStatus e = getAuditStatusEnum(); + return e != null ? e.getDesc() : "未知"; + } + + public String getStatusText() { + CommonStatus e = getStatusEnum(); + return e != null ? e.getDesc() : "未知"; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Transaction.java b/src/main/java/com/xjhs/findmemerchant/entity/Transaction.java new file mode 100644 index 0000000..4a1c803 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Transaction.java @@ -0,0 +1,133 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.id.SnowflakeGenerated; +import com.xjhs.findmemerchant.types.TransactionType; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 钱包交易流水 + * 对应表:wallet_transactions + */ +@Getter +@Setter +@Entity +@Table( + name = "wallet_transactions", + indexes = { + @Index(name = "idx_wallet_transactions_wallet_id", columnList = "wallet_id"), + @Index(name = "idx_wallet_transactions_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_wallet_transactions_type", columnList = "type"), + @Index(name = "idx_wallet_transactions_created_at", columnList = "created_at") + } +) +public class Transaction { + + /** + * 主键(雪花ID) + */ + @Id + @GeneratedValue + @SnowflakeGenerated + @Comment("主键ID") + private Long id; + + + /** + * 交易类型:1-收入 2-支出 3-冻结 4-解冻 5-提现 + */ + @Column(name = "type",columnDefinition = "VARCHAR(20)",length = 20) + @Comment("交易类型:1收入 2支出 3冻结 4解冻 5提现") + private TransactionType type; + + /** + * 交易金额 + */ + @Column(name = "amount", precision = 12, scale = 2) + @Comment("交易金额") + private BigDecimal amount; + + /** + * 交易前余额 + */ + @Column(name = "balance_before", precision = 12, scale = 2) + @Comment("交易前余额") + private BigDecimal balanceBefore; + + /** + * 交易后余额 + */ + @Column(name = "balance_after", precision = 12, scale = 2) + @Comment("交易后余额") + private BigDecimal balanceAfter; + + /** + * 关联类型: order, withdrawal, settlement + */ + @Column(name = "ref_type", length = 32) + @Comment("关联类型:order/withdrawal/settlement等") + private String refType; + + /** + * 关联ID + */ + @Column(name = "ref_id") + @Comment("关联业务ID") + private Long refId; + + /** + * 描述 + */ + @Column(name = "description", length = 200) + @Comment("交易描述") + private String description; + + /** + * 创建时间 + */ + @Column(name = "created_at") + @Comment("创建时间") + private LocalDateTime createdAt; + + /** + * 所属钱包 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "wallet_id", insertable = false, updatable = false) + private Wallet wallet; + + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + + // ========== 业务方法 ========== + + public TransactionType getTypeEnum() { + return this.type; + } + + /** + * 交易类型文案 + */ + public String getTypeText() { + TransactionType t = getTypeEnum(); + return t != null ? t.getDesc() : "未知"; + } + + /** + * 是否收入流水 + */ + public boolean isIncome() { + return getTypeEnum() == TransactionType.INCOME; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Wallet.java b/src/main/java/com/xjhs/findmemerchant/entity/Wallet.java new file mode 100644 index 0000000..06dffe2 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Wallet.java @@ -0,0 +1,100 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; + +/** + * 商家钱包 + * 对应表:wallets + */ +@Getter +@Setter +@Entity +@Table( + name = "wallets", + uniqueConstraints = { + @UniqueConstraint(name = "uk_wallets_merchant_id", columnNames = "merchant_id") + } +) +public class Wallet extends AbstractBaseEntity { + + /** + * 可用余额 + */ + @Column(name = "balance", precision = 12, scale = 2) + @Comment("可用余额") + private BigDecimal balance = BigDecimal.ZERO; + + /** + * 冻结余额(提现中) + */ + @Column(name = "frozen_balance", precision = 12, scale = 2) + @Comment("冻结余额(提现中)") + private BigDecimal frozenBalance = BigDecimal.ZERO; + + /** + * 累计收入 + */ + @Column(name = "total_income", precision = 12, scale = 2) + @Comment("累计收入") + private BigDecimal totalIncome = BigDecimal.ZERO; + + /** + * 累计提现 + */ + @Column(name = "total_withdrawn", precision = 12, scale = 2) + @Comment("累计提现") + private BigDecimal totalWithdrawn = BigDecimal.ZERO; + + /** + * 待结算金额 + */ + @Column(name = "pending_settlement", precision = 12, scale = 2) + @Comment("待结算金额") + private BigDecimal pendingSettlement = BigDecimal.ZERO; + + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id") + private Merchant merchant; + + // ========== 业务方法 ========== + + /** + * 可提现余额 + */ + public BigDecimal getAvailableBalance() { + return balance != null ? balance : BigDecimal.ZERO; + } + + /** + * 总余额(含冻结) + */ + public BigDecimal getTotalBalance() { + BigDecimal b = balance != null ? balance : BigDecimal.ZERO; + BigDecimal f = frozenBalance != null ? frozenBalance : BigDecimal.ZERO; + return b.add(f); + } + + /** + * 是否可提现指定金额 + */ + public boolean canWithdraw(BigDecimal amount) { + if (amount == null) { + return false; + } + if (amount.compareTo(BigDecimal.ZERO) <= 0) { + return false; + } + BigDecimal b = balance != null ? balance : BigDecimal.ZERO; + return b.compareTo(amount) >= 0; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/entity/Withdrawal.java b/src/main/java/com/xjhs/findmemerchant/entity/Withdrawal.java new file mode 100644 index 0000000..8efa02e --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/entity/Withdrawal.java @@ -0,0 +1,175 @@ +package com.xjhs.findmemerchant.entity; + +import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; +import com.xjhs.findmemerchant.types.WithdrawalStatus; +import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; +import org.hibernate.annotations.Comment; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * 提现申请 + * 对应表:withdrawals + */ +@Getter +@Setter +@Entity +@Table( + name = "withdrawals", + indexes = { + @Index(name = "idx_withdrawals_merchant_id", columnList = "merchant_id"), + @Index(name = "idx_withdrawals_wallet_id", columnList = "wallet_id"), + @Index(name = "idx_withdrawals_status", columnList = "status"), + @Index(name = "idx_withdrawals_created_at", columnList = "created_at") + } +) +public class Withdrawal extends AbstractBaseEntity { + + + /** + * 提现金额 + */ + @Column(name = "amount", precision = 12, scale = 2) + @Comment("提现金额") + private BigDecimal amount; + + /** + * 手续费 + */ + @Column(name = "fee", precision = 10, scale = 2) + @Comment("提现手续费") + private BigDecimal fee = BigDecimal.ZERO; + + /** + * 实际到账金额 + */ + @Column(name = "actual_amount", precision = 12, scale = 2) + @Comment("实际到账金额") + private BigDecimal actualAmount; + + /** + * 银行名称 + */ + @Column(name = "bank_name", length = 50) + @Comment("银行名称") + private String bankName; + + /** + * 银行账号(加密存储) + */ + @Column(name = "bank_account", length = 30) + @Comment("银行账号(加密)") + private String bankAccount; + + /** + * 户名 + */ + @Column(name = "account_name", length = 50) + @Comment("开户人姓名") + private String accountName; + + /** + * 状态:0-待审核 1-处理中 2-已完成 3-已拒绝 4-已取消 + */ + @Column(name = "status") + @Comment("提现状态") + private Byte status = 0; + + /** + * 拒绝原因 + */ + @Column(name = "reject_reason", length = 200) + @Comment("拒绝原因") + private String rejectReason; + + /** + * 审核/处理时间 + */ + @Column(name = "processed_at") + @Comment("审核/处理时间") + private LocalDateTime processedAt; + + /** + * 完成时间 + */ + @Column(name = "completed_at") + @Comment("完成时间") + private LocalDateTime completedAt; + + /** + * 银行流水号 + */ + @Column(name = "transaction_no", length = 64) + @Comment("银行流水号") + private String transactionNo; + + /** + * 备注 + */ + @Column(name = "remark", length = 200) + @Comment("备注") + private String remark; + + /** + * 商家 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "merchant_id", insertable = false, updatable = false) + private Merchant merchant; + + /** + * 钱包 + */ + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "wallet_id", insertable = false, updatable = false) + private Wallet wallet; + + // ========= 业务方法 ========= + + public WithdrawalStatus getStatusEnum() { + return WithdrawalStatus.fromCode(this.status); + } + + public void setStatusEnum(WithdrawalStatus statusEnum) { + this.status = statusEnum == null ? null : statusEnum.code(); + } + + public String getStatusText() { + WithdrawalStatus e = getStatusEnum(); + return e != null ? e.getDesc() : "未知"; + } + + /** + * 是否待审核 + */ + public boolean isPending() { + return getStatusEnum() == WithdrawalStatus.PENDING; + } + + /** + * 是否已完成 + */ + public boolean isCompleted() { + return getStatusEnum() == WithdrawalStatus.COMPLETED; + } + + /** + * 是否可以取消 + */ + public boolean canCancel() { + return getStatusEnum() == WithdrawalStatus.PENDING; + } + + /** + * 脱敏银行卡号 + */ + public String getMaskedBankAccount() { + if (bankAccount == null || bankAccount.length() <= 8) { + return bankAccount; + } + return bankAccount.substring(0, 4) + "****" + bankAccount.substring(bankAccount.length() - 4); + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/file/FileController.java b/src/main/java/com/xjhs/findmemerchant/file/FileController.java deleted file mode 100644 index 15eb8ab..0000000 --- a/src/main/java/com/xjhs/findmemerchant/file/FileController.java +++ /dev/null @@ -1,108 +0,0 @@ -package com.xjhs.findmemerchant.file; - -import com.xjhs.findmemerchant.common.ApiResult; -import com.xjhs.findmemerchant.file.dao.FileMetaInfo; -import com.xjhs.findmemerchant.file.dao.FileMetaInfoRepository; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.apache.tika.mime.MimeTypes; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.multipart.MultipartFile; - -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.time.LocalDate; -import java.time.format.DateTimeFormatter; -import java.util.UUID; - -/** - * 统一文件管理控制器 - */ -@Slf4j -@RestController -@RequiredArgsConstructor -public class FileController { - - - @Value("${appconfig.saveFileRoot}") - private String fileSaveRoot="./file-data"; - - private final FileMetaInfoRepository fileMetaInfoRepository; - - /** - * 获取并检查创建文件存储目录 - * @return 文件存储目录带日期 - */ - public Path getFileSavePath() throws IOException { - var datePath = DateTimeFormatter.ofPattern("yyyy/MM-dd").format(LocalDate.now()); - var path = Path.of(this.fileSaveRoot, datePath); - if (!Files.exists(path)){ - Files.createDirectories(path); - } - return path; - } - - - /** - * 上传文件 - * - * @param file 文件数据内容 - * @return 文件描信息 - */ - - @PostMapping("/platform/file/upload") - public ApiResult uploadFile(@RequestPart(name = "file") MultipartFile file) { - try { - var ext = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")); - if (StringUtils.isEmpty(ext)) { - try { - ext = MimeTypes.getDefaultMimeTypes().forName(file.getContentType()).getExtension(); - } catch (Exception e) { - ext = ""; - } - } - - var filePath = Path.of(this.fileSaveRoot, UUID.randomUUID() + ext); - file.transferTo(filePath); - var fileMetaInfo = new FileMetaInfo(); - fileMetaInfo.setName(file.getOriginalFilename()); - fileMetaInfo.setContentType(file.getContentType()); - fileMetaInfo.setExtension(ext); - fileMetaInfo.setSavePath(filePath.toFile().getAbsolutePath()); - fileMetaInfoRepository.save(fileMetaInfo); - return ApiResult.data(fileMetaInfo); - } catch (Exception e) { - log.error(e.getMessage(),e); - return ApiResult.fail(e.getMessage()); - } - } - - /** - * 预览文件 - * @param fileId 文件id - * @return 文件内容 - */ - @GetMapping("/platform/file/view/{fileId}") - public ResponseEntity uploadFile(@PathVariable("fileId") String fileId) { - return this.fileMetaInfoRepository.findById(fileId).map(item->{ - try { - var bytes = Files.readAllBytes(Paths.get(item.getSavePath())); - return ResponseEntity.ok() - .contentType(MediaType.parseMediaType(item.getContentType())) - .body(bytes); - } catch (IOException e) { - return ResponseEntity.internalServerError().build(); - } - - }).orElse(ResponseEntity.internalServerError().build()); - - } - - -} \ No newline at end of file diff --git a/src/main/java/com/xjhs/findmemerchant/file/dao/FileMetaInfo.java b/src/main/java/com/xjhs/findmemerchant/file/dao/FileMetaInfo.java deleted file mode 100644 index d735ee9..0000000 --- a/src/main/java/com/xjhs/findmemerchant/file/dao/FileMetaInfo.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.xjhs.findmemerchant.file.dao; - -import com.xjhs.findmemerchant.common.jpa.id.SnowflakeGenerated; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import lombok.Data; -import org.hibernate.annotations.Comment; - -import java.time.LocalDateTime; - - -/** - * 文件信息表 - */ -@Data -@Entity -@Comment("文件信息表") -public class FileMetaInfo { - @Id - @SnowflakeGenerated - @Comment("主键") - private Long id; - @Comment("文件原始名称") - private String name; - @Comment("文件媒体类型") - private String contentType; - @Comment("文件扩展名称") - @Column(length = 10) - private String extension; - @Comment("本地存储路径") - private String savePath; - @Comment("是否已迁移到云服务") - private boolean moveToCloud = false; - @Comment("云对象id") - @Column(length = 50) - private String cloudObjectId; - @Comment("创建时间") - private LocalDateTime createTime = LocalDateTime.now(); - -} \ No newline at end of file diff --git a/src/main/java/com/xjhs/findmemerchant/file/dao/FileMetaInfoRepository.java b/src/main/java/com/xjhs/findmemerchant/file/dao/FileMetaInfoRepository.java deleted file mode 100644 index a7f845a..0000000 --- a/src/main/java/com/xjhs/findmemerchant/file/dao/FileMetaInfoRepository.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.xjhs.findmemerchant.file.dao; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; -import org.springframework.stereotype.Repository; - -@Repository -public interface FileMetaInfoRepository extends JpaRepository, JpaSpecificationExecutor { - -} \ No newline at end of file diff --git a/src/main/java/com/xjhs/findmemerchant/mapper/EmployeeMapper.java b/src/main/java/com/xjhs/findmemerchant/mapper/EmployeeMapper.java new file mode 100644 index 0000000..5ec5ed3 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/mapper/EmployeeMapper.java @@ -0,0 +1,20 @@ +package com.xjhs.findmemerchant.mapper; + +import com.xjhs.findmemerchant.dto.member.EmployeeDto; +import com.xjhs.findmemerchant.entity.Employee; +import com.xjhs.findmemerchant.vo.member.EmployeeCreateVo; +import com.xjhs.findmemerchant.vo.member.EmployeeUpdateVo; +import org.mapstruct.*; + +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE,unmappedSourcePolicy = ReportingPolicy.IGNORE) +public interface EmployeeMapper { + @Mapping(target = "storeId",source = "store.id") + @Mapping(target = "roleId",source = "role.id") + EmployeeDto toDto(Employee employee); + + Employee toEntity(EmployeeCreateVo createVo); + + @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) + void updateEntityFormUpdateVo(EmployeeUpdateVo updateVo, @MappingTarget Employee employee); + +} diff --git a/src/main/java/com/xjhs/findmemerchant/mapper/MerchantMapper.java b/src/main/java/com/xjhs/findmemerchant/mapper/MerchantMapper.java index 95c0db5..e74e846 100644 --- a/src/main/java/com/xjhs/findmemerchant/mapper/MerchantMapper.java +++ b/src/main/java/com/xjhs/findmemerchant/mapper/MerchantMapper.java @@ -1,12 +1,15 @@ package com.xjhs.findmemerchant.mapper; -import com.xjhs.findmemerchant.dto.merchant.MerchantDto; +import com.xjhs.findmemerchant.dto.MerchantDto; import com.xjhs.findmemerchant.entity.Merchant; import org.mapstruct.Mapper; +import org.mapstruct.Mapping; import org.mapstruct.ReportingPolicy; @Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE,unmappedSourcePolicy = ReportingPolicy.IGNORE) public interface MerchantMapper { + + @Mapping(target = "authStatusDesc",source = "authStatus.desc") MerchantDto toDto(Merchant merchant); } diff --git a/src/main/java/com/xjhs/findmemerchant/mapper/StoreMapper.java b/src/main/java/com/xjhs/findmemerchant/mapper/StoreMapper.java new file mode 100644 index 0000000..0db647e --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/mapper/StoreMapper.java @@ -0,0 +1,32 @@ +package com.xjhs.findmemerchant.mapper; + +import com.xjhs.findmemerchant.dto.store.BusinessPeriodDto; +import com.xjhs.findmemerchant.dto.store.StoreBusinessStatusDto; +import com.xjhs.findmemerchant.dto.store.StoreDto; +import com.xjhs.findmemerchant.entity.BusinessPeriod; +import com.xjhs.findmemerchant.entity.Store; +import com.xjhs.findmemerchant.vo.store.BusinessPeriodVo; +import com.xjhs.findmemerchant.vo.store.StoreBusinessStatusUpdateVo; +import com.xjhs.findmemerchant.vo.store.StoreCreateVo; +import com.xjhs.findmemerchant.vo.store.StoreUpdateVo; +import org.mapstruct.*; + +import java.util.List; + +@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE,unmappedSourcePolicy = ReportingPolicy.IGNORE) +public interface StoreMapper { + StoreDto toDto(Store store); + StoreBusinessStatusDto toBusinessStatusDto(Store store); + Store toEntity(StoreCreateVo createVo); + Store toEntity(StoreUpdateVo updateVo); + + @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) + void updateFromVo(StoreUpdateVo vo, @MappingTarget Store entity); + @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) + void updateFromBusinessUpdateVo(StoreBusinessStatusUpdateVo updateVo,@MappingTarget Store store); + + BusinessPeriod toEntity(BusinessPeriodVo vo); + @Mapping(source = "store.id",target = "storeId") + BusinessPeriodDto toDto(BusinessPeriod entity); + List toDtoList(List entityList); +} diff --git a/src/main/java/com/xjhs/findmemerchant/mapper/SystemUserMapper.java b/src/main/java/com/xjhs/findmemerchant/mapper/SystemUserMapper.java deleted file mode 100644 index cca0ad0..0000000 --- a/src/main/java/com/xjhs/findmemerchant/mapper/SystemUserMapper.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.xjhs.findmemerchant.mapper; - -import com.xjhs.findmemerchant.security.LoginUser; -import com.xjhs.findmemerchant.system.entity.SystemUser; -import org.mapstruct.Mapper; -import org.mapstruct.Mapping; -import org.mapstruct.ReportingPolicy; - - -@Mapper(componentModel = "spring",unmappedTargetPolicy = ReportingPolicy.IGNORE,unmappedSourcePolicy = ReportingPolicy.IGNORE) -public interface SystemUserMapper { - - @Mapping(target = "merchantId",source = "systemUser.merchant.id") - LoginUser toLoginUserInfo(SystemUser systemUser); -} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/ActivityRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/ActivityRepository.java new file mode 100644 index 0000000..fd53c89 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/ActivityRepository.java @@ -0,0 +1,14 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Activity; +import com.xjhs.findmemerchant.types.ActivityStatus; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface ActivityRepository extends JpaRepository { + + List findByMerchant_Id(Long merchantId); + + List findByStatus(ActivityStatus status); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/BankCardRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/BankCardRepository.java new file mode 100644 index 0000000..7c2df2b --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/BankCardRepository.java @@ -0,0 +1,25 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.BankCard; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +/** + * 商家银行卡仓储 + */ +public interface BankCardRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按商家查询所有银行卡 + */ + List findByMerchant_Id(Long merchantId); + + /** + * 查询商家的默认卡 + */ + Optional findByMerchant_IdAndIsDefaultTrue(Long merchantId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/BusinessLicenseRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/BusinessLicenseRepository.java new file mode 100644 index 0000000..5dcf65a --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/BusinessLicenseRepository.java @@ -0,0 +1,16 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.BusinessLicense; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +public interface BusinessLicenseRepository extends JpaRepository, + JpaSpecificationExecutor { + + List findByMerchant_Id(Long merchantId); + + Optional findTopByMerchant_IdOrderByCreatedAtDesc(Long merchantId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/BusinessPeriodRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/BusinessPeriodRepository.java new file mode 100644 index 0000000..0980b1b --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/BusinessPeriodRepository.java @@ -0,0 +1,24 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.BusinessPeriod; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 门店营业时间段仓储 + */ +public interface BusinessPeriodRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按门店查询所有营业时间段 + */ + List findByStore_Id(Long storeId); + + /** + * 按门店 + 周几查询启用的时间段 + */ + List findByStore_IdAndDayOfWeekAndIsEnabledTrue(Long storeId, Byte dayOfWeek); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/CouponCodeRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/CouponCodeRepository.java new file mode 100644 index 0000000..2d21ff2 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/CouponCodeRepository.java @@ -0,0 +1,30 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.CouponCode; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +/** + * 优惠券码仓储 + */ +public interface CouponCodeRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按券模板查询券码 + */ + List findByCoupon_Id(Long couponId); + + /** + * 按会员查询券码 + */ + List findByMember_Id(Long memberId); + + /** + * 按券码查询 + */ + Optional findByCode(String code); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/CouponRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/CouponRepository.java new file mode 100644 index 0000000..6638486 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/CouponRepository.java @@ -0,0 +1,29 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Coupon; +import com.xjhs.findmemerchant.types.CouponStatus; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Optional; + +/** + * 优惠券模板仓储 + */ +public interface CouponRepository extends JpaRepository { + + /** + * 按商家查询优惠券 + */ + List findByMerchant_Id(Long merchantId); + + /** + * 按状态查询优惠券 + */ + List findByStatus(CouponStatus status); + + /** + * 按ID + 商家ID 查询(防越权) + */ + Optional findByIdAndMerchant_Id(Long id, Long merchantId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/CouponStoreRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/CouponStoreRepository.java new file mode 100644 index 0000000..8e762d8 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/CouponStoreRepository.java @@ -0,0 +1,20 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.CouponStore; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +/** + * 优惠券与门店关联仓储 + */ +public interface CouponStoreRepository extends JpaSpecificationExecutor,JpaRepository { + + List findByCoupon_Id(Long couponId); + + List findByStore_Id(Long storeId); + + Optional findByCoupon_IdAndStore_Id(Long couponId, Long storeId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/EmployeeRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/EmployeeRepository.java new file mode 100644 index 0000000..042e926 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/EmployeeRepository.java @@ -0,0 +1,17 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Employee; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +/** + * 员工仓储 + */ +public interface EmployeeRepository extends JpaRepository, + JpaSpecificationExecutor { + + List findByStoreId(Long storeId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/HealthCertificateRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/HealthCertificateRepository.java new file mode 100644 index 0000000..99ba8e9 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/HealthCertificateRepository.java @@ -0,0 +1,15 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.HealthCertificate; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +public interface HealthCertificateRepository extends JpaRepository, + JpaSpecificationExecutor { + + List findByStore_Id(Long storeId); + + List findByEmployee_Id(Long employeeId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/MemberRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/MemberRepository.java new file mode 100644 index 0000000..87edaf7 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/MemberRepository.java @@ -0,0 +1,27 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Member; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +/** + * 会员仓储 + */ +public interface MemberRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按商家查询会员 + */ + List findByMerchant_Id(Long merchantId); + + /** + * 按商家 + 手机号查询(唯一) + */ + Optional findByPhone(String phone); + + +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/MerchantRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/MerchantRepository.java index ae7944c..0a51aaa 100644 --- a/src/main/java/com/xjhs/findmemerchant/repository/MerchantRepository.java +++ b/src/main/java/com/xjhs/findmemerchant/repository/MerchantRepository.java @@ -6,6 +6,16 @@ import org.springframework.data.jpa.repository.JpaSpecificationExecutor; import java.util.Optional; -public interface MerchantRepository extends JpaSpecificationExecutor, JpaRepository { - Optional findBySystemUserPhone(String phone); +/** + * 商家仓储 + */ +public interface MerchantRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 根据手机号查询 + */ + Optional findByPhone(String phone); + + Boolean existsByPhone(String phone); } diff --git a/src/main/java/com/xjhs/findmemerchant/repository/MessageRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/MessageRepository.java new file mode 100644 index 0000000..79989a0 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/MessageRepository.java @@ -0,0 +1,26 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Message; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 消息仓储 + */ +public interface MessageRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按商家查询消息 + */ + List findByMerchant_Id(Long merchantId); + + List findByMerchant_IdAndIsRead(Long merchantId, Boolean isRead); + + /** + * 统计未读消息数量 + */ + long countByMerchant_IdAndIsRead(Long merchantId, Boolean isRead); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/OrderItemRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/OrderItemRepository.java new file mode 100644 index 0000000..138e3c9 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/OrderItemRepository.java @@ -0,0 +1,21 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.OrderItem; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 订单明细仓储 + */ +public interface OrderItemRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按订单查询订单明细 + */ + List findByOrder_Id(Long orderId); + + List findByProductId(Long productId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/OrderRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/OrderRepository.java new file mode 100644 index 0000000..f32769e --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/OrderRepository.java @@ -0,0 +1,27 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Order; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +/** + * 订单仓储 + */ +public interface OrderRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按订单号查询(唯一) + */ + Optional findByOrderNo(String orderNo); + + /** + * 按门店查询订单 + */ + List findByStore_Id(Long storeId); + + List findByMember_Id(Long memberId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/ProductCategoryRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/ProductCategoryRepository.java new file mode 100644 index 0000000..59f6448 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/ProductCategoryRepository.java @@ -0,0 +1,24 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.ProductCategory; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 商品分类仓储 + */ +public interface ProductCategoryRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按商家查询所有分类 + */ + List findByMerchant_Id(Long merchantId); + + /** + * 查询某商家下指定父分类的子分类 + */ + List findByMerchantIdAndParentId(Long merchantId, Long parentId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/ProductRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/ProductRepository.java new file mode 100644 index 0000000..77a861f --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/ProductRepository.java @@ -0,0 +1,32 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Product; +import com.xjhs.findmemerchant.types.ProductStatus; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 商品仓储 + */ +public interface ProductRepository extends JpaRepository, + JpaSpecificationExecutor { + + List findByMerchant_Id(Long merchantId); + + /** + * 按门店查询商品 + */ + List findByStoreId(Long storeId); + + /** + * 按分类查询商品 + */ + List findByCategoryId(Long categoryId); + + /** + * 按状态查询商品 + */ + List findByStatus(ProductStatus status); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/ProductSKURepository.java b/src/main/java/com/xjhs/findmemerchant/repository/ProductSKURepository.java new file mode 100644 index 0000000..71f2a8d --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/ProductSKURepository.java @@ -0,0 +1,24 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.ProductSKU; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 商品SKU仓储 + */ +public interface ProductSKURepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 查询商品下的所有SKU + */ + List findByProductId(Long productId); + + /** + * 按编码查询 + */ + List findBySkuCode(String skuCode); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/ReviewReplyRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/ReviewReplyRepository.java new file mode 100644 index 0000000..42a1fc7 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/ReviewReplyRepository.java @@ -0,0 +1,16 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.ReviewReply; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Optional; + +/** + * 评价回复仓储 + */ +public interface ReviewReplyRepository extends JpaRepository, + JpaSpecificationExecutor { + + Optional findByReviewId(Long reviewId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/ReviewRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/ReviewRepository.java new file mode 100644 index 0000000..79a70cd --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/ReviewRepository.java @@ -0,0 +1,22 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Review; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 用户评价仓储 + */ +public interface ReviewRepository extends JpaRepository, + JpaSpecificationExecutor { + + List findByMerchant_Id(Long merchantId); + + List findByStoreId(Long storeId); + + List findByOrderId(Long orderId); + + List findByUserId(Long userId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/RoleRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/RoleRepository.java new file mode 100644 index 0000000..7971f97 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/RoleRepository.java @@ -0,0 +1,19 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Role; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Optional; + +/** + * 角色仓储 + */ +public interface RoleRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按编码查询角色 + */ + Optional findByCode(String code); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/SettlementRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/SettlementRepository.java new file mode 100644 index 0000000..275b644 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/SettlementRepository.java @@ -0,0 +1,25 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Settlement; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +/** + * 结算记录仓储 + */ +public interface SettlementRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按结算单号查询 + */ + Optional findBySettlementNo(String settlementNo); + + /** + * 按商家查询结算记录 + */ + List findByMerchantId(Long merchantId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/StoreRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/StoreRepository.java new file mode 100644 index 0000000..2ee48b0 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/StoreRepository.java @@ -0,0 +1,22 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Store; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; +import java.util.Optional; + +/** + * 门店仓储 + */ +public interface StoreRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按商家查询门店 + */ + List findByMerchantId(Long merchantId); + + Optional findByMerchant_IdAndId(Long merchantId, Long id); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/TransactionRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/TransactionRepository.java new file mode 100644 index 0000000..ef1d01b --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/TransactionRepository.java @@ -0,0 +1,24 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Transaction; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 钱包交易流水仓储 + */ +public interface TransactionRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按钱包查询流水 + */ + List findByWalletId(Long walletId); + + /** + * 按商家查询流水 + */ + List findByMerchantId(Long merchantId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/WalletRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/WalletRepository.java new file mode 100644 index 0000000..515f6b1 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/WalletRepository.java @@ -0,0 +1,19 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Wallet; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.Optional; + +/** + * 商家钱包仓储 + */ +public interface WalletRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 根据商家ID查询钱包(唯一) + */ + Optional findByMerchantId(Long merchantId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/repository/WithdrawalRepository.java b/src/main/java/com/xjhs/findmemerchant/repository/WithdrawalRepository.java new file mode 100644 index 0000000..0754d57 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/repository/WithdrawalRepository.java @@ -0,0 +1,24 @@ +package com.xjhs.findmemerchant.repository; + +import com.xjhs.findmemerchant.entity.Withdrawal; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +import java.util.List; + +/** + * 提现仓储 + */ +public interface WithdrawalRepository extends JpaRepository, + JpaSpecificationExecutor { + + /** + * 按商家查提现记录 + */ + List findByMerchantId(Long merchantId); + + /** + * 按钱包查提现记录 + */ + List findByWalletId(Long walletId); +} diff --git a/src/main/java/com/xjhs/findmemerchant/security/JwtAuthenticationFilter.java b/src/main/java/com/xjhs/findmemerchant/security/JwtAuthenticationFilter.java index bb23f89..fd97ad4 100644 --- a/src/main/java/com/xjhs/findmemerchant/security/JwtAuthenticationFilter.java +++ b/src/main/java/com/xjhs/findmemerchant/security/JwtAuthenticationFilter.java @@ -1,7 +1,7 @@ package com.xjhs.findmemerchant.security; -import com.xjhs.findmemerchant.mapper.SystemUserMapper; +import com.xjhs.findmemerchant.repository.MemberRepository; import com.xjhs.findmemerchant.repository.MerchantRepository; import com.xjhs.findmemerchant.security.sms.SmsAuthenticationToken; import jakarta.servlet.FilterChain; @@ -24,18 +24,24 @@ public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtTokenService jwtTokenService; private final MerchantRepository merchantRepository; - private final SystemUserMapper systemUserMapper; + private final MemberRepository memberRepository; - private SmsAuthenticationToken getAuthenticationToken(String phone) throws Exception { + + private SmsAuthenticationToken getAuthenticationToken(String phone) throws Exception { // 手机号查商家 - var merchant = merchantRepository.findBySystemUserPhone(phone).orElse(null); - if (merchant != null) { + var merchant = merchantRepository.findByPhone(phone).orElse(null); + if(merchant != null){ var authorities = List.of(new SimpleGrantedAuthority("ROLE_USER")); - var loginUser = systemUserMapper.toLoginUserInfo(merchant.getSystemUser()); - return new SmsAuthenticationToken(loginUser, authorities); + return new SmsAuthenticationToken(merchant, authorities); } - throw new Exception("用户信息不存在"); + // 手机号查员工 + var member = memberRepository.findByPhone(phone).orElse(null); + if(member != null){ + var authorities = List.of(new SimpleGrantedAuthority("ROLE_MEMBER")); + return new SmsAuthenticationToken(member, authorities); + } + throw new Exception("用户信息不存在"); } @Override diff --git a/src/main/java/com/xjhs/findmemerchant/security/LoginUser.java b/src/main/java/com/xjhs/findmemerchant/security/LoginUser.java deleted file mode 100644 index 4c7b133..0000000 --- a/src/main/java/com/xjhs/findmemerchant/security/LoginUser.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.xjhs.findmemerchant.security; - -import lombok.Data; - -/** - * 登录用户信息 - */ -@Data -public class LoginUser { - /** - * 用户id - */ - private Long userId; - /** - * 手机号 - */ - private String phone; - /** - * 关联商户id,不存在则为null - */ - private Long merchantId; - -} diff --git a/src/main/java/com/xjhs/findmemerchant/security/sms/SmsAuthenticationProvider.java b/src/main/java/com/xjhs/findmemerchant/security/sms/SmsAuthenticationProvider.java index fe5acfc..199089a 100644 --- a/src/main/java/com/xjhs/findmemerchant/security/sms/SmsAuthenticationProvider.java +++ b/src/main/java/com/xjhs/findmemerchant/security/sms/SmsAuthenticationProvider.java @@ -1,31 +1,25 @@ package com.xjhs.findmemerchant.security.sms; -import com.xjhs.findmemerchant.mapper.SystemUserMapper; -import com.xjhs.findmemerchant.system.SystemUserService; +import com.xjhs.findmemerchant.repository.MemberRepository; +import com.xjhs.findmemerchant.repository.MerchantRepository; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.CredentialsExpiredException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Objects; -@Slf4j @Component @RequiredArgsConstructor public class SmsAuthenticationProvider implements AuthenticationProvider { private final SmsCodeService smsCodeService; - private final SystemUserService systemUserService; - private final SystemUserMapper systemUserMapper; + private final MerchantRepository merchantRepository; + private final MemberRepository memberRepository; @Override - @Transactional(readOnly = true) public Authentication authenticate(Authentication authentication) throws AuthenticationException { SmsAuthenticationToken token = (SmsAuthenticationToken) authentication; String phone = (String) token.getPrincipal(); @@ -33,17 +27,21 @@ public class SmsAuthenticationProvider implements AuthenticationProvider { try { this.smsCodeService.verifyCode(phone,"login" ,code); } catch (Exception e) { - throw new CredentialsExpiredException(e.getMessage()); + throw new UsernameNotFoundException(e.getMessage()); } - // 取回商家身份 - var systemUser = systemUserService.getAndRegisterByPhone(phone); - if (Objects.isNull(systemUser.getMerchant())){ - throw new UsernameNotFoundException("手机号码未注册"); + // 手机号查商家 + var merchant = merchantRepository.findByPhone(phone).orElse(null); + if(merchant != null){ + var authorities = List.of(new SimpleGrantedAuthority("ROLE_USER")); + return new SmsAuthenticationToken(merchant, authorities); } - - var loginUser = this.systemUserMapper.toLoginUserInfo(systemUser); - var authorities = List.of(new SimpleGrantedAuthority("ADMIN")); - return new SmsAuthenticationToken(loginUser, authorities); + // 手机号查员工 + var member = memberRepository.findByPhone(phone).orElse(null); + if(member != null){ + var authorities = List.of(new SimpleGrantedAuthority("ROLE_MEMBER")); + return new SmsAuthenticationToken(member, authorities); + } + throw new UsernameNotFoundException("用户信息不存在"); } @Override diff --git a/src/main/java/com/xjhs/findmemerchant/security/sms/SmsCodeService.java b/src/main/java/com/xjhs/findmemerchant/security/sms/SmsCodeService.java index 25356e9..ca61396 100644 --- a/src/main/java/com/xjhs/findmemerchant/security/sms/SmsCodeService.java +++ b/src/main/java/com/xjhs/findmemerchant/security/sms/SmsCodeService.java @@ -17,7 +17,7 @@ public class SmsCodeService { private static final String SMS_CODE_KEY_PREFIX = "sms:code:"; /** 验证码有效期:5 分钟 */ - private static final Duration SMS_CODE_TTL = Duration.ofMinutes(1); + private static final Duration SMS_CODE_TTL = Duration.ofMinutes(5); private final StringRedisTemplate redisTemplate; private final Random random = new Random(); @@ -29,10 +29,10 @@ public class SmsCodeService { } /** - * 生成 4 位数字验证码 + * 生成 6 位数字验证码 */ private String generateCode() { - return String.format("%04d", random.nextInt(10000)); + return String.format("%06d", random.nextInt(1_000_000)); } /** @@ -64,6 +64,7 @@ public class SmsCodeService { // 对齐 Go 里的 ErrSMSCodeExpired throw new Exception("验证码已过期或未发送"); } + if (!realCode.equals(inputCode)) { // 不正确,但不删除,让用户继续尝试(错误次数由 AuthService 控制) throw new Exception("验证码错误"); diff --git a/src/main/java/com/xjhs/findmemerchant/service/MerchantService.java b/src/main/java/com/xjhs/findmemerchant/service/MerchantService.java new file mode 100644 index 0000000..7f3e11b --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/service/MerchantService.java @@ -0,0 +1,85 @@ +package com.xjhs.findmemerchant.service; + +import com.xjhs.findmemerchant.dto.MerchantDto; +import com.xjhs.findmemerchant.mapper.MerchantMapper; +import com.xjhs.findmemerchant.repository.MerchantRepository; +import com.xjhs.findmemerchant.types.AuthStatus; +import com.xjhs.findmemerchant.vo.merchant.MerchantUpdateVo; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Slf4j +@Service +@RequiredArgsConstructor +public class MerchantService { + public final MerchantRepository merchantRepository; + public final MerchantMapper merchantMapper; + + /** + * 根据商家id获取商家信息 + * @param id 商家id + * @return 商家信息 + */ + public Optional getById(Long id) { + return this.merchantRepository.findById(id) + .map(this.merchantMapper::toDto); + } + + /** + * 更新商家信息 + * @param id 商家id + * @param merchantUpdateVo 更新信息 + * @return 商家信息 + * @throws Exception 错误信息 + */ + @Transactional(rollbackOn = Exception.class) + public MerchantDto updateMerchant(Long id, MerchantUpdateVo merchantUpdateVo) throws Exception { + var entity = this.merchantRepository.findById(id) + .orElseThrow(() -> new Exception("商家信息不存在")); + entity.setRealName(merchantUpdateVo.getRealName()); + this.merchantRepository.save(entity); + return this.merchantMapper.toDto(entity); + } + + /** + * 商家身份证信息验证 + * + * @param id 商家id + * @param idCardNo 身份证号 + * @param realName 真实姓名 + * @throws Exception 验证异常信息 + */ + @Transactional(rollbackOn = Exception.class) + public MerchantDto verifyMerchant(Long id, String idCardNo, String realName) throws Exception { + var entity = this.merchantRepository.findById(id) + .orElseThrow(() -> new Exception("商家信息不存在")); + if (entity.getAuthStatus() == AuthStatus.VERIFIED) { + throw new Exception("商家信息已认证"); + } + this.idCardVerify(idCardNo, realName); + entity.setAuthStatus(AuthStatus.VERIFIED); + entity.setIdCardNo(idCardNo); + entity.setIdCardEncrypted(idCardNo); + entity.setRealName(realName); + this.merchantRepository.save(entity); + return this.merchantMapper.toDto(entity); + } + + + /** + * 第三方验证 + * @param idCardNo 身份证号码 + * @param realName 真实姓名 + * @throws Exception 验证失败信息 + */ + public void idCardVerify(String idCardNo, String realName) throws Exception { + // TODO: 调用腾讯云身份证二要素核验接口 + throw new Exception("验证失败,正在开发中"); + } + + +} diff --git a/src/main/java/com/xjhs/findmemerchant/service/StoreService.java b/src/main/java/com/xjhs/findmemerchant/service/StoreService.java new file mode 100644 index 0000000..acdc4b9 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/service/StoreService.java @@ -0,0 +1,34 @@ +package com.xjhs.findmemerchant.service; + +import com.xjhs.findmemerchant.common.jpa.query.JpaSpecs; +import com.xjhs.findmemerchant.dto.store.StoreDto; +import com.xjhs.findmemerchant.mapper.StoreMapper; +import com.xjhs.findmemerchant.repository.StoreRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class StoreService { + + private final StoreRepository storeRepository; + private final StoreMapper storeMapper; + + /** + * 分页查询 + * + * @param pageable 分页参数 + * @param merchantId 商家id + * @return 分页数据 + */ + public Page findPage(Pageable pageable, Long merchantId) { + return this.storeRepository.findAll(Specification.allOf( + JpaSpecs.eq("merchant.id", merchantId) + ), pageable).map(this.storeMapper::toDto); + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/system/SystemUserService.java b/src/main/java/com/xjhs/findmemerchant/system/SystemUserService.java deleted file mode 100644 index e590d2d..0000000 --- a/src/main/java/com/xjhs/findmemerchant/system/SystemUserService.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.xjhs.findmemerchant.system; - -import com.xjhs.findmemerchant.system.entity.SystemUser; -import com.xjhs.findmemerchant.system.repository.SystemUserRepository; -import lombok.AllArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.Optional; - -@Slf4j -@Service -@AllArgsConstructor -public class SystemUserService { - - private final SystemUserRepository systemUserRepository; - /** - * 通过手机号获取用户信息,不存在则进行注册 - * - * @param phone 手机号码 - * @return 用户信息 - */ - public SystemUser getAndRegisterByPhone(String phone) { - return this.systemUserRepository.findByPhoneAndDeleteTimeIsNull(phone) - .orElseGet(() -> { - var systemUser = new SystemUser(); - systemUser.setPhone(phone); - return this.systemUserRepository.save(systemUser); - }); - } - - public Optional findByPhone(String phone){ - return this.systemUserRepository.findByPhoneAndDeleteTimeIsNull(phone); - } -} diff --git a/src/main/java/com/xjhs/findmemerchant/system/entity/SystemUser.java b/src/main/java/com/xjhs/findmemerchant/system/entity/SystemUser.java deleted file mode 100644 index 39b4264..0000000 --- a/src/main/java/com/xjhs/findmemerchant/system/entity/SystemUser.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.xjhs.findmemerchant.system.entity; - -import com.xjhs.findmemerchant.common.jpa.AbstractBaseEntity; -import com.xjhs.findmemerchant.entity.Merchant; -import jakarta.persistence.*; -import lombok.Getter; -import lombok.Setter; -import org.hibernate.annotations.Comment; - -/** - * 用户信息表 - */ - -@Getter -@Setter -@Entity -@Table -public class SystemUser extends AbstractBaseEntity { - @Column(columnDefinition = "CHAR(11)",length = 11) - @Comment("用户手机号") - private String phone; - @Column(length = 20) - @Comment("用户真实姓名") - private String realName; - @Column(length = 18) - @Comment("身份证号") - private String idCardNo; - @OneToOne(mappedBy = "systemUser",cascade = CascadeType.ALL) - private Merchant merchant; - -} diff --git a/src/main/java/com/xjhs/findmemerchant/system/repository/SystemUserRepository.java b/src/main/java/com/xjhs/findmemerchant/system/repository/SystemUserRepository.java deleted file mode 100644 index bae01fc..0000000 --- a/src/main/java/com/xjhs/findmemerchant/system/repository/SystemUserRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.xjhs.findmemerchant.system.repository; - -import com.xjhs.findmemerchant.system.entity.SystemUser; -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; - -import java.util.Optional; - -public interface SystemUserRepository extends JpaRepository , JpaSpecificationExecutor { - Optional findByPhoneAndDeleteTimeIsNull(String phone); -} diff --git a/src/main/java/com/xjhs/findmemerchant/types/ActivityStatus.java b/src/main/java/com/xjhs/findmemerchant/types/ActivityStatus.java new file mode 100644 index 0000000..a0d47a7 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/ActivityStatus.java @@ -0,0 +1,52 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 活动状态 + * 0-未开始 1-进行中 2-已结束 3-已下架 + */ +@Getter +@AllArgsConstructor +public enum ActivityStatus { + /** + * 未开始 + */ + NOT_STARTED("未开始"), + /** + * 进行中 + */ + ONGOING("进行中"), + /** + * 已结束 + */ + ENDED("已结束"), + /** + * 已下架 + */ + OFFLINE("已下架"); + + private final String desc; + + public static ActivityStatus fromCode(Byte code) { + if (code == null) return null; + + return switch (code) { + case 0 -> NOT_STARTED; + case 1 -> ONGOING; + case 2 -> ENDED; + case 3 -> OFFLINE; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case NOT_STARTED -> 0; + case ONGOING -> 1; + case ENDED -> 2; + case OFFLINE -> 3; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/ActivityType.java b/src/main/java/com/xjhs/findmemerchant/types/ActivityType.java new file mode 100644 index 0000000..c07b365 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/ActivityType.java @@ -0,0 +1,44 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum ActivityType { + + /** + * 团购 + */ + GROUP_BUY("团购"), + /** + * 折扣 + */ + DISCOUNT("折扣"), + /** + * 限时优惠 + */ + FLASH_SALE("限时优惠"); + + private final String desc; + + // 数据库存储 tinyint -> 转为枚举 + public static ActivityType fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 1 -> GROUP_BUY; + case 2 -> DISCOUNT; + case 3 -> FLASH_SALE; + default -> null; + }; + } + + // 枚举 -> 数据库存储值 + public byte code() { + return switch (this) { + case GROUP_BUY -> 1; + case DISCOUNT -> 2; + case FLASH_SALE -> 3; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/AuthStatus.java b/src/main/java/com/xjhs/findmemerchant/types/AuthStatus.java new file mode 100644 index 0000000..4c817cd --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/AuthStatus.java @@ -0,0 +1,40 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 商家实名认证状态 + * 0-未认证 1-已认证 + */ +@Getter +@AllArgsConstructor +public enum AuthStatus { + + /** + * 未认证 + */ + NOT_VERIFIED("未认证"), + /** + * 已认证 + */ + VERIFIED("已认证"); + + private final String desc; + + public static AuthStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> NOT_VERIFIED; + case 1 -> VERIFIED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case NOT_VERIFIED -> 0; + case VERIFIED -> 1; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/BusinessLicenseStatus.java b/src/main/java/com/xjhs/findmemerchant/types/BusinessLicenseStatus.java new file mode 100644 index 0000000..6643d75 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/BusinessLicenseStatus.java @@ -0,0 +1,47 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 营业执照审核状态 + * 0-待审核 1-已通过 2-已拒绝 + */ +@Getter +@AllArgsConstructor +public enum BusinessLicenseStatus { + + /** + * 待审核 + */ + PENDING("待审核"), + /** + * 已通过 + */ + APPROVED("已通过"), + /** + * 已拒绝 + */ + REJECTED("已拒绝"); + + private final String desc; + + public static BusinessLicenseStatus fromCode(Byte code) { + if (code == null) return null; + + return switch (code) { + case 0 -> PENDING; + case 1 -> APPROVED; + case 2 -> REJECTED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case PENDING -> 0; + case APPROVED -> 1; + case REJECTED -> 2; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/BusinessStatus.java b/src/main/java/com/xjhs/findmemerchant/types/BusinessStatus.java new file mode 100644 index 0000000..e8622cc --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/BusinessStatus.java @@ -0,0 +1,46 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 门店营业状态 + * 1-营业中 0-已打烊 2-临时打烊 + */ +@Getter +@AllArgsConstructor +public enum BusinessStatus { + + /** + * 已打烊 + */ + CLOSED("已打烊"), // 0 + /** + * 营业中 + */ + OPEN("营业中"), // 1 + /** + * 临时打烊 + */ + TEMP_CLOSED("临时打烊"); // 2 + + private final String desc; + + public static BusinessStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> CLOSED; + case 1 -> OPEN; + case 2 -> TEMP_CLOSED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case CLOSED -> 0; + case OPEN -> 1; + case TEMP_CLOSED -> 2; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/CommonStatus.java b/src/main/java/com/xjhs/findmemerchant/types/CommonStatus.java new file mode 100644 index 0000000..a98d6a2 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/CommonStatus.java @@ -0,0 +1,40 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 通用启用/禁用状态 + * 0-禁用 1-启用 + */ +@Getter +@AllArgsConstructor +public enum CommonStatus { + + /** + * 禁用 + */ + DISABLED("禁用"), + /** + * 启用 + */ + ENABLED("启用"); + + private final String desc; + + public static CommonStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> DISABLED; + case 1 -> ENABLED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case DISABLED -> 0; + case ENABLED -> 1; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/CouponCodeStatus.java b/src/main/java/com/xjhs/findmemerchant/types/CouponCodeStatus.java new file mode 100644 index 0000000..bb3e650 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/CouponCodeStatus.java @@ -0,0 +1,46 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 券码状态 + * 0-未领取 1-已领取 2-已核销 3-已过期 + */ +@Getter +@AllArgsConstructor +public enum CouponCodeStatus { + + /** + * 未领取 + */ + UNCLAIMED("未领取"), + /** + * 已领取 + */ + CLAIMED("已领取"), + /** + * 已核销 + */ + VERIFIED("已核销"), + /** + * 已过期 + */ + EXPIRED("已过期"); + + private final String desc; + + + public static CouponCodeStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> UNCLAIMED; + case 1 -> CLAIMED; + case 2 -> VERIFIED; + case 3 -> EXPIRED; + default -> null; + }; + } + + +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/CouponStatus.java b/src/main/java/com/xjhs/findmemerchant/types/CouponStatus.java new file mode 100644 index 0000000..f9ad8fb --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/CouponStatus.java @@ -0,0 +1,46 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 优惠券状态 + * 0-下架 1-进行中 2-已结束 + */ +@Getter +@AllArgsConstructor +public enum CouponStatus { + + /** + * 下架 + */ + OFFLINE("下架"), + /** + * 进行中 + */ + ONLINE("进行中"), + /** + * 已结束 + */ + ENDED("已结束"); + + private final String desc; + + public static CouponStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> OFFLINE; + case 1 -> ONLINE; + case 2 -> ENDED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case OFFLINE -> 0; + case ONLINE -> 1; + case ENDED -> 2; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/CouponType.java b/src/main/java/com/xjhs/findmemerchant/types/CouponType.java new file mode 100644 index 0000000..7a4118a --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/CouponType.java @@ -0,0 +1,58 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 优惠券类型 + * 1-折扣券 2-满减券 3-现金券 4-赠品券 + */ +@Getter +@AllArgsConstructor +public enum CouponType { + + /** + * 折扣券 + */ + DISCOUNT("折扣券"), + /** + * 满减券 + */ + REDUCE("满减券"), + /** + * 现金券 + */ + CASH("现金券"), + /** + * 赠品券 + */ + GIFT("赠品券"); + + private final String desc; + + /** + * 数据库 tinyint -> 枚举 + */ + public static CouponType fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 1 -> DISCOUNT; + case 2 -> REDUCE; + case 3 -> CASH; + case 4 -> GIFT; + default -> null; + }; + } + + /** + * 枚举 -> 数据库 tinyint + */ + public byte code() { + return switch (this) { + case DISCOUNT -> 1; + case REDUCE -> 2; + case CASH -> 3; + case GIFT -> 4; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/HealthCertificateStatus.java b/src/main/java/com/xjhs/findmemerchant/types/HealthCertificateStatus.java new file mode 100644 index 0000000..477ae33 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/HealthCertificateStatus.java @@ -0,0 +1,47 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 健康证状态 + * 0-待审核 1-有效 2-过期 + */ +@Getter +@AllArgsConstructor +public enum HealthCertificateStatus { + + /** + * 待审核 + */ + PENDING("待审核"), + /** + * 有效 + */ + VALID("有效"), + /** + * 已过期 + */ + EXPIRED("已过期"); + + private final String desc; + + public static HealthCertificateStatus fromCode(Byte code) { + if (code == null) return null; + + return switch (code) { + case 0 -> PENDING; + case 1 -> VALID; + case 2 -> EXPIRED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case PENDING -> 0; + case VALID -> 1; + case EXPIRED -> 2; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/MessageType.java b/src/main/java/com/xjhs/findmemerchant/types/MessageType.java new file mode 100644 index 0000000..5ed8cd9 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/MessageType.java @@ -0,0 +1,46 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 消息类型 + * 1-系统通知 2-活动提醒 3-私信 + */ +@Getter +@AllArgsConstructor +public enum MessageType { + + /** + * 系统通知 + */ + SYSTEM("系统通知"), + /** + * 活动提醒 + */ + ACTIVITY("活动提醒"), + /** + * 私信 + */ + PRIVATE("私信"); + + private final String desc; + + public static MessageType fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 1 -> SYSTEM; + case 2 -> ACTIVITY; + case 3 -> PRIVATE; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case SYSTEM -> 1; + case ACTIVITY -> 2; + case PRIVATE -> 3; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/OrderStatus.java b/src/main/java/com/xjhs/findmemerchant/types/OrderStatus.java new file mode 100644 index 0000000..3f872ec --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/OrderStatus.java @@ -0,0 +1,65 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 订单状态 + * 1-待支付 2-已支付 3-已完成 4-已退款 5-已取消 + */ +@Getter +@AllArgsConstructor +public enum OrderStatus { + + /** + * 待支付 + */ + PENDING("待支付"), // 1 + /** + * 已支付 + */ + PAID("已支付"), // 2 + /** + * 已完成 + */ + COMPLETED("已完成"), // 3 + /** + * 已退款 + */ + REFUNDED("已退款"), // 4 + /** + * 已取消 + */ + CANCELLED("已取消"); // 5 + + private final String desc; + + public static OrderStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 1 -> PENDING; + case 2 -> PAID; + case 3 -> COMPLETED; + case 4 -> REFUNDED; + case 5 -> CANCELLED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case PENDING -> 1; + case PAID -> 2; + case COMPLETED -> 3; + case REFUNDED -> 4; + case CANCELLED -> 5; + }; + } + + /** + * 数值比较用 + */ + public int getCodeValue() { + return code(); + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/ProductStatus.java b/src/main/java/com/xjhs/findmemerchant/types/ProductStatus.java new file mode 100644 index 0000000..4f0f015 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/ProductStatus.java @@ -0,0 +1,40 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 商品状态 + * 0-下架 1-上架 + */ +@Getter +@AllArgsConstructor +public enum ProductStatus { + + /** + * 已下架 + */ + OFF_SALE("已下架"), + /** + * 已上架 + */ + ON_SALE("已上架"); + + private final String desc; + + public static ProductStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> OFF_SALE; + case 1 -> ON_SALE; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case OFF_SALE -> 0; + case ON_SALE -> 1; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/ReviewStatus.java b/src/main/java/com/xjhs/findmemerchant/types/ReviewStatus.java new file mode 100644 index 0000000..b5fcd6d --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/ReviewStatus.java @@ -0,0 +1,40 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 评价状态 + * 1-正常 0-隐藏 + */ +@Getter +@AllArgsConstructor +public enum ReviewStatus { + + /** + * 隐藏 + */ + HIDDEN("隐藏"), + /** + * 正常 + */ + NORMAL("正常"); + + private final String desc; + + public static ReviewStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> HIDDEN; + case 1 -> NORMAL; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case HIDDEN -> 0; + case NORMAL -> 1; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/SettlementStatus.java b/src/main/java/com/xjhs/findmemerchant/types/SettlementStatus.java new file mode 100644 index 0000000..d9caf44 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/SettlementStatus.java @@ -0,0 +1,40 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 结算状态 + * 0-待结算 1-已结算 + */ +@Getter +@AllArgsConstructor +public enum SettlementStatus { + + /** + * 待结算 + */ + PENDING("待结算"), + /** + * 已结算 + */ + SETTLED("已结算"); + + private final String desc; + + public static SettlementStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> PENDING; + case 1 -> SETTLED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case PENDING -> 0; + case SETTLED -> 1; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/SettlementType.java b/src/main/java/com/xjhs/findmemerchant/types/SettlementType.java new file mode 100644 index 0000000..43536a7 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/SettlementType.java @@ -0,0 +1,40 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 结算类型 + * 1-日结 2-周结 + */ +@Getter +@AllArgsConstructor +public enum SettlementType { + + /** + * 日结 + */ + DAILY("日结"), + /** + * 周结 + */ + WEEKLY("周结"); + + private final String desc; + + public static SettlementType fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 1 -> DAILY; + case 2 -> WEEKLY; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case DAILY -> 1; + case WEEKLY -> 2; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/StoreAuditStatus.java b/src/main/java/com/xjhs/findmemerchant/types/StoreAuditStatus.java new file mode 100644 index 0000000..1f8fe0b --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/StoreAuditStatus.java @@ -0,0 +1,46 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 门店审核状态 + * 0-待审核 1-已通过 2-已拒绝 + */ +@Getter +@AllArgsConstructor +public enum StoreAuditStatus { + + /** + * 待审核 + */ + PENDING("待审核"), + /** + * 已通过 + */ + APPROVED("已通过"), + /** + * 已拒绝 + */ + REJECTED("已拒绝"); + + private final String desc; + + public static StoreAuditStatus fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 0 -> PENDING; + case 1 -> APPROVED; + case 2 -> REJECTED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case PENDING -> 0; + case APPROVED -> 1; + case REJECTED -> 2; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/TransactionType.java b/src/main/java/com/xjhs/findmemerchant/types/TransactionType.java new file mode 100644 index 0000000..50b7f86 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/TransactionType.java @@ -0,0 +1,58 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 钱包交易类型 + * 1-收入 2-支出 3-冻结 4-解冻 5-提现 + */ +@Getter +@AllArgsConstructor +public enum TransactionType { + + /** + * 收入 + */ + INCOME("收入"), // 1 + /** + * 支出 + */ + EXPENSE("支出"), // 2 + /** + * 冻结 + */ + FREEZE("冻结"), // 3 + /** + * 解冻 + */ + UNFREEZE("解冻"), // 4 + /** + * 提现 + */ + WITHDRAW("提现"); // 5 + + private final String desc; + + public static TransactionType fromCode(Byte code) { + if (code == null) return null; + return switch (code) { + case 1 -> INCOME; + case 2 -> EXPENSE; + case 3 -> FREEZE; + case 4 -> UNFREEZE; + case 5 -> WITHDRAW; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case INCOME -> 1; + case EXPENSE -> 2; + case FREEZE -> 3; + case UNFREEZE -> 4; + case WITHDRAW -> 5; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/types/WithdrawalStatus.java b/src/main/java/com/xjhs/findmemerchant/types/WithdrawalStatus.java new file mode 100644 index 0000000..400a6f1 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/types/WithdrawalStatus.java @@ -0,0 +1,59 @@ +package com.xjhs.findmemerchant.types; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 提现状态 + * 0-待审核 1-处理中 2-已完成 3-已拒绝 4-已取消 + */ +@Getter +@AllArgsConstructor +public enum WithdrawalStatus { + + /** + * 待审核 + */ + PENDING("待审核"), + /** + * 处理中 + */ + PROCESSING("处理中"), + /** + * 已完成 + */ + COMPLETED("已完成"), + /** + * 已拒绝 + */ + REJECTED("已拒绝"), + /** + * 已取消 + */ + CANCELLED("已取消"); + + private final String desc; + + public static WithdrawalStatus fromCode(Byte code) { + if (code == null) return null; + + return switch (code) { + case 0 -> PENDING; + case 1 -> PROCESSING; + case 2 -> COMPLETED; + case 3 -> REJECTED; + case 4 -> CANCELLED; + default -> null; + }; + } + + public byte code() { + return switch (this) { + case PENDING -> 0; + case PROCESSING -> 1; + case COMPLETED -> 2; + case REJECTED -> 3; + case CANCELLED -> 4; + }; + } +} diff --git a/src/main/java/com/xjhs/findmemerchant/vo/auth/RegisterVo.java b/src/main/java/com/xjhs/findmemerchant/vo/auth/RegisterVo.java index 5270338..c0d031c 100644 --- a/src/main/java/com/xjhs/findmemerchant/vo/auth/RegisterVo.java +++ b/src/main/java/com/xjhs/findmemerchant/vo/auth/RegisterVo.java @@ -19,6 +19,6 @@ public class RegisterVo { * 短信验证码 */ @NotBlank - @Size(max = 4, min = 4) + @Size(max = 6, min = 6) private String code; } diff --git a/src/main/java/com/xjhs/findmemerchant/vo/member/EmployeeCreateVo.java b/src/main/java/com/xjhs/findmemerchant/vo/member/EmployeeCreateVo.java new file mode 100644 index 0000000..e412ccc --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/vo/member/EmployeeCreateVo.java @@ -0,0 +1,37 @@ +package com.xjhs.findmemerchant.vo.member; + +import com.xjhs.findmemerchant.common.jackson.JsonLong; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Data +public class EmployeeCreateVo { + /** + * 员工姓名 + */ + @NotBlank(message = "name 不能为空") + @Size(min = 2, max = 50, message = "name 长度必须在 2~50 之间") + private String name; + /** + * 员工手机号 + */ + @NotBlank(message = "phone 不能为空") + @Pattern(regexp = "^\\d{11}$", message = "phone 必须是 11 位数字") + private String phone; + /** + * 角色id(前端传递请使用 string 类型) + */ + @NotNull(message = "roleId 不能为空") + @JsonLong + private Long roleId; + /** + * 角色id(前端传递请使用 string 类型) + */ + @NotNull(message = "storeId 不能为空") + @JsonLong + @Deprecated(since = "多余的") + private Long storeId; +} diff --git a/src/main/java/com/xjhs/findmemerchant/vo/member/EmployeeUpdateVo.java b/src/main/java/com/xjhs/findmemerchant/vo/member/EmployeeUpdateVo.java new file mode 100644 index 0000000..64bcfc2 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/vo/member/EmployeeUpdateVo.java @@ -0,0 +1,22 @@ +package com.xjhs.findmemerchant.vo.member; + +import com.xjhs.findmemerchant.common.jackson.JsonLong; +import jakarta.validation.constraints.Size; +import lombok.Data; + +/** + * 员工更新参数 + */ +@Data +public class EmployeeUpdateVo { + /** + * 员工姓名 + */ + @Size(min = 2,max = 50) + private String name; + /** + * 员工角色(前端传递string类型) + */ + @JsonLong + private Long roleId; +} diff --git a/src/main/java/com/xjhs/findmemerchant/vo/merchant/MerchantUpdateVo.java b/src/main/java/com/xjhs/findmemerchant/vo/merchant/MerchantUpdateVo.java index 34b917a..bb5dfde 100644 --- a/src/main/java/com/xjhs/findmemerchant/vo/merchant/MerchantUpdateVo.java +++ b/src/main/java/com/xjhs/findmemerchant/vo/merchant/MerchantUpdateVo.java @@ -2,7 +2,13 @@ package com.xjhs.findmemerchant.vo.merchant; import lombok.Data; +/** + * 商家信息更新对象 + */ @Data public class MerchantUpdateVo { - + /** + * 真实姓名 + */ + private String realName; } diff --git a/src/main/java/com/xjhs/findmemerchant/vo/merchant/MerchantVerifyVo.java b/src/main/java/com/xjhs/findmemerchant/vo/merchant/MerchantVerifyVo.java new file mode 100644 index 0000000..22ed468 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/vo/merchant/MerchantVerifyVo.java @@ -0,0 +1,24 @@ +package com.xjhs.findmemerchant.vo.merchant; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +/** + * 商家验证参数 + */ +@Data +public class MerchantVerifyVo { + /** + * 身份证号 + */ + @NotBlank + @Size(min = 18, max = 18) + private String idCardNo; + /** + * 真实姓名 + */ + @NotBlank + @Size(min = 2, max = 50) + private String realName; +} diff --git a/src/main/java/com/xjhs/findmemerchant/vo/store/BusinessPeriodVo.java b/src/main/java/com/xjhs/findmemerchant/vo/store/BusinessPeriodVo.java new file mode 100644 index 0000000..e6fc08b --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/vo/store/BusinessPeriodVo.java @@ -0,0 +1,30 @@ +package com.xjhs.findmemerchant.vo.store; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.Data; + +@Data +public class BusinessPeriodVo { + /** + * 周几,周天0,... + */ + @Size(max = 6) + @NotNull + private Integer dayOfWeek; + /** + * 开始营业时间 HH:mm 格式 + */ + @NotBlank + private String startTime; + /** + * 结束营业时间 HH:mm 格式 + */ + @NotBlank + private String endTime; + /** + * 是否启用 + */ + private Boolean enabled; +} diff --git a/src/main/java/com/xjhs/findmemerchant/vo/store/StoreBusinessStatusUpdateVo.java b/src/main/java/com/xjhs/findmemerchant/vo/store/StoreBusinessStatusUpdateVo.java new file mode 100644 index 0000000..459133b --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/vo/store/StoreBusinessStatusUpdateVo.java @@ -0,0 +1,24 @@ +package com.xjhs.findmemerchant.vo.store; + +import com.xjhs.findmemerchant.types.BusinessStatus; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +@Data +public class StoreBusinessStatusUpdateVo { + /** + * 营业状态 + */ + @NotNull + private BusinessStatus businessStatus; + + /** + * 临时关闭原因(可选;temp_closed 时使用) + */ + private String reason; + + /** + * 重新营业时间(RFC3339 字符串,可选) + */ + private String until; +} diff --git a/src/main/java/com/xjhs/findmemerchant/vo/store/StoreCreateVo.java b/src/main/java/com/xjhs/findmemerchant/vo/store/StoreCreateVo.java new file mode 100644 index 0000000..4bc7741 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/vo/store/StoreCreateVo.java @@ -0,0 +1,57 @@ +package com.xjhs.findmemerchant.vo.store; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +/** + * 创建门店参数 + */ +@Data +public class StoreCreateVo { + /** + * 门店名称 + */ + @NotBlank + @Size(min = 2, max = 100) + private String name; + /** + * 门店logo + */ + private String logo; + /** + * 联系电话 + */ + @NotBlank + @Size(min = 11, max = 11) + private String phone; + /** + * 省份 + */ + @NotBlank + @Size(max = 50) + private String province; + /** + * 市 + */ + @NotBlank + @Size(max = 50) + private String city; + /** + * 街道 + */ + @NotBlank + @Size(max = 50) + private String district; + /** + * 地址 + */ + @NotBlank + @Size(max = 200) + private String address; + /** + * 营业时间 + */ + private String businessHours; + +} diff --git a/src/main/java/com/xjhs/findmemerchant/vo/store/StoreUpdateVo.java b/src/main/java/com/xjhs/findmemerchant/vo/store/StoreUpdateVo.java new file mode 100644 index 0000000..97ad487 --- /dev/null +++ b/src/main/java/com/xjhs/findmemerchant/vo/store/StoreUpdateVo.java @@ -0,0 +1,66 @@ +package com.xjhs.findmemerchant.vo.store; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Size; +import lombok.Data; + +/** + * 门店更新参数 + */ +@Data +public class StoreUpdateVo { + /** + * 门店名称 + */ + @NotBlank + @Size(max = 100, message = "name长度不能超过100") + private String name; + /** + * 门店logo + */ + @Size(max = 255, message = "logo长度不能超过255") + private String logo; + + /** + * 联系电话 + */ + // @Pattern(regexp = "^(\\+\\d{1,3})?\\d{6,20}$", message = "phone格式不正确") + @NotBlank + @Size(min = 11, max = 11) + private String phone; + /** + * 省 + */ + @NotBlank + @Size(max = 50, message = "province长度不能超过50") + private String province; + /** + * 市 + */ + @NotBlank + @Size(max = 50, message = "city长度不能超过50") + private String city; + /** + * 区 + */ + @NotBlank + @Size(max = 50, message = "district长度不能超过50") + private String district; + /** + * 地址 + */ + @NotBlank + @Size(max = 255, message = "address长度不能超过255") + private String address; + /** + * 营业时间 + */ + @Size(max = 100, message = "businessHours长度不能超过100") + private String businessHours; + + /** + * 验证码(先按常见4~8位数字) + */ + @NotBlank + private String phoneVerifyCode; +} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml new file mode 100644 index 0000000..074d7f7 --- /dev/null +++ b/src/main/resources/application-local.yml @@ -0,0 +1,14 @@ + +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://192.168.1.20:3306/findme-merchant?useSSL=false&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + username: root + password: 123456 + data: + redis: + host: 192.168.1.20 + port: 6379 + password: 123456 + database: 0 + timeout: 3s \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 83feb8c..8c6d574 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,6 +1,6 @@ spring: profiles: - active: default + active: default,local application: name: findme-backend-merchant main: @@ -21,30 +21,13 @@ spring: format_sql: true datasource: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://${MYSQL_HOST:8.137.94.92}:${MYSQL_PORT:23306}/findme-merchant?useSSL=false&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + url: jdbc:mysql://${MYSQL_HOST:192.168.1.20}:${MYSQL_PORT:3306}/findme-merchant?useSSL=false&useUnicode=true&characterEncoding=utf-8&autoReconnect=true&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true username: ${MYSQL_USER:root} - password: ${MYSQL_PASS:pW2CwlHte3%^#y8Z} + password: ${MYSQL_PASS:123456} data: redis: - host: ${REDIS_HOST:8.137.94.92} - port: ${REDIS_PORT:26379} - password: ${REDIS_PASS:9Hii(AaVzTNY<%e} + host: ${REDIS_HOST:192.168.1.20} + port: ${REDIS_PORT:6379} + password: ${REDIS_PASS:123456} database: 0 - timeout: 3s - -appconfig: - saveFileRoot: ${SAVE_FILE_ROOT:./file-data} - amapKey: ${AMAP_KEY:c618de6e686c43095a8593db836c7de2} - tencentSms: - sdkAppId: ${SMS_SDKAPP_ID:1401031336} - templateId: ${SMS_TEMPLATE_ID:2512787} - signName: ${SMS_SIGN_NAME:新疆火烁智能科技} - secretId: ${SMS_SECRET_ID:AKIDWyGMFwQinhPFzXt54rTuAD5kEYheOyOd} - secretKey: ${SMS_SECRET_KEY:62mLjvwmQs9GAsQ5f6LQ7umgWCgy31sX} - tencentCos: - secretId: ${COS_SECRET_ID:AKIDWyGMFwQinhPFzXt54rTuAD5kEYheOyOd} - secretKey: ${COS_SECRET_KEY:62mLjvwmQs9GAsQ5f6LQ7umgWCgy31sX} - appId: ${COS_APP_ID:1375214531} - bucketName: ${COS_APP_BUCKET:merchant-1375214531} - - + timeout: 3s \ No newline at end of file