2025-09-25 15:08:17 +08:00
|
|
|
import { message } from 'ant-design-vue';
|
|
|
|
|
import axios from 'axios';
|
|
|
|
|
import { ref } from 'vue';
|
|
|
|
|
|
|
|
|
|
import { downloadFile } from '../services/utils';
|
|
|
|
|
|
|
|
|
|
const vwedApi = '/vwedApi';
|
|
|
|
|
const API_BASE_URL = '' + vwedApi + '/api/vwed-map-converter';
|
|
|
|
|
|
|
|
|
|
const mapConverterHttp = axios.create();
|
|
|
|
|
|
|
|
|
|
export function useMapConversion() {
|
|
|
|
|
const isConverting = ref(false);
|
|
|
|
|
|
2025-09-25 16:23:53 +08:00
|
|
|
/**
|
|
|
|
|
* Imports or updates a Scene using an SMAP file.
|
|
|
|
|
* Calls the smap-to-scene API endpoint.
|
|
|
|
|
* @param smapFile The .smap file.
|
|
|
|
|
* @param sceneFile Optional .scene file for updates. If not provided, a new scene is created.
|
|
|
|
|
* @returns The resulting scene JSON string, or null if failed.
|
|
|
|
|
*/
|
|
|
|
|
const convertSmapToScene = async (smapFile: File, sceneFile?: File): Promise<string | null> => {
|
2025-09-25 15:08:17 +08:00
|
|
|
isConverting.value = true;
|
2025-09-25 16:23:53 +08:00
|
|
|
const isUpdate = !!sceneFile;
|
|
|
|
|
const actionText = isUpdate ? '更新' : '新建';
|
|
|
|
|
|
2025-09-25 15:08:17 +08:00
|
|
|
try {
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
formData.append('smap_file', smapFile);
|
2025-09-25 16:23:53 +08:00
|
|
|
if (sceneFile) {
|
|
|
|
|
formData.append('scene_file', sceneFile);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 15:08:17 +08:00
|
|
|
const response = await mapConverterHttp.post<any>(`${API_BASE_URL}/smap-to-scene`, formData, {
|
|
|
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
|
|
|
});
|
2025-09-25 16:23:53 +08:00
|
|
|
|
2025-09-25 15:08:17 +08:00
|
|
|
if (response.data.code === 200 || response.data.success) {
|
2025-09-25 16:23:53 +08:00
|
|
|
message.success(`通过 SMAP ${actionText} Scene 成功!`);
|
2025-09-25 15:08:17 +08:00
|
|
|
return JSON.stringify(response.data.data, null, 2);
|
|
|
|
|
} else {
|
2025-09-25 16:23:53 +08:00
|
|
|
throw new Error(response.data.message || `${actionText}失败`);
|
2025-09-25 15:08:17 +08:00
|
|
|
}
|
|
|
|
|
} catch (error: any) {
|
2025-09-25 16:23:53 +08:00
|
|
|
const errorMessage = error.response?.data?.message || error.message || `通过 SMAP ${actionText} Scene 失败`;
|
2025-09-25 15:08:17 +08:00
|
|
|
message.error(errorMessage);
|
|
|
|
|
return null;
|
|
|
|
|
} finally {
|
|
|
|
|
isConverting.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-25 16:23:53 +08:00
|
|
|
/**
|
|
|
|
|
* Exports a Scene to an SMAP file format.
|
|
|
|
|
* Requires both a scene and a base smap file.
|
|
|
|
|
* Calls the scene-to-smap API endpoint.
|
|
|
|
|
* @param sceneFile The .scene file to export.
|
|
|
|
|
* @param smapFile The base .smap file to update.
|
|
|
|
|
* @param filename The base name for the downloaded file.
|
|
|
|
|
*/
|
|
|
|
|
const exportSceneToSmap = async (sceneFile: File, smapFile: File, filename: string) => {
|
2025-09-25 15:08:17 +08:00
|
|
|
isConverting.value = true;
|
|
|
|
|
try {
|
|
|
|
|
const formData = new FormData();
|
2025-09-25 16:23:53 +08:00
|
|
|
formData.append('scene_file', sceneFile);
|
|
|
|
|
formData.append('smap_file', smapFile);
|
2025-09-25 15:08:17 +08:00
|
|
|
|
|
|
|
|
const response = await mapConverterHttp.post<any>(`${API_BASE_URL}/scene-to-smap`, formData, {
|
|
|
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (response.data.code === 200 || response.data.success) {
|
|
|
|
|
const smapContent = JSON.stringify(response.data?.data, null, 2);
|
|
|
|
|
const blob = new Blob([smapContent], { type: 'application/json' });
|
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
|
const outputFilename = response.data?.output_file
|
|
|
|
|
? response.data.output_file.split(/[/\\]/).pop()
|
|
|
|
|
: `${filename}.smap`;
|
|
|
|
|
downloadFile(url, outputFilename);
|
|
|
|
|
URL.revokeObjectURL(url);
|
2025-09-25 16:23:53 +08:00
|
|
|
message.success('导出到 SMAP 文件成功!');
|
2025-09-25 15:08:17 +08:00
|
|
|
} else {
|
2025-09-25 16:23:53 +08:00
|
|
|
throw new Error(response.data.message || '导出失败');
|
2025-09-25 15:08:17 +08:00
|
|
|
}
|
|
|
|
|
} catch (error: any) {
|
2025-09-25 16:23:53 +08:00
|
|
|
const errorMessage = error.response?.data?.message || error.message || '导出到 SMAP 文件失败';
|
2025-09-25 15:08:17 +08:00
|
|
|
message.error(errorMessage);
|
|
|
|
|
} finally {
|
|
|
|
|
isConverting.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-25 17:03:42 +08:00
|
|
|
const convertSceneToIray = async (
|
|
|
|
|
sceneJson: string,
|
|
|
|
|
smapFile: File,
|
|
|
|
|
filename: string,
|
|
|
|
|
irayParams?: { mapWidth: number; mapHeight: number; xAttrMin: number; yAttrMin: number },
|
|
|
|
|
) => {
|
2025-09-25 15:08:17 +08:00
|
|
|
isConverting.value = true;
|
|
|
|
|
try {
|
|
|
|
|
const formData = new FormData();
|
|
|
|
|
const sceneBlob = new Blob([sceneJson], { type: 'application/json' });
|
|
|
|
|
formData.append('scene_file', sceneBlob, `${filename}.scene`);
|
2025-09-25 16:48:29 +08:00
|
|
|
formData.append('smap_file', smapFile);
|
2025-09-25 15:08:17 +08:00
|
|
|
|
2025-09-25 17:03:42 +08:00
|
|
|
// Append IRAY parameters if they exist
|
|
|
|
|
if (irayParams) {
|
|
|
|
|
formData.append('map_width', String(irayParams.mapWidth));
|
|
|
|
|
formData.append('map_height', String(irayParams.mapHeight));
|
|
|
|
|
formData.append('x_attr_min', String(irayParams.xAttrMin));
|
|
|
|
|
formData.append('y_attr_min', String(irayParams.yAttrMin));
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 16:48:29 +08:00
|
|
|
const response = await mapConverterHttp.post(`${API_BASE_URL}/smap-to-iray`, formData, {
|
2025-09-25 15:08:17 +08:00
|
|
|
headers: { 'Content-Type': 'multipart/form-data' },
|
|
|
|
|
responseType: 'blob',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const blob = response?.data as unknown as Blob;
|
|
|
|
|
if (!blob || blob.size === 0) {
|
|
|
|
|
throw new Error('返回的二进制文件为空');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const disposition = response?.headers?.['content-disposition'] || '';
|
2025-09-25 16:23:53 +08:00
|
|
|
let downloadFilename = `${filename}.zip`;
|
2025-09-25 15:08:17 +08:00
|
|
|
const filenameMatch = disposition.match(/filename=([^;]+)/i);
|
|
|
|
|
if (filenameMatch && filenameMatch[1]) {
|
|
|
|
|
downloadFilename = decodeURIComponent(filenameMatch[1].replace(/"/g, ''));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const url = URL.createObjectURL(blob);
|
|
|
|
|
downloadFile(url, downloadFilename);
|
|
|
|
|
URL.revokeObjectURL(url);
|
|
|
|
|
message.success('Scene 转换为 IRAY 并下载成功!');
|
|
|
|
|
} catch (error: any) {
|
|
|
|
|
const errorMessage = error.response?.data?.message || error.message || 'Scene 转换为 IRAY 失败';
|
|
|
|
|
message.error(errorMessage);
|
|
|
|
|
} finally {
|
|
|
|
|
isConverting.value = false;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
isConverting,
|
|
|
|
|
convertSmapToScene,
|
2025-09-25 16:23:53 +08:00
|
|
|
exportSceneToSmap,
|
2025-09-25 15:08:17 +08:00
|
|
|
convertSceneToIray,
|
|
|
|
|
};
|
|
|
|
|
}
|