task-24: java-modules.ts 改为纯 re-export 聚合器,upload helpers 移至 upload.ts
This commit is contained in:
@@ -1,15 +1,3 @@
|
||||
import {
|
||||
del,
|
||||
get,
|
||||
http,
|
||||
post,
|
||||
put,
|
||||
type JavaApiResponse,
|
||||
unwrapJavaResponse,
|
||||
} from "./http.ts";
|
||||
import { getTaskProgressCacheTtlMs, getTaskProgressTimeoutMs } from "../task-progress-config.ts";
|
||||
import { createTaskProgressRequestCache } from "../task-progress-request-cache.ts";
|
||||
|
||||
export * from "./types/modules/dedupe.ts";
|
||||
export * from "./types/modules/split.ts";
|
||||
export * from "./types/modules/convert.ts";
|
||||
@@ -26,166 +14,13 @@ export * from "./types/modules/image-video.ts";
|
||||
export * from "./types/modules/brand.ts";
|
||||
export * from "./types/modules/permission.ts";
|
||||
export * from "./types/modules/digital-human.ts";
|
||||
import type {
|
||||
ProductRiskCandidateVo,
|
||||
ProductRiskDashboardVo,
|
||||
ProductRiskMatchShopsVo,
|
||||
ProductRiskShopQueueItem,
|
||||
} from "./types/modules/shop-match.ts";
|
||||
import type {
|
||||
QueryAsinCandidateVo,
|
||||
QueryAsinDashboardVo,
|
||||
} from "./types/modules/query-asin.ts";
|
||||
|
||||
const JAVA_API_PREFIX = "/newApi/api";
|
||||
|
||||
interface TaskProgressBatchOptions {
|
||||
force?: boolean;
|
||||
}
|
||||
|
||||
/** 进度批量接口的响应缓存与并发合并:TTL 过期、有界条目、in-flight 去重 */
|
||||
const taskProgressResponseCache = createTaskProgressRequestCache<unknown>({
|
||||
ttlMs: () => getTaskProgressCacheTtlMs(),
|
||||
maxEntries: 100,
|
||||
maxInflight: 16,
|
||||
});
|
||||
|
||||
function getCurrentUserId() {
|
||||
const raw =
|
||||
typeof window === "undefined"
|
||||
? ""
|
||||
: window.localStorage.getItem("uid") || "";
|
||||
const value = Number(raw);
|
||||
if (!Number.isFinite(value) || value <= 0) {
|
||||
throw new Error("未获取到用户ID");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function normalizeTaskIds(taskIds: number[]) {
|
||||
return Array.from(
|
||||
new Set(
|
||||
(taskIds || [])
|
||||
.map((taskId) => Number(taskId))
|
||||
.filter((taskId) => Number.isFinite(taskId) && taskId > 0),
|
||||
),
|
||||
).sort((left, right) => left - right);
|
||||
}
|
||||
|
||||
function buildTaskProgressRequestKey(path: string, taskIds: number[]) {
|
||||
return `${path}::${taskIds.join(",")}`;
|
||||
}
|
||||
|
||||
async function postTaskProgressBatch<T>(
|
||||
path: string,
|
||||
taskIds: number[],
|
||||
options: TaskProgressBatchOptions = {},
|
||||
) {
|
||||
const normalizedTaskIds = normalizeTaskIds(taskIds);
|
||||
if (!normalizedTaskIds.length) {
|
||||
return { items: [], missingTaskIds: [] } as T;
|
||||
}
|
||||
|
||||
const cacheKey = buildTaskProgressRequestKey(path, normalizedTaskIds);
|
||||
const cached = taskProgressResponseCache.get(cacheKey);
|
||||
if (!options.force && cached !== undefined) {
|
||||
return cached as T;
|
||||
}
|
||||
|
||||
const inflight = taskProgressResponseCache.getInflight(cacheKey);
|
||||
if (!options.force && inflight) {
|
||||
return (await inflight) as T;
|
||||
}
|
||||
|
||||
const requestPromise = unwrapJavaResponse(
|
||||
post<JavaApiResponse<T>, { taskIds: number[] }>(path, { taskIds: normalizedTaskIds }, {
|
||||
timeout: getTaskProgressTimeoutMs(),
|
||||
}),
|
||||
)
|
||||
.then((data) => {
|
||||
taskProgressResponseCache.set(cacheKey, data);
|
||||
return data;
|
||||
})
|
||||
.finally(() => {
|
||||
taskProgressResponseCache.endInflight(cacheKey);
|
||||
});
|
||||
|
||||
taskProgressResponseCache.startInflight(cacheKey, requestPromise);
|
||||
return requestPromise;
|
||||
}
|
||||
|
||||
export interface UploadedFileRef {
|
||||
fileKey: string;
|
||||
originalFilename?: string;
|
||||
relativePath?: string;
|
||||
}
|
||||
|
||||
export interface UploadFileVo {
|
||||
fileKey: string;
|
||||
originalFilename: string;
|
||||
localPath: string;
|
||||
size: number;
|
||||
relativePath?: string;
|
||||
objectKey?: string;
|
||||
url?: string;
|
||||
mediaType?: "image" | "video" | "audio" | "file" | string;
|
||||
}
|
||||
|
||||
export interface UploadTempFileOptions {
|
||||
relativePath?: string;
|
||||
uploadToOss?: boolean;
|
||||
moduleType?: string;
|
||||
}
|
||||
|
||||
export async function uploadTempFileToJava(
|
||||
file: File,
|
||||
relativePathOrOptions?: string | UploadTempFileOptions,
|
||||
) {
|
||||
const options =
|
||||
typeof relativePathOrOptions === 'string'
|
||||
? { relativePath: relativePathOrOptions }
|
||||
: relativePathOrOptions || {}
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
if (options.relativePath) {
|
||||
formData.append('relativePath', options.relativePath)
|
||||
}
|
||||
if (options.uploadToOss) {
|
||||
formData.append('uploadToOss', 'true')
|
||||
}
|
||||
if (options.moduleType) {
|
||||
formData.append('moduleType', options.moduleType)
|
||||
}
|
||||
const response = await http.post<JavaApiResponse<UploadFileVo>>(
|
||||
`${JAVA_API_PREFIX}/files/upload`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
timeout: 120000,
|
||||
},
|
||||
)
|
||||
return response.data
|
||||
}
|
||||
|
||||
|
||||
export function getJavaDownloadUrl(path: string) {
|
||||
let raw =
|
||||
path.startsWith("http://") || path.startsWith("https://")
|
||||
? path
|
||||
: `${JAVA_API_PREFIX}${path}`;
|
||||
// pywebview 的 save_file_from_url_new 需要完整且带 schema 的 URL
|
||||
if (
|
||||
!raw.startsWith("http://") &&
|
||||
!raw.startsWith("https://") &&
|
||||
typeof window !== "undefined"
|
||||
) {
|
||||
raw = `${window.location.origin}${raw}`;
|
||||
}
|
||||
const separator = raw.includes("?") ? "&" : "?";
|
||||
return `${raw}${separator}user_id=${encodeURIComponent(String(getCurrentUserId()))}`;
|
||||
}
|
||||
|
||||
export { JAVA_API_PREFIX, http };
|
||||
|
||||
export * from "./upload.ts";
|
||||
export * from "./download-url.ts";
|
||||
export { JAVA_API_PREFIX } from "./url.ts";
|
||||
export { http } from "./http.ts";
|
||||
export type { JavaApiResponse } from "./http.ts";
|
||||
export type {
|
||||
ApiResponse,
|
||||
LegacyApiSuccess,
|
||||
LegacyApiFailure,
|
||||
} from "./http.ts";
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
import { http, type JavaApiResponse } from './http.ts'
|
||||
import { JAVA_API_PREFIX } from './url.ts'
|
||||
|
||||
export interface UploadedFileRef {
|
||||
fileKey: string;
|
||||
originalFilename?: string;
|
||||
relativePath?: string;
|
||||
}
|
||||
|
||||
export interface UploadFileVo {
|
||||
fileKey: string;
|
||||
originalFilename: string;
|
||||
localPath: string;
|
||||
size: number;
|
||||
relativePath?: string;
|
||||
objectKey?: string;
|
||||
url?: string;
|
||||
mediaType?: "image" | "video" | "audio" | "file" | string;
|
||||
}
|
||||
|
||||
export interface UploadTempFileOptions {
|
||||
relativePath?: string;
|
||||
uploadToOss?: boolean;
|
||||
moduleType?: string;
|
||||
}
|
||||
|
||||
export async function uploadTempFileToJava(
|
||||
file: File,
|
||||
relativePathOrOptions?: string | UploadTempFileOptions,
|
||||
) {
|
||||
const options =
|
||||
typeof relativePathOrOptions === 'string'
|
||||
? { relativePath: relativePathOrOptions }
|
||||
: relativePathOrOptions || {}
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
if (options.relativePath) {
|
||||
formData.append('relativePath', options.relativePath)
|
||||
}
|
||||
if (options.uploadToOss) {
|
||||
formData.append('uploadToOss', 'true')
|
||||
}
|
||||
if (options.moduleType) {
|
||||
formData.append('moduleType', options.moduleType)
|
||||
}
|
||||
const response = await http.post<JavaApiResponse<UploadFileVo>>(
|
||||
`${JAVA_API_PREFIX}/files/upload`,
|
||||
formData,
|
||||
{
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
timeout: 120000,
|
||||
},
|
||||
)
|
||||
return response.data
|
||||
}
|
||||
Reference in New Issue
Block a user