|
@@ -27,6 +27,7 @@ import com.xuekairui.user.dto.WechatLoginRequest;
|
|
|
import com.xuekairui.user.entity.User;
|
|
import com.xuekairui.user.entity.User;
|
|
|
import com.xuekairui.user.enums.LicenseStatus;
|
|
import com.xuekairui.user.enums.LicenseStatus;
|
|
|
import com.xuekairui.user.enums.MembershipLevel;
|
|
import com.xuekairui.user.enums.MembershipLevel;
|
|
|
|
|
+import com.xuekairui.user.enums.OperationSource;
|
|
|
import com.xuekairui.user.enums.OperationType;
|
|
import com.xuekairui.user.enums.OperationType;
|
|
|
import com.xuekairui.user.enums.OperatorRole;
|
|
import com.xuekairui.user.enums.OperatorRole;
|
|
|
import com.xuekairui.user.event.UserRegisteredEvent;
|
|
import com.xuekairui.user.event.UserRegisteredEvent;
|
|
@@ -44,6 +45,7 @@ import org.springframework.transaction.support.TransactionSynchronization;
|
|
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
|
|
|
|
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalDateTime;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 认证服务
|
|
* 认证服务
|
|
@@ -67,6 +69,8 @@ public class AuthService {
|
|
|
private final ExternalUserSyncService externalUserSyncService;
|
|
private final ExternalUserSyncService externalUserSyncService;
|
|
|
private final CertificateSyncService certificateSyncService;
|
|
private final CertificateSyncService certificateSyncService;
|
|
|
private final BusinessLicenseService businessLicenseService;
|
|
private final BusinessLicenseService businessLicenseService;
|
|
|
|
|
+ private final ShopResourceSyncService shopResourceSyncService;
|
|
|
|
|
+ private final com.xuekairui.user.mapper.LicenseSyncDiffMapper licenseSyncDiffMapper;
|
|
|
private final com.xuekairui.user.mapper.PlatformAccountMapper platformAccountMapper;
|
|
private final com.xuekairui.user.mapper.PlatformAccountMapper platformAccountMapper;
|
|
|
private final com.xuekairui.user.mapper.CrawlerUsageLogMapper crawlerUsageLogMapper;
|
|
private final com.xuekairui.user.mapper.CrawlerUsageLogMapper crawlerUsageLogMapper;
|
|
|
private final com.xuekairui.user.mapper.SearchRecordMapper searchRecordMapper;
|
|
private final com.xuekairui.user.mapper.SearchRecordMapper searchRecordMapper;
|
|
@@ -136,6 +140,9 @@ public class AuthService {
|
|
|
}
|
|
}
|
|
|
auditLogService.logSuccess(user.getId(), user.getNickname(), OperatorRole.USER.getCode(),
|
|
auditLogService.logSuccess(user.getId(), user.getNickname(), OperatorRole.USER.getCode(),
|
|
|
OperationType.USER_LOGIN, "USER:" + user.getId(), user.getId());
|
|
OperationType.USER_LOGIN, "USER:" + user.getId(), user.getId());
|
|
|
|
|
+
|
|
|
|
|
+ // 登录时检查入驻信息,未同步成功则补推一次到第三方
|
|
|
|
|
+ syncShopResourceOnLogin(user.getId());
|
|
|
return response;
|
|
return response;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -160,6 +167,7 @@ public class AuthService {
|
|
|
user.setLastLoginIp(ip);
|
|
user.setLastLoginIp(ip);
|
|
|
user.setLoginSource("PC");
|
|
user.setLoginSource("PC");
|
|
|
userMapper.updateById(user);
|
|
userMapper.updateById(user);
|
|
|
|
|
+ syncShopResourceOnLogin(user.getId());
|
|
|
return buildLoginResponse(user);
|
|
return buildLoginResponse(user);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -262,6 +270,7 @@ public class AuthService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 4. 生成正式Token
|
|
// 4. 生成正式Token
|
|
|
|
|
+ syncShopResourceOnLogin(wechatUser.getId());
|
|
|
return buildLoginResponse(wechatUser);
|
|
return buildLoginResponse(wechatUser);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -639,7 +648,9 @@ public class AuthService {
|
|
|
|
|
|
|
|
/** 映射第三方 shop_type → 内部 terminalType */
|
|
/** 映射第三方 shop_type → 内部 terminalType */
|
|
|
private static String mapShopType(String shopType) {
|
|
private static String mapShopType(String shopType) {
|
|
|
- if (shopType == null) return null;
|
|
|
|
|
|
|
+ if (shopType == null) {
|
|
|
|
|
+ return null;
|
|
|
|
|
+ }
|
|
|
return switch (shopType) {
|
|
return switch (shopType) {
|
|
|
case "1" -> "SINGLE";
|
|
case "1" -> "SINGLE";
|
|
|
case "2" -> "CHAIN";
|
|
case "2" -> "CHAIN";
|
|
@@ -648,9 +659,11 @@ public class AuthService {
|
|
|
};
|
|
};
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /** 映射第三方 status → Integer */
|
|
|
|
|
- private static Integer mapStatus(String status) {
|
|
|
|
|
- if (status == null || status.isBlank()) return 0;
|
|
|
|
|
|
|
+ /** 映射第三方 status → int */
|
|
|
|
|
+ private static int mapStatus(String status) {
|
|
|
|
|
+ if (status == null || status.isBlank()) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
try {
|
|
try {
|
|
|
return Integer.parseInt(status);
|
|
return Integer.parseInt(status);
|
|
|
} catch (NumberFormatException e) {
|
|
} catch (NumberFormatException e) {
|
|
@@ -687,7 +700,7 @@ public class AuthService {
|
|
|
private void syncBusinessLicenseFromShopReport(SyncShopReportRequest req, Long userId) {
|
|
private void syncBusinessLicenseFromShopReport(SyncShopReportRequest req, Long userId) {
|
|
|
String storeName = isNotBlank(req.getContactShop()) ? req.getContactShop() : null;
|
|
String storeName = isNotBlank(req.getContactShop()) ? req.getContactShop() : null;
|
|
|
String terminalType = mapShopType(req.getShopType());
|
|
String terminalType = mapShopType(req.getShopType());
|
|
|
- Integer status = mapStatus(req.getStatus());
|
|
|
|
|
|
|
+ int status = mapStatus(req.getStatus());
|
|
|
|
|
|
|
|
boolean hasLicenseField = isNotBlank(storeName)
|
|
boolean hasLicenseField = isNotBlank(storeName)
|
|
|
|| isNotBlank(terminalType)
|
|
|| isNotBlank(terminalType)
|
|
@@ -701,7 +714,7 @@ public class AuthService {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
String reviewStatus;
|
|
String reviewStatus;
|
|
|
- if (status == null || status == 0) {
|
|
|
|
|
|
|
+ if (status == 0) {
|
|
|
reviewStatus = LicenseStatus.PENDING.name();
|
|
reviewStatus = LicenseStatus.PENDING.name();
|
|
|
} else if (status == 1) {
|
|
} else if (status == 1) {
|
|
|
reviewStatus = LicenseStatus.APPROVED.name();
|
|
reviewStatus = LicenseStatus.APPROVED.name();
|
|
@@ -739,16 +752,36 @@ public class AuthService {
|
|
|
grantLicenseApprovedReward(userId, license.getId());
|
|
grantLicenseApprovedReward(userId, license.getId());
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
- // 已存在记录:仅允许更新审核状态,其他字段保留原值(后续由运营端确认更新)
|
|
|
|
|
|
|
+ // 已存在记录:保存第三方变更的入驻信息到数据库
|
|
|
|
|
+ // 尤其是双方都审核通过(APPROVED)的情况,需要记录第三方变更的字段
|
|
|
boolean upgradedToApproved = false;
|
|
boolean upgradedToApproved = false;
|
|
|
- if (!LicenseStatus.APPROVED.name().equals(existing.getReviewStatus())) {
|
|
|
|
|
|
|
+ boolean wasApproved = LicenseStatus.APPROVED.name().equals(existing.getReviewStatus());
|
|
|
|
|
+
|
|
|
|
|
+ // 更新审核状态
|
|
|
|
|
+ if (!wasApproved) {
|
|
|
|
|
+ // 我方未审核通过:允许第三方直接覆盖本地
|
|
|
existing.setReviewStatus(reviewStatus);
|
|
existing.setReviewStatus(reviewStatus);
|
|
|
upgradedToApproved = LicenseStatus.APPROVED.name().equals(reviewStatus);
|
|
upgradedToApproved = LicenseStatus.APPROVED.name().equals(reviewStatus);
|
|
|
|
|
+ applyThirdPartyLicenseFields(existing, req, storeName, terminalType);
|
|
|
|
|
+ } else if (LicenseStatus.APPROVED.name().equals(reviewStatus)) {
|
|
|
|
|
+ // 双方都审核通过:检测字段是否不一致
|
|
|
|
|
+ // 不直接覆盖本地,而是保存差异记录,等待运营人工确认
|
|
|
|
|
+ Map<String, String[]> diff = detectLicenseDiff(existing, req, storeName, terminalType);
|
|
|
|
|
+ if (!diff.isEmpty()) {
|
|
|
|
|
+ log.info("第三方与本地入驻信息存在差异(双方均已审核通过),保存差异记录待运营确认: userId={}, licenseId={}, diffFields={}",
|
|
|
|
|
+ userId, existing.getId(), diff.keySet());
|
|
|
|
|
+ saveLicenseSyncDiffRecords(userId, existing.getId(), diff);
|
|
|
|
|
+ recordThirdPartyUpdateAudit(req.getPhone(), userId, existing.getId(), diff);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 本地已审核通过,第三方变为非通过状态:仅更新状态,保留本地字段
|
|
|
|
|
+ existing.setReviewStatus(reviewStatus);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
businessLicenseService.updateById(existing);
|
|
businessLicenseService.updateById(existing);
|
|
|
|
|
|
|
|
- log.info("第三方店铺同步已存在记录仅更新状态: licenseId={}, userId={}, oldStatus={}, newStatus={}",
|
|
|
|
|
- existing.getId(), userId, existing.getReviewStatus(), reviewStatus);
|
|
|
|
|
|
|
+ log.info("第三方店铺同步已存在记录: licenseId={}, userId={}, wasApproved={}, thirdStatus={}, upgradedToApproved={}",
|
|
|
|
|
+ existing.getId(), userId, wasApproved, reviewStatus, upgradedToApproved);
|
|
|
|
|
|
|
|
if (upgradedToApproved) {
|
|
if (upgradedToApproved) {
|
|
|
grantLicenseApprovedReward(userId, existing.getId());
|
|
grantLicenseApprovedReward(userId, existing.getId());
|
|
@@ -756,6 +789,149 @@ public class AuthService {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将双方都审核通过时的字段差异保存到 t_license_sync_diff 表,等待运营确认
|
|
|
|
|
+ */
|
|
|
|
|
+ private void saveLicenseSyncDiffRecords(Long userId, Long licenseId, Map<String, String[]> diff) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ diff.forEach((field, values) -> {
|
|
|
|
|
+ com.xuekairui.user.entity.LicenseSyncDiff record =
|
|
|
|
|
+ com.xuekairui.user.entity.LicenseSyncDiff.builder()
|
|
|
|
|
+ .licenseId(licenseId)
|
|
|
|
|
+ .userId(userId)
|
|
|
|
|
+ .fieldName(field)
|
|
|
|
|
+ .localValue(values[0])
|
|
|
|
|
+ .thirdPartyValue(values[1])
|
|
|
|
|
+ .status(0)
|
|
|
|
|
+ .build();
|
|
|
|
|
+ licenseSyncDiffMapper.insert(record);
|
|
|
|
|
+ });
|
|
|
|
|
+ log.info("保存入驻信息差异记录成功: licenseId={}, count={}", licenseId, diff.size());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("保存入驻信息差异记录失败(不阻断同步): licenseId={}, error={}", licenseId, e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 将第三方传入的入驻字段覆盖到本地记录(非空即覆盖)
|
|
|
|
|
+ */
|
|
|
|
|
+ private void applyThirdPartyLicenseFields(
|
|
|
|
|
+ com.xuekairui.user.entity.BusinessLicense existing,
|
|
|
|
|
+ SyncShopReportRequest req, String storeName, String terminalType) {
|
|
|
|
|
+ if (storeName != null) {
|
|
|
|
|
+ existing.setStoreName(storeName);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (terminalType != null) {
|
|
|
|
|
+ existing.setTerminalType(terminalType);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getContactProvince())) {
|
|
|
|
|
+ existing.setProvince(req.getContactProvince());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getContactCity())) {
|
|
|
|
|
+ existing.setCity(req.getContactCity());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getContactArea())) {
|
|
|
|
|
+ existing.setDistrict(req.getContactArea());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getContactAddr())) {
|
|
|
|
|
+ existing.setStoreAddress(req.getContactAddr());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getContactName())) {
|
|
|
|
|
+ existing.setContactPerson(req.getContactName());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getContactPhone())) {
|
|
|
|
|
+ existing.setContactPhone(req.getContactPhone());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getBusinessLicenseImage())) {
|
|
|
|
|
+ existing.setLicenseImageUrl(req.getBusinessLicenseImage());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getDrugBusinessLicenseImage())) {
|
|
|
|
|
+ existing.setDrugLicenseUrl(req.getDrugBusinessLicenseImage());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getTwoMedicalDeviceRegistration())) {
|
|
|
|
|
+ existing.setMedicalDeviceClass2Url(req.getTwoMedicalDeviceRegistration());
|
|
|
|
|
+ }
|
|
|
|
|
+ if (isNotBlank(req.getThreeMedicalDeviceBusinessLicense())) {
|
|
|
|
|
+ existing.setMedicalDeviceClass3Url(req.getThreeMedicalDeviceBusinessLicense());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 检测本地入驻信息与第三方传入字段的不一致项
|
|
|
|
|
+ * <p>返回 Map:key=字段名,value=[本地值, 第三方值]
|
|
|
|
|
+ */
|
|
|
|
|
+ private Map<String, String[]> detectLicenseDiff(
|
|
|
|
|
+ com.xuekairui.user.entity.BusinessLicense existing,
|
|
|
|
|
+ SyncShopReportRequest req, String storeName, String terminalType) {
|
|
|
|
|
+ Map<String, String[]> diff = new java.util.LinkedHashMap<>();
|
|
|
|
|
+ if (storeName != null && !storeName.equals(existing.getStoreName())) {
|
|
|
|
|
+ diff.put("storeName", new String[]{existing.getStoreName(), storeName});
|
|
|
|
|
+ }
|
|
|
|
|
+ if (terminalType != null && !terminalType.equals(existing.getTerminalType())) {
|
|
|
|
|
+ diff.put("terminalType", new String[]{existing.getTerminalType(), terminalType});
|
|
|
|
|
+ }
|
|
|
|
|
+ putIfDiff(diff, "province", existing.getProvince(), req.getContactProvince());
|
|
|
|
|
+ putIfDiff(diff, "city", existing.getCity(), req.getContactCity());
|
|
|
|
|
+ putIfDiff(diff, "district", existing.getDistrict(), req.getContactArea());
|
|
|
|
|
+ putIfDiff(diff, "storeAddress", existing.getStoreAddress(), req.getContactAddr());
|
|
|
|
|
+ putIfDiff(diff, "contactPerson", existing.getContactPerson(), req.getContactName());
|
|
|
|
|
+ putIfDiff(diff, "contactPhone", existing.getContactPhone(), req.getContactPhone());
|
|
|
|
|
+ putIfDiff(diff, "licenseImageUrl", existing.getLicenseImageUrl(), req.getBusinessLicenseImage());
|
|
|
|
|
+ putIfDiff(diff, "drugLicenseUrl", existing.getDrugLicenseUrl(), req.getDrugBusinessLicenseImage());
|
|
|
|
|
+ putIfDiff(diff, "medicalDeviceClass2Url",
|
|
|
|
|
+ existing.getMedicalDeviceClass2Url(), req.getTwoMedicalDeviceRegistration());
|
|
|
|
|
+ putIfDiff(diff, "medicalDeviceClass3Url",
|
|
|
|
|
+ existing.getMedicalDeviceClass3Url(), req.getThreeMedicalDeviceBusinessLicense());
|
|
|
|
|
+ return diff;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private static void putIfDiff(Map<String, String[]> diff, String field, String local, String third) {
|
|
|
|
|
+ if (third != null && !third.isBlank() && !third.equals(local)) {
|
|
|
|
|
+ diff.put(field, new String[]{local, third});
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 记录第三方变更入驻信息的审计日志
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 第三方同步入驻信息时,我们不对对方谁操作做验证,
|
|
|
|
|
+ * 只通过对方传过来的用户手机号判断变更了谁的信息。
|
|
|
|
|
+ * 审计日志中记录:被变更用户的手机号、用户ID、变更前后的字段值。
|
|
|
|
|
+ *
|
|
|
|
|
+ * @param phone 第三方传入的用户手机号(用于识别被变更的用户)
|
|
|
|
|
+ * @param userId 被变更的用户ID
|
|
|
|
|
+ * @param licenseId 入驻信息ID
|
|
|
|
|
+ * @param diff 变更字段差异(key=字段名,value=[本地值, 第三方值])
|
|
|
|
|
+ */
|
|
|
|
|
+ private void recordThirdPartyUpdateAudit(String phone, Long userId, Long licenseId, Map<String, String[]> diff) {
|
|
|
|
|
+ try {
|
|
|
|
|
+ Map<String, Object> beforeData = new java.util.LinkedHashMap<>();
|
|
|
|
|
+ Map<String, Object> afterData = new java.util.LinkedHashMap<>();
|
|
|
|
|
+ diff.forEach((field, values) -> {
|
|
|
|
|
+ beforeData.put(field, values[0]);
|
|
|
|
|
+ afterData.put(field, values[1]);
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // 目标标识:用户手机号 + 用户ID,便于审计时定位"变更了谁的信息"
|
|
|
|
|
+ String targetIdentifier = String.format("PHONE:%s|USER:%d|LICENSE:%d",
|
|
|
|
|
+ phone != null ? phone : "UNKNOWN", userId, licenseId);
|
|
|
|
|
+
|
|
|
|
|
+ auditLogService.logSuccess(
|
|
|
|
|
+ 0L,
|
|
|
|
|
+ OperatorRole.SYSTEM,
|
|
|
|
|
+ OperationType.LICENSE_THIRD_UPDATE,
|
|
|
|
|
+ targetIdentifier,
|
|
|
|
|
+ licenseId,
|
|
|
|
|
+ beforeData,
|
|
|
|
|
+ afterData,
|
|
|
|
|
+ String.format("第三方变更入驻信息(双方均已审核通过,待运营确认):用户手机号 %s(ID=%d),共 %d 个字段不一致: %s",
|
|
|
|
|
+ phone != null ? phone : "UNKNOWN", userId, diff.size(), diff.keySet()),
|
|
|
|
|
+ OperationSource.SYSTEM_SYNC);
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("记录第三方变更入驻信息审计日志失败: licenseId={}, error={}", licenseId, e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 第三方登录接口同步入驻信息(适配 ExternalTokenRequest → SyncInfoRequest)
|
|
* 第三方登录接口同步入驻信息(适配 ExternalTokenRequest → SyncInfoRequest)
|
|
|
*/
|
|
*/
|
|
@@ -1101,6 +1277,110 @@ public class AuthService {
|
|
|
.build();
|
|
.build();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 登录时检查入驻信息并同步到第三方(智价云药店版)
|
|
|
|
|
+ * <p>
|
|
|
|
|
+ * 仅在我方系统自行登录(短信/密码/微信/小程序)时触发,第三方登录不走此逻辑。
|
|
|
|
|
+ * 幂等策略:仅当入驻记录存在且 status != 1(未同步成功)时才补推一次,
|
|
|
|
|
+ * 避免每次登录都重复调用第三方接口。
|
|
|
|
|
+ * 同步在事务提交后异步执行,不阻塞登录响应,失败仅记录日志。
|
|
|
|
|
+ */
|
|
|
|
|
+ private void syncShopResourceOnLogin(Long userId) {
|
|
|
|
|
+ if (userId == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ com.xuekairui.user.entity.BusinessLicense license =
|
|
|
|
|
+ businessLicenseService.getByUserId(userId);
|
|
|
|
|
+ if (license == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ // status=1 表示已同步成功,跳过;0=未同步,2=同步失败,需补推
|
|
|
|
|
+ if (license.getStatus() != null && license.getStatus() == 1) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ User user = userMapper.selectById(userId);
|
|
|
|
|
+ if (user == null) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ String phone = user.getPhone();
|
|
|
|
|
+ String userName = user.getNickname() != null
|
|
|
|
|
+ ? user.getNickname() : String.valueOf(userId);
|
|
|
|
|
+ String storeName = license.getStoreName() != null ? license.getStoreName() : "未知药店";
|
|
|
|
|
+ String targetIdentifier = String.format("PHONE:%s|USER:%d|LICENSE:%d",
|
|
|
|
|
+ phone != null ? phone : "UNKNOWN", userId, license.getId());
|
|
|
|
|
+
|
|
|
|
|
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public void afterCommit() {
|
|
|
|
|
+ try {
|
|
|
|
|
+ ShopResourceSyncService.SyncResult result =
|
|
|
|
|
+ shopResourceSyncService.syncShopResource(user, license);
|
|
|
|
|
+ if (result != null && result.getUserId() != null) {
|
|
|
|
|
+ license.setExternalId(result.getUserId());
|
|
|
|
|
+ license.setStatus(1);
|
|
|
|
|
+ businessLicenseService.updateById(license);
|
|
|
|
|
+ log.info("登录时同步入驻信息到第三方成功: userId={}, externalUserId={}",
|
|
|
|
|
+ userId, result.getUserId());
|
|
|
|
|
+
|
|
|
|
|
+ auditLogService.logSuccess(
|
|
|
|
|
+ 0L,
|
|
|
|
|
+ OperatorRole.SYSTEM,
|
|
|
|
|
+ OperationType.LICENSE_SYNC_THIRD,
|
|
|
|
|
+ targetIdentifier,
|
|
|
|
|
+ license.getId(),
|
|
|
|
|
+ null,
|
|
|
|
|
+ Map.of("userId", userId, "userName", userName, "storeName", storeName,
|
|
|
|
|
+ "phone", phone != null ? phone : "UNKNOWN",
|
|
|
|
|
+ "trigger", "LOGIN",
|
|
|
|
|
+ "externalUserId", result.getUserId(), "newUser", result.getNewUser()),
|
|
|
|
|
+ String.format("登录时同步客户「%s」(手机号:%s,药店:%s)的入驻信息到第三方成功,第三方用户ID:%s",
|
|
|
|
|
+ userName, phone != null ? phone : "UNKNOWN", storeName, result.getUserId()),
|
|
|
|
|
+ OperationSource.SYSTEM_SYNC);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ license.setStatus(2);
|
|
|
|
|
+ businessLicenseService.updateById(license);
|
|
|
|
|
+ log.warn("登录时同步入驻信息到第三方未成功(未返回user_id): userId={}", userId);
|
|
|
|
|
+
|
|
|
|
|
+ auditLogService.logSuccess(
|
|
|
|
|
+ 0L,
|
|
|
|
|
+ OperatorRole.SYSTEM,
|
|
|
|
|
+ OperationType.LICENSE_SYNC_THIRD,
|
|
|
|
|
+ targetIdentifier,
|
|
|
|
|
+ license.getId(),
|
|
|
|
|
+ null,
|
|
|
|
|
+ Map.of("userId", userId, "userName", userName, "storeName", storeName,
|
|
|
|
|
+ "phone", phone != null ? phone : "UNKNOWN",
|
|
|
|
|
+ "trigger", "LOGIN", "result", "no_user_id"),
|
|
|
|
|
+ String.format("登录时同步客户「%s」(手机号:%s,药店:%s)的入驻信息到第三方未成功:第三方未返回用户ID",
|
|
|
|
|
+ userName, phone != null ? phone : "UNKNOWN", storeName),
|
|
|
|
|
+ OperationSource.SYSTEM_SYNC);
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("登录时同步入驻信息到第三方失败(不阻断登录): userId={}, error={}",
|
|
|
|
|
+ userId, e.getMessage());
|
|
|
|
|
+
|
|
|
|
|
+ auditLogService.logSuccess(
|
|
|
|
|
+ 0L,
|
|
|
|
|
+ OperatorRole.SYSTEM,
|
|
|
|
|
+ OperationType.LICENSE_SYNC_THIRD,
|
|
|
|
|
+ targetIdentifier,
|
|
|
|
|
+ license.getId(),
|
|
|
|
|
+ null,
|
|
|
|
|
+ Map.of("userId", userId, "userName", userName, "storeName", storeName,
|
|
|
|
|
+ "phone", phone != null ? phone : "UNKNOWN",
|
|
|
|
|
+ "trigger", "LOGIN", "error", e.getMessage()),
|
|
|
|
|
+ String.format("登录时同步客户「%s」(手机号:%s,药店:%s)的入驻信息到第三方失败:%s",
|
|
|
|
|
+ userName, phone != null ? phone : "UNKNOWN", storeName, e.getMessage()),
|
|
|
|
|
+ OperationSource.SYSTEM_SYNC);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("登录时检查入驻信息失败(不阻断登录): userId={}, error={}", userId, e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* 转换用户信息响应
|
|
* 转换用户信息响应
|
|
|
*/
|
|
*/
|
|
@@ -1215,6 +1495,7 @@ public class AuthService {
|
|
|
LoginResponse response = buildLoginResponse(user);
|
|
LoginResponse response = buildLoginResponse(user);
|
|
|
auditLogService.logSuccess(user.getId(), user.getNickname(), OperatorRole.USER.getCode(),
|
|
auditLogService.logSuccess(user.getId(), user.getNickname(), OperatorRole.USER.getCode(),
|
|
|
OperationType.USER_LOGIN, "USER:" + user.getId(), user.getId());
|
|
OperationType.USER_LOGIN, "USER:" + user.getId(), user.getId());
|
|
|
|
|
+ syncShopResourceOnLogin(user.getId());
|
|
|
return response;
|
|
return response;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1360,6 +1641,7 @@ public class AuthService {
|
|
|
auditLogService.logSuccess(user.getId(), user.getNickname(), OperatorRole.USER.getCode(),
|
|
auditLogService.logSuccess(user.getId(), user.getNickname(), OperatorRole.USER.getCode(),
|
|
|
isNewLocal ? OperationType.USER_REGISTER : OperationType.USER_LOGIN,
|
|
isNewLocal ? OperationType.USER_REGISTER : OperationType.USER_LOGIN,
|
|
|
"USER:" + user.getId(), user.getId());
|
|
"USER:" + user.getId(), user.getId());
|
|
|
|
|
+ syncShopResourceOnLogin(user.getId());
|
|
|
return response;
|
|
return response;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1416,7 +1698,7 @@ public class AuthService {
|
|
|
eventPublisher.publishEvent(new UserRegisteredEvent(
|
|
eventPublisher.publishEvent(new UserRegisteredEvent(
|
|
|
this, wechatUser.getId(), request.getInviteCode()));
|
|
this, wechatUser.getId(), request.getInviteCode()));
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+ syncShopResourceOnLogin(wechatUser.getId());
|
|
|
return buildMiniAppLoginResponse(wechatUser);
|
|
return buildMiniAppLoginResponse(wechatUser);
|
|
|
}
|
|
}
|
|
|
|
|
|