更新外观模块

This commit is contained in:
super
2026-05-06 22:41:26 +08:00
parent a00ff1804c
commit 8cd1a4e2b1
24 changed files with 1378 additions and 175 deletions

View File

@@ -1604,7 +1604,13 @@ export function getAppearancePatentResultDownloadUrl(resultId: number) {
return getJavaDownloadUrl(`/appearance-patent/results/${resultId}/download`);
}
// ========== 相似ASIN检测 ==========
// ========== 货源查询 ==========
export interface SimilarAsinFilterConditionVo {
id: number;
conditionText: string;
createdAt?: string;
}
export interface SimilarAsinParsedRow {
rowIndex: number;
@@ -1696,7 +1702,7 @@ export interface SimilarAsinTaskBatchVo {
missingTaskIds?: number[];
}
export function parseSimilarAsin(files: UploadedFileRef[], aiPrompt: string, apiKey?: string) {
export function parseSimilarAsin(files: UploadedFileRef[], filterCondition: string, apiKey?: string) {
return unwrapJavaResponse(
post<
JavaApiResponse<SimilarAsinParseVo>,
@@ -1704,12 +1710,41 @@ export function parseSimilarAsin(files: UploadedFileRef[], aiPrompt: string, api
>(`${JAVA_API_PREFIX}/similar-asin/parse`, {
user_id: getCurrentUserId(),
files,
ai_prompt: aiPrompt,
ai_prompt: filterCondition,
api_key: apiKey,
}),
);
}
export function listSimilarAsinFilterConditions() {
return unwrapJavaResponse(
get<JavaApiResponse<SimilarAsinFilterConditionVo[]>>(
`${JAVA_API_PREFIX}/similar-asin/filter-conditions`,
{ params: { user_id: getCurrentUserId() } },
),
);
}
export function addSimilarAsinFilterCondition(conditionText: string) {
return unwrapJavaResponse(
post<
JavaApiResponse<SimilarAsinFilterConditionVo>,
{ user_id: number; condition_text: string }
>(`${JAVA_API_PREFIX}/similar-asin/filter-conditions`, {
user_id: getCurrentUserId(),
condition_text: conditionText,
}),
);
}
export function deleteSimilarAsinFilterCondition(id: number) {
return unwrapJavaResponse(
del<JavaApiResponse<null>>(`${JAVA_API_PREFIX}/similar-asin/filter-conditions/${id}`, {
params: { user_id: getCurrentUserId() },
}),
);
}
export function getSimilarAsinDashboard() {
return unwrapJavaResponse(
get<JavaApiResponse<SimilarAsinDashboardVo>>(

View File

@@ -0,0 +1,156 @@
export type ApiSecretModuleKey = 'appearance-patent' | 'similar-asin'
export type ApiSecretRetention = 'session' | '1d' | '7d' | '30d' | 'forever'
type ApiSecretRecord = {
value: string
retention: ApiSecretRetention
expiresAt: number | null
updatedAt: number
}
export type ApiSecretSnapshot = {
value: string
retention: ApiSecretRetention
expiresAt: number | null
updatedAt: number | null
exists: boolean
}
const STORAGE_PREFIX = 'brand:api-secret'
function currentUserStorageId() {
if (typeof window === 'undefined') return '0'
return window.localStorage.getItem('uid') || '0'
}
function buildStorageKey(moduleKey: ApiSecretModuleKey) {
return `${STORAGE_PREFIX}:${currentUserStorageId()}:${moduleKey}`
}
function readStorageRecord(storage: Storage, moduleKey: ApiSecretModuleKey): ApiSecretRecord | null {
const raw = storage.getItem(buildStorageKey(moduleKey))
if (!raw) return null
try {
const parsed = JSON.parse(raw) as Partial<ApiSecretRecord>
if (typeof parsed.value !== 'string') return null
const retention = normalizeRetention(parsed.retention)
const expiresAt = typeof parsed.expiresAt === 'number' ? parsed.expiresAt : null
const updatedAt = typeof parsed.updatedAt === 'number' ? parsed.updatedAt : Date.now()
return {
value: parsed.value,
retention,
expiresAt,
updatedAt,
}
} catch {
return null
}
}
function normalizeRetention(value: unknown): ApiSecretRetention {
switch (value) {
case '1d':
case '7d':
case '30d':
case 'forever':
case 'session':
return value
default:
return 'session'
}
}
function retentionToExpiresAt(retention: ApiSecretRetention, now: number) {
switch (retention) {
case '1d':
return now + 24 * 60 * 60 * 1000
case '7d':
return now + 7 * 24 * 60 * 60 * 1000
case '30d':
return now + 30 * 24 * 60 * 60 * 1000
case 'forever':
return null
case 'session':
default:
return null
}
}
function isExpired(record: ApiSecretRecord) {
return record.expiresAt != null && record.expiresAt <= Date.now()
}
function clearStorageRecord(storage: Storage, moduleKey: ApiSecretModuleKey) {
storage.removeItem(buildStorageKey(moduleKey))
}
function getLiveRecord(moduleKey: ApiSecretModuleKey): ApiSecretRecord | null {
if (typeof window === 'undefined') return null
const sessionRecord = readStorageRecord(window.sessionStorage, moduleKey)
if (sessionRecord) {
return sessionRecord
}
const localRecord = readStorageRecord(window.localStorage, moduleKey)
if (!localRecord) return null
if (isExpired(localRecord)) {
clearStorageRecord(window.localStorage, moduleKey)
return null
}
return localRecord
}
export function getStoredApiSecret(moduleKey: ApiSecretModuleKey) {
return getLiveRecord(moduleKey)?.value || ''
}
export function getStoredApiSecretSnapshot(moduleKey: ApiSecretModuleKey): ApiSecretSnapshot {
const record = getLiveRecord(moduleKey)
if (!record) {
return {
value: '',
retention: 'session',
expiresAt: null,
updatedAt: null,
exists: false,
}
}
return {
value: record.value,
retention: record.retention,
expiresAt: record.expiresAt,
updatedAt: record.updatedAt,
exists: true,
}
}
export function saveStoredApiSecret(
moduleKey: ApiSecretModuleKey,
value: string,
retention: ApiSecretRetention,
) {
if (typeof window === 'undefined') return
const trimmedValue = value.trim()
clearStoredApiSecret(moduleKey)
if (!trimmedValue) return
const now = Date.now()
const record: ApiSecretRecord = {
value: trimmedValue,
retention,
expiresAt: retentionToExpiresAt(retention, now),
updatedAt: now,
}
const storage = retention === 'session' ? window.sessionStorage : window.localStorage
storage.setItem(buildStorageKey(moduleKey), JSON.stringify(record))
}
export function clearStoredApiSecret(moduleKey: ApiSecretModuleKey) {
if (typeof window === 'undefined') return
clearStorageRecord(window.sessionStorage, moduleKey)
clearStorageRecord(window.localStorage, moduleKey)
}