This commit is contained in:
2025-07-09 20:36:32 +08:00
commit af33978d28
43 changed files with 9434 additions and 0 deletions

143
src/api/modules/editor.ts Normal file
View File

@ -0,0 +1,143 @@
import { httpClient } from '../core/request'
import { fileUploader } from '../core/upload'
import { fileDownloader } from '../core/download'
import { ApiResponse, PaginationParams, PaginationResponse } from '../types'
import { API_ENDPOINTS } from '../config'
/**
* 项目数据类型
*/
export interface ProjectData {
id: string
name: string
description?: string
thumbnail?: string
sceneData: any
createdAt: string
updatedAt: string
userId: string
}
/**
* 订单数据类型
*/
export interface OrderData {
id: string
projectId: string
status: 'pending' | 'processing' | 'completed' | 'failed'
result?: any
createdAt: string
updatedAt: string
}
/**
* 编辑器API类
*/
export class EditorApi {
/**
* 创建订单
*/
public async createOrder(params: any): Promise<ApiResponse<OrderData>> {
return httpClient.post<OrderData>(API_ENDPOINTS.EDITOR.CREATE_ORDER, params)
}
/**
* 保存项目
*/
public async saveProject(projectData: Partial<ProjectData>): Promise<ApiResponse<ProjectData>> {
return httpClient.post<ProjectData>(API_ENDPOINTS.EDITOR.SAVE_PROJECT, projectData)
}
/**
* 加载项目
*/
public async loadProject(projectId: string): Promise<ApiResponse<ProjectData>> {
return httpClient.get<ProjectData>(`${API_ENDPOINTS.EDITOR.LOAD_PROJECT}/${projectId}`)
}
/**
* 删除项目
*/
public async deleteProject(projectId: string): Promise<ApiResponse<void>> {
return httpClient.delete<void>(`${API_ENDPOINTS.EDITOR.DELETE_PROJECT}/${projectId}`)
}
/**
* 获取项目列表
*/
public async getProjectList(params: PaginationParams): Promise<ApiResponse<PaginationResponse<ProjectData>>> {
return httpClient.get<PaginationResponse<ProjectData>>(API_ENDPOINTS.EDITOR.LOAD_PROJECT, params)
}
/**
* 上传项目缩略图
*/
public async uploadThumbnail(file: File, projectId: string): Promise<ApiResponse<{ url: string }>> {
return fileUploader.uploadImage(file, {
compress: true,
quality: 0.8,
maxWidth: 400,
maxHeight: 300,
onProgress: (progress) => {
console.log(`缩略图上传进度: ${progress}%`)
}
})
}
/**
* 导出项目
*/
public async exportProject(projectId: string, format: 'json' | 'glb' | 'fbx' = 'json'): Promise<void> {
await fileDownloader.downloadAndSave({
url: `/editor/project/export/${projectId}`,
filename: `project_${projectId}.${format}`,
params: { format }
})
}
/**
* 导入项目
*/
public async importProject(file: File): Promise<ApiResponse<ProjectData>> {
const uploadResponse = await fileUploader.uploadFile({
file,
fieldName: 'projectFile',
data: {
action: 'import'
}
})
if (!uploadResponse.success) {
throw new Error(uploadResponse.message)
}
// 上传成功后调用导入API
return httpClient.post<ProjectData>('/editor/project/import', {
fileUrl: uploadResponse.data.url
})
}
/**
* 批量导出项目
*/
public async exportMultipleProjects(projectIds: string[], format: 'json' | 'glb' | 'fbx' = 'json'): Promise<void> {
const downloadUrls = projectIds.map(id => `/editor/project/export/${id}?format=${format}`)
await fileDownloader.downloadBatch(downloadUrls, {
concurrent: 2,
onProgress: (progress) => {
console.log(`批量导出进度: ${progress}%`)
},
onFileComplete: (url, result) => {
if (result instanceof Error) {
console.error(`导出失败: ${url}`, result)
} else {
console.log(`导出完成: ${url}`)
}
}
})
}
}
// 创建默认实例
export const editorApi = new EditorApi()

281
src/api/modules/resource.ts Normal file
View File

@ -0,0 +1,281 @@
import { httpClient } from '../core/request'
import { fileUploader } from '../core/upload'
import { fileDownloader } from '../core/download'
import { ApiResponse, PaginationParams, PaginationResponse } from '../types'
import { API_ENDPOINTS } from '../config'
/**
* 资源数据类型
*/
export interface ResourceData {
id: string
name: string
type: 'model' | 'texture' | 'material' | 'audio' | 'video' | 'other'
url: string
thumbnailUrl?: string
size: number
format: string
tags: string[]
description?: string
createdAt: string
updatedAt: string
userId: string
}
/**
* 资源分类类型
*/
export interface ResourceCategory {
id: string
name: string
description?: string
parentId?: string
children?: ResourceCategory[]
}
/**
* 资源搜索参数
*/
export interface ResourceSearchParams extends PaginationParams {
keyword?: string
type?: ResourceData['type']
tags?: string[]
categoryId?: string
format?: string
sizeMin?: number
sizeMax?: number
dateFrom?: string
dateTo?: string
}
/**
* 资源API类
*/
export class ResourceApi {
/**
* 获取资源列表
*/
public async getResourceList(params: ResourceSearchParams): Promise<ApiResponse<PaginationResponse<ResourceData>>> {
return httpClient.get<PaginationResponse<ResourceData>>(API_ENDPOINTS.RESOURCE.LIST, params)
}
/**
* 获取资源详情
*/
public async getResourceDetail(resourceId: string): Promise<ApiResponse<ResourceData>> {
return httpClient.get<ResourceData>(`${API_ENDPOINTS.RESOURCE.LIST}/${resourceId}`)
}
/**
* 上传资源
*/
public async uploadResource(
file: File,
metadata: {
name?: string
type: ResourceData['type']
tags?: string[]
description?: string
categoryId?: string
}
): Promise<ApiResponse<ResourceData>> {
// 根据文件类型选择上传方式
let uploadResponse
if (metadata.type === 'texture' && file.type.startsWith('image/')) {
// 图片资源,使用图片上传(带压缩)
uploadResponse = await fileUploader.uploadImage(file, {
compress: true,
quality: 0.9,
maxWidth: 2048,
maxHeight: 2048,
onProgress: (progress) => {
console.log(`资源上传进度: ${progress}%`)
}
})
} else if (file.size > 50 * 1024 * 1024) {
// 大文件,使用分片上传
uploadResponse = await fileUploader.uploadLargeFile(file, {
onProgress: (progress) => {
console.log(`大文件上传进度: ${progress}%`)
}
})
} else {
// 普通文件上传
uploadResponse = await fileUploader.uploadFile({
file,
data: metadata,
onProgress: (progress) => {
console.log(`文件上传进度: ${progress}%`)
}
})
}
if (!uploadResponse.success) {
throw new Error(uploadResponse.message)
}
// 创建资源记录
return httpClient.post<ResourceData>(API_ENDPOINTS.RESOURCE.UPLOAD, {
...metadata,
name: metadata.name || file.name,
url: uploadResponse.data.url,
size: file.size,
format: file.name.split('.').pop()?.toLowerCase() || 'unknown'
})
}
/**
* 批量上传资源
*/
public async uploadMultipleResources(
files: File[],
metadata: {
type: ResourceData['type']
tags?: string[]
categoryId?: string
}
): Promise<ApiResponse<ResourceData[]>> {
const results = await fileUploader.uploadBatch(files, {
concurrent: 3,
onProgress: (progress) => {
console.log(`批量上传进度: ${progress}%`)
},
onFileComplete: (file, result) => {
if (result instanceof Error) {
console.error(`文件上传失败: ${file.name}`, result)
} else {
console.log(`文件上传完成: ${file.name}`)
}
}
})
// 创建资源记录
const resourcePromises = results.success.map(uploadResult =>
httpClient.post<ResourceData>(API_ENDPOINTS.RESOURCE.UPLOAD, {
...metadata,
name: uploadResult.filename,
url: uploadResult.url,
size: uploadResult.size,
format: uploadResult.filename.split('.').pop()?.toLowerCase() || 'unknown'
})
)
const resourceResults = await Promise.all(resourcePromises)
const successResources = resourceResults
.filter(result => result.success)
.map(result => result.data)
return {
code: 0,
message: 'Success',
data: successResources,
success: true
}
}
/**
* 删除资源
*/
public async deleteResource(resourceId: string): Promise<ApiResponse<void>> {
return httpClient.delete<void>(`${API_ENDPOINTS.RESOURCE.DELETE}/${resourceId}`)
}
/**
* 批量删除资源
*/
public async deleteMultipleResources(resourceIds: string[]): Promise<ApiResponse<void>> {
return httpClient.post<void>('/resource/batch-delete', { resourceIds })
}
/**
* 更新资源信息
*/
public async updateResource(
resourceId: string,
data: Partial<Pick<ResourceData, 'name' | 'tags' | 'description'>>
): Promise<ApiResponse<ResourceData>> {
return httpClient.put<ResourceData>(`/resource/${resourceId}`, data)
}
/**
* 下载资源
*/
public async downloadResource(resource: ResourceData): Promise<void> {
await fileDownloader.downloadAndSave({
url: resource.url,
filename: resource.name
})
}
/**
* 批量下载资源
*/
public async downloadMultipleResources(resources: ResourceData[]): Promise<void> {
const downloadFiles = resources.map(resource => ({
url: resource.url,
filename: resource.name
}))
await fileDownloader.downloadAsZip(downloadFiles, 'resources.zip')
}
/**
* 获取资源分类
*/
public async getResourceCategories(): Promise<ApiResponse<ResourceCategory[]>> {
return httpClient.get<ResourceCategory[]>('/resource/categories')
}
/**
* 创建资源分类
*/
public async createResourceCategory(
data: Pick<ResourceCategory, 'name' | 'description' | 'parentId'>
): Promise<ApiResponse<ResourceCategory>> {
return httpClient.post<ResourceCategory>('/resource/categories', data)
}
/**
* 搜索资源
*/
public async searchResources(params: ResourceSearchParams): Promise<ApiResponse<PaginationResponse<ResourceData>>> {
return httpClient.get<PaginationResponse<ResourceData>>('/resource/search', params)
}
/**
* 获取热门标签
*/
public async getPopularTags(limit: number = 20): Promise<ApiResponse<string[]>> {
return httpClient.get<string[]>('/resource/tags/popular', { limit })
}
/**
* 获取资源统计信息
*/
public async getResourceStats(): Promise<ApiResponse<{
total: number
byType: Record<ResourceData['type'], number>
totalSize: number
recentUploads: number
}>> {
return httpClient.get('/resource/stats')
}
/**
* 预览资源获取预览URL
*/
public async getResourcePreview(resourceId: string): Promise<ApiResponse<{ previewUrl: string }>> {
return httpClient.get<{ previewUrl: string }>(`/resource/${resourceId}/preview`)
}
/**
* 生成资源缩略图
*/
public async generateThumbnail(resourceId: string): Promise<ApiResponse<{ thumbnailUrl: string }>> {
return httpClient.post<{ thumbnailUrl: string }>(`/resource/${resourceId}/thumbnail`)
}
}
// 创建默认实例
export const resourceApi = new ResourceApi()