Files
geMoldInsight/static/script.js
T
2026-02-16 17:32:39 +08:00

658 lines
23 KiB
JavaScript
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.
// static/script.js
let selectedFile = null;
const uploadSection = document.getElementById('uploadSection');
const uploadArea = document.getElementById('uploadArea');
const fileInput = document.getElementById('fileInput');
const uploadBtn = document.getElementById('uploadBtn');
const loading = document.getElementById('loading');
const resultsSection = document.getElementById('resultsSection');
const errorMessage = document.getElementById('errorMessage');
const taskInfo = document.getElementById('taskInfo');
const geometryData = document.getElementById('geometryData');
const boundingBoxData = document.getElementById('boundingBoxData');
const topologyData = document.getElementById('topologyData');
const featuresData = document.getElementById('featuresData');
const recommendationsData = document.getElementById('recommendationsData');
const metricsData = document.getElementById('metricsData');
const analysisInfo = document.getElementById('analysisInfo');
// 页面加载时初始化
document.addEventListener('DOMContentLoaded', function() {
console.log('页面加载完成');
showUploadSection();
});
// 显示上传区域
function showUploadSection() {
uploadSection.style.display = 'block';
resultsSection.style.display = 'none';
resetUploadArea();
}
// 显示结果区域
function showResultsSection() {
uploadSection.style.display = 'none';
resultsSection.style.display = 'block';
}
// 重置上传区域
function resetUploadArea() {
selectedFile = null;
uploadArea.innerHTML = `
<div class="upload-icon">📁</div>
<h3>拖放文件到此处或点击选择</h3>
<p>最大文件大小: 100MB</p>
<input type="file" id="fileInput" class="file-input" accept=".stp,.step">
<button class="upload-btn" onclick="document.getElementById('fileInput').click()">
选择文件
</button>
`;
uploadBtn.disabled = true;
hideError();
loading.style.display = 'none';
// 重新绑定事件
const newFileInput = document.getElementById('fileInput');
newFileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
handleFileSelect(e.target.files[0]);
}
});
}
// 拖放功能
uploadArea.addEventListener('dragover', (e) => {
e.preventDefault();
uploadArea.classList.add('dragover');
});
uploadArea.addEventListener('dragleave', () => {
uploadArea.classList.remove('dragover');
});
uploadArea.addEventListener('drop', (e) => {
e.preventDefault();
uploadArea.classList.remove('dragover');
const files = e.dataTransfer.files;
if (files.length > 0) {
handleFileSelect(files[0]);
}
});
// 文件选择
fileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) {
handleFileSelect(e.target.files[0]);
}
});
function handleFileSelect(file) {
if (!file.name.toLowerCase().endsWith('.stp') && !file.name.toLowerCase().endsWith('.step')) {
showError('请选择STP或STEP格式的文件');
return;
}
if (file.size > 100 * 1024 * 1024) {
showError('文件大小不能超过100MB');
return;
}
selectedFile = file;
uploadArea.innerHTML = `
<div class="upload-icon">✅</div>
<h3>已选择文件</h3>
<p><strong>${file.name}</strong></p>
<p>大小: ${(file.size / 1024 / 1024).toFixed(2)} MB</p>
`;
uploadBtn.disabled = false;
hideError();
}
async function uploadFile() {
if (!selectedFile) return;
loading.style.display = 'block';
uploadBtn.disabled = true;
hideError();
const formData = new FormData();
formData.append('file', selectedFile);
try {
const response = await fetch('/upload', {
method: 'POST',
body: formData
});
if (!response.ok) {
throw new Error(`上传失败: ${response.status} ${response.statusText}`);
}
const result = await response.json();
console.log('上传结果:', result);
// 开始轮询任务状态
pollTaskStatus(result.task_id);
} catch (error) {
showError('上传失败: ' + error.message);
loading.style.display = 'none';
uploadBtn.disabled = false;
}
}
async function pollTaskStatus(taskId) {
try {
const response = await fetch(`/status/${taskId}`, {
method: 'POST'
});
const task = await response.json();
console.log('任务状态:', task.status);
console.log('完整任务数据:', task);
updateTaskInfo(task);
if (task.status === 'completed') {
loading.style.display = 'none';
// 跳转到统一的分析结果页面
window.location.href = `/result/${task.task_id}`;
} else if (task.status === 'failed') {
loading.style.display = 'none';
showError('分析失败: ' + (task.error || '未知错误'));
uploadBtn.disabled = false;
} else {
setTimeout(() => pollTaskStatus(taskId), 1000);
}
} catch (error) {
console.error('轮询错误:', error);
loading.style.display = 'none';
showError('查询状态失败: ' + error.message);
uploadBtn.disabled = false;
}
}
function updateTaskInfo(task) {
taskInfo.innerHTML = `
<div class="data-item">
<div class="data-label">📋 任务ID</div>
<div class="data-value">${task.task_id || 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">🔄 状态</div>
<div class="data-value">
<span class="status-badge status-${task.status}">${getStatusText(task.status)}</span>
</div>
</div>
<div class="data-item">
<div class="data-label">📁 文件名</div>
<div class="data-value">${task.filename || 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">📏 文件大小</div>
<div class="data-value">${task.file_size ? formatFileSize(task.file_size) : 'N/A'}</div>
</div>
`;
}
function displayAllResults(task) {
console.log('显示所有结果:', task);
displayGeometryData(task);
displayBoundingBoxData(task);
displayTopologyData(task);
// 添加模具型腔数据显示
if (task.cavity_data) {
displayCavityData(task.cavity_data);
}
if (task.key_info) {
displayKeyInfo(task.key_info);
}
displayFeaturesData(task);
displayRecommendationsData(task);
displayMetricsData(task);
displayAnalysisInfo(task);
}
function displayGeometryData(task) {
if (task.geometry_data) {
const geo = task.geometry_data;
geometryData.innerHTML = `
<div class="data-item">
<div class="data-label">📦 体积</div>
<div class="data-value">
${geo.volume ? formatNumber(geo.volume) : 'N/A'}
<span class="data-unit">mm³</span>
</div>
</div>
<div class="data-item">
<div class="data-label">📐 表面积</div>
<div class="data-value">
${geo.surface_area ? formatNumber(geo.surface_area) : 'N/A'}
<span class="data-unit">mm²</span>
</div>
</div>
<div class="data-item">
<div class="data-label">📏 体积表面积比</div>
<div class="data-value">
${geo.volume && geo.surface_area ? (geo.volume / geo.surface_area).toFixed(4) : 'N/A'}
</div>
</div>
`;
} else {
geometryData.innerHTML = '<div class="data-item"><div class="data-value">无几何数据</div></div>';
}
}
function displayBoundingBoxData(task) {
if (task.geometry_data && task.geometry_data.bounding_box) {
const bbox = task.geometry_data.bounding_box;
boundingBoxData.innerHTML = `
<div class="data-item coordinate-item">
<div class="coordinate-label">📍 最小坐标</div>
<div class="coordinate-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 coordinate-item">
<div class="coordinate-label">📍 最大坐标</div>
<div class="coordinate-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)}
<span class="data-unit">mm</span>
</div>
</div>
`;
} else {
boundingBoxData.innerHTML = '<div class="data-item"><div class="data-value">无边界框数据</div></div>';
}
}
function displayTopologyData(task) {
if (task.geometry_data && task.geometry_data.topology) {
const topo = task.geometry_data.topology;
topologyData.innerHTML = `
<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>
<div class="data-item">
<div class="data-label">📊 拓扑复杂度</div>
<div class="data-value">${calculateTopologyComplexity(topo)}</div>
</div>
`;
} else {
topologyData.innerHTML = '<div class="data-item"><div class="data-value">无拓扑数据</div></div>';
}
}
function displayFeaturesData(task) {
if (task.analysis_result && task.analysis_result.detected_features) {
const features = task.analysis_result.detected_features;
if (features.length > 0) {
featuresData.innerHTML = features.map(feature => `
<div class="feature-item">
<div class="feature-header">
<div class="feature-type">${getFeatureTypeText(feature.feature_type)}</div>
<div class="confidence-badge">置信度: ${(feature.confidence * 100).toFixed(0)}%</div>
</div>
<div class="data-item">
<div class="data-label">📍 位置</div>
<div class="data-value">${feature.location.map(v => v.toFixed(2)).join(', ')}</div>
</div>
<div class="data-item">
<div class="data-label">📏 尺寸</div>
<div class="data-value">${feature.dimensions.map(v => v.toFixed(2)).join(' × ')} mm</div>
</div>
${feature.recommendations && feature.recommendations.length > 0 ? `
<div class="data-item">
<div class="data-label">💡 建议</div>
<ul class="recommendation-list">
${feature.recommendations.map(rec => `<li>${rec}</li>`).join('')}
</ul>
</div>
` : ''}
</div>
`).join('');
} else {
featuresData.innerHTML = '<div class="data-item"><div class="data-value">未检测到明显特征</div></div>';
}
} else {
featuresData.innerHTML = '<div class="data-item"><div class="data-value">无特征数据</div></div>';
}
}
function displayRecommendationsData(task) {
if (task.analysis_result && task.analysis_result.design_recommendations) {
const recommendations = task.analysis_result.design_recommendations;
if (recommendations.length > 0) {
recommendationsData.innerHTML = recommendations.map(rec => `
<div class="recommendation-item recommendation-${rec.priority}">
<div class="recommendation-header">
<div class="feature-type">${getRecommendationTypeText(rec.type)}</div>
<div class="priority-badge priority-${rec.priority}">${getPriorityText(rec.priority)}</div>
</div>
<div class="data-item">
<div class="data-label">📝 描述</div>
<div class="data-value">${rec.description}</div>
</div>
<div class="data-item">
<div class="data-label">📋 原因</div>
<div class="data-value">${rec.reason}</div>
</div>
${Object.keys(rec.parameters).length > 0 ? `
<div class="data-item">
<div class="data-label">⚙️ 参数</div>
<div class="data-value">${formatParameters(rec.parameters)}</div>
</div>
` : ''}
</div>
`).join('');
} else {
recommendationsData.innerHTML = '<div class="data-item"><div class="data-value">无设计建议</div></div>';
}
} else {
recommendationsData.innerHTML = '<div class="data-item"><div class="data-value">无建议数据</div></div>';
}
}
function displayMetricsData(task) {
if (task.analysis_result && task.analysis_result.quality_metrics) {
const metrics = task.analysis_result.quality_metrics;
metricsData.innerHTML = `
<div class="metric-item">
<div class="metric-label">体积利用率</div>
<div class="metric-value ${getMetricClass(metrics.volume_utilization, 0.3, 0.6)}">
${(metrics.volume_utilization * 100).toFixed(1)}%
</div>
<div class="data-value">${getVolumeUtilizationText(metrics.volume_utilization)}</div>
</div>
<div class="metric-item">
<div class="metric-label">拓扑复杂度</div>
<div class="metric-value ${getMetricClass(metrics.topology_complexity, 0.3, 0.7, true)}">
${metrics.topology_complexity.toFixed(2)}
</div>
<div class="data-value">${getComplexityText(metrics.topology_complexity)}</div>
</div>
<div class="metric-item">
<div class="metric-label">壁厚均匀性</div>
<div class="metric-value ${getMetricClass(metrics.wall_uniformity, 0.6, 0.8)}">
${(metrics.wall_uniformity * 100).toFixed(1)}%
</div>
<div class="data-value">${getUniformityText(metrics.wall_uniformity)}</div>
</div>
`;
} else {
metricsData.innerHTML = '<div class="data-item"><div class="data-value">无质量指标数据</div></div>';
}
}
function displayAnalysisInfo(task) {
let infoHTML = '';
if (task.geometry_data) {
const geo = task.geometry_data;
infoHTML += `
<div class="data-item">
<div class="data-label">🔧 分析方法</div>
<div class="data-value">${geo.analysis_method || '未知'}</div>
</div>
`;
}
if (task.analysis_result) {
const analysis = task.analysis_result;
infoHTML += `
<div class="data-item">
<div class="data-label">✅ 分析状态</div>
<div class="data-value">${task.status === 'completed' ? '分析完成' : '分析中'}</div>
</div>
<div class="data-item">
<div class="data-label">📋 分析摘要</div>
<div class="data-value">${analysis.analysis_summary || '无摘要'}</div>
</div>
`;
}
infoHTML += `
<div class="data-item">
<div class="data-label">📅 处理时间</div>
<div class="data-value">${task.completed_at ? new Date(task.completed_at).toLocaleString() : new Date().toLocaleString()}</div>
</div>
`;
analysisInfo.innerHTML = infoHTML;
}
// 工具函数
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);
}
}
function calculateTopologyComplexity(topo) {
const totalElements = (topo.faces || 0) + (topo.edges || 0) + (topo.vertices || 0);
if (totalElements < 100) return '简单';
if (totalElements < 1000) return '中等';
return '复杂';
}
function getFeatureTypeText(type) {
const typeMap = {
'thin_wall': '薄壁区域',
'thick_wall': '厚壁区域',
'rib_structure': '加强筋结构',
'boss_feature': 'BOSS柱',
'draft_angle': '拔模角度',
'cooling_system': '冷却系统'
};
return typeMap[type] || type;
}
function getRecommendationTypeText(type) {
const typeMap = {
'wall_thickness': '壁厚优化',
'draft_angle': '拔模角度',
'rib_design': '加强筋设计',
'boss_design': 'BOSS柱设计',
'cooling_system': '冷却系统'
};
return typeMap[type] || type;
}
function getPriorityText(priority) {
const priorityMap = {
'high': '高优先级',
'medium': '中优先级',
'low': '低优先级'
};
return priorityMap[priority] || priority;
}
function formatParameters(parameters) {
const parameterMap = {
'min_angle': '最小角度',
'preferred_angle': '推荐角度'
};
return Object.entries(parameters).map(([key, value]) => {
const displayKey = parameterMap[key] || key;
if (typeof value === 'number') {
return `${displayKey}: ${value.toFixed(2)}`;
}
return `${displayKey}: ${value}`;
}).join('; ');
}
function getMetricClass(value, goodThreshold, excellentThreshold, reverse = false) {
if (reverse) {
if (value <= goodThreshold) return 'metric-good';
if (value <= excellentThreshold) return 'metric-warning';
return 'metric-poor';
} else {
if (value >= excellentThreshold) return 'metric-good';
if (value >= goodThreshold) return 'metric-warning';
return 'metric-poor';
}
}
function getVolumeUtilizationText(value) {
if (value >= 0.6) return '优秀';
if (value >= 0.3) return '良好';
return '待优化';
}
function getComplexityText(value) {
if (value <= 0.3) return '简单';
if (value <= 0.7) return '中等';
return '复杂';
}
function getUniformityText(value) {
if (value >= 0.8) return '均匀';
if (value >= 0.6) return '一般';
return '不均匀';
}
function showError(message) {
errorMessage.textContent = message;
errorMessage.style.display = 'block';
}
function hideError() {
errorMessage.style.display = 'none';
}
// 跳转到历史页面
function goToHistory() {
// 创建表单进行POST请求跳转,更安全
const form = document.createElement('form');
form.method = 'POST';
form.action = '/history';
document.body.appendChild(form);
form.submit();
}
// 添加显示函数
function displayCavityData(cavityData) {
const cavityDiv = document.getElementById('cavityData');
cavityDiv.innerHTML = `
<pre>${JSON.stringify(cavityData, null, 2)}</pre>
`;
}
function displayKeyInfo(keyInfo) {
const keyInfoDiv = document.getElementById('keyInfoData');
if (!keyInfo) {
keyInfoDiv.innerHTML = '<div class="data-item"><div class="data-value">无关键信息数据</div></div>';
return;
}
// 从正确的数据结构中提取数据
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 || {};
keyInfoDiv.innerHTML = `
<div class="data-item">
<div class="data-label">🔧 模具参数</div>
</div>
<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" style="margin-top: 15px;">
<div class="data-label">📐 几何特性</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" style="margin-top: 15px;">
<div class="data-label">⚙️ 制造要求</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.mold_hardness || 'N/A'}</div>
</div>
<div class="data-item">
<div class="data-label">表面光洁度</div>
<div class="data-value">${manufacturingInfo.surface_finish || '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>
`;
}