Compare commits

...
28 Commits
Author SHA1 Message Date
timi c8e2e16ba5 Merge pull request 'v1.0.15' (#24) from dev into master
Reviewed-on: #24
2026-08-15 17:49:51 +00:00
Timi bdc4cbb240 v1.0.15
CI / build-deploy (pull_request) Successful in 27s
CI / notify-on-failure (pull_request) Skipped
2026-08-16 01:49:18 +08:00
timi 99b44faf09 Merge pull request 'v1.0.15' (#23) from dev into master
Reviewed-on: #23
2026-08-15 17:45:26 +00:00
Timi 7f6cebd4e2 v1.0.15
CI / build-deploy (pull_request) Failing after 6s
CI / notify-on-failure (pull_request) Successful in 0s
2026-08-16 01:44:45 +08:00
Timi 75fd4bed18 fix event save fail for limit == 1 2026-08-15 15:01:08 +08:00
timi b3e3cbf84b Merge pull request 'v1.0.14' (#22) from dev into master
Reviewed-on: #22
2026-08-14 17:31:11 +00:00
Timi 8db6f962c9 v1.0.14
CI / build-deploy (pull_request) Successful in 22s
CI / notify-on-failure (pull_request) Skipped
2026-08-15 01:30:51 +08:00
timi 0aee11d824 Merge pull request 'v1.0.14' (#21) from dev into master
Reviewed-on: #21
2026-08-14 17:26:10 +00:00
timi fcf358a768 Merge pull request 'v1.0.13' (#20) from dev into master
Reviewed-on: #20
2026-08-13 09:52:26 +00:00
timi 619369104c Merge pull request 'v1.0.12' (#19) from dev into master
Reviewed-on: #19
2026-08-12 17:02:43 +00:00
timi 4f1408b9d0 Merge pull request 'v1.0.11' (#18) from dev into master
Reviewed-on: #18
2026-08-11 16:49:08 +00:00
timi 029eea70cc Merge pull request 'v1.0.10' (#17) from dev into master
Reviewed-on: #17
2026-08-11 16:45:36 +00:00
timi 22b1e65385 Merge pull request 'v1.0.9' (#16) from dev into master
Reviewed-on: #16
2026-08-11 16:01:10 +00:00
timi 2170c48763 Merge pull request 'v1.0.8' (#15) from dev into master
Reviewed-on: #15
2026-08-03 16:36:19 +00:00
timi c2d1c48aae Merge pull request 'v0.0.18' (#14) from dev into master
Reviewed-on: #14
2026-08-03 11:59:20 +00:00
timi e14958c643 Merge pull request 'v0.0.18' (#13) from dev into master
Reviewed-on: #13
2026-08-03 11:58:16 +00:00
timi da288338cd Merge pull request 'v1.0.7' (#12) from dev into master
Reviewed-on: #12
2026-08-01 09:34:18 +00:00
timi ea430f2468 Merge pull request 'v1.0.6' (#11) from dev into master
Reviewed-on: #11
2026-08-01 09:03:48 +00:00
timi f76f79744a Merge pull request 'v1.0.5' (#10) from dev into master
Reviewed-on: #10
2026-08-01 08:52:52 +00:00
timi 19daaff907 Merge pull request 'v1.0.4' (#9) from dev into master
Reviewed-on: #9
2026-08-01 03:13:00 +00:00
timi db94d8f932 Merge pull request 'v1.0.3' (#8) from dev into master
Reviewed-on: #8
2026-07-31 17:19:48 +00:00
timi 53618fe362 Merge pull request 'v1.0.3' (#7) from dev into master
Reviewed-on: #7
2026-07-31 17:13:37 +00:00
timi 523edffc4e Merge pull request 'v1.0.2' (#6) from dev into master
Reviewed-on: #6
2026-04-13 10:28:11 +00:00
timi c7ddb1a8b0 Merge pull request 'v1.0.1' (#5) from dev into master
Reviewed-on: #5
2026-04-12 16:17:02 +00:00
timi 45c9fc814a Merge pull request 'v1.0.0' (#4) from dev into master
Reviewed-on: #4
2026-04-09 05:16:04 +00:00
timi 407dc13ac4 Merge pull request 'v1.0.0' (#3) from dev into master
Reviewed-on: #3
2026-04-09 04:09:16 +00:00
timi 0c06bf16c2 Merge pull request 'v1.0.0' (#2) from dev into master
Reviewed-on: #2
2026-04-09 04:03:43 +00:00
timi 1db39e77d3 Merge pull request 'v1.0.0' (#1) from dev into master
Reviewed-on: #1
2026-04-08 08:48:12 +00:00
11 changed files with 125 additions and 25 deletions
+5
View File
@@ -46,6 +46,11 @@ jobs:
<username>${{ vars.TIMI_NEXUS_USERNAME }}</username> <username>${{ vars.TIMI_NEXUS_USERNAME }}</username>
<password>${{ vars.TIMI_NEXUS_PASSWORD }}</password> <password>${{ vars.TIMI_NEXUS_PASSWORD }}</password>
</server> </server>
<server>
<id>e2ins_nexus</id>
<username>${{ vars.E2INS_NEXUS_USERNAME }}</username>
<password>${{ vars.E2INS_NEXUS_PASSWORD }}</password>
</server>
</servers> </servers>
</settings> </settings>
EOF EOF
+16 -1
View File
@@ -11,7 +11,7 @@
<groupId>com.imyeyu.timiserverapi</groupId> <groupId>com.imyeyu.timiserverapi</groupId>
<artifactId>TimiServerAPI</artifactId> <artifactId>TimiServerAPI</artifactId>
<version>1.0.14</version> <version>1.0.15</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>TimiServerAPI</name> <name>TimiServerAPI</name>
<description>imyeyu.com API</description> <description>imyeyu.com API</description>
@@ -167,6 +167,16 @@
<enabled>true</enabled> <enabled>true</enabled>
</snapshots> </snapshots>
</repository> </repository>
<repository>
<id>e2ins_nexus</id>
<url>https://nexus.e2ins.com/repository/maven-public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories> </repositories>
<dependencies> <dependencies>
@@ -225,6 +235,11 @@
<groupId>org.flywaydb</groupId> <groupId>org.flywaydb</groupId>
<artifactId>flyway-mysql</artifactId> <artifactId>flyway-mysql</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.e2ins.ms.notify</groupId>
<artifactId>e2ins-msg-notify-service-sdk</artifactId>
<version>0.0.9</version>
</dependency>
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId> <artifactId>spring-boot-starter-freemarker</artifactId>
@@ -1,5 +1,6 @@
package com.imyeyu.api.config; package com.imyeyu.api.config;
import com.e2ins.ms.notify.SmsNotifyService;
import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.MapperFeature;
@@ -31,6 +32,12 @@ public class BeanConfig {
.build(); .build();
} }
@Bean
public SmsNotifyService smsNotifyService() {
// TODO
return new SmsNotifyService(null, null);
}
@Bean @Bean
public Yaml yaml() { public Yaml yaml() {
return new Yaml(); return new Yaml();
@@ -12,7 +12,7 @@ public class GaoUserInviteCache {
/// 发起邀请的用户 ID /// 发起邀请的用户 ID
private String inviterUserId; private String inviterUserId;
/// 门店 ID /// 门店 IDGLOBAL_MANAGER 可为空
private String storeId; private String storeId;
/// 角色 ID /// 角色 ID
@@ -62,7 +62,9 @@ public class GaoEventController {
@RequireGaoPermission(GaoPermissionCode.EVENT_READ) @RequireGaoPermission(GaoPermissionCode.EVENT_READ)
@PostMapping("/detail") @PostMapping("/detail")
public GaoEvent detail(@RequestParam String id) { public GaoEvent detail(@RequestParam String id) {
return service.get(id); GaoEvent event = service.get(id);
event.setRoleCodeList(service.listRoleCode(event.getId()));
return event;
} }
@AOPLog @AOPLog
@@ -221,7 +221,7 @@ public class GaoEventServiceImplement extends AbstractEntityService<GaoEvent, St
TimiException.required(event.getValueUnit(), "NUMBER 事件必须配置数值单位"); TimiException.required(event.getValueUnit(), "NUMBER 事件必须配置数值单位");
} }
if (TimiJava.isNotEmpty(event.getLimitType()) && event.getLimitType() != GaoEvent.LimitType.NONE) { if (TimiJava.isNotEmpty(event.getLimitType()) && event.getLimitType() != GaoEvent.LimitType.NONE) {
TimiException.requiredTrue(event.getLimitType().getMin() < event.getLimitValue(), "约束值最低 %s".formatted(event.getLimitType().getMin())); TimiException.requiredTrue(event.getLimitType().getMin() <= event.getLimitValue(), "约束值最低 %s".formatted(event.getLimitType().getMin()));
} }
if (event.getBeginAt() != null || event.getEndAt() != null) { if (event.getBeginAt() != null || event.getEndAt() != null) {
TimiException.requiredTrue(event.getBeginAt() == null || event.getEndAt() == null || event.getBeginAt() <= event.getEndAt(), "invalid beginAt or endAt"); TimiException.requiredTrue(event.getBeginAt() == null || event.getEndAt() == null || event.getBeginAt() <= event.getEndAt(), "invalid beginAt or endAt");
@@ -1,5 +1,6 @@
package com.imyeyu.api.modules.gao.service.implement; package com.imyeyu.api.modules.gao.service.implement;
import com.imyeyu.api.bean.CoreRoleCode;
import com.imyeyu.api.bean.ModuleCode; import com.imyeyu.api.bean.ModuleCode;
import com.imyeyu.api.config.dbsource.TimiServerDBConfig; import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.modules.gao.bean.GaoUserInviteCache; import com.imyeyu.api.modules.gao.bean.GaoUserInviteCache;
@@ -96,30 +97,36 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
String inviterUserId = userLoginService.getRequireLoginUserId(); String inviterUserId = userLoginService.getRequireLoginUserId();
logger.setUserId(inviterUserId); logger.setUserId(inviterUserId);
permissionChecker.checkAny(ModuleCode.GAO, GaoPermissionCode.USER_CREATE.getValue()); permissionChecker.checkAny(ModuleCode.GAO, GaoPermissionCode.USER_CREATE.getValue());
Role requestedRole = roleService.get(req.getRoleId());
boolean adminInviteGlobalManager = roleChecker.hasAny(ModuleCode.CORE, CoreRoleCode.ADMIN.name())
&& isGlobalManagerRole(requestedRole);
boolean globalManager = authorizationScopeService.isSystemAdmin(inviterUserId) boolean globalManager = authorizationScopeService.isSystemAdmin(inviterUserId)
|| roleChecker.hasAny(ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name()); || roleChecker.hasAny(ModuleCode.GAO, GaoRoleCode.GLOBAL_MANAGER.name());
boolean storeManager = !globalManager; boolean storeManager = !globalManager;
GaoStore loginStore = storeManager ? gaoStoreService.getByUserId(inviterUserId) : null; GaoStore loginStore = storeManager ? gaoStoreService.getByUserId(inviterUserId) : null;
String storeId = storeManager ? loginStore == null ? null : loginStore.getId() : req.getStoreId(); String storeId = adminInviteGlobalManager ? null : storeManager ? loginStore == null ? null : loginStore.getId() : req.getStoreId();
if (!adminInviteGlobalManager) {
TimiException.required(storeId, "not found storeId"); TimiException.required(storeId, "not found storeId");
checkStoreScope(inviterUserId, storeId); checkStoreScope(inviterUserId, storeId);
}
GaoStore store = requireActiveStore(storeId); if (storeId != null) {
requireActiveStore(storeId);
}
Role role = requireInvitableRole(inviterUserId, req.getRoleId(), storeId); Role role = requireInvitableRole(inviterUserId, req.getRoleId(), storeId);
long createdAt = Time.now(); long createdAt = Time.now();
long expireAt = createdAt + INVITE_TTL; long expireAt = createdAt + INVITE_TTL;
GaoUserInviteCache cache = new GaoUserInviteCache(); GaoUserInviteCache cache = new GaoUserInviteCache();
cache.setInviterUserId(inviterUserId); cache.setInviterUserId(inviterUserId);
cache.setStoreId(store.getId()); cache.setStoreId(storeId);
cache.setRoleId(role.getId()); cache.setRoleId(role.getId());
cache.setScene(storeManager ? "STORE_MANAGER" : "STORE_MANAGEMENT"); cache.setScene(adminInviteGlobalManager ? "CORE_ADMIN" : storeManager ? "STORE_MANAGER" : "STORE_MANAGEMENT");
cache.setCreatedAt(createdAt); cache.setCreatedAt(createdAt);
cache.setExpireAt(expireAt); cache.setExpireAt(expireAt);
String code = saveInvite(cache); String code = saveInvite(cache);
logger.setContent("storeId=%s;roleId=%s;scene=%s;createdAt=%d;expireAt=%d".formatted( logger.setContent("storeId=%s;roleId=%s;scene=%s;createdAt=%d;expireAt=%d".formatted(
store.getId(), role.getId(), cache.getScene(), createdAt, expireAt)); storeId, role.getId(), cache.getScene(), createdAt, expireAt));
logger.setResult("created"); logger.setResult("created");
return new GaoUserInviteCreateResponse(code, expireAt); return new GaoUserInviteCreateResponse(code, expireAt);
} catch (TimiException e) { } catch (TimiException e) {
@@ -141,8 +148,7 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
TimiException.required(code, "not found code"); TimiException.required(code, "not found code");
checkCodeRateLimit(code); checkCodeRateLimit(code);
GaoUserInviteCache cache = requireValidInvite(code); GaoUserInviteCache cache = requireValidInvite(code);
requireActiveStore(cache.getStoreId()); validateInviteTarget(cache);
requireValidRole(cache.getRoleId(), cache.getStoreId());
return new GaoUserInviteValidateResponse(true, cache.getExpireAt()); return new GaoUserInviteValidateResponse(true, cache.getExpireAt());
} }
@@ -163,8 +169,7 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
try { try {
cache = requireValidInvite(code); cache = requireValidInvite(code);
logger.setContent(buildLogContent(cache)); logger.setContent(buildLogContent(cache));
requireActiveStore(cache.getStoreId()); validateInviteTarget(cache);
requireValidRole(cache.getRoleId(), cache.getStoreId());
TimiException.requiredNull(userService.getByName(data.getName()), "existed user name"); TimiException.requiredNull(userService.getByName(data.getName()), "existed user name");
TimiException.requiredNull(userService.getByPhoneNo(data.getPhoneNo()), "existed phone number"); TimiException.requiredNull(userService.getByPhoneNo(data.getPhoneNo()), "existed phone number");
if (!redisInvite.destroy(getInviteKey(code))) { if (!redisInvite.destroy(getInviteKey(code))) {
@@ -176,10 +181,16 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
user.setPhoneNo(data.getPhoneNo()); user.setPhoneNo(data.getPhoneNo());
user.setPassword(data.getPassword()); user.setPassword(data.getPassword());
if (cache.getStoreId() == null) {
// TODO 用更好的方式
userService.create(user);
userService.verifyPhoneNo(user.getId());
} else {
GaoUser gaoUser = new GaoUser(); GaoUser gaoUser = new GaoUser();
gaoUser.setStoreId(cache.getStoreId()); gaoUser.setStoreId(cache.getStoreId());
gaoUser.setUser(user); gaoUser.setUser(user);
gaoUserService.create(gaoUser); gaoUserService.create(gaoUser);
}
UserRole userRole = new UserRole(); UserRole userRole = new UserRole();
userRole.setId(UUID.randomUUID().toString()); userRole.setId(UUID.randomUUID().toString());
@@ -265,7 +276,7 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
private Role requireValidRole(String roleId, String storeId) { private Role requireValidRole(String roleId, String storeId) {
Role role = roleService.get(roleId); Role role = roleService.get(roleId);
if (role == null || role.getModuleCode() != ModuleCode.GAO || !isRoleUsableForStore(role, storeId)) { if (role == null || role.getModuleCode() != ModuleCode.GAO || (storeId == null && !isGlobalManagerRole(role)) || !isRoleUsableForStore(role, storeId)) {
throw invalidInvite(); throw invalidInvite();
} }
return role; return role;
@@ -274,7 +285,20 @@ public class GaoUserInviteServiceImplement implements GaoUserInviteService {
private boolean isRoleUsableForStore(Role role, String storeId) { private boolean isRoleUsableForStore(Role role, String storeId) {
return role.getOwnerType() == null return role.getOwnerType() == null
|| role.getOwnerType() == AuthOwnerType.MODULE && (TimiJava.isEmpty(role.getOwnerId()) || ModuleCode.GAO.name().equals(role.getOwnerId())) || role.getOwnerType() == AuthOwnerType.MODULE && (TimiJava.isEmpty(role.getOwnerId()) || ModuleCode.GAO.name().equals(role.getOwnerId()))
|| role.getOwnerType() == AuthOwnerType.STORE && storeId.equals(role.getOwnerId()); || role.getOwnerType() == AuthOwnerType.STORE && storeId != null && storeId.equals(role.getOwnerId());
}
private boolean isGlobalManagerRole(Role role) {
return role != null
&& role.getModuleCode() == ModuleCode.GAO
&& GaoRoleCode.GLOBAL_MANAGER.name().equals(role.getCode());
}
private void validateInviteTarget(GaoUserInviteCache cache) {
if (cache.getStoreId() != null) {
requireActiveStore(cache.getStoreId());
}
requireValidRole(cache.getRoleId(), cache.getStoreId());
} }
private void checkStoreScope(String userId, String storeId) { private void checkStoreScope(String userId, String storeId) {
@@ -0,0 +1,22 @@
package com.imyeyu.api.modules.gao.vo;
import com.fasterxml.jackson.annotation.JsonView;
import com.imyeyu.api.modules.gao.entity.GaoEventRecord;
import com.imyeyu.spring.bean.PageResult;
import com.imyeyu.spring.util.ResponseView;
import lombok.Data;
import lombok.EqualsAndHashCode;
///
/// 登记事件记录分页查询结果
///
/// @author Codex
/// @since 2026-08-14
@Data
@EqualsAndHashCode(callSuper = true)
public class GaoEventRecordPageResult extends PageResult<GaoEventRecord> {
/// 指定单个数值事件的登记数值合计,未指定单个 NUMBER 事件时为空
@JsonView(ResponseView.Public.class)
private Long numberValueTotal;
}
@@ -10,7 +10,7 @@ import lombok.Data;
@Data @Data
public class GaoUserInviteCreateRequest { public class GaoUserInviteCreateRequest {
/// 门店管理场景的目标门店 ID,店长场景不使用 /// 门店管理场景的目标门店 ID,店长场景及 ADMIN 邀请 GLOBAL_MANAGER 时不使用
private String storeId; private String storeId;
/// 目标角色 ID /// 目标角色 ID
@@ -1,5 +1,6 @@
package com.imyeyu.api.modules.user.service; package com.imyeyu.api.modules.user.service;
import com.e2ins.ms.notify.vo.sms.CaptchaVerifyReq;
import com.imyeyu.api.modules.user.entity.User; import com.imyeyu.api.modules.user.entity.User;
import com.imyeyu.api.modules.user.vo.LoginRequest; import com.imyeyu.api.modules.user.vo.LoginRequest;
import com.imyeyu.api.modules.user.vo.LoginResponse; import com.imyeyu.api.modules.user.vo.LoginResponse;
@@ -23,6 +24,8 @@ public interface UserLoginService {
LoginResponse login(String token, String userId); LoginResponse login(String token, String userId);
LoginResponse loginBySms(CaptchaVerifyReq req);
/** /**
* 根据令牌获取用户 * 根据令牌获取用户
* *
@@ -1,5 +1,8 @@
package com.imyeyu.api.modules.user.service.implement; package com.imyeyu.api.modules.user.service.implement;
import com.e2ins.ms.notify.SmsNotifyService;
import com.e2ins.ms.notify.bean.NotifyDetail;
import com.e2ins.ms.notify.vo.sms.CaptchaVerifyReq;
import com.imyeyu.api.config.dbsource.TimiServerDBConfig; import com.imyeyu.api.config.dbsource.TimiServerDBConfig;
import com.imyeyu.api.modules.common.entity.Attachment; import com.imyeyu.api.modules.common.entity.Attachment;
import com.imyeyu.api.modules.common.entity.Setting; import com.imyeyu.api.modules.common.entity.Setting;
@@ -7,13 +10,13 @@ import com.imyeyu.api.modules.common.service.AttachmentService;
import com.imyeyu.api.modules.common.service.SettingService; import com.imyeyu.api.modules.common.service.SettingService;
import com.imyeyu.api.modules.user.bean.BootstrapData; import com.imyeyu.api.modules.user.bean.BootstrapData;
import com.imyeyu.api.modules.user.entity.User; import com.imyeyu.api.modules.user.entity.User;
import com.imyeyu.api.modules.user.service.RoleService;
import com.imyeyu.api.modules.user.service.UserLoginService; import com.imyeyu.api.modules.user.service.UserLoginService;
import com.imyeyu.api.modules.user.service.UserRoleService; import com.imyeyu.api.modules.user.service.UserRoleService;
import com.imyeyu.api.modules.user.service.UserService; import com.imyeyu.api.modules.user.service.UserService;
import com.imyeyu.api.modules.user.vo.LoginRequest; import com.imyeyu.api.modules.user.vo.LoginRequest;
import com.imyeyu.api.modules.user.vo.LoginResponse; import com.imyeyu.api.modules.user.vo.LoginResponse;
import com.imyeyu.java.TimiJava; import com.imyeyu.java.TimiJava;
import com.imyeyu.java.bean.timi.TimiCode;
import com.imyeyu.java.bean.timi.TimiException; import com.imyeyu.java.bean.timi.TimiException;
import com.imyeyu.spring.TimiSpring; import com.imyeyu.spring.TimiSpring;
import com.imyeyu.spring.util.Redis; import com.imyeyu.spring.util.Redis;
@@ -27,6 +30,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
@@ -44,9 +48,9 @@ public class UserLoginServiceImplement implements UserLoginService, TimiJava {
private static final long PHONE_VERIFY_CODE_TTL = Time.M * 5; private static final long PHONE_VERIFY_CODE_TTL = Time.M * 5;
private final UserService userService; private final UserService userService;
private final RoleService roleService;
private final SettingService settingService; private final SettingService settingService;
private final UserRoleService userRoleService; private final UserRoleService userRoleService;
private final SmsNotifyService smsNotifyService;
private final AttachmentService attachmentService; private final AttachmentService attachmentService;
private final Redis<String, String> redisUserToken; private final Redis<String, String> redisUserToken;
@@ -98,6 +102,24 @@ public class UserLoginServiceImplement implements UserLoginService, TimiJava {
return result; return result;
} }
@Override
public LoginResponse loginBySms(CaptchaVerifyReq req) {
try {
NotifyDetail detail = smsNotifyService.captchaVerify(req);
// 无报错即成功
User user = userService.getByPhoneNo(detail.getSendTo());
if (!user.isValidPhone()) {
user.setPhoneNoVerifyAt(Time.now());
userService.update(user);
}
return login(UUID.randomUUID().toString(), user.getId());
} catch (IOException e) {
log.error("login by sms error", e);
throw new TimiException(TimiCode.ERROR, "验证短信失败");
}
}
@Override @Override
public User getLoginUser(String token) { public User getLoginUser(String token) {
if (TimiJava.isEmpty(token)) { if (TimiJava.isEmpty(token)) {