VWED_server/web_demo.html

316 lines
15 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>