VWED_server/web_demo.html

316 lines
15 KiB
HTML
Raw Permalink Normal View History

2025-09-25 10:52:52 +08:00
<!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>