awake
This commit is contained in:
143
src/api/modules/editor.ts
Normal file
143
src/api/modules/editor.ts
Normal 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
281
src/api/modules/resource.ts
Normal 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()
|
Reference in New Issue
Block a user