138 lines
4.4 KiB
TypeScript
138 lines
4.4 KiB
TypeScript
import axios from 'axios';
|
|
|
|
import { decodeTextFile } from './utils';
|
|
|
|
export type ProcessJsonListItem = {
|
|
floors: number;
|
|
type: 'smap' | 'scene';
|
|
[key: string]: any;
|
|
OriginalProperties: string;
|
|
};
|
|
|
|
export type ProcessJsonListResult =
|
|
| { kind: 'zip'; blob: Blob; filename: string | null; headers: Record<string, string> }
|
|
| { kind: 'json'; data: any; headers: Record<string, string> };
|
|
|
|
export type FloorImportItem = { name: string; fileList: any[]; keepProperties: boolean };
|
|
|
|
export async function collectOriginalProperties(
|
|
currentFloorScenes: any[] | any,
|
|
floorImportList: FloorImportItem[],
|
|
normalizeSceneJson: (raw: unknown) => unknown,
|
|
): Promise<string[]> {
|
|
const currentScenesArray: any[] = Array.isArray(currentFloorScenes)
|
|
? currentFloorScenes
|
|
: currentFloorScenes
|
|
? [currentFloorScenes]
|
|
: [];
|
|
|
|
const list = await Promise.all(
|
|
floorImportList.map(async (_floor, idx) => {
|
|
const keep = !!_floor.keepProperties;
|
|
if (!keep) return '';
|
|
let source: any = currentScenesArray[idx];
|
|
if (source == null && currentScenesArray.length === 1) {
|
|
source = currentScenesArray[0];
|
|
}
|
|
if (source == null) return '';
|
|
try {
|
|
const normalized = normalizeSceneJson(source) as any;
|
|
if (!normalized || typeof normalized !== 'object' || Array.isArray(normalized)) {
|
|
return '';
|
|
}
|
|
return JSON.stringify([normalized]);
|
|
} catch {
|
|
return '';
|
|
}
|
|
}),
|
|
);
|
|
return list;
|
|
}
|
|
|
|
export async function buildProcessJsonListPayload(
|
|
floorImportList: FloorImportItem[],
|
|
originalProperties: string[],
|
|
): Promise<ProcessJsonListItem[]> {
|
|
const payload: ProcessJsonListItem[] = [];
|
|
for (let i = 0; i < floorImportList.length; i += 1) {
|
|
const floor = floorImportList[i];
|
|
const files = (floor.fileList || []) as any[];
|
|
if (!files.length) throw new Error(`楼层 ${floor.name} 需要至少选择一个文件`);
|
|
|
|
const placeholders: string[] = [];
|
|
const exts: string[] = [];
|
|
for (const fileInfo of files) {
|
|
const file = fileInfo.originFileObj as File;
|
|
const content = await decodeTextFile(file);
|
|
if (!content) throw new Error(`楼层 ${floor.name} 的文件 ${file?.name} 读取为空`);
|
|
placeholders.push(content);
|
|
const ext =
|
|
String(file?.name || '')
|
|
.toLowerCase()
|
|
.split('.')
|
|
.pop() || '';
|
|
exts.push(ext);
|
|
}
|
|
|
|
// 校验
|
|
if (placeholders.length > 1) {
|
|
const hasNonSmap = exts.some((e) => e !== 'smap');
|
|
if (hasNonSmap) {
|
|
throw new Error(`楼层 ${floor.name} 上传了多个文件,但包含非 .smap 文件,请仅上传 .smap 文件`);
|
|
}
|
|
} else {
|
|
const ext0 = exts[0];
|
|
if (ext0 !== 'smap' && ext0 !== 'scene') {
|
|
throw new Error(`楼层 ${floor.name} 仅支持 .scene 或 .smap 文件`);
|
|
}
|
|
}
|
|
|
|
// 类型推断
|
|
let type: 'scene' | 'smap' = 'scene';
|
|
const hasSmap = exts.some((e) => e === 'smap');
|
|
if (placeholders.length > 1 || hasSmap) {
|
|
type = 'smap';
|
|
} else {
|
|
type = exts[0] === 'smap' ? 'smap' : 'scene';
|
|
}
|
|
|
|
const item: ProcessJsonListItem = {
|
|
floors: i + 1,
|
|
type,
|
|
OriginalProperties: originalProperties[i] || '',
|
|
} as ProcessJsonListItem;
|
|
|
|
placeholders.forEach((p, idx) => {
|
|
(item as any)[`placeholder${idx + 1}`] = p;
|
|
});
|
|
|
|
payload.push(item);
|
|
}
|
|
|
|
return payload;
|
|
}
|
|
|
|
export async function postProcessJsonList(payload: ProcessJsonListItem[]): Promise<ProcessJsonListResult> {
|
|
const client = axios.create();
|
|
const url = '/vwedApi/api/map-converter/process-json-list';
|
|
const response = await client.post(url, payload, { responseType: 'blob' });
|
|
|
|
const contentType = (response.headers?.['content-type'] || '').toString().toLowerCase();
|
|
const headers: Record<string, string> = {};
|
|
Object.entries(response.headers || {}).forEach(([k, v]) => (headers[k] = String(v)));
|
|
|
|
if (contentType.includes('application/json')) {
|
|
const text = await (response.data as Blob).text();
|
|
const data = JSON.parse(text);
|
|
return { kind: 'json', data, headers };
|
|
}
|
|
|
|
let filename: string | null = null;
|
|
const disposition = headers['content-disposition'] || '';
|
|
const match = disposition.match(/filename=([^;]+)/i);
|
|
if (match && match[1]) {
|
|
filename = decodeURIComponent(match[1].replace(/\"/g, ''));
|
|
}
|
|
return { kind: 'zip', blob: response.data as Blob, filename, headers };
|
|
}
|