web-map/src/hooks/useMapConversion.ts

150 lines
5.3 KiB
TypeScript
Raw Normal View History

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);
/**
* 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> => {
isConverting.value = true;
const isUpdate = !!sceneFile;
const actionText = isUpdate ? '更新' : '新建';
try {
const formData = new FormData();
formData.append('smap_file', smapFile);
if (sceneFile) {
formData.append('scene_file', sceneFile);
}
const response = await mapConverterHttp.post<any>(`${API_BASE_URL}/smap-to-scene`, formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
if (response.data.code === 200 || response.data.success) {
message.success(`通过 SMAP ${actionText} Scene 成功!`);
return JSON.stringify(response.data.data, null, 2);
} else {
throw new Error(response.data.message || `${actionText}失败`);
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || `通过 SMAP ${actionText} Scene 失败`;
message.error(errorMessage);
return null;
} finally {
isConverting.value = false;
}
};
/**
* 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) => {
isConverting.value = true;
try {
const formData = new FormData();
formData.append('scene_file', sceneFile);
formData.append('smap_file', smapFile);
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);
message.success('导出到 SMAP 文件成功!');
} else {
throw new Error(response.data.message || '导出失败');
}
} catch (error: any) {
const errorMessage = error.response?.data?.message || error.message || '导出到 SMAP 文件失败';
message.error(errorMessage);
} finally {
isConverting.value = false;
}
};
const convertSceneToIray = async (
sceneJson: string,
smapFile: File,
filename: string,
irayParams?: { mapWidth: number; mapHeight: number; xAttrMin: number; yAttrMin: number },
) => {
isConverting.value = true;
try {
const formData = new FormData();
const sceneBlob = new Blob([sceneJson], { type: 'application/json' });
formData.append('scene_file', sceneBlob, `${filename}.scene`);
formData.append('smap_file', smapFile);
// 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));
}
const response = await mapConverterHttp.post(`${API_BASE_URL}/smap-to-iray`, formData, {
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'] || '';
let downloadFilename = `${filename}.zip`;
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,
exportSceneToSmap,
convertSceneToIray,
};
}