更新外观模块
This commit is contained in:
@@ -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>>(
|
||||
|
||||
156
frontend-vue/src/shared/utils/api-secret-store.ts
Normal file
156
frontend-vue/src/shared/utils/api-secret-store.ts
Normal 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)
|
||||
}
|
||||
Reference in New Issue
Block a user