web-map/src/services/map-converter.service.ts

138 lines
4.4 KiB
TypeScript
Raw Normal View History

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 };
}