Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce695463d3 | ||
|
|
aff056712e | ||
|
|
af18b0999d | ||
|
|
83c683d473 | ||
|
|
4963988ec2 | ||
|
|
9555474b0b | ||
|
|
022185079c | ||
|
|
acc3f05f12 |
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<groupId>com.imyeyu.timiserverapi</groupId>
|
<groupId>com.imyeyu.timiserverapi</groupId>
|
||||||
<artifactId>TimiServerAPI</artifactId>
|
<artifactId>TimiServerAPI</artifactId>
|
||||||
<version>1.0.18</version>
|
<version>1.0.21</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
<name>TimiServerAPI</name>
|
<name>TimiServerAPI</name>
|
||||||
<description>imyeyu.com API</description>
|
<description>imyeyu.com API</description>
|
||||||
@@ -205,6 +205,11 @@
|
|||||||
<artifactId>timi-utils</artifactId>
|
<artifactId>timi-utils</artifactId>
|
||||||
<version>0.0.13</version>
|
<version>0.0.13</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.majiajie</groupId>
|
||||||
|
<artifactId>tinypinyin</artifactId>
|
||||||
|
<version>2.0.3</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.imyeyu.font.icon</groupId>
|
<groupId>com.imyeyu.font.icon</groupId>
|
||||||
<artifactId>timi-icon-font</artifactId>
|
<artifactId>timi-icon-font</artifactId>
|
||||||
|
|||||||
@@ -42,6 +42,19 @@ public class NotifyQueueConfig {
|
|||||||
private String secretId;
|
private String secretId;
|
||||||
|
|
||||||
private String secretKey;
|
private String secretKey;
|
||||||
|
|
||||||
|
private Captcha captcha;
|
||||||
|
|
||||||
|
/// 短信验证码
|
||||||
|
@Data
|
||||||
|
public static class Captcha {
|
||||||
|
|
||||||
|
private String templateId;
|
||||||
|
|
||||||
|
private int ttlMinute;
|
||||||
|
|
||||||
|
private int argIndex;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 微信队列配置
|
/// 微信队列配置
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.imyeyu.api.modules.common.entity;
|
package com.imyeyu.api.modules.common.entity;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.imyeyu.java.bean.Language;
|
import com.imyeyu.java.bean.Language;
|
||||||
|
import com.imyeyu.spring.annotation.table.Column;
|
||||||
import com.imyeyu.spring.entity.UUIDEntity;
|
import com.imyeyu.spring.entity.UUIDEntity;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
@@ -15,6 +17,18 @@ public class Multilingual extends UUIDEntity {
|
|||||||
|
|
||||||
protected String zhCN;
|
protected String zhCN;
|
||||||
|
|
||||||
|
@Column("zh_cn_pinyin_full")
|
||||||
|
@JsonIgnore
|
||||||
|
protected String zhCNPinyinFull;
|
||||||
|
|
||||||
|
@Column("zh_cn_pinyin_initial")
|
||||||
|
@JsonIgnore
|
||||||
|
protected String zhCNPinyinInitial;
|
||||||
|
|
||||||
|
@Column("zh_cn_pinyin_mixed")
|
||||||
|
@JsonIgnore
|
||||||
|
protected String zhCNPinyinMixed;
|
||||||
|
|
||||||
protected String zhTW;
|
protected String zhTW;
|
||||||
|
|
||||||
protected String enUS;
|
protected String enUS;
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
//package com.imyeyu.api.modules.common.service;
|
||||||
|
//
|
||||||
|
//import com.e2ins.ms.notify.entity.Notify;
|
||||||
|
//import com.e2ins.ms.notify.entity.NotifyDetail;
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// *
|
||||||
|
// *
|
||||||
|
// * @author 夜雨
|
||||||
|
// * @since 2026-05-14 12:12
|
||||||
|
// */
|
||||||
|
//public interface SmsService {
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 创建短信验证码通知
|
||||||
|
// *
|
||||||
|
// * @param detail 通知
|
||||||
|
// * @return 通知详情 ID
|
||||||
|
// */
|
||||||
|
// String captchaCreate(Notify detail);
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 校验短信验证码
|
||||||
|
// *
|
||||||
|
// * @param detailId 通知详情 ID
|
||||||
|
// * @param captcha 请求验证码
|
||||||
|
// * @return 通知详情
|
||||||
|
// */
|
||||||
|
// NotifyDetail captchaVerify(String detailId, String captcha);
|
||||||
|
//}
|
||||||
+23
@@ -3,6 +3,7 @@ package com.imyeyu.api.modules.common.service.implement;
|
|||||||
import com.imyeyu.api.modules.common.entity.Multilingual;
|
import com.imyeyu.api.modules.common.entity.Multilingual;
|
||||||
import com.imyeyu.api.modules.common.mapper.MultilingualMapper;
|
import com.imyeyu.api.modules.common.mapper.MultilingualMapper;
|
||||||
import com.imyeyu.api.modules.common.service.MultilingualService;
|
import com.imyeyu.api.modules.common.service.MultilingualService;
|
||||||
|
import com.imyeyu.api.util.PinyinUtil;
|
||||||
import com.imyeyu.spring.mapper.BaseMapper;
|
import com.imyeyu.spring.mapper.BaseMapper;
|
||||||
import com.imyeyu.spring.service.AbstractEntityService;
|
import com.imyeyu.spring.service.AbstractEntityService;
|
||||||
import com.imyeyu.spring.util.Redis;
|
import com.imyeyu.spring.util.Redis;
|
||||||
@@ -34,6 +35,18 @@ public class MultilingualServiceImplement extends AbstractEntityService<Multilin
|
|||||||
return mapper;
|
return mapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(Multilingual multilingual) {
|
||||||
|
fillPinyin(multilingual);
|
||||||
|
super.create(multilingual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void update(Multilingual multilingual) {
|
||||||
|
fillPinyin(multilingual);
|
||||||
|
super.update(multilingual);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Multilingual get(String id) {
|
public Multilingual get(String id) {
|
||||||
Multilingual result = redisLanguage.get(getKey(id));
|
Multilingual result = redisLanguage.get(getKey(id));
|
||||||
@@ -81,4 +94,14 @@ public class MultilingualServiceImplement extends AbstractEntityService<Multilin
|
|||||||
private String getKey(String id) {
|
private String getKey(String id) {
|
||||||
return "%s%s".formatted(KEY_PREFIX, id);
|
return "%s%s".formatted(KEY_PREFIX, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillPinyin(Multilingual multilingual) {
|
||||||
|
if (multilingual == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String zhCN = multilingual.getZhCN();
|
||||||
|
multilingual.setZhCNPinyinFull(PinyinUtil.full(zhCN));
|
||||||
|
multilingual.setZhCNPinyinInitial(PinyinUtil.initial(zhCN));
|
||||||
|
multilingual.setZhCNPinyinMixed(PinyinUtil.mixed(zhCN));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+82
@@ -0,0 +1,82 @@
|
|||||||
|
//package com.imyeyu.api.modules.common.service.implement;
|
||||||
|
//
|
||||||
|
//import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
//import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||||
|
//import com.imyeyu.api.modules.common.config.NotifyQueueConfig;
|
||||||
|
//import com.imyeyu.api.modules.common.entity.Notify;
|
||||||
|
//import com.imyeyu.api.modules.common.entity.NotifyDetail;
|
||||||
|
//import com.imyeyu.api.modules.common.service.NotifyDetailService;
|
||||||
|
//import com.imyeyu.api.modules.common.service.NotifyService;
|
||||||
|
//import com.imyeyu.api.modules.common.service.SmsService;
|
||||||
|
//import com.imyeyu.java.bean.timi.TimiException;
|
||||||
|
//import com.imyeyu.utils.Regex;
|
||||||
|
//import com.imyeyu.utils.Text;
|
||||||
|
//import com.imyeyu.utils.Time;
|
||||||
|
//import lombok.RequiredArgsConstructor;
|
||||||
|
//import lombok.extern.slf4j.Slf4j;
|
||||||
|
//import org.springframework.beans.factory.annotation.Value;
|
||||||
|
//import org.springframework.stereotype.Service;
|
||||||
|
//
|
||||||
|
//import java.util.List;
|
||||||
|
//
|
||||||
|
///**
|
||||||
|
// *
|
||||||
|
// *
|
||||||
|
// * @author 夜雨
|
||||||
|
// * @since 2026-05-14 12:12
|
||||||
|
// */
|
||||||
|
//@Slf4j
|
||||||
|
//@Service
|
||||||
|
//@RequiredArgsConstructor
|
||||||
|
//public class SmsServiceImplement implements SmsService {
|
||||||
|
//
|
||||||
|
// @Value("${spring.profiles.active}")
|
||||||
|
// private String env;
|
||||||
|
//
|
||||||
|
// private final NotifyQueueConfig config;
|
||||||
|
// private final ObjectMapper jackson;
|
||||||
|
//
|
||||||
|
// private final NotifyService notifyService;
|
||||||
|
// private final NotifyDetailService notifyDetailService;
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public String captchaCreate(Notify notify) {
|
||||||
|
// NotifyQueueConfig.Sms.Captcha captchaConf = config.getSms().getCaptcha();
|
||||||
|
// TimiException.required(notify.getAppId(), "not found appId");
|
||||||
|
//
|
||||||
|
// NotifyDetail detail = notify.getDetailList().getFirst();
|
||||||
|
//
|
||||||
|
// TimiException.requiredTrue(Regex.isMatch(Regex.MOBILE_PHONE, detail.getSendTo()), "invalid mobilePhone", "captcha.sms.invalid_mobile_phone");
|
||||||
|
//
|
||||||
|
// String code = Text.randomString("0123456789", 6);
|
||||||
|
// if (!env.equalsIgnoreCase("prod")) {
|
||||||
|
// code = "123456";
|
||||||
|
// }
|
||||||
|
// detail.setMsgType(NotifyDetail.MsgType.SMS);
|
||||||
|
// detail.setTemplateId(captchaConf.getTemplateId());
|
||||||
|
// detail.setArgs(jackson.valueToTree(List.of(code, captchaConf.getTtlMinute())));
|
||||||
|
//
|
||||||
|
// notifyService.create(notify);
|
||||||
|
// return notifyDetailService.listByNotifyId(notify.getId()).getFirst().getId();
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public NotifyDetail captchaVerify(String detailId, String captcha) {
|
||||||
|
// AppConfig.Sms.Captcha captchaConf = config.getSms().getCaptcha();
|
||||||
|
//
|
||||||
|
// NotifyDetail detail = notifyDetailService.get(detailId);
|
||||||
|
// if (Time.M * captchaConf.getTtlMinute() < Time.now() - detail.getSendAt()) {
|
||||||
|
// throw new AppException(ResultCode.ARG_EXPIRED).msgKey("captcha.expired");
|
||||||
|
// }
|
||||||
|
// if (detail.getArgs() instanceof ArrayNode array) {
|
||||||
|
// String dbCaptcha = array.get(captchaConf.getArgIndex()).asText();
|
||||||
|
// if (!dbCaptcha.equalsIgnoreCase(captcha)) {
|
||||||
|
// throw new AppException(ResultCode.RESULT_BAD).msgKey("captcha.invalid");
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// throw new AppException(ResultCode.ERROR, "not array args");
|
||||||
|
// }
|
||||||
|
// detail.setNotify(notifyService.get(detail.getNotifyId()));
|
||||||
|
// return detail;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
@@ -6,7 +6,9 @@ import com.imyeyu.api.modules.common.entity.Attachment;
|
|||||||
import com.imyeyu.api.modules.common.entity.TagApply;
|
import com.imyeyu.api.modules.common.entity.TagApply;
|
||||||
import com.imyeyu.api.modules.user.bean.Gender;
|
import com.imyeyu.api.modules.user.bean.Gender;
|
||||||
import com.imyeyu.api.modules.user.entity.User;
|
import com.imyeyu.api.modules.user.entity.User;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
|
import com.imyeyu.spring.annotation.table.Column;
|
||||||
import com.imyeyu.spring.annotation.table.Transient;
|
import com.imyeyu.spring.annotation.table.Transient;
|
||||||
import com.imyeyu.spring.entity.UUIDEntity;
|
import com.imyeyu.spring.entity.UUIDEntity;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -59,6 +61,18 @@ public class GaoCustomer extends UUIDEntity {
|
|||||||
/// 姓名
|
/// 姓名
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
|
@Column("name_pinyin_full")
|
||||||
|
@JsonIgnore
|
||||||
|
private String namePinyinFull;
|
||||||
|
|
||||||
|
@Column("name_pinyin_initial")
|
||||||
|
@JsonIgnore
|
||||||
|
private String namePinyinInitial;
|
||||||
|
|
||||||
|
@Column("name_pinyin_mixed")
|
||||||
|
@JsonIgnore
|
||||||
|
private String namePinyinMixed;
|
||||||
|
|
||||||
/// 性别
|
/// 性别
|
||||||
private Gender gender;
|
private Gender gender;
|
||||||
|
|
||||||
|
|||||||
@@ -17,9 +17,12 @@ public class GaoPointLedger extends UUIDEntity {
|
|||||||
/// 流水变化类型
|
/// 流水变化类型
|
||||||
public enum ChangeType {
|
public enum ChangeType {
|
||||||
|
|
||||||
/// 登记事件积分变化
|
/// 登记事件发放积分
|
||||||
EARN,
|
EARN,
|
||||||
|
|
||||||
|
/// 登记事件消费积分
|
||||||
|
CONSUME,
|
||||||
|
|
||||||
/// 删除登记记录撤销积分
|
/// 删除登记记录撤销积分
|
||||||
REVOKE,
|
REVOKE,
|
||||||
|
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ public interface GaoPointLedgerMapper extends BaseMapper<GaoPointLedger, String>
|
|||||||
/// @return 流水
|
/// @return 流水
|
||||||
GaoPointLedger selectByIdempotencyKey(@Param("idempotencyKey") String idempotencyKey);
|
GaoPointLedger selectByIdempotencyKey(@Param("idempotencyKey") String idempotencyKey);
|
||||||
|
|
||||||
/// 查询登记记录产生的原始获得积分流水
|
/// 查询登记记录产生的原始规则积分流水
|
||||||
///
|
///
|
||||||
/// @param eventRecordId 登记记录 ID
|
/// @param eventRecordId 登记记录 ID
|
||||||
/// @return 获得积分流水
|
/// @return 原始规则积分流水
|
||||||
List<GaoPointLedger> selectEarnByEventRecordId(@Param("eventRecordId") String eventRecordId);
|
List<GaoPointLedger> selectRuleChangeByEventRecordId(@Param("eventRecordId") String eventRecordId);
|
||||||
|
|
||||||
/// 批量查询幂等键对应的流水
|
/// 批量查询幂等键对应的流水
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -15,18 +15,18 @@ import com.imyeyu.spring.service.BaseService;
|
|||||||
/// @since 2026-08-11
|
/// @since 2026-08-11
|
||||||
public interface GaoPointLedgerService extends BaseService<GaoPointLedger, String> {
|
public interface GaoPointLedgerService extends BaseService<GaoPointLedger, String> {
|
||||||
|
|
||||||
/// 写入登记获得积分流水
|
/// 写入登记规则积分流水
|
||||||
///
|
///
|
||||||
/// @param record 登记记录
|
/// @param record 登记记录
|
||||||
/// @param rule 命中规则
|
/// @param rule 命中规则
|
||||||
/// @param pointDelta 积分变化
|
/// @param pointDelta 积分变化
|
||||||
/// @param sourcePayload 来源快照
|
/// @param sourcePayload 来源快照
|
||||||
/// @return 积分流水
|
/// @return 积分流水
|
||||||
GaoPointLedger earn(GaoEventRecord record, GaoPointRule rule, long pointDelta, JsonNode sourcePayload);
|
GaoPointLedger applyRule(GaoEventRecord record, GaoPointRule rule, long pointDelta, JsonNode sourcePayload);
|
||||||
|
|
||||||
/// 写入删除登记记录的撤销流水
|
/// 写入删除登记记录的撤销流水
|
||||||
///
|
///
|
||||||
/// @param originLedger 原始获得积分流水
|
/// @param originLedger 原始规则积分流水
|
||||||
/// @param record 登记记录
|
/// @param record 登记记录
|
||||||
/// @return 撤销流水
|
/// @return 撤销流水
|
||||||
GaoPointLedger revoke(GaoPointLedger originLedger, GaoEventRecord record);
|
GaoPointLedger revoke(GaoPointLedger originLedger, GaoEventRecord record);
|
||||||
|
|||||||
+10
@@ -21,6 +21,7 @@ import com.imyeyu.api.modules.gao.vo.GaoCustomerTrendStateReq;
|
|||||||
import com.imyeyu.api.modules.system.entity.Logger;
|
import com.imyeyu.api.modules.system.entity.Logger;
|
||||||
import com.imyeyu.api.modules.system.service.LoggerService;
|
import com.imyeyu.api.modules.system.service.LoggerService;
|
||||||
import com.imyeyu.api.modules.user.service.UserLoginService;
|
import com.imyeyu.api.modules.user.service.UserLoginService;
|
||||||
|
import com.imyeyu.api.util.PinyinUtil;
|
||||||
import com.imyeyu.java.TimiJava;
|
import com.imyeyu.java.TimiJava;
|
||||||
import com.imyeyu.java.bean.timi.TimiCode;
|
import com.imyeyu.java.bean.timi.TimiCode;
|
||||||
import com.imyeyu.java.bean.timi.TimiException;
|
import com.imyeyu.java.bean.timi.TimiException;
|
||||||
@@ -91,6 +92,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
public void create(GaoCustomer customer) {
|
public void create(GaoCustomer customer) {
|
||||||
TimiException.required(customer.getName(), "not found customer.name");
|
TimiException.required(customer.getName(), "not found customer.name");
|
||||||
TimiException.required(customer.getStoreId(), "not found customer.storeId");
|
TimiException.required(customer.getStoreId(), "not found customer.storeId");
|
||||||
|
fillPinyin(customer);
|
||||||
|
|
||||||
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_CREATE");
|
Logger logger = new Logger(Logger.Module.GAO, "GAO_CUSTOMER_CREATE");
|
||||||
try {
|
try {
|
||||||
@@ -169,6 +171,7 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
dbCustomer.setName(customer.getName());
|
dbCustomer.setName(customer.getName());
|
||||||
|
fillPinyin(dbCustomer);
|
||||||
dbCustomer.setGender(customer.getGender());
|
dbCustomer.setGender(customer.getGender());
|
||||||
dbCustomer.setAge(customer.getAge());
|
dbCustomer.setAge(customer.getAge());
|
||||||
dbCustomer.setBirthdateCalendar(customer.getBirthdateCalendar());
|
dbCustomer.setBirthdateCalendar(customer.getBirthdateCalendar());
|
||||||
@@ -424,4 +427,11 @@ public class GaoCustomerServiceImplement extends AbstractEntityService<GaoCustom
|
|||||||
customer.setInvitedCount(customer.getInvitedCount() + delta);
|
customer.setInvitedCount(customer.getInvitedCount() + delta);
|
||||||
mapper.update(customer);
|
mapper.update(customer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void fillPinyin(GaoCustomer customer) {
|
||||||
|
String name = customer.getName();
|
||||||
|
customer.setNamePinyinFull(PinyinUtil.full(name));
|
||||||
|
customer.setNamePinyinInitial(PinyinUtil.initial(name));
|
||||||
|
customer.setNamePinyinMixed(PinyinUtil.mixed(name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -71,12 +71,13 @@ public class GaoPointLedgerServiceImplement extends AbstractEntityService<GaoPoi
|
|||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
@Override
|
@Override
|
||||||
public GaoPointLedger earn(GaoEventRecord record, GaoPointRule rule, long pointDelta, JsonNode sourcePayload) {
|
public GaoPointLedger applyRule(GaoEventRecord record, GaoPointRule rule, long pointDelta, JsonNode sourcePayload) {
|
||||||
TimiException.required(record, "not found event record");
|
TimiException.required(record, "not found event record");
|
||||||
TimiException.required(rule, "not found point rule");
|
TimiException.required(rule, "not found point rule");
|
||||||
TimiException.requiredTrue(pointDelta != 0, "pointDelta invalid");
|
TimiException.requiredTrue(pointDelta != 0, "pointDelta invalid");
|
||||||
String idempotencyKey = "GAO_EVENT_RECORD:%s:RULE:%s:EARN".formatted(record.getId(), rule.getId());
|
String idempotencyKey = "GAO_EVENT_RECORD:%s:RULE:%s:EARN".formatted(record.getId(), rule.getId());
|
||||||
return apply(record.getStoreId(), record.getCustomerId(), GaoPointLedger.ChangeType.EARN, pointDelta, rule.getId(), record.getEventId(), record.getId(), sourcePayload, idempotencyKey, rule.getRemark(), record.getOperatorUserId(), record.getRegisteredAt());
|
GaoPointLedger.ChangeType changeType = pointDelta < 0 ? GaoPointLedger.ChangeType.CONSUME : GaoPointLedger.ChangeType.EARN;
|
||||||
|
return apply(record.getStoreId(), record.getCustomerId(), changeType, pointDelta, rule.getId(), record.getEventId(), record.getId(), sourcePayload, idempotencyKey, rule.getRemark(), record.getOperatorUserId(), record.getRegisteredAt());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
@Transactional(TimiServerDBConfig.ROLLBACKER)
|
||||||
|
|||||||
+2
-2
@@ -73,7 +73,7 @@ public class GaoPointTriggerServiceImplement implements GaoPointTriggerService {
|
|||||||
}
|
}
|
||||||
long pointDelta = resolution.pointDelta();
|
long pointDelta = resolution.pointDelta();
|
||||||
if (pointDelta != 0) {
|
if (pointDelta != 0) {
|
||||||
ledgerService.earn(record, rule, pointDelta, resolution.sourcePayload());
|
ledgerService.applyRule(record, rule, pointDelta, resolution.sourcePayload());
|
||||||
pointDeltaTotal = Math.addExact(pointDeltaTotal, pointDelta);
|
pointDeltaTotal = Math.addExact(pointDeltaTotal, pointDelta);
|
||||||
}
|
}
|
||||||
if (Boolean.TRUE.equals(rule.getExclusive())) {
|
if (Boolean.TRUE.equals(rule.getExclusive())) {
|
||||||
@@ -88,7 +88,7 @@ public class GaoPointTriggerServiceImplement implements GaoPointTriggerService {
|
|||||||
@Override
|
@Override
|
||||||
public void revokeByEventRecord(GaoEventRecord record) {
|
public void revokeByEventRecord(GaoEventRecord record) {
|
||||||
TimiException.required(record, "not found event record");
|
TimiException.required(record, "not found event record");
|
||||||
List<GaoPointLedger> originLedgerList = ledgerMapper.selectEarnByEventRecordId(record.getId());
|
List<GaoPointLedger> originLedgerList = ledgerMapper.selectRuleChangeByEventRecordId(record.getId());
|
||||||
if (originLedgerList.isEmpty()) {
|
if (originLedgerList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package com.imyeyu.api.util;
|
||||||
|
|
||||||
|
import me.majiajie.tinypinyin.Pinyin;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/// 拼音搜索工具
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-21
|
||||||
|
public final class PinyinUtil {
|
||||||
|
|
||||||
|
private PinyinUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 转换为无声调全拼
|
||||||
|
///
|
||||||
|
/// @param value 原始文字
|
||||||
|
/// @return 无声调全拼
|
||||||
|
public static String full(String value) {
|
||||||
|
return convert(value, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 转换为拼音首字母
|
||||||
|
///
|
||||||
|
/// @param value 原始文字
|
||||||
|
/// @return 拼音首字母
|
||||||
|
public static String initial(String value) {
|
||||||
|
return convert(value, true, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 转换为首字全拼、后续字首字母的混合拼音
|
||||||
|
///
|
||||||
|
/// @param value 原始文字
|
||||||
|
/// @return 混合拼音
|
||||||
|
public static String mixed(String value) {
|
||||||
|
return convert(value, false, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String convert(String value, boolean initial, boolean mixed) {
|
||||||
|
if (value == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder result = new StringBuilder(value.length());
|
||||||
|
boolean first = true;
|
||||||
|
for (char character : value.toCharArray()) {
|
||||||
|
if (Character.isWhitespace(character)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
String pinyin = Pinyin.toPinyin(character).toLowerCase(Locale.ROOT);
|
||||||
|
if (pinyin.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (initial || (mixed && !first)) {
|
||||||
|
result.append(pinyin.charAt(0));
|
||||||
|
} else {
|
||||||
|
result.append(pinyin);
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package db.migration.timiserver;
|
||||||
|
|
||||||
|
import com.imyeyu.api.util.PinyinUtil;
|
||||||
|
import org.flywaydb.core.api.migration.BaseJavaMigration;
|
||||||
|
import org.flywaydb.core.api.migration.Context;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
|
||||||
|
/// 回填拼音搜索字段
|
||||||
|
///
|
||||||
|
/// @author Codex
|
||||||
|
/// @since 2026-08-21
|
||||||
|
public class V37__backfill_pinyin_search extends BaseJavaMigration {
|
||||||
|
|
||||||
|
private static final int BATCH_SIZE = 500;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void migrate(Context context) throws Exception {
|
||||||
|
backfillMultilingual(context.getConnection());
|
||||||
|
backfillCustomer(context.getConnection());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void backfillMultilingual(Connection connection) throws Exception {
|
||||||
|
try (PreparedStatement select = connection.prepareStatement("""
|
||||||
|
SELECT `id`, `zh_cn`
|
||||||
|
FROM `multilingual`
|
||||||
|
WHERE `zh_cn` IS NOT NULL
|
||||||
|
AND (`zh_cn_pinyin_full` IS NULL OR `zh_cn_pinyin_initial` IS NULL OR `zh_cn_pinyin_mixed` IS NULL)
|
||||||
|
""");
|
||||||
|
PreparedStatement update = connection.prepareStatement("""
|
||||||
|
UPDATE `multilingual`
|
||||||
|
SET `zh_cn_pinyin_full` = ?, `zh_cn_pinyin_initial` = ?, `zh_cn_pinyin_mixed` = ?
|
||||||
|
WHERE `id` = ?
|
||||||
|
""")) {
|
||||||
|
try (ResultSet resultSet = select.executeQuery()) {
|
||||||
|
int batchSize = 0;
|
||||||
|
while (resultSet.next()) {
|
||||||
|
addMultilingualBatch(update, resultSet.getString("id"), resultSet.getString("zh_cn"));
|
||||||
|
batchSize++;
|
||||||
|
if (batchSize >= BATCH_SIZE) {
|
||||||
|
update.executeBatch();
|
||||||
|
batchSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (batchSize > 0) {
|
||||||
|
update.executeBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void backfillCustomer(Connection connection) throws Exception {
|
||||||
|
try (PreparedStatement select = connection.prepareStatement("""
|
||||||
|
SELECT `id`, `name`
|
||||||
|
FROM `gao_customer`
|
||||||
|
WHERE `name` IS NOT NULL
|
||||||
|
AND (`name_pinyin_full` IS NULL OR `name_pinyin_initial` IS NULL OR `name_pinyin_mixed` IS NULL)
|
||||||
|
""");
|
||||||
|
PreparedStatement update = connection.prepareStatement("""
|
||||||
|
UPDATE `gao_customer`
|
||||||
|
SET `name_pinyin_full` = ?, `name_pinyin_initial` = ?, `name_pinyin_mixed` = ?
|
||||||
|
WHERE `id` = ?
|
||||||
|
""")) {
|
||||||
|
try (ResultSet resultSet = select.executeQuery()) {
|
||||||
|
int batchSize = 0;
|
||||||
|
while (resultSet.next()) {
|
||||||
|
addCustomerBatch(update, resultSet.getString("id"), resultSet.getString("name"));
|
||||||
|
batchSize++;
|
||||||
|
if (batchSize >= BATCH_SIZE) {
|
||||||
|
update.executeBatch();
|
||||||
|
batchSize = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (batchSize > 0) {
|
||||||
|
update.executeBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addMultilingualBatch(PreparedStatement update, String id, String value) throws Exception {
|
||||||
|
update.setString(1, PinyinUtil.full(value));
|
||||||
|
update.setString(2, PinyinUtil.initial(value));
|
||||||
|
update.setString(3, PinyinUtil.mixed(value));
|
||||||
|
update.setString(4, id);
|
||||||
|
update.addBatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addCustomerBatch(PreparedStatement update, String id, String value) throws Exception {
|
||||||
|
update.setString(1, PinyinUtil.full(value));
|
||||||
|
update.setString(2, PinyinUtil.initial(value));
|
||||||
|
update.setString(3, PinyinUtil.mixed(value));
|
||||||
|
update.setString(4, id);
|
||||||
|
update.addBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
ALTER TABLE `multilingual`
|
||||||
|
ADD COLUMN `zh_cn_pinyin_full` TEXT NULL COMMENT '简体中文全拼' AFTER `zh_cn`,
|
||||||
|
ADD COLUMN `zh_cn_pinyin_initial` TEXT NULL COMMENT '简体中文拼音首字母' AFTER `zh_cn_pinyin_full`,
|
||||||
|
ADD COLUMN `zh_cn_pinyin_mixed` TEXT NULL COMMENT '简体中文混合拼音' AFTER `zh_cn_pinyin_initial`,
|
||||||
|
ADD KEY `idx_multilingual_zh_cn_pinyin_full` (`zh_cn_pinyin_full`(128)),
|
||||||
|
ADD KEY `idx_multilingual_zh_cn_pinyin_initial` (`zh_cn_pinyin_initial`(128)),
|
||||||
|
ADD KEY `idx_multilingual_zh_cn_pinyin_mixed` (`zh_cn_pinyin_mixed`(128));
|
||||||
|
|
||||||
|
ALTER TABLE `gao_customer`
|
||||||
|
ADD COLUMN `name_pinyin_full` VARCHAR(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '姓名全拼' AFTER `name`,
|
||||||
|
ADD COLUMN `name_pinyin_initial` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '姓名拼音首字母' AFTER `name_pinyin_full`,
|
||||||
|
ADD COLUMN `name_pinyin_mixed` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '姓名混合拼音' AFTER `name_pinyin_initial`,
|
||||||
|
ADD KEY `idx_gao_customer_store_name_pinyin_full` (`store_id`, `deleted_at`, `name_pinyin_full`(128)),
|
||||||
|
ADD KEY `idx_gao_customer_store_name_pinyin_initial` (`store_id`, `deleted_at`, `name_pinyin_initial`),
|
||||||
|
ADD KEY `idx_gao_customer_store_name_pinyin_mixed` (`store_id`, `deleted_at`, `name_pinyin_mixed`);
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
UPDATE `gao_point_ledger`
|
||||||
|
SET `change_type` = 'CONSUME'
|
||||||
|
WHERE `change_type` = 'EARN'
|
||||||
|
AND `point_delta` < 0;
|
||||||
@@ -32,6 +32,9 @@
|
|||||||
OR `m`.`ja_jp` LIKE CONCAT('%', #{keyword}, '%')
|
OR `m`.`ja_jp` LIKE CONCAT('%', #{keyword}, '%')
|
||||||
OR `m`.`de_de` LIKE CONCAT('%', #{keyword}, '%')
|
OR `m`.`de_de` LIKE CONCAT('%', #{keyword}, '%')
|
||||||
OR `m`.`ko_kr` LIKE CONCAT('%', #{keyword}, '%')
|
OR `m`.`ko_kr` LIKE CONCAT('%', #{keyword}, '%')
|
||||||
|
OR `m`.`zh_cn_pinyin_full` LIKE CONCAT(#{keyword}, '%')
|
||||||
|
OR `m`.`zh_cn_pinyin_initial` LIKE CONCAT(#{keyword}, '%')
|
||||||
|
OR `m`.`zh_cn_pinyin_mixed` LIKE CONCAT(#{keyword}, '%')
|
||||||
)
|
)
|
||||||
</if>
|
</if>
|
||||||
AND `t`.`deleted_at` IS NULL
|
AND `t`.`deleted_at` IS NULL
|
||||||
|
|||||||
@@ -29,6 +29,9 @@
|
|||||||
`c`.`code` LIKE CONCAT('%', #{keyword}, '%')
|
`c`.`code` LIKE CONCAT('%', #{keyword}, '%')
|
||||||
OR `c`.`name` LIKE CONCAT('%', #{keyword}, '%')
|
OR `c`.`name` LIKE CONCAT('%', #{keyword}, '%')
|
||||||
OR `c`.`telephone` LIKE CONCAT('%', #{keyword}, '%')
|
OR `c`.`telephone` LIKE CONCAT('%', #{keyword}, '%')
|
||||||
|
OR `c`.`name_pinyin_full` LIKE CONCAT(#{keyword}, '%')
|
||||||
|
OR `c`.`name_pinyin_initial` LIKE CONCAT(#{keyword}, '%')
|
||||||
|
OR `c`.`name_pinyin_mixed` LIKE CONCAT(#{keyword}, '%')
|
||||||
)
|
)
|
||||||
</if>
|
</if>
|
||||||
<if test="tagIdList != null and !tagIdList.isEmpty()">
|
<if test="tagIdList != null and !tagIdList.isEmpty()">
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
LIMIT 1
|
LIMIT 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectEarnByEventRecordId" resultType="com.imyeyu.api.modules.gao.entity.GaoPointLedger">
|
<select id="selectRuleChangeByEventRecordId" resultType="com.imyeyu.api.modules.gao.entity.GaoPointLedger">
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM `gao_point_ledger`
|
FROM `gao_point_ledger`
|
||||||
WHERE `event_record_id` = #{eventRecordId}
|
WHERE `event_record_id` = #{eventRecordId}
|
||||||
AND `change_type` = 'EARN'
|
AND `change_type` IN ('EARN', 'CONSUME')
|
||||||
AND `deleted_at` IS NULL
|
AND `deleted_at` IS NULL
|
||||||
ORDER BY `created_at` ASC, `id` ASC
|
ORDER BY `created_at` ASC, `id` ASC
|
||||||
</select>
|
</select>
|
||||||
|
|||||||
Reference in New Issue
Block a user