新增删除增加公司名

This commit is contained in:
super
2026-04-04 00:10:08 +08:00
parent 46d91fd8ca
commit 1ff6d5220e
12 changed files with 244 additions and 28 deletions

View File

@@ -12,7 +12,7 @@ zn_username=%E8%87%AA%E5%8A%A8%E5%8C%96_Robot
client_name=ShuFuAI
java_api_base=http://127.0.0.1:18080
# java_api_base=http://8.136.19.173:18080
# java_api_base=http://127.0.0.1:18080
java_api_base=http://8.136.19.173:18080

View File

@@ -12,6 +12,7 @@ public class DeleteBrandParsedFileCacheDto {
private String fileKey;
private String sourceFilename;
private String shopName;
private String companyName;
private String shopId;
private String platform;
private String openStoreUrl;

View File

@@ -21,6 +21,9 @@ public class DeleteBrandResultItemVo {
@Schema(description = "按 Excel 文件名解析出的店铺名")
private String shopName;
@Schema(description = "紫鸟公司名称")
private String companyName;
@Schema(description = "是否匹配到紫鸟店铺")
private boolean matched;

View File

@@ -133,6 +133,7 @@ public class DeleteBrandRunService {
item.setMatched(matchResult.isMatched());
if (matchResult.isMatched()) {
item.setShopId(matchResult.getShopId());
item.setCompanyName(matchResult.getCompanyName());
item.setPlatform(matchResult.getPlatform());
item.setOpenStoreUrl(matchResult.getOpenStoreUrl());
}
@@ -153,6 +154,7 @@ public class DeleteBrandRunService {
cacheDto.setSourceFilename(sourceFile.getOriginalFilename());
cacheDto.setShopName(item.getShopName());
cacheDto.setShopId(item.getShopId());
cacheDto.setCompanyName(item.getCompanyName());
cacheDto.setPlatform(item.getPlatform());
cacheDto.setOpenStoreUrl(item.getOpenStoreUrl());
cacheDto.setTotalRows(parsed.totalRows());
@@ -204,7 +206,7 @@ public class DeleteBrandRunService {
task.setSuccessFileCount(parsedSuccessCount);
task.setFailedFileCount(parsedFailedCount);
task.setResultJson(JSONUtil.toJsonStr(items));
task.setResultJson(toCompactTaskResultJsonForDb(items));
task.setUpdatedAt(LocalDateTime.now());
task.setSourceFileCount(processableFileCount);
if (processableFileCount <= 0) {
@@ -295,6 +297,7 @@ public class DeleteBrandRunService {
}
item.setShopId(candidate.getShopId());
item.setCompanyName(candidate.getCompanyName());
item.setPlatform(candidate.getPlatform());
item.setOpenStoreUrl(candidate.getOpenStoreUrl());
@@ -716,6 +719,7 @@ public class DeleteBrandRunService {
String oldStatus = item.getMatchStatus();
boolean oldMatched = item.isMatched();
String oldShopId = item.getShopId();
String oldCompanyName = item.getCompanyName();
String oldPlatform = item.getPlatform();
String oldOpenStoreUrl = item.getOpenStoreUrl();
String oldMessage = item.getMatchMessage();
@@ -724,12 +728,14 @@ public class DeleteBrandRunService {
item.setMatchStatus(refreshed.getMatchStatus());
item.setMatchMessage(refreshed.getMatchMessage());
item.setShopId(refreshed.getShopId());
item.setCompanyName(refreshed.getCompanyName());
item.setPlatform(refreshed.getPlatform());
item.setOpenStoreUrl(refreshed.getOpenStoreUrl());
if (!java.util.Objects.equals(oldStatus, item.getMatchStatus())
|| oldMatched != item.isMatched()
|| !java.util.Objects.equals(oldShopId, item.getShopId())
|| !java.util.Objects.equals(oldCompanyName, item.getCompanyName())
|| !java.util.Objects.equals(oldPlatform, item.getPlatform())
|| !java.util.Objects.equals(oldOpenStoreUrl, item.getOpenStoreUrl())
|| !java.util.Objects.equals(oldMessage, item.getMatchMessage())) {
@@ -745,7 +751,7 @@ public class DeleteBrandRunService {
if (!changed) {
return task;
}
task.setResultJson(JSONUtil.toJsonStr(items));
task.setResultJson(toCompactTaskResultJsonForDb(items));
task.setSourceFileCount(matchedCount);
task.setFailedFileCount(unmatchedCount);
task.setUpdatedAt(LocalDateTime.now());
@@ -1120,6 +1126,7 @@ public class DeleteBrandRunService {
item.setFileKey(parsedFile.getFileKey());
item.setSourceFilename(parsedFile.getSourceFilename());
item.setShopName(parsedFile.getShopName());
item.setCompanyName(parsedFile.getCompanyName());
item.setOutputFilename(outputFile.getName());
item.setDownloadUrl(ossStorageService.getPublicUrl(objectKey));
item.setTotalRows(parsedFile.getTotalRows());
@@ -1140,7 +1147,7 @@ public class DeleteBrandRunService {
task.setStatus("SUCCESS");
task.setSuccessFileCount(successCount);
task.setErrorMessage(null);
task.setResultJson(JSONUtil.toJsonStr(finalItems));
task.setResultJson(toCompactTaskResultJsonForDb(finalItems));
task.setUpdatedAt(LocalDateTime.now());
task.setFinishedAt(LocalDateTime.now());
fileTaskMapper.updateById(task);
@@ -1351,6 +1358,33 @@ public class DeleteBrandRunService {
return normalized.isBlank() ? defaultValue : normalized;
}
/**
* 落库用 result_json去掉国家分组、预览行等大字段保留匹配摘要与计数。
* 索引常命中后单次任务 JSON 体积会陡增,易触发 max_allowed_packet / 更新失败,进而前端 unwrap 报「请求失败」。
*/
private String toCompactTaskResultJsonForDb(List<DeleteBrandResultItemVo> items) {
if (items == null || items.isEmpty()) {
return JSONUtil.toJsonStr(List.of());
}
try {
List<DeleteBrandResultItemVo> clone = objectMapper.readValue(
objectMapper.writeValueAsString(items),
new TypeReference<List<DeleteBrandResultItemVo>>() {
});
for (DeleteBrandResultItemVo vo : clone) {
if (vo == null) {
continue;
}
vo.setCountries(new ArrayList<>());
vo.setPreviewRows(new ArrayList<>());
}
return JSONUtil.toJsonStr(clone);
} catch (Exception ex) {
log.warn("[delete-brand] compact task result json failed, msg={}", ex.getMessage());
return JSONUtil.toJsonStr(items);
}
}
private record ParsedDeleteBrandFile(int totalRows,
List<DeleteBrandCountryGroupVo> countries,
List<DeleteBrandPreviewRowVo> previewRows) {

View File

@@ -1,6 +1,7 @@
package com.nanri.aiimage.modules.ziniao.memory.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@@ -15,6 +16,8 @@ public class ZiniaoMemoryStoreEntity {
private Long id;
private String cacheType;
private String cacheKey;
@TableField("company_name")
private String companyName;
private String payloadJson;
private LocalDateTime expiresAt;
private LocalDateTime createdAt;

View File

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.nanri.aiimage.common.exception.BusinessException;
import com.nanri.aiimage.modules.ziniao.memory.mapper.ZiniaoMemoryStoreMapper;
import com.nanri.aiimage.modules.ziniao.memory.model.entity.ZiniaoMemoryStoreEntity;
import com.nanri.aiimage.modules.ziniao.model.cache.ZiniaoShopIndexEntryDto;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
@@ -25,6 +26,9 @@ public class ZiniaoMemoryStoreService {
/** 本表仅用于持久化店铺索引条目(见 ZiniaoShopIndexService。 */
public static final String CACHE_TYPE_SHOP_INDEX_ENTRY = "SHOP_INDEX_ENTRY";
/** INFO 日志里 company_name 采样最大字符数(避免过长刷屏)。 */
private static final int COMPANY_NAME_LOG_SAMPLE_MAX_CHARS = 64;
private final ZiniaoMemoryStoreMapper ziniaoMemoryStoreMapper;
private final ObjectMapper objectMapper;
@@ -115,29 +119,33 @@ public class ZiniaoMemoryStoreService {
}
LocalDateTime now = LocalDateTime.now();
LocalDateTime expiresAt = now.plusSeconds(ttl.getSeconds());
String companyName = resolveCompanyName(payload);
ZiniaoMemoryStoreEntity entity = findOne(normalizedType, normalizedKey);
if (entity == null) {
entity = new ZiniaoMemoryStoreEntity();
entity.setCacheType(normalizedType);
entity.setCacheKey(normalizedKey);
entity.setCompanyName(companyName);
entity.setPayloadJson(payloadJson);
entity.setExpiresAt(expiresAt);
entity.setCreatedAt(now);
entity.setUpdatedAt(now);
ziniaoMemoryStoreMapper.insert(entity);
if (CACHE_TYPE_SHOP_INDEX_ENTRY.equals(normalizedType)) {
log.info("[ziniao-shop-index-db] insert cacheKey={} expiresAt={} bytes={}",
normalizedKey, expiresAt, payloadJson.length());
log.info("[ziniao-shop-index-db] insert cacheKey={} companyNameSample={} expiresAt={} bytes={}",
normalizedKey, sampleCompanyNameForLog(companyName), expiresAt, payloadJson.length());
}
return;
}
companyName = mergeCompanyNameForPersist(entity.getCompanyName(), companyName);
entity.setCompanyName(companyName);
entity.setPayloadJson(payloadJson);
entity.setExpiresAt(expiresAt);
entity.setUpdatedAt(now);
ziniaoMemoryStoreMapper.updateById(entity);
if (CACHE_TYPE_SHOP_INDEX_ENTRY.equals(normalizedType)) {
log.info("[ziniao-shop-index-db] update cacheKey={} id={} expiresAt={} bytes={}",
normalizedKey, entity.getId(), expiresAt, payloadJson.length());
log.info("[ziniao-shop-index-db] update cacheKey={} id={} companyNameSample={} expiresAt={} bytes={}",
normalizedKey, entity.getId(), sampleCompanyNameForLog(companyName), expiresAt, payloadJson.length());
}
}
@@ -149,7 +157,8 @@ public class ZiniaoMemoryStoreService {
if (entity != null) {
ziniaoMemoryStoreMapper.deleteById(entity.getId());
if (CACHE_TYPE_SHOP_INDEX_ENTRY.equals(normalizedType)) {
log.info("[ziniao-shop-index-db] delete cacheKey={} id={}", entity.getCacheKey(), entity.getId());
log.info("[ziniao-shop-index-db] delete cacheKey={} id={} companyNameSample={}",
entity.getCacheKey(), entity.getId(), sampleCompanyNameForLog(entity.getCompanyName()));
}
}
}
@@ -210,6 +219,39 @@ public class ZiniaoMemoryStoreService {
return entity.getExpiresAt() == null || !entity.getExpiresAt().isAfter(LocalDateTime.now());
}
private String resolveCompanyName(Object payload) {
if (payload instanceof ZiniaoShopIndexEntryDto dto) {
return Objects.toString(dto.getCompanyName(), "").trim();
}
return "";
}
/**
* 更新行时:若 payload 未带公司名,保留库里已有值,避免历史/仅改 status 的回写把 company_name 清空。
*/
private static String mergeCompanyNameForPersist(String existingDbValue, String fromPayload) {
String fromNew = fromPayload == null ? "" : fromPayload.trim();
if (!fromNew.isEmpty()) {
return fromNew;
}
String existing = existingDbValue == null ? "" : existingDbValue.trim();
return existing;
}
/**
* 日志用 company_name 采样:空显示 (empty),过长截断并附带原长度,便于运行时对照 DB 写入意图且不刷屏。
*/
private static String sampleCompanyNameForLog(String companyName) {
String s = companyName == null ? "" : companyName.trim();
if (s.isEmpty()) {
return "(empty)";
}
if (s.length() <= COMPANY_NAME_LOG_SAMPLE_MAX_CHARS) {
return s;
}
return s.substring(0, COMPANY_NAME_LOG_SAMPLE_MAX_CHARS) + "…(" + s.length() + " chars)";
}
private String normalizeRequired(String value, String message) {
String normalized = Objects.toString(value, "").trim();
if (normalized.isEmpty()) {

View File

@@ -10,6 +10,7 @@ public class ZiniaoShopIndexEntryDto {
private String normalizedShopName;
private String shopId;
private String shopName;
private String companyName;
private String platform;
private Long matchedUserId;
private Long companyId;

View File

@@ -13,6 +13,12 @@ public class ZiniaoShopIndexRefreshCursorDto {
private Long lastStartedAt;
private Long lastFinishedAt;
private Long lastSuccessAt;
/** 下一轮刷新从 apiKey 列表的哪个 offset 开始。 */
private Integer nextApiKeyOffset;
/** 最近一轮可见 apiKey 总量。 */
private Integer apiKeyTotal;
/** 最近一轮实际处理的 apiKey 数。 */
private Integer lastProcessedApiKeyCount;
private Integer invalidUserCount;
private List<Long> sampleInvalidUserIds = new ArrayList<>();
}

View File

@@ -19,6 +19,9 @@ public class ZiniaoShopMatchResultVo {
@Schema(description = "店铺名称")
private String shopName;
@Schema(description = "紫鸟公司名称")
private String companyName;
@Schema(description = "平台")
private String platform;

View File

@@ -7,7 +7,9 @@ import com.nanri.aiimage.modules.shopkey.model.entity.ShopKeyEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@Service
@RequiredArgsConstructor
@@ -15,16 +17,33 @@ public class ZiniaoApiKeyProvider {
private final ShopKeyMapper shopKeyMapper;
public List<ApiKeyAccount> listApiKeyAccounts() {
List<ShopKeyEntity> entities = shopKeyMapper.selectList(new LambdaQueryWrapper<ShopKeyEntity>()
.orderByDesc(ShopKeyEntity::getId));
Map<String, String> accountByApiKey = new LinkedHashMap<>();
for (ShopKeyEntity entity : entities) {
String apiKey = normalizeApiKey(entity == null ? null : entity.getZiniaoToken());
if (apiKey == null) {
continue;
}
String accountName = entity.getZiniaoAccountName() == null ? null : entity.getZiniaoAccountName().trim();
if (!accountByApiKey.containsKey(apiKey)) {
accountByApiKey.put(apiKey, accountName);
continue;
}
String existingName = accountByApiKey.get(apiKey);
if ((existingName == null || existingName.isBlank()) && accountName != null && !accountName.isBlank()) {
accountByApiKey.put(apiKey, accountName);
}
}
return accountByApiKey.entrySet().stream()
.map(entry -> new ApiKeyAccount(entry.getKey(), entry.getValue()))
.toList();
}
public List<String> listApiKeys() {
return shopKeyMapper.selectList(new LambdaQueryWrapper<ShopKeyEntity>()
.orderByDesc(ShopKeyEntity::getId))
.stream()
.map(ShopKeyEntity::getZiniaoToken)
.filter(token -> token != null && !token.isBlank())
.map(String::trim)
.map(token -> token.regionMatches(true, 0, "Bearer ", 0, 7) ? token.substring(7).trim() : token)
.filter(token -> !token.isBlank())
.distinct()
return listApiKeyAccounts().stream()
.map(ApiKeyAccount::apiKey)
.toList();
}
@@ -40,4 +59,18 @@ public class ZiniaoApiKeyProvider {
Long total = shopKeyMapper.selectCount(new LambdaQueryWrapper<ShopKeyEntity>());
return total != null && total > 0;
}
private String normalizeApiKey(String token) {
if (token == null || token.isBlank()) {
return null;
}
String normalized = token.trim();
if (normalized.regionMatches(true, 0, "Bearer ", 0, 7)) {
normalized = normalized.substring(7).trim();
}
return normalized.isBlank() ? null : normalized;
}
public record ApiKeyAccount(String apiKey, String accountName) {
}
}

View File

@@ -69,6 +69,7 @@ public class ZiniaoShopIndexService {
cursor.setScopeKey("global");
cursor.setStatus("IDLE");
cursor.setMessage("索引刷新任务尚未执行");
cursor.setNextApiKeyOffset(0);
}
return cursor;
}
@@ -107,25 +108,45 @@ public class ZiniaoShopIndexService {
return pendingResult("店铺索引缺少 companyId请等待后台刷新");
}
String openStoreUrl = ziniaoAuthService.buildOpenStoreUrlByScope(apiKey, companyId, entry.getMatchedUserId(), entry.getShopId());
String openStoreUrl = null;
boolean openUrlFailed = false;
try {
openStoreUrl = ziniaoAuthService.buildOpenStoreUrlByScope(apiKey, companyId, entry.getMatchedUserId(), entry.getShopId());
} catch (BusinessException ex) {
openUrlFailed = true;
log.warn("[ziniao-shop-index] buildOpenStoreUrl failed normalizedName={} msg={}", normalizedShopName, ex.getMessage());
}
ZiniaoShopMatchResultVo vo = new ZiniaoShopMatchResultVo();
vo.setMatched(true);
vo.setShopId(entry.getShopId());
vo.setShopName(entry.getShopName());
vo.setCompanyName(entry.getCompanyName());
vo.setPlatform(entry.getPlatform());
vo.setMatchedUserId(entry.getMatchedUserId());
vo.setOpenStoreUrl(openStoreUrl);
vo.setMatchStatus(isFresh(entry) ? MATCH_STATUS_MATCHED : MATCH_STATUS_STALE);
vo.setMatchMessage(isFresh(entry) ? null : "店铺索引已过保鲜期,请等待后台刷新");
if (openUrlFailed) {
vo.setMatchStatus(MATCH_STATUS_STALE);
vo.setMatchMessage("打开店铺链接暂时无法生成,请稍后重试");
} else {
vo.setMatchStatus(isFresh(entry) ? MATCH_STATUS_MATCHED : MATCH_STATUS_STALE);
vo.setMatchMessage(isFresh(entry) ? null : "店铺索引已过保鲜期,请等待后台刷新");
}
return vo;
}
public void refreshShopIndex() {
long now = Instant.now().toEpochMilli();
ZiniaoShopIndexRefreshCursorDto previousCursor = ziniaoTransientCacheService
.get(CACHE_TYPE_SHOP_INDEX_REFRESH_CURSOR, "global", ZiniaoShopIndexRefreshCursorDto.class)
.orElse(null);
int previousOffset = previousCursor == null || previousCursor.getNextApiKeyOffset() == null
? 0
: Math.max(previousCursor.getNextApiKeyOffset(), 0);
ZiniaoShopIndexRefreshCursorDto cursor = new ZiniaoShopIndexRefreshCursorDto();
cursor.setScopeKey("global");
cursor.setStatus("RUNNING");
cursor.setLastStartedAt(now);
cursor.setNextApiKeyOffset(previousOffset);
ziniaoTransientCacheService.put(CACHE_TYPE_SHOP_INDEX_REFRESH_CURSOR, "global", cursor, DEFAULT_CURSOR_TTL);
log.info("[ziniao-index] refresh started");
@@ -134,11 +155,16 @@ public class ZiniaoShopIndexService {
Set<Long> allInvalidUserIds = new LinkedHashSet<>();
int refreshBatchSize = resolveRefreshBatchSize();
try {
List<String> apiKeys = ziniaoApiKeyProvider.listApiKeys();
if (refreshBatchSize > 0 && apiKeys.size() > refreshBatchSize) {
apiKeys = apiKeys.subList(0, refreshBatchSize);
}
for (String apiKey : apiKeys) {
List<ZiniaoApiKeyProvider.ApiKeyAccount> allApiKeyAccounts = ziniaoApiKeyProvider.listApiKeyAccounts();
List<ZiniaoApiKeyProvider.ApiKeyAccount> apiKeyAccounts = selectApiKeyBatchByOffset(
allApiKeyAccounts,
previousOffset,
refreshBatchSize
);
int nextOffset = computeNextOffset(allApiKeyAccounts.size(), previousOffset, apiKeyAccounts.size(), refreshBatchSize);
for (ZiniaoApiKeyProvider.ApiKeyAccount apiKeyAccount : apiKeyAccounts) {
String apiKey = apiKeyAccount.apiKey();
String companyName = apiKeyAccount.accountName();
Long companyId;
try {
companyId = ziniaoAuthService.resolveCompanyIdForIndex(apiKey);
@@ -198,6 +224,7 @@ public class ZiniaoShopIndexService {
entry.setNormalizedShopName(normalizedShopName);
entry.setShopId(store.getShopId());
entry.setShopName(store.getShopName());
entry.setCompanyName(companyName);
entry.setPlatform(store.getPlatform());
entry.setMatchedUserId(userId);
entry.setCompanyId(companyId);
@@ -260,12 +287,16 @@ public class ZiniaoShopIndexService {
cursor.setMessage(allInvalidUserIds.isEmpty()
? null
: "本轮刷新已跳过无效 userId 数: " + allInvalidUserIds.size());
cursor.setApiKeyTotal(allApiKeyAccounts.size());
cursor.setLastProcessedApiKeyCount(apiKeyAccounts.size());
cursor.setNextApiKeyOffset(nextOffset);
cursor.setInvalidUserCount(allInvalidUserIds.size());
cursor.setSampleInvalidUserIds(allInvalidUserIds.stream().limit(20).toList());
cursor.setLastFinishedAt(now);
cursor.setLastSuccessAt(now);
ziniaoTransientCacheService.put(CACHE_TYPE_SHOP_INDEX_REFRESH_CURSOR, "global", cursor, DEFAULT_CURSOR_TTL);
log.info("[ziniao-index] refresh success invalidUsersSkipped={}", allInvalidUserIds.size());
log.info("[ziniao-index] refresh success invalidUsersSkipped={} apiKeyProcessed={}/{} nextOffset={}",
allInvalidUserIds.size(), apiKeyAccounts.size(), allApiKeyAccounts.size(), nextOffset);
} catch (Exception ex) {
cursor.setStatus("FAILED");
cursor.setMessage(ex.getMessage());
@@ -313,6 +344,7 @@ public class ZiniaoShopIndexService {
entry.setNormalizedShopName(normalizedShopName);
entry.setStatus(STATUS_CONFLICT);
entry.setShopName(representative == null ? normalizedShopName : representative.getShopName());
entry.setCompanyName(representative == null ? null : representative.getCompanyName());
entry.setCompanyId(representative == null ? null : representative.getCompanyId());
entry.setApiKeyHash(representative == null ? null : representative.getApiKeyHash());
entry.setCandidateCount(candidates == null ? 0 : candidates.size());
@@ -427,6 +459,17 @@ public class ZiniaoShopIndexService {
|| existingEntry.getNormalizedShopName().isBlank()) {
continue;
}
String companyNameInRow = entity.getCompanyName();
if ((existingEntry.getCompanyName() == null || existingEntry.getCompanyName().isBlank())
&& companyNameInRow != null && !companyNameInRow.isBlank()) {
existingEntry.setCompanyName(companyNameInRow.trim());
}
if (existingEntry.getCompanyName() == null || existingEntry.getCompanyName().isBlank()) {
String accountFromKeys = resolveAccountNameByApiKeyHash(existingEntry.getApiKeyHash());
if (accountFromKeys != null && !accountFromKeys.isBlank()) {
existingEntry.setCompanyName(accountFromKeys.trim());
}
}
if (STATUS_CONFLICT.equals(existingEntry.getStatus())
&& (existingEntry.getCandidateCount() == null || existingEntry.getCandidateCount() <= 0)
&& (existingEntry.getShopName() == null || existingEntry.getShopName().isBlank())
@@ -475,6 +518,36 @@ public class ZiniaoShopIndexService {
return batchSize;
}
private List<ZiniaoApiKeyProvider.ApiKeyAccount> selectApiKeyBatchByOffset(
List<ZiniaoApiKeyProvider.ApiKeyAccount> allApiKeyAccounts,
int offset,
int refreshBatchSize) {
if (allApiKeyAccounts == null || allApiKeyAccounts.isEmpty()) {
return List.of();
}
int total = allApiKeyAccounts.size();
if (refreshBatchSize <= 0 || refreshBatchSize >= total) {
return new ArrayList<>(allApiKeyAccounts);
}
int normalizedOffset = Math.floorMod(offset, total);
List<ZiniaoApiKeyProvider.ApiKeyAccount> selected = new ArrayList<>(refreshBatchSize);
for (int i = 0; i < refreshBatchSize; i++) {
selected.add(allApiKeyAccounts.get((normalizedOffset + i) % total));
}
return selected;
}
private int computeNextOffset(int totalApiKeys, int previousOffset, int processedCount, int refreshBatchSize) {
if (totalApiKeys <= 0) {
return 0;
}
int step = processedCount > 0 ? processedCount : Math.max(refreshBatchSize, 0);
if (step <= 0) {
return Math.floorMod(previousOffset, totalApiKeys);
}
return Math.floorMod(previousOffset + step, totalApiKeys);
}
private List<Long> buildUserIds(List<ZiniaoStaffItemVo> staff) {
List<Long> userIds = new ArrayList<>();
for (ZiniaoStaffItemVo item : staff) {
@@ -535,6 +608,19 @@ public class ZiniaoShopIndexService {
return null;
}
private String resolveAccountNameByApiKeyHash(String apiKeyHash) {
String apiKey = findApiKeyByHash(apiKeyHash);
if (apiKey == null) {
return null;
}
for (ZiniaoApiKeyProvider.ApiKeyAccount acc : ziniaoApiKeyProvider.listApiKeyAccounts()) {
if (apiKey.equals(acc.apiKey())) {
return acc.accountName();
}
}
return null;
}
private String buildApiKeyHash(String apiKey) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");

View File

@@ -0,0 +1,4 @@
ALTER TABLE biz_ziniao_memory_store
ADD COLUMN company_name VARCHAR(255) NULL COMMENT '紫鸟公司名称' AFTER cache_key;
CREATE INDEX idx_company_name ON biz_ziniao_memory_store (company_name);