task-23: 拆分 image-video / brand / permission / digital-human 模块 API 至 types/modules/,旧文件转 re-export 存根
This commit is contained in:
@@ -1,108 +1 @@
|
|||||||
import { requestDeleteJson, requestGetJson, requestPostJson } from '@/shared/api/http'
|
export * from './types/modules/brand'
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BrandExpandFolderItem {
|
|
||||||
absolutePath: string
|
|
||||||
relativePath: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BrandExpandFolderResponse {
|
|
||||||
success: boolean
|
|
||||||
items?: BrandExpandFolderItem[]
|
|
||||||
error?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BrandTaskResultPaths {
|
|
||||||
zip_url?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BrandTaskItem {
|
|
||||||
id: number | string
|
|
||||||
status?: 'pending' | 'running' | 'success' | 'failed' | 'cancelled' | string
|
|
||||||
desc?: string
|
|
||||||
file_paths?: string[]
|
|
||||||
created_at?: string
|
|
||||||
progress_total?: number
|
|
||||||
progress_current?: number
|
|
||||||
result_paths?: BrandTaskResultPaths
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BrandTaskListResponse {
|
|
||||||
success: boolean
|
|
||||||
items?: BrandTaskItem[]
|
|
||||||
error?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BrandTaskDetailResponse {
|
|
||||||
success: boolean
|
|
||||||
task?: BrandTaskItem
|
|
||||||
error?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BrandTaskMutationResponse {
|
|
||||||
success: boolean
|
|
||||||
task_id?: string
|
|
||||||
error?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const API_PREFIX = ''
|
|
||||||
|
|
||||||
export function getBrandTaskEventsUrl(taskId: string | number) {
|
|
||||||
return `${API_PREFIX}/api/brand/tasks/${taskId}/events?user_id=${encodeURIComponent(String(getCurrentUserId()))}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBrandTaskDownloadUrl(taskId: string | number) {
|
|
||||||
return `${API_PREFIX}/api/brand/tasks/${taskId}/download?user_id=${encodeURIComponent(String(getCurrentUserId()))}`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBrandTemplateXlsxUrl() {
|
|
||||||
return `${API_PREFIX}/static/品牌文档格式_模板.xlsx`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBrandTemplateZipUrl() {
|
|
||||||
return `${API_PREFIX}/static/模板2-以文件夹方式上传.zip`
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandBrandFolder(folder: string) {
|
|
||||||
return requestPostJson<BrandExpandFolderResponse>(`${API_PREFIX}/api/brand/expand-folder`, { folder })
|
|
||||||
}
|
|
||||||
|
|
||||||
export function expandBrandFolderRecursive(folder: string) {
|
|
||||||
return requestPostJson<BrandExpandFolderResponse>(`${API_PREFIX}/api/brand/expand-folder-recursive`, { folder })
|
|
||||||
}
|
|
||||||
|
|
||||||
export function runBrandNow(paths: string[], strategy: string) {
|
|
||||||
return requestPostJson<BrandTaskMutationResponse>(`${API_PREFIX}/api/brand/run`, { paths, strategy })
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createBrandTask(paths: string[], strategy: string) {
|
|
||||||
return requestPostJson<BrandTaskMutationResponse>(`${API_PREFIX}/api/brand/tasks?userId=${encodeURIComponent(String(getCurrentUserId()))}`, { paths, strategy })
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBrandTasks() {
|
|
||||||
return requestGetJson<BrandTaskListResponse>(`${API_PREFIX}/api/brand/tasks?userId=${encodeURIComponent(String(getCurrentUserId()))}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBrandTask(taskId: string | number) {
|
|
||||||
return requestGetJson<BrandTaskDetailResponse>(`${API_PREFIX}/api/brand/tasks/${taskId}?userId=${encodeURIComponent(String(getCurrentUserId()))}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cancelBrandTask(taskId: string | number) {
|
|
||||||
return requestPostJson<BrandTaskMutationResponse>(`${API_PREFIX}/api/brand/tasks/${taskId}/cancel?userId=${encodeURIComponent(String(getCurrentUserId()))}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteBrandTask(taskId: string | number) {
|
|
||||||
return requestDeleteJson<BrandTaskMutationResponse>(`${API_PREFIX}/api/brand/tasks/${taskId}?userId=${encodeURIComponent(String(getCurrentUserId()))}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createBrandTaskEvents(taskId: string | number) {
|
|
||||||
return new EventSource(getBrandTaskEventsUrl(taskId))
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,157 +1 @@
|
|||||||
import { get, post, del, type JavaApiResponse, unwrapJavaResponse } from '@/shared/api/http'
|
export * from './types/modules/digital-human'
|
||||||
|
|
||||||
const JAVA_API_PREFIX = '/newApi/api/digital-human/versions'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 数字人版本信息
|
|
||||||
*/
|
|
||||||
export interface DigitalHumanVersion {
|
|
||||||
id: number
|
|
||||||
version: string
|
|
||||||
ossObjectKey: string
|
|
||||||
fileSize: number
|
|
||||||
md5: string
|
|
||||||
changelog: string | null
|
|
||||||
minClientVersion: string | null
|
|
||||||
isLatest: boolean
|
|
||||||
status: 'DRAFT' | 'RELEASED' | 'DEPRECATED'
|
|
||||||
createdBy: string | null
|
|
||||||
createdAt: string
|
|
||||||
releasedAt: string | null
|
|
||||||
downloadUrl?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载链接信息
|
|
||||||
*/
|
|
||||||
export interface DownloadUrlVo {
|
|
||||||
version: string
|
|
||||||
downloadUrl: string
|
|
||||||
expiresIn: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页查询参数
|
|
||||||
*/
|
|
||||||
export interface VersionListParams {
|
|
||||||
page?: number
|
|
||||||
pageSize?: number
|
|
||||||
status?: 'DRAFT' | 'RELEASED' | 'DEPRECATED'
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分页结果
|
|
||||||
*/
|
|
||||||
export interface PageResult<T> {
|
|
||||||
records: T[]
|
|
||||||
total: number
|
|
||||||
size: number
|
|
||||||
current: number
|
|
||||||
pages: number
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 上传新版本
|
|
||||||
*/
|
|
||||||
export function uploadDigitalHumanVersion(
|
|
||||||
file: File,
|
|
||||||
version: string,
|
|
||||||
changelog?: string,
|
|
||||||
minClientVersion?: string,
|
|
||||||
) {
|
|
||||||
const formData = new FormData()
|
|
||||||
formData.append('file', file)
|
|
||||||
formData.append('version', version)
|
|
||||||
if (changelog) formData.append('changelog', changelog)
|
|
||||||
if (minClientVersion) formData.append('minClientVersion', minClientVersion)
|
|
||||||
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<DigitalHumanVersion>>(
|
|
||||||
`${JAVA_API_PREFIX}/upload`,
|
|
||||||
formData,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'multipart/form-data',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询版本列表
|
|
||||||
*/
|
|
||||||
export function getDigitalHumanVersions(params?: VersionListParams) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
get<JavaApiResponse<PageResult<DigitalHumanVersion>>>(
|
|
||||||
JAVA_API_PREFIX,
|
|
||||||
{ params },
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取最新版本
|
|
||||||
*/
|
|
||||||
export function getLatestDigitalHumanVersion() {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
get<JavaApiResponse<DigitalHumanVersion>>(
|
|
||||||
`${JAVA_API_PREFIX}/latest`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定版本详情
|
|
||||||
*/
|
|
||||||
export function getDigitalHumanVersion(version: string) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
get<JavaApiResponse<DigitalHumanVersion>>(
|
|
||||||
`${JAVA_API_PREFIX}/${version}`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布版本
|
|
||||||
*/
|
|
||||||
export function releaseDigitalHumanVersion(version: string) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<void>>(
|
|
||||||
`${JAVA_API_PREFIX}/${version}/release`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设为最新版本
|
|
||||||
*/
|
|
||||||
export function setLatestDigitalHumanVersion(version: string) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<void>>(
|
|
||||||
`${JAVA_API_PREFIX}/${version}/set-latest`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 删除版本
|
|
||||||
*/
|
|
||||||
export function deleteDigitalHumanVersion(version: string) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
del<JavaApiResponse<void>>(
|
|
||||||
`${JAVA_API_PREFIX}/${version}`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取下载链接
|
|
||||||
*/
|
|
||||||
export function getDigitalHumanVersionDownloadUrl(version: string) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
get<JavaApiResponse<DownloadUrlVo>>(
|
|
||||||
`${JAVA_API_PREFIX}/${version}/download-url`,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ export * from "./types/modules/shop-match.ts";
|
|||||||
export * from "./types/modules/query-asin.ts";
|
export * from "./types/modules/query-asin.ts";
|
||||||
export * from "./types/modules/withdraw.ts";
|
export * from "./types/modules/withdraw.ts";
|
||||||
export * from "./types/modules/collect-data.ts";
|
export * from "./types/modules/collect-data.ts";
|
||||||
|
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 {
|
import type {
|
||||||
ProductRiskCandidateVo,
|
ProductRiskCandidateVo,
|
||||||
ProductRiskDashboardVo,
|
ProductRiskDashboardVo,
|
||||||
@@ -166,274 +170,6 @@ export async function uploadTempFileToJava(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// ========== 视频复刻 / 图生视频 ==========
|
|
||||||
|
|
||||||
export interface ImageVideoDouyinCopyVo {
|
|
||||||
recognizedContent?: string;
|
|
||||||
scriptDraft?: string;
|
|
||||||
executeId?: string;
|
|
||||||
debugUrl?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoDouyinCopyPayload {
|
|
||||||
url: string;
|
|
||||||
api_key?: string;
|
|
||||||
t8_key?: string;
|
|
||||||
duration?: number;
|
|
||||||
proc_info?: {
|
|
||||||
type: string;
|
|
||||||
name: string;
|
|
||||||
proc_image: string[];
|
|
||||||
properties: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoSecretStatusVo {
|
|
||||||
userId?: number;
|
|
||||||
configured?: boolean;
|
|
||||||
valid?: boolean;
|
|
||||||
expired?: boolean;
|
|
||||||
hasCopyApiKey?: boolean;
|
|
||||||
hasT8Key?: boolean;
|
|
||||||
hasT8VideoKey?: boolean;
|
|
||||||
hasVoiceApiKey?: boolean;
|
|
||||||
hasVoiceGroupId?: boolean;
|
|
||||||
copyApiKeyMasked?: string;
|
|
||||||
t8KeyMasked?: string;
|
|
||||||
t8VideoKeyMasked?: string;
|
|
||||||
voiceApiKeyMasked?: string;
|
|
||||||
voiceGroupIdMasked?: string;
|
|
||||||
expireDays?: number;
|
|
||||||
expiresAt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoSecretSavePayload {
|
|
||||||
copyApiKey?: string;
|
|
||||||
t8Key?: string;
|
|
||||||
t8VideoKey?: string;
|
|
||||||
voiceApiKey?: string;
|
|
||||||
voiceGroupId?: string;
|
|
||||||
expireDays: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoWorkflowParameters {
|
|
||||||
api_key_info: {
|
|
||||||
t8star_key: string;
|
|
||||||
t8_video_key: string;
|
|
||||||
ai_conductor_key: string;
|
|
||||||
};
|
|
||||||
bg_info: {
|
|
||||||
type: number;
|
|
||||||
prompt: string;
|
|
||||||
bg_image: string;
|
|
||||||
};
|
|
||||||
face_info: {
|
|
||||||
type: number;
|
|
||||||
model_figure: string;
|
|
||||||
model_image: string[];
|
|
||||||
};
|
|
||||||
proc_info: {
|
|
||||||
type: string;
|
|
||||||
name: string;
|
|
||||||
proc_image: string[];
|
|
||||||
properties: string;
|
|
||||||
};
|
|
||||||
text_info: {
|
|
||||||
type: number;
|
|
||||||
language: string;
|
|
||||||
text: string;
|
|
||||||
file_url: string;
|
|
||||||
};
|
|
||||||
audio_info: {
|
|
||||||
audio_url: string;
|
|
||||||
type: number;
|
|
||||||
bgm_url: string;
|
|
||||||
mode: number;
|
|
||||||
voice_name: string;
|
|
||||||
};
|
|
||||||
video_info: {
|
|
||||||
video_url: string;
|
|
||||||
share_url: string;
|
|
||||||
ref_video_mode: string;
|
|
||||||
mode: string;
|
|
||||||
draft: boolean;
|
|
||||||
model: string;
|
|
||||||
prompt: string;
|
|
||||||
ratio: string;
|
|
||||||
resolution: string;
|
|
||||||
duration: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoWorkflowResponse {
|
|
||||||
code?: number;
|
|
||||||
msg?: string;
|
|
||||||
data?: string;
|
|
||||||
execute_id?: string;
|
|
||||||
debug_url?: string;
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ImageVideoAsyncTaskStatus = 'PENDING' | 'RUNNING' | 'WAITING' | 'POLLING' | 'SUCCESS' | 'FAILED'
|
|
||||||
|
|
||||||
export interface ImageVideoAsyncTaskVo {
|
|
||||||
taskId: number;
|
|
||||||
taskType: string;
|
|
||||||
status: ImageVideoAsyncTaskStatus;
|
|
||||||
cozeExecuteId?: string;
|
|
||||||
cozeStatus?: string;
|
|
||||||
debugUrl?: string;
|
|
||||||
result?: unknown;
|
|
||||||
errorMessage?: string;
|
|
||||||
submittedAt?: string;
|
|
||||||
completedAt?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoMediaUploadVo {
|
|
||||||
url: string;
|
|
||||||
objectKey: string;
|
|
||||||
originalFilename: string;
|
|
||||||
mediaType: "image" | "video" | "audio" | string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoVoiceWorkflowResponse {
|
|
||||||
code?: number;
|
|
||||||
msg?: string;
|
|
||||||
data?: unknown;
|
|
||||||
execute_id?: string;
|
|
||||||
debug_url?: string;
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoWorkflowRunRequest {
|
|
||||||
userId: number;
|
|
||||||
parameters: ImageVideoWorkflowParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageVideoWorkflowResultRequest {
|
|
||||||
userId: number;
|
|
||||||
executeId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getImageVideoSecretStatus() {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
get<JavaApiResponse<ImageVideoSecretStatusVo>>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/secrets`,
|
|
||||||
{ params: { user_id: getCurrentUserId() } },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function saveImageVideoSecrets(payload: ImageVideoSecretSavePayload) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
put<JavaApiResponse<ImageVideoSecretStatusVo>, ImageVideoSecretSavePayload & { userId: number }>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/secrets`,
|
|
||||||
{ ...payload, userId: getCurrentUserId() },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function runImageVideoDouyinCopy(payload: ImageVideoDouyinCopyPayload) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<ImageVideoAsyncTaskVo>, ImageVideoDouyinCopyPayload & { userId: number }>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/douyin-copy`,
|
|
||||||
{ userId: getCurrentUserId(), ...payload },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function runImageVideoWorkflow(parameters: ImageVideoWorkflowParameters) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<ImageVideoAsyncTaskVo>, ImageVideoWorkflowRunRequest>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/workflow/run`,
|
|
||||||
{ userId: getCurrentUserId(), parameters },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getImageVideoWorkflowResult(executeId: string) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<ImageVideoAsyncTaskVo>, ImageVideoWorkflowResultRequest>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/workflow/result`,
|
|
||||||
{ userId: getCurrentUserId(), executeId },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getImageVideoAsyncTask(taskId: number) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
get<JavaApiResponse<ImageVideoAsyncTaskVo>>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/tasks/${taskId}`,
|
|
||||||
{ params: { user_id: getCurrentUserId() } },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function uploadImageVideoMedia(file: File) {
|
|
||||||
const response = await uploadTempFileToJava(file, {
|
|
||||||
uploadToOss: true,
|
|
||||||
moduleType: "IMAGE_VIDEO",
|
|
||||||
});
|
|
||||||
if (!response.success) {
|
|
||||||
throw new Error(response.message || "请求失败");
|
|
||||||
}
|
|
||||||
const data = response.data;
|
|
||||||
if (!data?.url || !data.objectKey) {
|
|
||||||
throw new Error("OSS 上传未返回有效 URL");
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
url: data.url,
|
|
||||||
objectKey: data.objectKey,
|
|
||||||
originalFilename: data.originalFilename || file.name,
|
|
||||||
mediaType: data.mediaType || resolveImageVideoMediaType(file),
|
|
||||||
} as ImageVideoMediaUploadVo;
|
|
||||||
}
|
|
||||||
|
|
||||||
function resolveImageVideoMediaType(file: File) {
|
|
||||||
const type = (file.type || "").toLowerCase();
|
|
||||||
const name = (file.name || "").toLowerCase();
|
|
||||||
if (type.startsWith("image/") || /\.(png|jpe?g|webp|gif|bmp|svg)$/.test(name)) return "image";
|
|
||||||
if (type.startsWith("video/") || /\.(mp4|mov|webm|m4v|ogg|avi|mkv)$/.test(name)) return "video";
|
|
||||||
if (type.startsWith("audio/") || /\.(mp3|wav|m4a|aac|flac)$/.test(name)) return "audio";
|
|
||||||
return "file";
|
|
||||||
}
|
|
||||||
|
|
||||||
export function listImageVideoVoices(name = "") {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<ImageVideoAsyncTaskVo>, { userId: number; name: string }>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/voice/list`,
|
|
||||||
{ userId: getCurrentUserId(), name },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deleteImageVideoVoice(voiceId: string) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<ImageVideoAsyncTaskVo>, { userId: number; voiceId: string }>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/voice/delete`,
|
|
||||||
{ userId: getCurrentUserId(), voiceId },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function cloneImageVideoVoice(payload: { name?: string; audioUrl?: string; videoUrl?: string }) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<ImageVideoAsyncTaskVo>, { userId: number; name?: string; audioUrl?: string; videoUrl?: string }>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/voice/clone`,
|
|
||||||
{ userId: getCurrentUserId(), ...payload },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function synthesizeImageVideoVoice(payload: { text: string; voiceId: string }) {
|
|
||||||
return unwrapJavaResponse(
|
|
||||||
post<JavaApiResponse<ImageVideoAsyncTaskVo>, { userId: number; text: string; voiceId: string }>(
|
|
||||||
`${JAVA_API_PREFIX}/image-video/voice/synthesis`,
|
|
||||||
{ userId: getCurrentUserId(), ...payload },
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getJavaDownloadUrl(path: string) {
|
export function getJavaDownloadUrl(path: string) {
|
||||||
let raw =
|
let raw =
|
||||||
path.startsWith("http://") || path.startsWith("https://")
|
path.startsWith("http://") || path.startsWith("https://")
|
||||||
|
|||||||
@@ -1,85 +1 @@
|
|||||||
import { requestGetJson } from '@/shared/api/http'
|
export * from './types/modules/permission'
|
||||||
|
|
||||||
export interface PermissionMenuItem {
|
|
||||||
id: number | string
|
|
||||||
name?: string
|
|
||||||
column_key?: string
|
|
||||||
columnKey?: string
|
|
||||||
route_path?: string
|
|
||||||
routePath?: string
|
|
||||||
menu_type?: string
|
|
||||||
parent_id?: number | string | null
|
|
||||||
parentId?: number | string | null
|
|
||||||
root_column_key?: string
|
|
||||||
rootColumnKey?: string
|
|
||||||
sort_order?: number
|
|
||||||
created_at?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
interface PermissionMenuResponse {
|
|
||||||
success: boolean
|
|
||||||
data?: PermissionMenuItem[]
|
|
||||||
items?: PermissionMenuItem[]
|
|
||||||
error?: string
|
|
||||||
message?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
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 getAppPermissionCacheKey(uid: number) {
|
|
||||||
return `app_column_permissions:${String(uid)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function getAuthToken() {
|
|
||||||
return typeof window === 'undefined' ? '' : window.localStorage.getItem('aiimage_auth_token') || ''
|
|
||||||
}
|
|
||||||
|
|
||||||
function normalizeColumnKeys(items: PermissionMenuItem[] | undefined) {
|
|
||||||
const keys = new Set<string>()
|
|
||||||
for (const item of items || []) {
|
|
||||||
for (const value of [item.column_key, item.columnKey, item.route_path, item.routePath]) {
|
|
||||||
const key = String(value || '').trim().toLowerCase()
|
|
||||||
if (key) {
|
|
||||||
keys.add(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Array.from(keys)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getCurrentUserAppColumnKeys() {
|
|
||||||
const uid = getCurrentUserId()
|
|
||||||
const cacheKey = getAppPermissionCacheKey(uid)
|
|
||||||
|
|
||||||
const headers: Record<string, string> = {}
|
|
||||||
const token = getAuthToken()
|
|
||||||
if (token) {
|
|
||||||
headers.Authorization = `Bearer ${token}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const res = await requestGetJson<PermissionMenuResponse>(
|
|
||||||
`/newApi/api/admin/permission-users/${encodeURIComponent(String(uid))}/column-permissions`,
|
|
||||||
{
|
|
||||||
params: { menuType: 'app' },
|
|
||||||
headers,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!res.success) {
|
|
||||||
throw new Error(res.error || res.message || '获取菜单权限失败')
|
|
||||||
}
|
|
||||||
|
|
||||||
const items = res.data || res.items || []
|
|
||||||
try {
|
|
||||||
window.localStorage.setItem(cacheKey, JSON.stringify(items))
|
|
||||||
} catch (_error) {}
|
|
||||||
|
|
||||||
return normalizeColumnKeys(items)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { requestDeleteJson, requestGetJson, requestPostJson } from '../../http.ts'
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrandExpandFolderItem {
|
||||||
|
absolutePath: string
|
||||||
|
relativePath: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrandExpandFolderResponse {
|
||||||
|
success: boolean
|
||||||
|
items?: BrandExpandFolderItem[]
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrandTaskResultPaths {
|
||||||
|
zip_url?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrandTaskItem {
|
||||||
|
id: number | string
|
||||||
|
status?: 'pending' | 'running' | 'success' | 'failed' | 'cancelled' | string
|
||||||
|
desc?: string
|
||||||
|
file_paths?: string[]
|
||||||
|
created_at?: string
|
||||||
|
progress_total?: number
|
||||||
|
progress_current?: number
|
||||||
|
result_paths?: BrandTaskResultPaths
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrandTaskListResponse {
|
||||||
|
success: boolean
|
||||||
|
items?: BrandTaskItem[]
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrandTaskDetailResponse {
|
||||||
|
success: boolean
|
||||||
|
task?: BrandTaskItem
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BrandTaskMutationResponse {
|
||||||
|
success: boolean
|
||||||
|
task_id?: string
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const API_PREFIX = ''
|
||||||
|
|
||||||
|
export function getBrandTaskEventsUrl(taskId: string | number) {
|
||||||
|
return `${API_PREFIX}/api/brand/tasks/${taskId}/events?user_id=${encodeURIComponent(String(getCurrentUserId()))}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBrandTaskDownloadUrl(taskId: string | number) {
|
||||||
|
return `${API_PREFIX}/api/brand/tasks/${taskId}/download?user_id=${encodeURIComponent(String(getCurrentUserId()))}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBrandTemplateXlsxUrl() {
|
||||||
|
return `${API_PREFIX}/static/品牌文档格式_模板.xlsx`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBrandTemplateZipUrl() {
|
||||||
|
return `${API_PREFIX}/static/模板2-以文件夹方式上传.zip`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expandBrandFolder(folder: string) {
|
||||||
|
return requestPostJson<BrandExpandFolderResponse>(`${API_PREFIX}/api/brand/expand-folder`, { folder })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expandBrandFolderRecursive(folder: string) {
|
||||||
|
return requestPostJson<BrandExpandFolderResponse>(`${API_PREFIX}/api/brand/expand-folder-recursive`, { folder })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runBrandNow(paths: string[], strategy: string) {
|
||||||
|
return requestPostJson<BrandTaskMutationResponse>(`${API_PREFIX}/api/brand/run`, { paths, strategy })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createBrandTask(paths: string[], strategy: string) {
|
||||||
|
return requestPostJson<BrandTaskMutationResponse>(`${API_PREFIX}/api/brand/tasks?userId=${encodeURIComponent(String(getCurrentUserId()))}`, { paths, strategy })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBrandTasks() {
|
||||||
|
return requestGetJson<BrandTaskListResponse>(`${API_PREFIX}/api/brand/tasks?userId=${encodeURIComponent(String(getCurrentUserId()))}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBrandTask(taskId: string | number) {
|
||||||
|
return requestGetJson<BrandTaskDetailResponse>(`${API_PREFIX}/api/brand/tasks/${taskId}?userId=${encodeURIComponent(String(getCurrentUserId()))}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cancelBrandTask(taskId: string | number) {
|
||||||
|
return requestPostJson<BrandTaskMutationResponse>(`${API_PREFIX}/api/brand/tasks/${taskId}/cancel?userId=${encodeURIComponent(String(getCurrentUserId()))}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteBrandTask(taskId: string | number) {
|
||||||
|
return requestDeleteJson<BrandTaskMutationResponse>(`${API_PREFIX}/api/brand/tasks/${taskId}?userId=${encodeURIComponent(String(getCurrentUserId()))}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createBrandTaskEvents(taskId: string | number) {
|
||||||
|
return new EventSource(getBrandTaskEventsUrl(taskId))
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import { get, post, del, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
||||||
|
|
||||||
|
const JAVA_API_PREFIX = '/newApi/api/digital-human/versions'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 数字人版本信息
|
||||||
|
*/
|
||||||
|
export interface DigitalHumanVersion {
|
||||||
|
id: number
|
||||||
|
version: string
|
||||||
|
ossObjectKey: string
|
||||||
|
fileSize: number
|
||||||
|
md5: string
|
||||||
|
changelog: string | null
|
||||||
|
minClientVersion: string | null
|
||||||
|
isLatest: boolean
|
||||||
|
status: 'DRAFT' | 'RELEASED' | 'DEPRECATED'
|
||||||
|
createdBy: string | null
|
||||||
|
createdAt: string
|
||||||
|
releasedAt: string | null
|
||||||
|
downloadUrl?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载链接信息
|
||||||
|
*/
|
||||||
|
export interface DownloadUrlVo {
|
||||||
|
version: string
|
||||||
|
downloadUrl: string
|
||||||
|
expiresIn: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页查询参数
|
||||||
|
*/
|
||||||
|
export interface VersionListParams {
|
||||||
|
page?: number
|
||||||
|
pageSize?: number
|
||||||
|
status?: 'DRAFT' | 'RELEASED' | 'DEPRECATED'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分页结果
|
||||||
|
*/
|
||||||
|
export interface PageResult<T> {
|
||||||
|
records: T[]
|
||||||
|
total: number
|
||||||
|
size: number
|
||||||
|
current: number
|
||||||
|
pages: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传新版本
|
||||||
|
*/
|
||||||
|
export function uploadDigitalHumanVersion(
|
||||||
|
file: File,
|
||||||
|
version: string,
|
||||||
|
changelog?: string,
|
||||||
|
minClientVersion?: string,
|
||||||
|
) {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
formData.append('version', version)
|
||||||
|
if (changelog) formData.append('changelog', changelog)
|
||||||
|
if (minClientVersion) formData.append('minClientVersion', minClientVersion)
|
||||||
|
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<DigitalHumanVersion>>(
|
||||||
|
`${JAVA_API_PREFIX}/upload`,
|
||||||
|
formData,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询版本列表
|
||||||
|
*/
|
||||||
|
export function getDigitalHumanVersions(params?: VersionListParams) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
get<JavaApiResponse<PageResult<DigitalHumanVersion>>>(
|
||||||
|
JAVA_API_PREFIX,
|
||||||
|
{ params },
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取最新版本
|
||||||
|
*/
|
||||||
|
export function getLatestDigitalHumanVersion() {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
get<JavaApiResponse<DigitalHumanVersion>>(
|
||||||
|
`${JAVA_API_PREFIX}/latest`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定版本详情
|
||||||
|
*/
|
||||||
|
export function getDigitalHumanVersion(version: string) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
get<JavaApiResponse<DigitalHumanVersion>>(
|
||||||
|
`${JAVA_API_PREFIX}/${version}`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发布版本
|
||||||
|
*/
|
||||||
|
export function releaseDigitalHumanVersion(version: string) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<void>>(
|
||||||
|
`${JAVA_API_PREFIX}/${version}/release`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设为最新版本
|
||||||
|
*/
|
||||||
|
export function setLatestDigitalHumanVersion(version: string) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<void>>(
|
||||||
|
`${JAVA_API_PREFIX}/${version}/set-latest`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除版本
|
||||||
|
*/
|
||||||
|
export function deleteDigitalHumanVersion(version: string) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
del<JavaApiResponse<void>>(
|
||||||
|
`${JAVA_API_PREFIX}/${version}`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取下载链接
|
||||||
|
*/
|
||||||
|
export function getDigitalHumanVersionDownloadUrl(version: string) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
get<JavaApiResponse<DownloadUrlVo>>(
|
||||||
|
`${JAVA_API_PREFIX}/${version}/download-url`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
import { get, post, put, type JavaApiResponse, unwrapJavaResponse } from '../../http.ts'
|
||||||
|
import { buildJavaUrl, JAVA_API_PREFIX } from '../../url.ts'
|
||||||
|
import { getCurrentUserId } from '../../user.ts'
|
||||||
|
|
||||||
|
export interface ImageVideoDouyinCopyVo {
|
||||||
|
recognizedContent?: string;
|
||||||
|
scriptDraft?: string;
|
||||||
|
executeId?: string;
|
||||||
|
debugUrl?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoDouyinCopyPayload {
|
||||||
|
url: string;
|
||||||
|
api_key?: string;
|
||||||
|
t8_key?: string;
|
||||||
|
duration?: number;
|
||||||
|
proc_info?: {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
proc_image: string[];
|
||||||
|
properties: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoSecretStatusVo {
|
||||||
|
userId?: number;
|
||||||
|
configured?: boolean;
|
||||||
|
valid?: boolean;
|
||||||
|
expired?: boolean;
|
||||||
|
hasCopyApiKey?: boolean;
|
||||||
|
hasT8Key?: boolean;
|
||||||
|
hasT8VideoKey?: boolean;
|
||||||
|
hasVoiceApiKey?: boolean;
|
||||||
|
hasVoiceGroupId?: boolean;
|
||||||
|
copyApiKeyMasked?: string;
|
||||||
|
t8KeyMasked?: string;
|
||||||
|
t8VideoKeyMasked?: string;
|
||||||
|
voiceApiKeyMasked?: string;
|
||||||
|
voiceGroupIdMasked?: string;
|
||||||
|
expireDays?: number;
|
||||||
|
expiresAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoSecretSavePayload {
|
||||||
|
copyApiKey?: string;
|
||||||
|
t8Key?: string;
|
||||||
|
t8VideoKey?: string;
|
||||||
|
voiceApiKey?: string;
|
||||||
|
voiceGroupId?: string;
|
||||||
|
expireDays: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoWorkflowParameters {
|
||||||
|
api_key_info: {
|
||||||
|
t8star_key: string;
|
||||||
|
t8_video_key: string;
|
||||||
|
ai_conductor_key: string;
|
||||||
|
};
|
||||||
|
bg_info: {
|
||||||
|
type: number;
|
||||||
|
prompt: string;
|
||||||
|
bg_image: string;
|
||||||
|
};
|
||||||
|
face_info: {
|
||||||
|
type: number;
|
||||||
|
model_figure: string;
|
||||||
|
model_image: string[];
|
||||||
|
};
|
||||||
|
proc_info: {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
proc_image: string[];
|
||||||
|
properties: string;
|
||||||
|
};
|
||||||
|
text_info: {
|
||||||
|
type: number;
|
||||||
|
language: string;
|
||||||
|
text: string;
|
||||||
|
file_url: string;
|
||||||
|
};
|
||||||
|
audio_info: {
|
||||||
|
audio_url: string;
|
||||||
|
type: number;
|
||||||
|
bgm_url: string;
|
||||||
|
mode: number;
|
||||||
|
voice_name: string;
|
||||||
|
};
|
||||||
|
video_info: {
|
||||||
|
video_url: string;
|
||||||
|
share_url: string;
|
||||||
|
ref_video_mode: string;
|
||||||
|
mode: string;
|
||||||
|
draft: boolean;
|
||||||
|
model: string;
|
||||||
|
prompt: string;
|
||||||
|
ratio: string;
|
||||||
|
resolution: string;
|
||||||
|
duration: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoWorkflowResponse {
|
||||||
|
code?: number;
|
||||||
|
msg?: string;
|
||||||
|
data?: string;
|
||||||
|
execute_id?: string;
|
||||||
|
debug_url?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ImageVideoAsyncTaskStatus = 'PENDING' | 'RUNNING' | 'WAITING' | 'POLLING' | 'SUCCESS' | 'FAILED'
|
||||||
|
|
||||||
|
export interface ImageVideoAsyncTaskVo {
|
||||||
|
taskId: number;
|
||||||
|
taskType: string;
|
||||||
|
status: ImageVideoAsyncTaskStatus;
|
||||||
|
cozeExecuteId?: string;
|
||||||
|
cozeStatus?: string;
|
||||||
|
debugUrl?: string;
|
||||||
|
result?: unknown;
|
||||||
|
errorMessage?: string;
|
||||||
|
submittedAt?: string;
|
||||||
|
completedAt?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoMediaUploadVo {
|
||||||
|
url: string;
|
||||||
|
objectKey: string;
|
||||||
|
originalFilename: string;
|
||||||
|
mediaType: "image" | "video" | "audio" | string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoVoiceWorkflowResponse {
|
||||||
|
code?: number;
|
||||||
|
msg?: string;
|
||||||
|
data?: unknown;
|
||||||
|
execute_id?: string;
|
||||||
|
debug_url?: string;
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoWorkflowRunRequest {
|
||||||
|
userId: number;
|
||||||
|
parameters: ImageVideoWorkflowParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageVideoWorkflowResultRequest {
|
||||||
|
userId: number;
|
||||||
|
executeId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getImageVideoSecretStatus() {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
get<JavaApiResponse<ImageVideoSecretStatusVo>>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/secrets`,
|
||||||
|
{ params: { user_id: getCurrentUserId() } },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveImageVideoSecrets(payload: ImageVideoSecretSavePayload) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
put<JavaApiResponse<ImageVideoSecretStatusVo>, ImageVideoSecretSavePayload & { userId: number }>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/secrets`,
|
||||||
|
{ ...payload, userId: getCurrentUserId() },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runImageVideoDouyinCopy(payload: ImageVideoDouyinCopyPayload) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<ImageVideoAsyncTaskVo>, ImageVideoDouyinCopyPayload & { userId: number }>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/douyin-copy`,
|
||||||
|
{ userId: getCurrentUserId(), ...payload },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function runImageVideoWorkflow(parameters: ImageVideoWorkflowParameters) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<ImageVideoAsyncTaskVo>, ImageVideoWorkflowRunRequest>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/workflow/run`,
|
||||||
|
{ userId: getCurrentUserId(), parameters },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getImageVideoWorkflowResult(executeId: string) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<ImageVideoAsyncTaskVo>, ImageVideoWorkflowResultRequest>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/workflow/result`,
|
||||||
|
{ userId: getCurrentUserId(), executeId },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getImageVideoAsyncTask(taskId: number) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
get<JavaApiResponse<ImageVideoAsyncTaskVo>>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/tasks/${taskId}`,
|
||||||
|
{ params: { user_id: getCurrentUserId() } },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveImageVideoMediaType(file: File) {
|
||||||
|
const type = (file.type || "").toLowerCase();
|
||||||
|
const name = (file.name || "").toLowerCase();
|
||||||
|
if (type.startsWith("image/") || /\.(png|jpe?g|webp|gif|bmp|svg)$/.test(name)) return "image";
|
||||||
|
if (type.startsWith("video/") || /\.(mp4|mov|webm|m4v|ogg|avi|mkv)$/.test(name)) return "video";
|
||||||
|
if (type.startsWith("audio/") || /\.(mp3|wav|m4a|aac|flac)$/.test(name)) return "audio";
|
||||||
|
return "file";
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function uploadImageVideoMedia(file: File) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("file", file);
|
||||||
|
formData.append("uploadToOss", "true");
|
||||||
|
formData.append("moduleType", "IMAGE_VIDEO");
|
||||||
|
const response = await post<JavaApiResponse<{ url?: string; objectKey?: string; originalFilename?: string; mediaType?: string }>>(
|
||||||
|
`${JAVA_API_PREFIX}/files/upload`,
|
||||||
|
formData,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data',
|
||||||
|
},
|
||||||
|
timeout: 120000,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!response.success) {
|
||||||
|
throw new Error(response.message || "请求失败");
|
||||||
|
}
|
||||||
|
const data = response.data;
|
||||||
|
if (!data?.url || !data.objectKey) {
|
||||||
|
throw new Error("OSS 上传未返回有效 URL");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
url: data.url,
|
||||||
|
objectKey: data.objectKey,
|
||||||
|
originalFilename: data.originalFilename || file.name,
|
||||||
|
mediaType: data.mediaType || resolveImageVideoMediaType(file),
|
||||||
|
} as ImageVideoMediaUploadVo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function listImageVideoVoices(name = "") {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<ImageVideoAsyncTaskVo>, { userId: number; name: string }>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/voice/list`,
|
||||||
|
{ userId: getCurrentUserId(), name },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteImageVideoVoice(voiceId: string) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<ImageVideoAsyncTaskVo>, { userId: number; voiceId: string }>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/voice/delete`,
|
||||||
|
{ userId: getCurrentUserId(), voiceId },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cloneImageVideoVoice(payload: { name?: string; audioUrl?: string; videoUrl?: string }) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<ImageVideoAsyncTaskVo>, { userId: number; name?: string; audioUrl?: string; videoUrl?: string }>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/voice/clone`,
|
||||||
|
{ userId: getCurrentUserId(), ...payload },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function synthesizeImageVideoVoice(payload: { text: string; voiceId: string }) {
|
||||||
|
return unwrapJavaResponse(
|
||||||
|
post<JavaApiResponse<ImageVideoAsyncTaskVo>, { userId: number; text: string; voiceId: string }>(
|
||||||
|
`${JAVA_API_PREFIX}/image-video/voice/synthesis`,
|
||||||
|
{ userId: getCurrentUserId(), ...payload },
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
import { requestGetJson } from '../../http.ts'
|
||||||
|
|
||||||
|
export interface PermissionMenuItem {
|
||||||
|
id: number | string
|
||||||
|
name?: string
|
||||||
|
column_key?: string
|
||||||
|
columnKey?: string
|
||||||
|
route_path?: string
|
||||||
|
routePath?: string
|
||||||
|
menu_type?: string
|
||||||
|
parent_id?: number | string | null
|
||||||
|
parentId?: number | string | null
|
||||||
|
root_column_key?: string
|
||||||
|
rootColumnKey?: string
|
||||||
|
sort_order?: number
|
||||||
|
created_at?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PermissionMenuResponse {
|
||||||
|
success: boolean
|
||||||
|
data?: PermissionMenuItem[]
|
||||||
|
items?: PermissionMenuItem[]
|
||||||
|
error?: string
|
||||||
|
message?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
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 getAppPermissionCacheKey(uid: number) {
|
||||||
|
return `app_column_permissions:${String(uid)}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAuthToken() {
|
||||||
|
return typeof window === 'undefined' ? '' : window.localStorage.getItem('aiimage_auth_token') || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeColumnKeys(items: PermissionMenuItem[] | undefined) {
|
||||||
|
const keys = new Set<string>()
|
||||||
|
for (const item of items || []) {
|
||||||
|
for (const value of [item.column_key, item.columnKey, item.route_path, item.routePath]) {
|
||||||
|
const key = String(value || '').trim().toLowerCase()
|
||||||
|
if (key) {
|
||||||
|
keys.add(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Array.from(keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getCurrentUserAppColumnKeys() {
|
||||||
|
const uid = getCurrentUserId()
|
||||||
|
const cacheKey = getAppPermissionCacheKey(uid)
|
||||||
|
|
||||||
|
const headers: Record<string, string> = {}
|
||||||
|
const token = getAuthToken()
|
||||||
|
if (token) {
|
||||||
|
headers.Authorization = `Bearer ${token}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await requestGetJson<PermissionMenuResponse>(
|
||||||
|
`/newApi/api/admin/permission-users/${encodeURIComponent(String(uid))}/column-permissions`,
|
||||||
|
{
|
||||||
|
params: { menuType: 'app' },
|
||||||
|
headers,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!res.success) {
|
||||||
|
throw new Error(res.error || res.message || '获取菜单权限失败')
|
||||||
|
}
|
||||||
|
|
||||||
|
const items = res.data || res.items || []
|
||||||
|
try {
|
||||||
|
window.localStorage.setItem(cacheKey, JSON.stringify(items))
|
||||||
|
} catch (_error) {}
|
||||||
|
|
||||||
|
return normalizeColumnKeys(items)
|
||||||
|
}
|
||||||
@@ -0,0 +1,217 @@
|
|||||||
|
import { test } from 'node:test'
|
||||||
|
import assert from 'node:assert/strict'
|
||||||
|
import { http } from '../src/shared/api/http.ts'
|
||||||
|
import {
|
||||||
|
getImageVideoSecretStatus,
|
||||||
|
saveImageVideoSecrets,
|
||||||
|
runImageVideoDouyinCopy,
|
||||||
|
runImageVideoWorkflow,
|
||||||
|
getImageVideoWorkflowResult,
|
||||||
|
getImageVideoAsyncTask,
|
||||||
|
uploadImageVideoMedia,
|
||||||
|
listImageVideoVoices,
|
||||||
|
deleteImageVideoVoice,
|
||||||
|
cloneImageVideoVoice,
|
||||||
|
synthesizeImageVideoVoice,
|
||||||
|
} from '../src/shared/api/types/modules/image-video.ts'
|
||||||
|
import {
|
||||||
|
expandBrandFolderRecursive,
|
||||||
|
getBrandTasks,
|
||||||
|
createBrandTask,
|
||||||
|
getBrandTaskEventsUrl,
|
||||||
|
} from '../src/shared/api/types/modules/brand.ts'
|
||||||
|
import {
|
||||||
|
getCurrentUserAppColumnKeys,
|
||||||
|
type PermissionMenuItem,
|
||||||
|
} from '../src/shared/api/types/modules/permission.ts'
|
||||||
|
import {
|
||||||
|
getDigitalHumanVersions,
|
||||||
|
releaseDigitalHumanVersion,
|
||||||
|
getDigitalHumanVersionDownloadUrl,
|
||||||
|
} from '../src/shared/api/types/modules/digital-human.ts'
|
||||||
|
|
||||||
|
function setupWindow() {
|
||||||
|
const store = new Map<string, string>([['uid', '42']])
|
||||||
|
;(globalThis as Record<string, unknown>).window = {
|
||||||
|
localStorage: {
|
||||||
|
getItem: (key: string) => store.get(key) ?? null,
|
||||||
|
setItem: (key: string, value: string) => void store.set(key, value),
|
||||||
|
},
|
||||||
|
location: { origin: 'http://localhost' },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockRequest(
|
||||||
|
t: Parameters<typeof test>[1] extends (t: infer T) => unknown ? T : never,
|
||||||
|
impl: (config: { url?: string; method?: string; params?: Record<string, unknown>; data?: unknown; timeout?: number }) => Promise<unknown>,
|
||||||
|
) {
|
||||||
|
t.mock.method(http, 'request', impl as never)
|
||||||
|
}
|
||||||
|
|
||||||
|
const okResponse = (data: unknown) => Promise.resolve({ data: { success: true, message: 'ok', data } })
|
||||||
|
|
||||||
|
test('test_image_video_secrets', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
const calls: { url?: string; method?: string; params?: Record<string, unknown>; data?: unknown }[] = []
|
||||||
|
mockRequest(t, (config) => {
|
||||||
|
calls.push(config)
|
||||||
|
return okResponse({ userId: 42, configured: true })
|
||||||
|
})
|
||||||
|
await getImageVideoSecretStatus()
|
||||||
|
await saveImageVideoSecrets({ expireDays: 30 })
|
||||||
|
assert.equal(calls[0].url, '/newApi/api/image-video/secrets')
|
||||||
|
assert.deepEqual(calls[0].params, { user_id: 42 })
|
||||||
|
assert.equal(calls[1].url, '/newApi/api/image-video/secrets')
|
||||||
|
assert.equal(calls[1].method, 'PUT')
|
||||||
|
assert.deepEqual(calls[1].data, { expireDays: 30, userId: 42 })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_image_video_workflow', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
const calls: { url?: string; method?: string; data?: unknown }[] = []
|
||||||
|
mockRequest(t, (config) => {
|
||||||
|
calls.push(config)
|
||||||
|
return okResponse({ taskId: 1, taskType: 'workflow', status: 'RUNNING' })
|
||||||
|
})
|
||||||
|
const params = { api_key_info: { t8star_key: 'a', t8_video_key: 'b', ai_conductor_key: 'c' } }
|
||||||
|
await runImageVideoWorkflow(params as never)
|
||||||
|
await getImageVideoWorkflowResult('exec-1')
|
||||||
|
assert.equal(calls[0].url, '/newApi/api/image-video/workflow/run')
|
||||||
|
assert.equal(calls[0].method, 'POST')
|
||||||
|
assert.deepEqual(calls[0].data, { userId: 42, parameters: params })
|
||||||
|
assert.equal(calls[1].url, '/newApi/api/image-video/workflow/result')
|
||||||
|
assert.deepEqual(calls[1].data, { userId: 42, executeId: 'exec-1' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_image_video_douyin_async', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
const calls: { url?: string; method?: string; data?: unknown; params?: Record<string, unknown> }[] = []
|
||||||
|
mockRequest(t, (config) => {
|
||||||
|
calls.push(config)
|
||||||
|
return okResponse({ taskId: 2, taskType: 'copy', status: 'PENDING' })
|
||||||
|
})
|
||||||
|
await runImageVideoDouyinCopy({ url: 'https://x.com/v' })
|
||||||
|
await getImageVideoAsyncTask(7)
|
||||||
|
assert.equal(calls[0].url, '/newApi/api/image-video/douyin-copy')
|
||||||
|
assert.equal(calls[0].method, 'POST')
|
||||||
|
assert.deepEqual(calls[0].data, { userId: 42, url: 'https://x.com/v' })
|
||||||
|
assert.equal(calls[1].url, '/newApi/api/image-video/tasks/7')
|
||||||
|
assert.deepEqual(calls[1].params, { user_id: 42 })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_image_video_voice', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
const calls: { url?: string; method?: string; data?: unknown }[] = []
|
||||||
|
mockRequest(t, (config) => {
|
||||||
|
calls.push(config)
|
||||||
|
return okResponse({ taskId: 3, taskType: 'voice', status: 'SUCCESS' })
|
||||||
|
})
|
||||||
|
await listImageVideoVoices('v1')
|
||||||
|
await deleteImageVideoVoice('vid-1')
|
||||||
|
await cloneImageVideoVoice({ name: 'clone' })
|
||||||
|
await synthesizeImageVideoVoice({ text: '你好', voiceId: 'vid-1' })
|
||||||
|
assert.equal(calls[0].url, '/newApi/api/image-video/voice/list')
|
||||||
|
assert.deepEqual(calls[0].data, { userId: 42, name: 'v1' })
|
||||||
|
assert.equal(calls[1].url, '/newApi/api/image-video/voice/delete')
|
||||||
|
assert.deepEqual(calls[1].data, { userId: 42, voiceId: 'vid-1' })
|
||||||
|
assert.equal(calls[2].url, '/newApi/api/image-video/voice/clone')
|
||||||
|
assert.deepEqual(calls[2].data, { userId: 42, name: 'clone' })
|
||||||
|
assert.equal(calls[3].url, '/newApi/api/image-video/voice/synthesis')
|
||||||
|
assert.deepEqual(calls[3].data, { userId: 42, text: '你好', voiceId: 'vid-1' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_image_video_upload_media', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
const calls: { url?: string; method?: string; data?: unknown }[] = []
|
||||||
|
mockRequest(t, (config) => {
|
||||||
|
calls.push(config)
|
||||||
|
return okResponse({ url: 'https://oss/x', objectKey: 'k1', originalFilename: 'a.png', mediaType: 'image' })
|
||||||
|
})
|
||||||
|
const file = new File(['x'], 'a.png', { type: 'image/png' })
|
||||||
|
const result = await uploadImageVideoMedia(file)
|
||||||
|
assert.equal(calls[0].url, '/newApi/api/files/upload')
|
||||||
|
assert.equal(calls[0].method, 'POST')
|
||||||
|
assert.ok(calls[0].data instanceof FormData)
|
||||||
|
assert.deepEqual(result, { url: 'https://oss/x', objectKey: 'k1', originalFilename: 'a.png', mediaType: 'image' })
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_brand_tasks', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
const calls: { url?: string; method?: string; data?: unknown }[] = []
|
||||||
|
mockRequest(t, (config) => {
|
||||||
|
calls.push(config)
|
||||||
|
return Promise.resolve({ data: { success: true, items: [{ id: 1 }] } })
|
||||||
|
})
|
||||||
|
await getBrandTasks()
|
||||||
|
await createBrandTask(['/tmp/a'], 'STRATEGY_A')
|
||||||
|
await expandBrandFolderRecursive('/tmp/a')
|
||||||
|
assert.equal(calls[0].url, '/api/brand/tasks?userId=42')
|
||||||
|
assert.equal(calls[0].method, 'GET')
|
||||||
|
assert.equal(calls[1].url, '/api/brand/tasks?userId=42')
|
||||||
|
assert.equal(calls[1].method, 'POST')
|
||||||
|
assert.deepEqual(calls[1].data, { paths: ['/tmp/a'], strategy: 'STRATEGY_A' })
|
||||||
|
assert.equal(calls[2].url, '/api/brand/expand-folder-recursive')
|
||||||
|
assert.equal(calls[2].method, 'POST')
|
||||||
|
assert.deepEqual(calls[2].data, { folder: '/tmp/a' })
|
||||||
|
assert.equal(
|
||||||
|
getBrandTaskEventsUrl(7),
|
||||||
|
'/api/brand/tasks/7/events?user_id=42',
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_permission_column_keys', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
mockRequest(t, () =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: { success: true, data: [{ column_key: 'collect-data' }, { columnKey: 'Shop-Match' }] },
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
const keys = await getCurrentUserAppColumnKeys()
|
||||||
|
assert.deepEqual(keys, ['collect-data', 'shop-match'])
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_digital_human_versions', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
const calls: { url?: string; method?: string; params?: Record<string, unknown> }[] = []
|
||||||
|
mockRequest(t, (config) => {
|
||||||
|
calls.push(config)
|
||||||
|
return okResponse({ records: [{ id: 1, version: '1.0.0' }], total: 1 })
|
||||||
|
})
|
||||||
|
await getDigitalHumanVersions({ page: 1, pageSize: 10 })
|
||||||
|
await releaseDigitalHumanVersion('1.0.0')
|
||||||
|
await getDigitalHumanVersionDownloadUrl('1.0.0')
|
||||||
|
assert.equal(calls[0].url, '/newApi/api/digital-human/versions')
|
||||||
|
assert.deepEqual(calls[0].params, { page: 1, pageSize: 10 })
|
||||||
|
assert.equal(calls[1].url, '/newApi/api/digital-human/versions/1.0.0/release')
|
||||||
|
assert.equal(calls[1].method, 'POST')
|
||||||
|
assert.equal(calls[2].url, '/newApi/api/digital-human/versions/1.0.0/download-url')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_image_video_export_compat', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
const fromJavaModules = await import('../src/shared/api/java-modules.ts')
|
||||||
|
const fromImageVideo = await import('../src/shared/api/types/modules/image-video.ts')
|
||||||
|
const imageVideoNames = [
|
||||||
|
'getImageVideoSecretStatus', 'saveImageVideoSecrets', 'runImageVideoDouyinCopy',
|
||||||
|
'runImageVideoWorkflow', 'getImageVideoWorkflowResult', 'getImageVideoAsyncTask',
|
||||||
|
'uploadImageVideoMedia', 'listImageVideoVoices', 'deleteImageVideoVoice',
|
||||||
|
'cloneImageVideoVoice', 'synthesizeImageVideoVoice',
|
||||||
|
]
|
||||||
|
for (const name of imageVideoNames) {
|
||||||
|
assert.equal(fromJavaModules[name], fromImageVideo[name], `${name} 应为同一引用`)
|
||||||
|
}
|
||||||
|
const fromBrand = await import('../src/shared/api/types/modules/brand.ts')
|
||||||
|
assert.equal(typeof fromBrand.expandBrandFolderRecursive, 'function')
|
||||||
|
const item: PermissionMenuItem = { id: 1, column_key: 'x' }
|
||||||
|
assert.equal(item.column_key, 'x')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('test_image_video_unwrap_and_error', async (t) => {
|
||||||
|
setupWindow()
|
||||||
|
mockRequest(t, () => okResponse({ taskId: 1, taskType: 't', status: 'RUNNING' }))
|
||||||
|
const result = await getImageVideoAsyncTask(1)
|
||||||
|
assert.equal(result.taskId, 1)
|
||||||
|
|
||||||
|
mockRequest(t, () => Promise.resolve({ data: { success: false, message: '密钥未配置' } }))
|
||||||
|
await assert.rejects(getImageVideoSecretStatus(), /密钥未配置/)
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user