316 lines
15 KiB
HTML
316 lines
15 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="zh-cn">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<title>地图在线转换工具</title>
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||
<style>
|
||
body {
|
||
background: linear-gradient(120deg, #f0f4f8 0%, #e0e7ef 100%);
|
||
min-height: 100vh;
|
||
}
|
||
.container {
|
||
max-width: 500px;
|
||
margin-top: 60px;
|
||
background: #fff;
|
||
border-radius: 16px;
|
||
box-shadow: 0 4px 24px rgba(0,0,0,0.08);
|
||
padding: 32px 28px 24px 28px;
|
||
}
|
||
h2 {
|
||
font-weight: 700;
|
||
color: #2d3a4b;
|
||
margin-bottom: 28px;
|
||
}
|
||
.form-label {
|
||
font-weight: 500;
|
||
}
|
||
.btn-primary, .btn-success {
|
||
width: 100%;
|
||
margin-top: 12px;
|
||
}
|
||
#result {
|
||
margin-top: 18px;
|
||
background: #f8f9fa;
|
||
border-radius: 8px;
|
||
padding: 14px;
|
||
min-height: 40px;
|
||
font-size: 15px;
|
||
color: #333;
|
||
}
|
||
.download-btn {
|
||
margin-top: 16px;
|
||
width: 100%;
|
||
}
|
||
.iray-params {
|
||
margin-top: 18px;
|
||
padding: 16px;
|
||
background: #f8f9fa;
|
||
border-radius: 8px;
|
||
border: 1px solid #dee2e6;
|
||
}
|
||
.param-row {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.param-row .form-control {
|
||
flex: 1;
|
||
}
|
||
.param-section-title {
|
||
font-weight: 600;
|
||
color: #495057;
|
||
margin-bottom: 10px;
|
||
font-size: 14px;
|
||
}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="container">
|
||
<h2 class="text-center">地图在线转换</h2>
|
||
|
||
<!-- 转换类型选择 -->
|
||
<div class="mb-3">
|
||
<label class="form-label">选择转换类型</label>
|
||
<div class="btn-group w-100" role="group">
|
||
<input type="radio" class="btn-check" name="convertType" id="sceneConvert" value="scene" checked>
|
||
<label class="btn btn-outline-primary" for="sceneConvert">SMAP转Scene</label>
|
||
|
||
<input type="radio" class="btn-check" name="convertType" id="irayConvert" value="iray">
|
||
<label class="btn btn-outline-primary" for="irayConvert">SMAP转IRAY地图包</label>
|
||
|
||
<input type="radio" class="btn-check" name="convertType" id="sceneToSmapConvert" value="scene-to-smap">
|
||
<label class="btn btn-outline-primary" for="sceneToSmapConvert">Scene更新SMAP</label>
|
||
</div>
|
||
</div>
|
||
|
||
<form id="uploadForm">
|
||
<label for="fileInput" class="form-label" id="fileInputLabel">选择 .smap 文件 <span style="color:#888;font-size:13px;">(必选)</span></label>
|
||
<input type="file" class="form-control" id="fileInput" name="file" accept=".smap" required>
|
||
<label for="sceneInput" class="form-label" style="margin-top:18px;" id="sceneInputLabel">选择 .scene 文件 <span style="color:#888;font-size:13px;">(可选,仅Scene转换时使用)</span></label>
|
||
<input type="file" class="form-control" id="sceneInput" name="scene" accept=".scene">
|
||
|
||
<!-- IRAY转换参数区域 -->
|
||
<div id="irayParams" class="iray-params" style="display:none;">
|
||
<div class="param-section-title">📐 地图参数设置 (IRAY转换必填)</div>
|
||
|
||
<div class="param-row">
|
||
<div>
|
||
<label for="mapWidth" class="form-label">地图宽度 (mm)</label>
|
||
<input type="number" class="form-control" id="mapWidth" placeholder="94744" value="94744">
|
||
</div>
|
||
<div>
|
||
<label for="mapHeight" class="form-label">地图高度 (mm)</label>
|
||
<input type="number" class="form-control" id="mapHeight" placeholder="79960" value="79960">
|
||
</div>
|
||
</div>
|
||
|
||
<div class="param-row">
|
||
<div>
|
||
<label for="xAttrMin" class="form-label">X最小值 (mm)</label>
|
||
<input type="number" class="form-control" id="xAttrMin" placeholder="-46762" value="-46762">
|
||
</div>
|
||
<div>
|
||
<label for="yAttrMin" class="form-label">Y最小值 (mm)</label>
|
||
<input type="number" class="form-control" id="yAttrMin" placeholder="-63362" value="-63362">
|
||
</div>
|
||
</div>
|
||
|
||
<div style="font-size:12px;color:#6c757d;margin-top:8px;">
|
||
💡 提示:地图参数决定了生成的华睿地图包的坐标系范围和尺寸
|
||
</div>
|
||
</div>
|
||
|
||
<button type="submit" class="btn btn-primary">上传并转换</button>
|
||
</form>
|
||
<div id="result"></div>
|
||
<a id="downloadBtn" class="btn btn-outline-primary download-btn" style="display:none;" download>下载转换后的文件</a>
|
||
</div>
|
||
<script>
|
||
// 转换类型切换事件
|
||
document.querySelectorAll('input[name="convertType"]').forEach(radio => {
|
||
radio.addEventListener('change', function() {
|
||
const fileInputLabel = document.getElementById('fileInputLabel');
|
||
const sceneInputLabel = document.getElementById('sceneInputLabel');
|
||
const fileInput = document.getElementById('fileInput');
|
||
const sceneInput = document.getElementById('sceneInput');
|
||
const irayParams = document.getElementById('irayParams');
|
||
|
||
if (this.value === 'iray') {
|
||
fileInputLabel.innerHTML = '选择 .smap 文件 <span style="color:#888;font-size:13px;">(必选)</span>';
|
||
sceneInputLabel.innerHTML = '选择 .scene 文件 <span style="color:#888;font-size:13px;">(必选,IRAY转换需要Scene文件提取点位映射)</span>';
|
||
fileInput.accept = '.smap';
|
||
sceneInput.accept = '.scene';
|
||
irayParams.style.display = 'block';
|
||
} else if (this.value === 'scene-to-smap') {
|
||
fileInputLabel.innerHTML = '选择 .scene 文件 <span style="color:#888;font-size:13px;">(必选,包含更新后的点位坐标)</span>';
|
||
sceneInputLabel.innerHTML = '选择 .smap 文件 <span style="color:#888;font-size:13px;">(必选,需要更新的原SMAP文件)</span>';
|
||
fileInput.accept = '.scene';
|
||
sceneInput.accept = '.smap';
|
||
irayParams.style.display = 'none';
|
||
} else {
|
||
fileInputLabel.innerHTML = '选择 .smap 文件 <span style="color:#888;font-size:13px;">(必选)</span>';
|
||
sceneInputLabel.innerHTML = '选择 .scene 文件 <span style="color:#888;font-size:13px;">(可选,仅Scene转换时使用)</span>';
|
||
fileInput.accept = '.smap';
|
||
sceneInput.accept = '.scene';
|
||
irayParams.style.display = 'none';
|
||
}
|
||
});
|
||
});
|
||
|
||
document.getElementById('uploadForm').onsubmit = async function(e) {
|
||
e.preventDefault();
|
||
const fileInput = document.getElementById('fileInput');
|
||
const sceneInput = document.getElementById('sceneInput');
|
||
const convertType = document.querySelector('input[name="convertType"]:checked').value;
|
||
|
||
if (!fileInput.files.length) {
|
||
document.getElementById('result').textContent = '请先选择 .smap 文件';
|
||
return;
|
||
}
|
||
|
||
// IRAY转换时的特殊验证
|
||
if (convertType === 'iray') {
|
||
if (!sceneInput.files.length) {
|
||
document.getElementById('result').textContent = 'IRAY转换需要同时选择 .scene 文件用于提取点位映射';
|
||
return;
|
||
}
|
||
|
||
// 验证必要参数
|
||
const mapWidth = document.getElementById('mapWidth').value;
|
||
const mapHeight = document.getElementById('mapHeight').value;
|
||
const xAttrMin = document.getElementById('xAttrMin').value;
|
||
const yAttrMin = document.getElementById('yAttrMin').value;
|
||
|
||
if (!mapWidth || !mapHeight || !xAttrMin || !yAttrMin) {
|
||
document.getElementById('result').textContent = 'IRAY转换需要填写所有地图参数';
|
||
return;
|
||
}
|
||
}
|
||
|
||
// Scene到SMAP转换时的特殊验证
|
||
if (convertType === 'scene-to-smap') {
|
||
if (!sceneInput.files.length) {
|
||
document.getElementById('result').textContent = 'Scene到SMAP转换需要同时选择 .smap 文件';
|
||
return;
|
||
}
|
||
}
|
||
|
||
const formData = new FormData();
|
||
|
||
// 根据转换类型处理文件上传
|
||
if (convertType === 'scene-to-smap') {
|
||
// Scene到SMAP转换:第一个文件是scene,第二个是smap
|
||
formData.append('scene_file', fileInput.files[0]);
|
||
formData.append('smap_file', sceneInput.files[0]);
|
||
} else {
|
||
// 其他转换:第一个文件是smap,第二个是scene
|
||
formData.append('smap_file', fileInput.files[0]);
|
||
if (sceneInput.files.length) {
|
||
formData.append('scene_file', sceneInput.files[0]);
|
||
}
|
||
}
|
||
|
||
// 添加IRAY转换参数
|
||
if (convertType === 'iray') {
|
||
formData.append('map_width', document.getElementById('mapWidth').value);
|
||
formData.append('map_height', document.getElementById('mapHeight').value);
|
||
formData.append('x_attr_min', document.getElementById('xAttrMin').value);
|
||
formData.append('y_attr_min', document.getElementById('yAttrMin').value);
|
||
}
|
||
|
||
document.getElementById('result').textContent = '正在上传并转换...';
|
||
document.getElementById('downloadBtn').style.display = 'none';
|
||
|
||
try {
|
||
let apiUrl;
|
||
if (convertType === 'iray') {
|
||
apiUrl = 'http://127.0.0.1:8000/api/vwed-map-converter/smap-to-iray';
|
||
} else if (convertType === 'scene-to-smap') {
|
||
apiUrl = 'http://127.0.0.1:8000/api/vwed-map-converter/scene-to-smap';
|
||
} else {
|
||
apiUrl = 'http://127.0.0.1:8000/api/vwed-map-converter/smap-to-scene';
|
||
}
|
||
|
||
let isIray = convertType === 'iray';
|
||
if (isIray) {
|
||
// 强制二进制返回模式
|
||
formData.append('response_mode', 'binary');
|
||
}
|
||
|
||
const resp = await fetch(apiUrl, { method: 'POST', body: formData });
|
||
|
||
const downloadBtn = document.getElementById('downloadBtn');
|
||
if (isIray) {
|
||
if (!resp.ok) {
|
||
const text = await resp.text();
|
||
document.getElementById('result').textContent = '转换失败:' + text;
|
||
return;
|
||
}
|
||
// 读取zip二进制
|
||
const blob = await resp.blob();
|
||
if (blob.size === 0) {
|
||
document.getElementById('result').textContent = '转换失败:返回空文件';
|
||
return;
|
||
}
|
||
const disposition = resp.headers.get('Content-Disposition') || '';
|
||
let filenameMatch = disposition.match(/filename=([^;]+)/i);
|
||
let filename = filenameMatch ? filenameMatch[1].replace(/"/g,'') : 'map_package.zip';
|
||
// 创建下载链接
|
||
const url = URL.createObjectURL(blob);
|
||
downloadBtn.href = url;
|
||
downloadBtn.download = filename;
|
||
downloadBtn.textContent = '下载华睿地图包 (' + filename + ')';
|
||
downloadBtn.onclick = null;
|
||
downloadBtn.style.display = 'block';
|
||
document.getElementById('result').textContent = '转换成功,已生成华睿地图包。';
|
||
return; // 结束
|
||
}
|
||
|
||
// 非IRAY还是按照JSON处理
|
||
const data = await resp.json();
|
||
const dataStr = JSON.stringify(data, null, 2);
|
||
const lines = dataStr.split('\n').slice(0, 100).join('\n');
|
||
document.getElementById('result').textContent = lines + (dataStr.split('\n').length > 100 ? '\n...(内容已截断)' : '');
|
||
|
||
if (convertType === 'scene-to-smap' && data.success && data.data) {
|
||
// Scene到SMAP转换成功,生成下载文件
|
||
const smapContent = JSON.stringify(data.data, null, 2);
|
||
const blob = new Blob([smapContent], { type: 'application/json' });
|
||
const url = URL.createObjectURL(blob);
|
||
downloadBtn.href = url;
|
||
|
||
// 使用服务器返回的输出文件名,如果没有则使用默认名称
|
||
let filename = 'updated.smap';
|
||
if (data.output_file) {
|
||
// 从完整路径中提取文件名
|
||
filename = data.output_file.split(/[/\\]/).pop();
|
||
}
|
||
downloadBtn.download = filename;
|
||
downloadBtn.textContent = '下载更新后的SMAP文件';
|
||
downloadBtn.onclick = null;
|
||
downloadBtn.style.display = 'block';
|
||
} else if (convertType === 'scene' && data.data) {
|
||
// Scene转换成功,生成下载文件
|
||
const sceneContent = JSON.stringify(data.data, null, 2);
|
||
const blob = new Blob([sceneContent], { type: 'application/json' });
|
||
const url = URL.createObjectURL(blob);
|
||
downloadBtn.href = url;
|
||
|
||
// 使用服务器返回的文件名,如果没有则使用默认名称
|
||
const filename = data.output_filename || 'converted.scene';
|
||
downloadBtn.download = filename;
|
||
downloadBtn.textContent = '下载Scene文件';
|
||
downloadBtn.onclick = null;
|
||
downloadBtn.style.display = 'block';
|
||
} else {
|
||
downloadBtn.style.display = 'none';
|
||
}
|
||
|
||
} catch (err) {
|
||
document.getElementById('result').textContent = '请求失败:' + err;
|
||
}
|
||
}
|
||
</script>
|
||
</body>
|
||
</html> |