Files
geMoldInsight/templates/result.html
T
2026-02-16 01:18:51 +08:00

437 lines
16 KiB
HTML
Raw 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.
<!-- templates/result.html -->
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分析结果 - STP文件几何分析工具</title>
<link rel="stylesheet" href="/static/style.css">
<style>
.result-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header-nav {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
border-bottom: 1px solid #ddd;
padding-bottom: 20px;
}
.nav-buttons {
display: flex;
gap: 10px;
}
.task-info-card {
background: white;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 20px;
margin-bottom: 20px;
}
.task-info-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
}
.info-item {
display: flex;
flex-direction: column;
}
.info-label {
font-weight: bold;
color: #666;
font-size: 14px;
margin-bottom: 5px;
}
.info-value {
color: #333;
font-size: 16px;
}
.status-badge {
padding: 4px 12px;
border-radius: 20px;
font-size: 14px;
font-weight: bold;
}
.status-completed {
background: #e8f5e8;
color: #2e7d32;
}
.status-processing {
background: #fff3e0;
color: #f57c00;
}
.status-failed {
background: #ffebee;
color: #c62828;
}
.results-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 20px;
}
.result-section {
background: white;
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 20px;
}
.section-title {
font-size: 18px;
font-weight: bold;
color: #333;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.data-grid {
display: grid;
gap: 10px;
}
.data-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f5f5f5;
}
.data-label {
font-weight: bold;
color: #666;
}
.data-value {
color: #333;
text-align: right;
}
.error-message {
background: #ffebee;
border: 1px solid #ffcdd2;
border-radius: 6px;
padding: 15px;
color: #c62828;
margin: 20px 0;
}
.no-data {
text-align: center;
color: #999;
padding: 40px;
font-size: 16px;
}
.action-buttons {
display: flex;
gap: 10px;
margin-top: 20px;
}
</style>
</head>
<body>
<div class="result-container">
<div class="header-nav">
<div>
<h1>📊 分析结果详情</h1>
<p>查看STP文件的详细分析结果</p>
</div>
<div class="nav-buttons">
<button class="upload-btn" onclick="location.href='/history'">
📋 返回历史记录
</button>
<button class="upload-btn" onclick="location.href='/upload'">
📁 上传新文件
</button>
<button class="upload-btn" onclick="location.href='/'">
🏠 返回主页
</button>
</div>
</div>
<div id="taskInfo" class="task-info-card">
<div class="loading">
<div class="spinner"></div>
<p>正在加载任务信息...</p>
</div>
</div>
<div class="results-grid" id="resultsGrid">
<!-- 结果内容将通过JavaScript动态加载 -->
</div>
</div>
<script>
// 从URL获取任务ID
const pathParts = window.location.pathname.split('/');
const taskId = pathParts[pathParts.length - 1];
// 页面加载完成后获取任务数据
document.addEventListener('DOMContentLoaded', function() {
loadTaskData(taskId);
});
async function loadTaskData(taskId) {
try {
const response = await fetch(`/status/${taskId}`);
if (!response.ok) {
throw new Error('获取任务数据失败');
}
const task = await response.json();
displayTaskInfo(task);
displayResults(task);
} catch (error) {
document.getElementById('taskInfo').innerHTML = `
<div class="error-message">
<h3>❌ 加载失败</h3>
<p>${error.message}</p>
<button class="upload-btn" onclick="loadTaskData('${taskId}')">
重试
</button>
</div>
`;
}
}
function displayTaskInfo(task) {
const taskInfo = document.getElementById('taskInfo');
taskInfo.innerHTML = `
<h2>📝 任务信息</h2>
<div class="task-info-grid">
<div class="info-item">
<div class="info-label">任务ID</div>
<div class="info-value">${task.task_id || 'N/A'}</div>
</div>
<div class="info-item">
<div class="info-label">文件名</div>
<div class="info-value">${task.filename || 'N/A'}</div>
</div>
<div class="info-item">
<div class="info-label">文件大小</div>
<div class="info-value">${task.file_size ? formatFileSize(task.file_size) : 'N/A'}</div>
</div>
<div class="info-item">
<div class="info-label">状态</div>
<div class="info-value">
<span class="status-badge status-${task.status}">${getStatusText(task.status)}</span>
</div>
</div>
<div class="info-item">
<div class="info-label">上传时间</div>
<div class="info-value">${task.upload_time ? new Date(task.upload_time).toLocaleString() : 'N/A'}</div>
</div>
<div class="info-item">
<div class="info-label">完成时间</div>
<div class="info-value">${task.completed_at ? new Date(task.completed_at).toLocaleString() : 'N/A'}</div>
</div>
</div>
${task.error ? `
<div class="error-message" style="margin-top: 15px;">
<strong>错误信息:</strong> ${task.error}
</div>
` : ''}
`;
}
function displayResults(task) {
const resultsGrid = document.getElementById('resultsGrid');
if (task.status !== 'completed') {
resultsGrid.innerHTML = `
<div class="no-data">
<div style="font-size: 48px; margin-bottom: 20px;">⏳</div>
<h3>任务尚未完成</h3>
<p>当前状态: ${getStatusText(task.status)}</p>
</div>
`;
return;
}
resultsGrid.innerHTML = `
<div class="result-section">
<div class="section-title">📐 几何属性</div>
<div class="data-grid">
${displayGeometryData(task.geometry_data)}
</div>
</div>
<div class="result-section">
<div class="section-title">🔧 关键工艺参数</div>
<div class="data-grid">
${displayKeyInfo(task.key_info)}
</div>
</div>
<div class="result-section">
<div class="section-title">📦 边界框信息</div>
<div class="data-grid">
${displayBoundingBoxData(task.geometry_data)}
</div>
</div>
<div class="result-section">
<div class="section-title">🔺 拓扑结构</div>
<div class="data-grid">
${displayTopologyData(task.geometry_data)}
</div>
</div>
`;
}
function displayGeometryData(geometryData) {
if (!geometryData) return '<div class="no-data">无几何数据</div>';
return `
<div class="data-item">
<div class="data-label">体积</div>
<div class="data-value">${geometryData.volume ? formatNumber(geometryData.volume) + ' mm³' : 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">表面积</div>
<div class="data-value">${geometryData.surface_area ? formatNumber(geometryData.surface_area) + ' mm²' : 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">体积表面积比</div>
<div class="data-value">${geometryData.volume && geometryData.surface_area ? (geometryData.volume / geometryData.surface_area).toFixed(4) : 'N/A'}</div>
</div>
`;
}
function displayKeyInfo(keyInfo) {
if (!keyInfo) return '<div class="no-data">无关键信息数据</div>';
const metadata = keyInfo.metadata || {};
const manufacturingInfo = keyInfo.manufacturing_info || {};
const moldCavities = keyInfo.mold_cavities || {};
const cavityKeyInfo = moldCavities.cavity_key_info || {};
const geoChars = cavityKeyInfo.geometric_characteristics || {};
return `
<div class="data-item">
<div class="data-label">收缩率</div>
<div class="data-value">${metadata.shrinkage_rate !== undefined ? metadata.shrinkage_rate : 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">拔模角</div>
<div class="data-value">${metadata.draft_angle !== undefined ? metadata.draft_angle + '°' : 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">分型线长度</div>
<div class="data-value">${manufacturingInfo.parting_line_length || 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">产品体积</div>
<div class="data-value">${geoChars.product_volume || 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">产品重量</div>
<div class="data-value">${geoChars.product_weight || 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">壁厚范围</div>
<div class="data-value">${geoChars.wall_thickness_range || 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">型腔材料</div>
<div class="data-value">${manufacturingInfo.mold_material || 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">预估周期</div>
<div class="data-value">${manufacturingInfo.estimated_cycle_time || 'N/A'}</div>
</div>
`;
}
function displayBoundingBoxData(geometryData) {
if (!geometryData || !geometryData.bounding_box) return '<div class="no-data">无边界框数据</div>';
const bbox = geometryData.bounding_box;
return `
<div class="data-item">
<div class="data-label">最小坐标</div>
<div class="data-value">X: ${bbox.min[0].toFixed(2)}<br>Y: ${bbox.min[1].toFixed(2)}<br>Z: ${bbox.min[2].toFixed(2)}</div>
</div>
<div class="data-item">
<div class="data-label">最大坐标</div>
<div class="data-value">X: ${bbox.max[0].toFixed(2)}<br>Y: ${bbox.max[1].toFixed(2)}<br>Z: ${bbox.max[2].toFixed(2)}</div>
</div>
<div class="data-item">
<div class="data-label">尺寸</div>
<div class="data-value">${bbox.dimensions[0].toFixed(2)} × ${bbox.dimensions[1].toFixed(2)} × ${bbox.dimensions[2].toFixed(2)} mm</div>
</div>
`;
}
function displayTopologyData(geometryData) {
if (!geometryData || !geometryData.topology) return '<div class="no-data">无拓扑数据</div>';
const topo = geometryData.topology;
return `
<div class="data-item">
<div class="data-label">面数</div>
<div class="data-value">${topo.faces || 0}</div>
</div>
<div class="data-item">
<div class="data-label">边数</div>
<div class="data-value">${topo.edges || 0}</div>
</div>
<div class="data-item">
<div class="data-label">顶点数</div>
<div class="data-value">${topo.vertices || 0}</div>
</div>
`;
}
// 工具函数
function getStatusText(status) {
const statusMap = {
'processing': '处理中',
'completed': '已完成',
'failed': '失败'
};
return statusMap[status] || status;
}
function formatFileSize(bytes) {
if (!bytes || bytes === 0) return '0 Bytes';
const k = 1024;
const sizes = ['Bytes', 'KB', 'MB', 'GB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}
function formatNumber(num) {
if (!num) return 'N/A';
if (num >= 1000000) {
return (num / 1000000).toFixed(2) + 'M';
} else if (num >= 1000) {
return (num / 1000).toFixed(2) + 'K';
} else {
return num.toFixed(2);
}
}
</script>
</body>
</html>