This commit is contained in:
cjw
2026-02-16 16:25:32 +08:00
parent 008f3f24f3
commit 49d6e0376a
5 changed files with 157 additions and 174 deletions
+133 -102
View File
@@ -117,14 +117,56 @@ async def upload_stp(
@router.get("/status/{task_id}") @router.get("/status/{task_id}")
@router.post("/status/{task_id}") @router.post("/status/{task_id}")
async def get_status(task_id: str): async def get_status(task_id: str, db_session: AsyncSession = Depends(get_db_session)):
"""获取任务状态""" """获取任务状态"""
if task_id not in tasks: # 先从内存查找
if task_id in tasks:
task = tasks[task_id]
logger.info(f"返回任务状态(内存): {task_id} - {task['status']}")
return task
# 内存中没有,从数据库查找
from sqlalchemy import select
from models.database import ProcessingTask, STPFile
result = await db_session.execute(
select(ProcessingTask, STPFile)
.join(STPFile, ProcessingTask.stp_file_id == STPFile.id)
.where(ProcessingTask.task_id == task_id)
)
task_record = result.first()
if not task_record:
raise HTTPException(404, "任务不存在") raise HTTPException(404, "任务不存在")
task = tasks[task_id] task, stp_file = task_record
logger.info(f"返回任务状态: {task_id} - {task['status']}") task_data = {
return task "task_id": task.task_id,
"filename": stp_file.original_filename if stp_file else "",
"file_size": stp_file.file_size if stp_file else 0,
"status": task.status,
"progress": task.progress,
"current_step": task.current_step,
"upload_time": task.created_time.isoformat() if task.created_time else "",
"completed_at": task.completed_time.isoformat() if task.completed_time else "",
"error": task.error_message if task.error_message else ""
}
# 尝试获取快照中的 key_info
from models.database import AnalysisResultSnapshot
snapshot_result = await db_session.execute(
select(AnalysisResultSnapshot)
.where(AnalysisResultSnapshot.stp_file_id == stp_file.id)
.order_by(AnalysisResultSnapshot.created_time.desc())
.limit(1)
)
snapshot = snapshot_result.scalar_one_or_none()
if snapshot and snapshot.key_info:
task_data["key_info"] = snapshot.key_info
logger.info(f"返回任务状态(数据库): {task_id} - {task['status']}")
return task_data
@router.get("/debug/tasks") @router.get("/debug/tasks")
@@ -316,121 +358,110 @@ async def result_page(request: Request, task_id: str, db_session: AsyncSession =
"""结果详情页面""" """结果详情页面"""
from sqlalchemy import select from sqlalchemy import select
from models.database import ProcessingTask, STPFile, GeometryData, MoldCavityData, HTMLFile, AnalysisResultSnapshot from models.database import ProcessingTask, STPFile, GeometryData, MoldCavityData, HTMLFile, AnalysisResultSnapshot
# 先尝试从分析结果快照获取数据(包含完整的 key_info) # 先查询任务记录
result = await db_session.execute( task_result = await db_session.execute(
select(AnalysisResultSnapshot, ProcessingTask, STPFile) select(ProcessingTask, STPFile)
.join(ProcessingTask, AnalysisResultSnapshot.stp_file_id == ProcessingTask.stp_file_id)
.join(STPFile, ProcessingTask.stp_file_id == STPFile.id) .join(STPFile, ProcessingTask.stp_file_id == STPFile.id)
.where(ProcessingTask.task_id == task_id) .where(ProcessingTask.task_id == task_id)
)
task_record = task_result.first()
if not task_record:
raise HTTPException(404, "任务不存在")
task, stp_file = task_record
# 构建任务详情数据
task_data = {
"task_id": task.task_id,
"filename": stp_file.original_filename if stp_file else "",
"file_size": stp_file.file_size if stp_file else 0,
"status": task.status,
"progress": task.progress,
"current_step": task.current_step,
"upload_time": task.created_time.isoformat() if task.created_time else "",
"completed_at": task.completed_time.isoformat() if task.completed_time else "",
"error": task.error_message if task.error_message else ""
}
# 尝试从分析结果快照获取数据
snapshot_result = await db_session.execute(
select(AnalysisResultSnapshot)
.where(AnalysisResultSnapshot.stp_file_id == stp_file.id)
.order_by(AnalysisResultSnapshot.created_time.desc()) .order_by(AnalysisResultSnapshot.created_time.desc())
.limit(1) .limit(1)
) )
snapshot = snapshot_result.scalar_one_or_none()
snapshot_record = result.first()
if snapshot:
# 构建任务详情数据
task_data = {}
if snapshot_record:
# 从快照获取完整数据
snapshot, task, stp_file = snapshot_record
task_data = {
"task_id": task.task_id,
"filename": stp_file.original_filename if stp_file else "",
"file_size": stp_file.file_size if stp_file else 0,
"status": task.status,
"progress": task.progress,
"current_step": task.current_step,
"upload_time": task.created_time.isoformat() if task.created_time else "",
"completed_at": task.completed_time.isoformat() if task.completed_time else "",
"error": task.error_message if task.error_message else ""
}
# 从快照获取完整的数据 # 从快照获取完整的数据
task_data["geometry_data"] = snapshot.geometry_data if snapshot.geometry_data else None task_data["geometry_data"] = snapshot.geometry_data if snapshot.geometry_data else None
task_data["key_info"] = snapshot.key_info if snapshot.key_info else None task_data["key_info"] = snapshot.key_info if snapshot.key_info else None
task_data["mold_cavity_data"] = snapshot.mold_cavity_data if snapshot.mold_cavity_data else None task_data["mold_cavity_data"] = snapshot.mold_cavity_data if snapshot.mold_cavity_data else None
logger.info(f"从快照加载任务数据: {task_id}") logger.info(f"从快照加载任务数据: {task_id}")
else: else:
# 如果没有快照,从各个表分别获取 # 如果没有快照,从各个表分别获取
result = await db_session.execute( result = await db_session.execute(
select(ProcessingTask, STPFile, GeometryData, MoldCavityData, HTMLFile) select(GeometryData, MoldCavityData, HTMLFile)
.join(STPFile, ProcessingTask.stp_file_id == STPFile.id) .outerjoin(MoldCavityData, GeometryData.stp_file_id == MoldCavityData.stp_file_id)
.outerjoin(GeometryData, STPFile.id == GeometryData.stp_file_id) .outerjoin(HTMLFile, GeometryData.stp_file_id == HTMLFile.stp_file_id)
.outerjoin(MoldCavityData, STPFile.id == MoldCavityData.stp_file_id) .where(GeometryData.stp_file_id == stp_file.id)
.outerjoin(HTMLFile, STPFile.id == HTMLFile.stp_file_id)
.where(ProcessingTask.task_id == task_id)
) )
task_record = result.first() other_data = result.first()
if not task_record: if other_data:
raise HTTPException(404, "任务不存在") geometry_data, mold_cavity_data, html_file = other_data
task, stp_file, geometry_data, mold_cavity_data, html_file = task_record # 如果有几何数据,添加到返回结果
if geometry_data:
task_data = { task_data["geometry_data"] = {
"task_id": task.task_id, "volume": geometry_data.volume,
"filename": stp_file.original_filename if stp_file else "", "surface_area": geometry_data.surface_area,
"file_size": stp_file.file_size if stp_file else 0, "bounding_box": {
"status": task.status, "min": geometry_data.bounding_box_min,
"progress": task.progress, "max": geometry_data.bounding_box_max,
"current_step": task.current_step, "dimensions": [
"upload_time": task.created_time.isoformat() if task.created_time else "", geometry_data.bounding_box_max[0] - geometry_data.bounding_box_min[0] if geometry_data.bounding_box_max and geometry_data.bounding_box_min else 0,
"completed_at": task.completed_time.isoformat() if task.completed_time else "", geometry_data.bounding_box_max[1] - geometry_data.bounding_box_min[1] if geometry_data.bounding_box_max and geometry_data.bounding_box_min else 0,
"error": task.error_message if task.error_message else "" geometry_data.bounding_box_max[2] - geometry_data.bounding_box_min[2] if geometry_data.bounding_box_max and geometry_data.bounding_box_min else 0
} ]
},
# 如果有几何数据,添加到返回结果 "topology": {
if geometry_data: "faces": geometry_data.topology_faces,
task_data["geometry_data"] = { "edges": geometry_data.topology_edges,
"volume": geometry_data.volume, "vertices": geometry_data.topology_vertices
"surface_area": geometry_data.surface_area, },
"bounding_box": { "center_of_mass": geometry_data.center_of_mass
"min": geometry_data.bounding_box_min, }
"max": geometry_data.bounding_box_max,
"dimensions": [ # 如果有模具型腔数据,添加到返回结果
geometry_data.bounding_box_max[0] - geometry_data.bounding_box_min[0] if geometry_data.bounding_box_max and geometry_data.bounding_box_min else 0, if mold_cavity_data:
geometry_data.bounding_box_max[1] - geometry_data.bounding_box_min[1] if geometry_data.bounding_box_max and geometry_data.bounding_box_min else 0, task_data["key_info"] = {
geometry_data.bounding_box_max[2] - geometry_data.bounding_box_min[2] if geometry_data.bounding_box_max and geometry_data.bounding_box_min else 0 "metadata": {
] "shrinkage_rate": mold_cavity_data.shrinkage_rate,
}, "draft_angle": mold_cavity_data.draft_angle
"topology": { },
"faces": geometry_data.topology_faces, "manufacturing_info": {
"edges": geometry_data.topology_edges, "mold_material": mold_cavity_data.mold_material,
"vertices": geometry_data.topology_vertices "estimated_clamping_force": mold_cavity_data.estimated_clamping_force,
}, "parting_line_length": mold_cavity_data.parting_line_length
"center_of_mass": geometry_data.center_of_mass },
} "mold_cavities": {
"cavity_key_info": {
# 如果有模具型腔数据,添加到返回结果 "geometric_characteristics": {
if mold_cavity_data: "product_weight": mold_cavity_data.product_weight,
task_data["key_info"] = { "product_volume": mold_cavity_data.product_volume,
"metadata": { "wall_thickness_range": mold_cavity_data.wall_thickness_range,
"shrinkage_rate": mold_cavity_data.shrinkage_rate, "complexity_score": mold_cavity_data.complexity_score
"draft_angle": mold_cavity_data.draft_angle }
},
"manufacturing_info": {
"mold_material": mold_cavity_data.mold_material,
"estimated_clamping_force": mold_cavity_data.estimated_clamping_force,
"parting_line_length": mold_cavity_data.parting_line_length
},
"mold_cavities": {
"cavity_key_info": {
"geometric_characteristics": {
"product_weight": mold_cavity_data.product_weight,
"product_volume": mold_cavity_data.product_volume,
"wall_thickness_range": mold_cavity_data.wall_thickness_range,
"complexity_score": mold_cavity_data.complexity_score
} }
} }
} }
}
logger.info(f"从各个表加载任务数据: {task_id}") logger.info(f"从各个表加载任务数据: {task_id}")
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
import os import os
# 简化路径配置,直接使用当前工作目录下的templates文件夹 # 简化路径配置,直接使用当前工作目录下的templates文件夹
+2 -24
View File
@@ -147,30 +147,8 @@ async function toggleFileRecords(filename) {
} }
async function viewRecordDetails(taskId) { async function viewRecordDetails(taskId) {
// 先检查任务状态,如果数据不完整,提示用户重新分析 // 直接跳转到结果页面,由后端从数据库加载完整数据
try { window.location.href = `/result/${taskId}`;
const response = await fetch(`/status/${taskId}`);
if (response.ok) {
const task = await response.json();
if (task.status === 'completed' && task.key_info) {
// 数据完整,跳转到结果页面
window.location.href = `/result/${taskId}`;
} else {
// 数据不完整,提示用户重新分析
if (confirm('该历史记录的分析数据不完整,是否重新分析?')) {
// 重新分析逻辑
await reanalyzeTask(taskId);
}
}
} else {
// 任务不存在或无法访问,跳转到结果页面尝试显示
window.location.href = `/result/${taskId}`;
}
} catch (error) {
console.error('检查任务状态失败:', error);
// 出错时直接跳转
window.location.href = `/result/${taskId}`;
}
} }
async function reanalyzeTask(taskId) { async function reanalyzeTask(taskId) {
+8 -3
View File
@@ -174,12 +174,18 @@ body {
} }
.key-info-categories { .key-info-categories {
display: grid; display: grid !important;
grid-template-columns: repeat(3, 1fr); grid-template-columns: repeat(3, 1fr) !important;
gap: 20px; gap: 20px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.data-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 10px;
}
.category-section { .category-section {
background: #f8f9fa; background: #f8f9fa;
border-radius: 10px; border-radius: 10px;
@@ -508,5 +514,4 @@ body {
.analysis-info { .analysis-info {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
}
} }
+11 -34
View File
@@ -5,7 +5,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分析结果 - STP文件几何分析工具</title> <title>分析结果 - STP文件几何分析工具</title>
<link rel="stylesheet" href="/static/style.css"> <link rel="stylesheet" href="/static/style.css?v=10">
<style> <style>
.result-container { .result-container {
max-width: 1200px; max-width: 1200px;
@@ -106,20 +106,12 @@
display: grid; display: grid;
gap: 10px; gap: 10px;
} }
.data-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f5f5f5;
}
.data-label { .data-label {
font-weight: bold; font-weight: bold;
color: #666; color: #666;
} }
.data-value { .data-value {
color: #333; color: #333;
text-align: right; text-align: right;
@@ -181,38 +173,23 @@
</div> </div>
<script> <script>
// 从URL获取任务ID // 从模板获取任务数据
const pathParts = window.location.pathname.split('/'); const task = {{ task | tojson | safe }};
const taskId = pathParts[pathParts.length - 1];
// 页面加载完成后显示任务数据
// 页面加载完成后获取任务数据
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
loadTaskData(taskId); if (task && task.task_id) {
});
async function loadTaskData(taskId) {
try {
const response = await fetch(`/status/${taskId}`);
if (!response.ok) {
throw new Error('获取任务数据失败');
}
const task = await response.json();
displayTaskInfo(task); displayTaskInfo(task);
displayResults(task); displayResults(task);
} else {
} catch (error) {
document.getElementById('taskInfo').innerHTML = ` document.getElementById('taskInfo').innerHTML = `
<div class="error-message"> <div class="error-message">
<h3>❌ 加载失败</h3> <h3>❌ 加载失败</h3>
<p>${error.message}</p> <p>无法获取任务数据</p>
<button class="upload-btn" onclick="loadTaskData('${taskId}')">
重试
</button>
</div> </div>
`; `;
} }
} });
function displayTaskInfo(task) { function displayTaskInfo(task) {
const taskInfo = document.getElementById('taskInfo'); const taskInfo = document.getElementById('taskInfo');
+3 -11
View File
@@ -5,7 +5,7 @@
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>分析结果快照 - STP文件几何分析工具</title> <title>分析结果快照 - STP文件几何分析工具</title>
<link rel="stylesheet" href="/static/style.css"> <link rel="stylesheet" href="/static/style.css?v=10">
<style> <style>
.snapshot-container { .snapshot-container {
max-width: 1200px; max-width: 1200px;
@@ -84,20 +84,12 @@
display: grid; display: grid;
gap: 10px; gap: 10px;
} }
.data-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f5f5f5;
}
.data-label { .data-label {
font-weight: bold; font-weight: bold;
color: #666; color: #666;
} }
.data-value { .data-value {
color: #333; color: #333;
text-align: right; text-align: right;