feat: 新增Revit和PDMS模型分析、优化与结果展示功能。
This commit is contained in:
parent
4762e2f39a
commit
db1ca7ba22
@ -1,11 +1,19 @@
|
||||
<template>
|
||||
<div class="geometry-complexity-result-page">
|
||||
<div class="page-header">
|
||||
<h2>
|
||||
<i class="fas fa-chart-line"></i>
|
||||
几何复杂度分析结果
|
||||
</h2>
|
||||
<p>Creo几何复杂度分析结果展示</p>
|
||||
<div class="header-title">
|
||||
<h2>
|
||||
<i class="fas fa-chart-line"></i>
|
||||
几何复杂度分析结果
|
||||
</h2>
|
||||
<p>Creo几何复杂度分析结果展示</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="export-report-btn" @click="exportReport" :disabled="isExporting">
|
||||
<i class="fas" :class="isExporting ? 'fa-spinner fa-spin' : 'fa-file-export'"></i>
|
||||
{{ isExporting ? '导出中...' : '导出报告' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
@ -166,6 +174,7 @@ const props = defineProps({
|
||||
const selectedParts = ref(new Set())
|
||||
const deletedParts = ref(new Set())
|
||||
const analysisTime = ref('')
|
||||
const isExporting = ref(false)
|
||||
|
||||
// 为零件添加稳定ID并过滤已删除的零件
|
||||
const partsData = computed(() => {
|
||||
@ -278,6 +287,228 @@ const deleteSelected = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const exportReport = () => {
|
||||
if (isExporting.value) return
|
||||
isExporting.value = true
|
||||
|
||||
try {
|
||||
const reportDate = analysisTimeFormatted.value || new Date().toLocaleString('zh-CN')
|
||||
let tableRows = ''
|
||||
|
||||
partsData.value.forEach(part => {
|
||||
const scoreClass = part.complexity_score >= 7.0 ? 'high' : (part.complexity_score >= 5.0 ? 'medium' : 'low')
|
||||
tableRows += `
|
||||
<tr>
|
||||
<td>${part.uniqueId}</td>
|
||||
<td>
|
||||
<strong>${part.part_name}</strong><br/>
|
||||
<span style="font-size:12px;color:#999;font-family:'Courier New', monospace;">${part.part_path || 'N/A'}</span>
|
||||
</td>
|
||||
<td>${part.surface_count}</td>
|
||||
<td>${part.feature_count}</td>
|
||||
<td>${part.curved_surface_count}</td>
|
||||
<td>${part.hole_count}</td>
|
||||
<td>${part.fillet_count}</td>
|
||||
<td class="score ${scoreClass}">${part.complexity_score.toFixed(2)}</td>
|
||||
<td>${formatVolume(part.volume)}</td>
|
||||
</tr>
|
||||
`
|
||||
})
|
||||
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>几何复杂度分析报告</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #4361ee;
|
||||
--success-color: #2ecc71;
|
||||
--warning-color: #f39c12;
|
||||
--danger-color: #e74c3c;
|
||||
--text-main: #2b2b2b;
|
||||
--text-light: #7f8c8d;
|
||||
--bg-color: #f8f9fa;
|
||||
--card-bg: #ffffff;
|
||||
--border-color: #e9ecef;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-main);
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: var(--card-bg);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #4361ee, #3a0ca3);
|
||||
color: white;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 32px;
|
||||
font-weight: 600;
|
||||
}
|
||||
.header p {
|
||||
margin: 0;
|
||||
opacity: 0.9;
|
||||
font-size: 16px;
|
||||
}
|
||||
.content {
|
||||
padding: 40px;
|
||||
}
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.summary-card {
|
||||
background: #f8f9fc;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
.summary-card:hover {
|
||||
transform: translateY(-5px);
|
||||
box-shadow: 0 8px 15px rgba(0,0,0,0.05);
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.summary-label {
|
||||
font-size: 15px;
|
||||
color: var(--text-light);
|
||||
font-weight: 500;
|
||||
}
|
||||
.section-title {
|
||||
font-size: 24px;
|
||||
color: var(--text-main);
|
||||
margin: 0 0 20px 0;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 2px solid var(--border-color);
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
th, td {
|
||||
padding: 16px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
th {
|
||||
background-color: #f1f3f5;
|
||||
color: #495057;
|
||||
font-weight: 600;
|
||||
font-size: 15px;
|
||||
}
|
||||
tr:hover {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
.score {
|
||||
font-weight: 700;
|
||||
}
|
||||
.score.high { color: var(--danger-color); }
|
||||
.score.medium { color: var(--warning-color); }
|
||||
.score.low { color: var(--success-color); }
|
||||
.footer {
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
color: var(--text-light);
|
||||
font-size: 14px;
|
||||
border-top: 1px solid var(--border-color);
|
||||
background: var(--card-bg);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>几何复杂度分析报告</h1>
|
||||
<p>生成时间: ${reportDate}</p>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${totalPartsAnalyzed.value}</div>
|
||||
<div class="summary-label">总零件数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${averageComplexity.value}</div>
|
||||
<div class="summary-label">平均复杂度</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${highComplexityCount.value}</div>
|
||||
<div class="summary-label">高复杂度零件</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2 class="section-title">零件详细分析数据</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="50">ID</th>
|
||||
<th width="250">零件信息</th>
|
||||
<th>表面数</th>
|
||||
<th>特征数</th>
|
||||
<th>曲面数</th>
|
||||
<th>孔数</th>
|
||||
<th>圆角数</th>
|
||||
<th>复杂度得分</th>
|
||||
<th>体积 (mm³)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
${tableRows}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
报告由系统自动生成 - 几何复杂度分析工具
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `几何复杂度分析报告_${new Date().getTime()}.html`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
ElMessageBox.success('报告导出成功')
|
||||
} catch (error) {
|
||||
console.error('导出报告失败', error)
|
||||
ElMessageBox.error('导出报告失败,请重试')
|
||||
} finally {
|
||||
isExporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
analysisTime.value = new Date().toLocaleString('zh-CN')
|
||||
@ -293,9 +524,12 @@ onMounted(() => {
|
||||
|
||||
.page-header {
|
||||
margin-bottom: var(--spacing-2xl);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.page-header h2 {
|
||||
.header-title h2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-md);
|
||||
@ -305,15 +539,44 @@ onMounted(() => {
|
||||
margin: 0 0 var(--spacing-sm) 0;
|
||||
}
|
||||
|
||||
.page-header h2 i {
|
||||
.header-title h2 i {
|
||||
color: var(--color-complexity);
|
||||
}
|
||||
|
||||
.page-header p {
|
||||
.header-title p {
|
||||
color: var(--color-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.export-report-btn {
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 12px rgba(67, 97, 238, 0.2);
|
||||
}
|
||||
|
||||
.export-report-btn:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(67, 97, 238, 0.3);
|
||||
background: #3651d4;
|
||||
}
|
||||
|
||||
.export-report-btn:disabled {
|
||||
background: #aab8f8;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@ -32,8 +32,8 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="hierarchy-actions">
|
||||
<button class="action-btn primary" @click="exportResults">
|
||||
<i class="fas fa-download"></i> 导出结果
|
||||
<button class="export-report-btn action-btn primary" @click="exportReport" :disabled="isExporting">
|
||||
<i class="fas" :class="isExporting ? 'fa-spinner fa-spin' : 'fa-file-export'"></i> {{ isExporting ? '导出中...' : '导出报告' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -212,6 +212,7 @@ const emit = defineEmits(['show-hierarchy-deletion-params', 'show-geometry-optim
|
||||
const currentView = ref('tree')
|
||||
const selectedComponents = ref(new Set())
|
||||
const hierarchyData = ref([]) // 直接存储所有组件数据
|
||||
const isExporting = ref(false)
|
||||
|
||||
// 直接使用API数据,照抄ShellAnalysisResult的方式
|
||||
const analysisResults = computed(() => {
|
||||
@ -380,20 +381,165 @@ const openGeometricOptimization = () => {
|
||||
}
|
||||
|
||||
|
||||
const exportResults = () => {
|
||||
const data = {
|
||||
analysisData: analysisResults.value,
|
||||
hierarchyData: hierarchyData.value,
|
||||
exportTime: new Date().toISOString()
|
||||
}
|
||||
const exportReport = () => {
|
||||
if (isExporting.value) return
|
||||
isExporting.value = true
|
||||
|
||||
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `hierarchy-analysis-${new Date().toISOString().slice(0, 10)}.json`
|
||||
a.click()
|
||||
URL.revokeObjectURL(url)
|
||||
try {
|
||||
const reportDate = new Date().toLocaleString('zh-CN')
|
||||
let tableRows = ''
|
||||
|
||||
hierarchyData.value.forEach((part, index) => {
|
||||
const safetyLabel = getSafetyLabel(part.deletion_safety)
|
||||
let scoreClass = 'low'
|
||||
if (part.deletion_safety === 'risky') scoreClass = 'medium'
|
||||
if (part.deletion_safety === 'forbidden') scoreClass = 'high'
|
||||
|
||||
tableRows += `
|
||||
<tr>
|
||||
<td>${index + 1}</td>
|
||||
<td>
|
||||
<strong>${part.filename}</strong><br/>
|
||||
<span style="font-size:12px;color:#999;font-family:'Courier New', monospace;">${part.path || 'N/A'}</span>
|
||||
</td>
|
||||
<td>${part.type}</td>
|
||||
<td>${part.level}</td>
|
||||
<td class="score ${scoreClass}">${safetyLabel}</td>
|
||||
</tr>
|
||||
`
|
||||
})
|
||||
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>层级分析结果报告</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #4361ee;
|
||||
--success-color: #2ecc71;
|
||||
--warning-color: #f39c12;
|
||||
--danger-color: #e74c3c;
|
||||
--text-main: #2b2b2b;
|
||||
--text-light: #7f8c8d;
|
||||
--bg-color: #f8f9fa;
|
||||
--card-bg: #ffffff;
|
||||
--border-color: #e9ecef;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-main);
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
background: var(--card-bg);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #4361ee, #3a0ca3);
|
||||
color: white;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 32px;
|
||||
}
|
||||
.content { padding: 40px; }
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.summary-card {
|
||||
background: #f8f9fc;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
th, td {
|
||||
padding: 16px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
th { background-color: #f1f3f5; }
|
||||
.score.high { color: var(--danger-color); font-weight: bold;}
|
||||
.score.medium { color: var(--warning-color); font-weight: bold;}
|
||||
.score.low { color: var(--success-color); font-weight: bold;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>层级分析结果报告</h1>
|
||||
<p>生成时间: ${reportDate}</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${(analysisResults.value?.total_components || 0) - 1}</div>
|
||||
<div class="summary-label">总组件数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${analysisResults.value?.total_levels || 0}</div>
|
||||
<div class="summary-label">层级数</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>层级组件详细数据</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>序号</th>
|
||||
<th>组件名称</th>
|
||||
<th>类型</th>
|
||||
<th>层级</th>
|
||||
<th>删除安全性</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>${tableRows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `层级分析结果报告_${new Date().getTime()}.html`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
ElMessageBox.success('报告导出成功')
|
||||
} catch (error) {
|
||||
console.error('导出报告失败', error)
|
||||
ElMessageBox.error('导出报告失败,请重试')
|
||||
} finally {
|
||||
isExporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const continueToDeleteConfig = () => {
|
||||
|
||||
@ -52,7 +52,6 @@
|
||||
<span>缩小体积</span>
|
||||
<span>定制类型保留</span>
|
||||
</div>
|
||||
<div class="status-badge" style="background: var(--color-success)">新功能</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="header-text">
|
||||
<h2>PDMS 导出工具</h2>
|
||||
<p>将当前PDMS模型导出为中性格式文件或指定格式</p>
|
||||
<p>将当前PDMS模型导出为 RVM 格式文件</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -48,21 +48,21 @@
|
||||
<div class="option-group">
|
||||
<label for="export-format">导出格式</label>
|
||||
<select id="export-format" v-model="exportForm.format" disabled>
|
||||
<option value="IFC">IFC 模型格式</option>
|
||||
<option value="RVM">模型导出(RVM)</option>
|
||||
</select>
|
||||
<small class="form-hint">系统当前支持直接导出标准 IFC 模型</small>
|
||||
<small class="form-hint">系统当前支持直接导出标准 RVM 模型</small>
|
||||
</div>
|
||||
|
||||
<div class="option-group">
|
||||
<label for="export-dir">输出目录 (选填)</label>
|
||||
<label for="export-dir">输出目录 (必填)</label>
|
||||
<input
|
||||
type="text"
|
||||
id="export-dir"
|
||||
v-model="exportForm.exportPath"
|
||||
placeholder="例如: C:\temp"
|
||||
placeholder="例如: D:\"
|
||||
class="form-input"
|
||||
>
|
||||
<small class="form-hint">指定服务端导出的文件夹路径。留空则使用默认路径</small>
|
||||
<small class="form-hint">指定服务端导出的文件夹路径。强烈建议使用绝对路径(例如 D:\)</small>
|
||||
</div>
|
||||
|
||||
<div class="option-group">
|
||||
@ -71,17 +71,49 @@
|
||||
type="text"
|
||||
id="file-name"
|
||||
v-model="exportForm.fileName"
|
||||
placeholder="例如: test_export.ifc"
|
||||
placeholder="例如: model.rvm"
|
||||
class="form-input"
|
||||
>
|
||||
<small class="form-hint">指定导出的文件名称(需带.ifc后缀)。留空则自动生成时间戳命名文件</small>
|
||||
<small class="form-hint">指定导出的文件名称(需带.rvm后缀)。留空则自动生成按时间戳命名文件</small>
|
||||
</div>
|
||||
|
||||
<div class="option-group checkbox-group">
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" v-model="exportForm.overwrite">
|
||||
覆盖现有文件
|
||||
</label>
|
||||
<small class="form-hint">勾选则自动覆盖同名文件(带 OVERWRITE 选项),否则按 READ 策略处理</small>
|
||||
</div>
|
||||
|
||||
<div class="option-group">
|
||||
<label for="selections">导出对象选择命令</label>
|
||||
<input
|
||||
type="text"
|
||||
id="selections"
|
||||
v-model="exportForm.selections"
|
||||
placeholder="/EQUIP, /PIPES"
|
||||
class="form-input"
|
||||
>
|
||||
<small class="form-hint">支持多个命令,用逗号分隔(不含 EXPORT 前缀也行)</small>
|
||||
</div>
|
||||
|
||||
<div class="option-group">
|
||||
<label for="export-system">导出驱动 (高级选项)</label>
|
||||
<input
|
||||
type="text"
|
||||
id="export-system"
|
||||
v-model="exportForm.exportSystem"
|
||||
placeholder="不建议填写"
|
||||
class="form-input"
|
||||
>
|
||||
<small class="form-hint" style="color:#e74c3c;">仅在明确需要特定系统驱动时传参,随意指定容易触发许可证错误!</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card-actions">
|
||||
<button class="btn btn-export btn-lg btn-full" :disabled="!canExport" @click="startExport">
|
||||
<i class="fas fa-download"></i>
|
||||
开始导出 {{ exportForm.format }}
|
||||
开始 {{ exportForm.format }} 模型导出
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -96,33 +128,44 @@ import { ElMessage } from 'element-plus'
|
||||
|
||||
// 导出表单数据
|
||||
const exportForm = reactive({
|
||||
format: 'IFC',
|
||||
exportPath: '',
|
||||
fileName: ''
|
||||
format: 'RVM',
|
||||
exportPath: 'D:\\',
|
||||
fileName: '',
|
||||
exportSystem: '',
|
||||
overwrite: true,
|
||||
selections: '/EQUIP, /PIPES'
|
||||
})
|
||||
|
||||
// 计算属性:是否可以开始导出
|
||||
const canExport = computed(() => {
|
||||
return true // 所有参数可选填,后端有默认值
|
||||
return !!exportForm.exportPath.trim() // 输出目录是必填项
|
||||
})
|
||||
|
||||
// 开始导出
|
||||
const startExport = async () => {
|
||||
try {
|
||||
if (pdmsApi.exportIfc) {
|
||||
const params = {}
|
||||
const params = {
|
||||
Overwrite: exportForm.overwrite
|
||||
}
|
||||
if (exportForm.exportPath && exportForm.exportPath.trim()) {
|
||||
params.ExportPath = exportForm.exportPath.trim()
|
||||
}
|
||||
if (exportForm.fileName && exportForm.fileName.trim()) {
|
||||
params.FileName = exportForm.fileName.trim()
|
||||
}
|
||||
if (exportForm.exportSystem && exportForm.exportSystem.trim()) {
|
||||
params.ExportSystem = exportForm.exportSystem.trim()
|
||||
}
|
||||
if (exportForm.selections && exportForm.selections.trim()) {
|
||||
params.Selections = exportForm.selections.split(',').map(s => s.trim()).filter(s => s)
|
||||
}
|
||||
|
||||
ElMessage.info(`正在请求 IFC 模型导出,请稍候...`)
|
||||
ElMessage.info(`正在请求 RVM 模型导出,请稍候...`)
|
||||
const response = await pdmsApi.exportIfc(params)
|
||||
|
||||
if (response && response.data && response.data.Success) {
|
||||
ElMessage.success(`导出成功!文件耗时 ${response.data.DurationSeconds}s,保存至: ${response.data.FullPath}`)
|
||||
ElMessage.success(`RVM导出成功!文件耗时 ${response.data.DurationSeconds}s,保存至: ${response.data.FullPath}`)
|
||||
} else {
|
||||
ElMessage.success(`已触发导出流程`)
|
||||
}
|
||||
@ -131,9 +174,9 @@ const startExport = async () => {
|
||||
}
|
||||
} catch(e) {
|
||||
if (e.response && e.response.data && e.response.data.message) {
|
||||
ElMessage.error(`导出失败: ${e.response.data.message}`)
|
||||
ElMessage.error(`模型导出失败: ${e.response.data.message}`)
|
||||
} else {
|
||||
ElMessage.error(`导出请求失败: ${e.message || '未知错误'}`)
|
||||
ElMessage.error(`模型导出请求失败: ${e.message || '未知错误'}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -329,6 +372,12 @@ const startExport = async () => {
|
||||
border-color: #e67e22;
|
||||
}
|
||||
|
||||
.option-group.checkbox-group label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.option-group input[type="checkbox"] {
|
||||
margin-right: var(--spacing-sm);
|
||||
accent-color: #e67e22;
|
||||
|
||||
@ -153,6 +153,9 @@
|
||||
</div>
|
||||
|
||||
<div class="result-actions">
|
||||
<button class="primary-btn export-report-btn" @click="exportReport" :disabled="isExporting" style="background: linear-gradient(135deg, #10b981 0%, #059669 100%);">
|
||||
<i class="fas" :class="isExporting ? 'fa-spinner fa-spin' : 'fa-file-export'"></i> {{ isExporting ? '导出中...' : '导出报告' }}
|
||||
</button>
|
||||
<button class="primary-btn" @click="resetTask">
|
||||
<i class="fas fa-redo"></i> 再次处理
|
||||
</button>
|
||||
@ -177,6 +180,7 @@ const taskStatus = ref('idle')
|
||||
const isStarting = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const taskResult = ref(null)
|
||||
const isExporting = ref(false)
|
||||
|
||||
const zoneFiltersInput = ref("")
|
||||
|
||||
@ -260,6 +264,166 @@ const startTask = async () => {
|
||||
}
|
||||
}
|
||||
|
||||
const exportReport = () => {
|
||||
if (isExporting.value || !taskResult.value) return
|
||||
isExporting.value = true
|
||||
|
||||
try {
|
||||
const reportDate = new Date().toLocaleString('zh-CN')
|
||||
|
||||
let zoneSummariesHTML = ''
|
||||
if (taskResult.value.ZoneSummaries && Object.keys(taskResult.value.ZoneSummaries).length > 0) {
|
||||
zoneSummariesHTML = `
|
||||
<h3 style="margin-top:20px;">Zone 处理汇总</h3>
|
||||
<ul>
|
||||
${Object.entries(taskResult.value.ZoneSummaries).map(([zone, count]) => `<li><span style="color:#10b981">${zone}</span> : ${count} 个移除</li>`).join('')}
|
||||
</ul>
|
||||
`
|
||||
}
|
||||
|
||||
let errorHTML = ''
|
||||
if (taskResult.value.Errors && taskResult.value.Errors.length > 0) {
|
||||
errorHTML = `
|
||||
<h3 style="margin-top:20px; color:#e74c3c">处理警告与错误</h3>
|
||||
<ul style="color:#e74c3c">
|
||||
${taskResult.value.Errors.map(e => `<li>${e}</li>`).join('')}
|
||||
</ul>
|
||||
`
|
||||
}
|
||||
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PDMS模型轻量化处理报告</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #10b981;
|
||||
--success-color: #2ecc71;
|
||||
--warning-color: #f39c12;
|
||||
--danger-color: #e74c3c;
|
||||
--text-main: #2b2b2b;
|
||||
--text-light: #7f8c8d;
|
||||
--bg-color: #f8f9fa;
|
||||
--card-bg: #ffffff;
|
||||
--border-color: #e9ecef;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-main);
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
background: var(--card-bg);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #10b981, #059669);
|
||||
color: white;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 32px;
|
||||
}
|
||||
.content { padding: 40px; }
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.summary-card {
|
||||
background: #f8f9fc;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.details-box {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>PDMS模型轻量化处理报告</h1>
|
||||
<p>生成时间: ${reportDate}</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color:var(--danger-color)">${taskResult.value.RemovedCount || 0}</div>
|
||||
<div class="summary-label">移除内部构件数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color:var(--success-color)">${taskResult.value.KeptCount || 0}</div>
|
||||
<div class="summary-label">保留构件数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${taskResult.value.TotalVisited || 0}</div>
|
||||
<div class="summary-label">扫描总数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color:var(--primary-color)">${taskResult.value.ShellKeptCount ?? 'N/A'}</div>
|
||||
<div class="summary-label">壳体保留数</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details-box">
|
||||
<h3>处理信息概要</h3>
|
||||
<p><strong>状态:</strong> ${taskResult.value.DryRun ? '模拟模式 (未真实删除)' : '正式执行'}</p>
|
||||
<p><strong>执行时间:</strong> ${formatTime(taskResult.value.StartedAt)} - ${formatTime(taskResult.value.CompletedAt)}</p>
|
||||
<p><strong>系统消息:</strong> ${taskResult.value.Message || '处理完毕'}</p>
|
||||
${zoneSummariesHTML}
|
||||
${errorHTML}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `PDMS模型轻量化处理报告_${new Date().getTime()}.html`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
ElNotification({
|
||||
title: '导出成功',
|
||||
message: '已成功导出分析报告',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('导出报告失败', error)
|
||||
} finally {
|
||||
isExporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
@ -63,7 +63,11 @@
|
||||
</div>
|
||||
|
||||
<div class="setting-group toggle-group">
|
||||
<label>安全设置</label>
|
||||
<label>高级设置</label>
|
||||
<div class="toggle-control" style="margin-bottom: 12px;">
|
||||
<span>跳过已连接元素 (Skip Linked)?可大幅减少警告</span>
|
||||
<el-switch v-model="formData.skipLinkedElements" active-color="#3b82f6" inactive-color="#ff4949"></el-switch>
|
||||
</div>
|
||||
<div class="toggle-control">
|
||||
<span>开启模拟模式 (Dry Run)?仅模拟不真删</span>
|
||||
<el-switch v-model="formData.dryRun" active-color="#3b82f6" inactive-color="#ff4949"></el-switch>
|
||||
@ -126,11 +130,20 @@
|
||||
<div class="metric-label">扫描构件总数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-card" v-if="taskResult.SkippedLinkedCount !== undefined">
|
||||
<div class="metric-icon"><i class="fas fa-link"></i></div>
|
||||
<div class="metric-info">
|
||||
<div class="metric-value">{{ taskResult.SkippedLinkedCount || 0 }}</div>
|
||||
<div class="metric-label">跳过连接构件数</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details-box">
|
||||
<h4>处理信息</h4>
|
||||
<p v-if="taskResult.Message">{{ taskResult.Message }}</p>
|
||||
<p v-if="taskResult.Message" :class="{ 'error-text': taskResult.Errors && taskResult.Errors.length > 0 }">
|
||||
{{ taskResult.Errors && taskResult.Errors.length > 0 ? '部分成功/有告警: ' : '' }}{{ taskResult.Message }}
|
||||
</p>
|
||||
<p v-if="taskResult.StartedAt && taskResult.CompletedAt">
|
||||
执行时间: {{ formatTime(taskResult.StartedAt) }} - {{ formatTime(taskResult.CompletedAt) }}
|
||||
</p>
|
||||
@ -156,6 +169,17 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Skipped Linked Elements Summary -->
|
||||
<div v-if="taskResult.SkippedLinkedElements && taskResult.SkippedLinkedElements.length > 0">
|
||||
<h5 style="margin-top:20px; color: var(--color-text-primary);">跳过连接元件示例</h5>
|
||||
<ul>
|
||||
<li v-for="(el, idx) in taskResult.SkippedLinkedElements.slice(0, 5)" :key="'s-'+idx">
|
||||
{{ el }}
|
||||
</li>
|
||||
<li v-if="taskResult.SkippedLinkedElements.length > 5">...以及其他 {{ taskResult.SkippedLinkedElements.length - 5 }} 个元件</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- Errors -->
|
||||
<div v-if="taskResult.Errors && taskResult.Errors.length > 0" class="error-message" style="margin-top:20px;">
|
||||
<p><i class="fas fa-exclamation-triangle"></i> 部分处理出错:</p>
|
||||
@ -167,6 +191,9 @@
|
||||
</div>
|
||||
|
||||
<div class="result-actions">
|
||||
<button class="primary-btn export-report-btn" @click="exportReport" :disabled="isExporting" style="background: linear-gradient(135deg, #10b981 0%, #059669 100%);">
|
||||
<i class="fas" :class="isExporting ? 'fa-spinner fa-spin' : 'fa-file-export'"></i> {{ isExporting ? '导出中...' : '导出报告' }}
|
||||
</button>
|
||||
<button class="primary-btn" @click="resetTask">
|
||||
<i class="fas fa-redo"></i> 再次处理
|
||||
</button>
|
||||
@ -190,12 +217,14 @@ const taskStatus = ref('idle')
|
||||
const isStarting = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const taskResult = ref(null)
|
||||
const isExporting = ref(false)
|
||||
|
||||
const zoneFiltersInput = ref("")
|
||||
|
||||
// 默认配置
|
||||
const DEFAULT_SIMPLIFY_CONFIG = {
|
||||
DRY_RUN: true,
|
||||
DRY_RUN: false,
|
||||
SKIP_LINKED: true,
|
||||
KEEP_TYPES: ["SITE", "ZONE", "STRU", "FRAME", "SHELL", "PLAT", "WALL"],
|
||||
REMOVE_TYPES: ["PIPE", "BRAN", "ELBO", "VALV", "FITT", "NOZZ", "EQUI"],
|
||||
PADDING: 0.0
|
||||
@ -204,6 +233,7 @@ const DEFAULT_SIMPLIFY_CONFIG = {
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
dryRun: DEFAULT_SIMPLIFY_CONFIG.DRY_RUN,
|
||||
skipLinkedElements: DEFAULT_SIMPLIFY_CONFIG.SKIP_LINKED,
|
||||
keepTypes: [...DEFAULT_SIMPLIFY_CONFIG.KEEP_TYPES],
|
||||
removeTypes: [...DEFAULT_SIMPLIFY_CONFIG.REMOVE_TYPES],
|
||||
padding: DEFAULT_SIMPLIFY_CONFIG.PADDING
|
||||
@ -231,19 +261,20 @@ const startTask = async () => {
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
DryRun: formData.dryRun,
|
||||
ZoneFilters: zoneFiltersInput.value ? zoneFiltersInput.value.split(',').map(s => s.trim()).filter(s => s) : [],
|
||||
KeepTypes: formData.keepTypes,
|
||||
RemoveTypes: formData.removeTypes,
|
||||
BoundingShell: {
|
||||
Padding: formData.padding
|
||||
dryRun: formData.dryRun,
|
||||
skipLinkedElements: formData.skipLinkedElements,
|
||||
zoneFilters: zoneFiltersInput.value ? zoneFiltersInput.value.split(',').map(s => s.trim()).filter(s => s) : [],
|
||||
keepTypes: formData.keepTypes,
|
||||
removeTypes: formData.removeTypes,
|
||||
boundingShell: {
|
||||
padding: formData.padding
|
||||
}
|
||||
}
|
||||
|
||||
const res = await pdmsApi.executeSimplify(payload)
|
||||
if (res.success && res.data && res.data.code === 0) {
|
||||
if (res && res.data && res.data.code === 0) {
|
||||
taskStatus.value = 'Completed'
|
||||
taskResult.value = res.data.data
|
||||
taskResult.value = res.data.data || res.data
|
||||
ElNotification({
|
||||
title: '处理完成',
|
||||
message: 'PDMS模型简化处理执行完毕。',
|
||||
@ -251,7 +282,7 @@ const startTask = async () => {
|
||||
})
|
||||
} else {
|
||||
taskStatus.value = 'failed'
|
||||
errorMessage.value = (res.data && res.data.message) || res.error || '执行简化失败,返回数据异常。'
|
||||
errorMessage.value = (res.data && res.data.message) || (res && res.message) || '模型轻量化失败,返回数据异常。'
|
||||
ElNotification({
|
||||
title: '处理失败',
|
||||
message: errorMessage.value,
|
||||
@ -260,7 +291,7 @@ const startTask = async () => {
|
||||
}
|
||||
} catch (err) {
|
||||
taskStatus.value = 'failed'
|
||||
errorMessage.value = err.message || '网络请求错误'
|
||||
errorMessage.value = err.response?.data?.message || err.message || '网络请求错误'
|
||||
ElNotification({
|
||||
title: '处理失败',
|
||||
message: errorMessage.value,
|
||||
@ -270,6 +301,166 @@ const startTask = async () => {
|
||||
isStarting.value = false
|
||||
}
|
||||
}
|
||||
const exportReport = () => {
|
||||
if (isExporting.value || !taskResult.value) return
|
||||
isExporting.value = true
|
||||
|
||||
try {
|
||||
const reportDate = new Date().toLocaleString('zh-CN')
|
||||
|
||||
let zoneSummariesHTML = ''
|
||||
if (taskResult.value.ZoneSummaries && taskResult.value.ZoneSummaries.length > 0) {
|
||||
zoneSummariesHTML = `
|
||||
<h3 style="margin-top:20px;">Zone 处理汇总</h3>
|
||||
<ul>
|
||||
${taskResult.value.ZoneSummaries.map(s => `<li>${s}</li>`).join('')}
|
||||
</ul>
|
||||
`
|
||||
}
|
||||
|
||||
let errorHTML = ''
|
||||
if (taskResult.value.Errors && taskResult.value.Errors.length > 0) {
|
||||
errorHTML = `
|
||||
<h3 style="margin-top:20px; color:#e74c3c">处理警告与错误</h3>
|
||||
<ul style="color:#e74c3c">
|
||||
${taskResult.value.Errors.map(e => `<li>${e}</li>`).join('')}
|
||||
</ul>
|
||||
`
|
||||
}
|
||||
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>PDMS模型简化处理报告</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #3b82f6;
|
||||
--success-color: #2ecc71;
|
||||
--warning-color: #f39c12;
|
||||
--danger-color: #e74c3c;
|
||||
--text-main: #2b2b2b;
|
||||
--text-light: #7f8c8d;
|
||||
--bg-color: #f8f9fa;
|
||||
--card-bg: #ffffff;
|
||||
--border-color: #e9ecef;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-main);
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
background: var(--card-bg);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #3b82f6, #1d4ed8);
|
||||
color: white;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 32px;
|
||||
}
|
||||
.content { padding: 40px; }
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.summary-card {
|
||||
background: #f8f9fc;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
.details-box {
|
||||
background: #f8f9fa;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>PDMS模型简化处理报告</h1>
|
||||
<p>生成时间: ${reportDate}</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color:var(--danger-color)">${taskResult.value.RemovedCount || 0}</div>
|
||||
<div class="summary-label">移除构件数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color:var(--success-color)">${taskResult.value.KeptCount || 0}</div>
|
||||
<div class="summary-label">保留构件数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${taskResult.value.TotalVisited || 0}</div>
|
||||
<div class="summary-label">扫描总数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color:var(--warning-color)">${taskResult.value.SkippedLinkedCount || 0}</div>
|
||||
<div class="summary-label">跳过连接构件</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="details-box">
|
||||
<h3>处理信息概要</h3>
|
||||
<p><strong>状态:</strong> ${taskResult.value.DryRun ? '模拟模式 (未真实删除)' : '正式执行'}</p>
|
||||
<p><strong>执行时间:</strong> ${formatTime(taskResult.value.StartedAt)} - ${formatTime(taskResult.value.CompletedAt)}</p>
|
||||
<p><strong>系统消息:</strong> ${taskResult.value.Message || '处理完毕'}</p>
|
||||
${zoneSummariesHTML}
|
||||
${errorHTML}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `PDMS模型简化处理报告_${new Date().getTime()}.html`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
ElNotification({
|
||||
title: '导出成功',
|
||||
message: '已成功导出分析报告',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('导出报告失败', error)
|
||||
} finally {
|
||||
isExporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -455,6 +646,11 @@ const startTask = async () => {
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.error-text {
|
||||
color: #ff4949;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.execution-panel {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
|
||||
@ -74,7 +74,6 @@
|
||||
<span>建筑专用</span>
|
||||
<span>模型减重</span>
|
||||
</div>
|
||||
<div class="status-badge" style="background: var(--color-success)">新功能</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -106,7 +105,7 @@
|
||||
</div>
|
||||
|
||||
<!-- 分析结果 -->
|
||||
<div v-if="analysisResults" class="revit-analysis-results">
|
||||
<div v-if="analysisResults && !optimizationResult" class="revit-analysis-results">
|
||||
<h3>
|
||||
<i class="fas fa-chart-line"></i>
|
||||
Revit分析结果
|
||||
@ -212,6 +211,16 @@
|
||||
</div>
|
||||
|
||||
<div class="revit-analysis-actions">
|
||||
<button
|
||||
class="export-report-btn revit-analysis-btn primary"
|
||||
@click="exportReport"
|
||||
:disabled="isExporting"
|
||||
style="margin-right: auto;"
|
||||
>
|
||||
<i class="fas" :class="isExporting ? 'fa-spinner fa-spin' : 'fa-file-export'"></i>
|
||||
{{ isExporting ? '导出中...' : '导出报告' }}
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="revit-analysis-btn primary"
|
||||
@click="applyOptimization"
|
||||
@ -227,6 +236,76 @@
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 优化结果 -->
|
||||
<div v-if="optimizationResult" class="revit-analysis-results">
|
||||
<h3>
|
||||
<i class="fas fa-flag-checkered"></i>
|
||||
优化执行完成
|
||||
</h3>
|
||||
|
||||
<div class="revit-results-overview">
|
||||
<div class="revit-result-metric success">
|
||||
<div class="metric-icon">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<div class="metric-value">{{ optimizationResult.removedCount || 0 }}</div>
|
||||
<div class="metric-label">删减构件总数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="revit-result-metric highlight">
|
||||
<div class="metric-icon">
|
||||
<i class="fas fa-hdd"></i>
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<div class="metric-value">{{ optimizationResult.originalSize || '未知' }}</div>
|
||||
<div class="metric-label">原始文件大小</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="revit-result-metric success">
|
||||
<div class="metric-icon">
|
||||
<i class="fas fa-compress-arrows-alt"></i>
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<div class="metric-value">{{ optimizationResult.optimizedSize || '未知' }}</div>
|
||||
<div class="metric-label">优化后大小</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="revit-result-metric primary">
|
||||
<div class="metric-icon">
|
||||
<i class="fas fa-percentage"></i>
|
||||
</div>
|
||||
<div class="metric-content">
|
||||
<div class="metric-value">{{ optimizationResult.reduction || '0%' }}</div>
|
||||
<div class="metric-label">体积缩减率</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="optimization-details" style="margin-top: 24px; padding: 20px; background: linear-gradient(135deg, var(--color-bg-secondary) 0%, var(--color-white-rgb-05) 100%); border-radius: 12px; border: 1px solid var(--color-border-primary);">
|
||||
<h4 style="margin-top: 0; color: var(--color-text-primary); margin-bottom: 16px; display: flex; align-items: center; gap: 8px;">
|
||||
<i class="fas fa-info-circle" style="color: var(--color-primary);"></i> 执行日志与备份信息
|
||||
</h4>
|
||||
<div style="color: var(--color-text-secondary); font-size: 0.95em; line-height: 1.8;">
|
||||
<div style="display: flex; gap: 10px; margin-bottom: 8px;">
|
||||
<span style="font-weight: 600; min-width: 80px;">原文件备份:</span>
|
||||
<span style="word-break: break-all; opacity: 0.9;">{{ optimizationResult.backupPath || '无备份信息' }}</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<span style="font-weight: 600; min-width: 80px;">处理耗时:</span>
|
||||
<span style="opacity: 0.9;">{{ optimizationResult.processingTimeSeconds || 0 }} 秒</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="revit-analysis-actions" style="margin-top: 32px;">
|
||||
<button class="revit-analysis-btn primary" @click="resetAnalysis">
|
||||
<i class="fas fa-home"></i> 返回分析中心
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -254,6 +333,8 @@ const progressText = ref('初始化分析引擎...')
|
||||
const analysisResults = ref(null)
|
||||
const selectedCategories = ref([])
|
||||
const isApplyingOptimization = ref(false)
|
||||
const isExporting = ref(false)
|
||||
const optimizationResult = ref(null)
|
||||
|
||||
// 计算属性
|
||||
const hasModel = computed(() => {
|
||||
@ -354,6 +435,7 @@ const startAnalysis = async () => {
|
||||
const resetAnalysis = () => {
|
||||
isAnalyzing.value = false
|
||||
analysisResults.value = null
|
||||
optimizationResult.value = null
|
||||
selectedStrategy.value = 'intelligent'
|
||||
currentProgress.value = 0
|
||||
progressText.value = '初始化分析引擎...'
|
||||
@ -400,7 +482,7 @@ const applyOptimization = async () => {
|
||||
try {
|
||||
const result = await revitApi.executeCustomDelete(selectedCategoryIds, true)
|
||||
|
||||
if (result.success) {
|
||||
if (result.success || result.code === 200) {
|
||||
ElNotification({
|
||||
title: '应用优化成功',
|
||||
message: `已成功删除 ${selectedCategories.value.length} 个类别的构件`,
|
||||
@ -408,8 +490,13 @@ const applyOptimization = async () => {
|
||||
position: 'top-right',
|
||||
duration: 3000
|
||||
})
|
||||
|
||||
// 更新优化结果UI数据 (解析后端返回结构 result.data.data)
|
||||
optimizationResult.value = result.data?.data || result.data || result
|
||||
// 清空选择
|
||||
selectedCategories.value = []
|
||||
} else {
|
||||
throw new Error(result.message || '优化执行失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('应用优化失败:', error)
|
||||
@ -423,9 +510,174 @@ const restartAnalysis = () => {
|
||||
selectedCategories.value = []
|
||||
startAnalysis()
|
||||
}
|
||||
|
||||
const exportReport = () => {
|
||||
if (isExporting.value || !analysisResults.value) return
|
||||
isExporting.value = true
|
||||
|
||||
try {
|
||||
const reportDate = new Date().toLocaleString('zh-CN')
|
||||
let tableRows = ''
|
||||
|
||||
analysisResults.value.categories.forEach(category => {
|
||||
tableRows += `
|
||||
<tr>
|
||||
<td>
|
||||
<strong>${category.name}</strong>
|
||||
</td>
|
||||
<td>${category.total}</td>
|
||||
<td style="color:#2ecc71">${category.keep}</td>
|
||||
<td style="color:#e74c3c">${category.remove}</td>
|
||||
<td><strong>${category.keepPercentage}</strong></td>
|
||||
</tr>
|
||||
`
|
||||
})
|
||||
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Revit智能化分析结果报告</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #4361ee;
|
||||
--success-color: #2ecc71;
|
||||
--warning-color: #f39c12;
|
||||
--danger-color: #e74c3c;
|
||||
--text-main: #2b2b2b;
|
||||
--text-light: #7f8c8d;
|
||||
--bg-color: #f8f9fa;
|
||||
--card-bg: #ffffff;
|
||||
--border-color: #e9ecef;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-main);
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 1000px;
|
||||
margin: 0 auto;
|
||||
background: var(--card-bg);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #4361ee, #3a0ca3);
|
||||
color: white;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 32px;
|
||||
}
|
||||
.content { padding: 40px; }
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.summary-card {
|
||||
background: #f8f9fc;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
th, td {
|
||||
padding: 16px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
th { background-color: #f1f3f5; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Revit智能化分析结果报告</h1>
|
||||
<p>生成时间: ${reportDate}</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${analysisResults.value.analysis.totalElements}</div>
|
||||
<div class="summary-label">总构件数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color:var(--success-color);">${analysisResults.value.analysis.keepElements}</div>
|
||||
<div class="summary-label">保留构件</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value" style="color:var(--danger-color);">${analysisResults.value.analysis.removeElements}</div>
|
||||
<div class="summary-label">移除构件</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${analysisResults.value.analysis.estimatedReduction}</div>
|
||||
<div class="summary-label">预计缩减</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>构件分类详细数据</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>构件类型</th>
|
||||
<th>总数</th>
|
||||
<th>保留</th>
|
||||
<th>移除</th>
|
||||
<th>保留率</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>${tableRows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `Revit智能化分析结果报告_${new Date().getTime()}.html`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
ElNotification({
|
||||
title: '报告导出成功',
|
||||
type: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('导出报告失败:', error)
|
||||
} finally {
|
||||
isExporting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
||||
|
||||
/* Revit分析专用样式 */
|
||||
.revit-analysis-welcome {
|
||||
background: linear-gradient(135deg, var(--color-bg-secondary) 0%, var(--color-bg-primary) 100%);
|
||||
@ -687,6 +939,16 @@ const restartAnalysis = () => {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
.export-report-btn {
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
|
||||
color: white;
|
||||
box-shadow: 0 4px 15px rgba(16, 185, 129, 0.4) !important;
|
||||
}
|
||||
|
||||
.export-report-btn:hover:not(:disabled) {
|
||||
box-shadow: 0 8px 25px rgba(16, 185, 129, 0.6) !important;
|
||||
}
|
||||
|
||||
.revit-analysis-btn.secondary {
|
||||
background: linear-gradient(135deg, var(--color-bg-secondary) 0%, var(--color-white-rgb-05) 100%);
|
||||
color: var(--color-text-primary);
|
||||
|
||||
@ -1,11 +1,19 @@
|
||||
<template>
|
||||
<div class="shell-analysis-result-page">
|
||||
<div class="page-header">
|
||||
<h2>
|
||||
<i class="fas fa-magic"></i>
|
||||
智能薄壳化分析结果
|
||||
</h2>
|
||||
<p>Creo智能薄壳化分析结果展示</p>
|
||||
<div class="header-title">
|
||||
<h2>
|
||||
<i class="fas fa-magic"></i>
|
||||
智能薄壳化分析结果
|
||||
</h2>
|
||||
<p>Creo智能薄壳化分析结果展示</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="export-report-btn" @click="exportReport" :disabled="isExporting">
|
||||
<i class="fas" :class="isExporting ? 'fa-spinner fa-spin' : 'fa-file-export'"></i>
|
||||
{{ isExporting ? '导出中...' : '导出报告' }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
@ -225,6 +233,8 @@ const analysisTime = computed(() => {
|
||||
return props.analysisData?.analysis_time || new Date().toLocaleString('zh-CN')
|
||||
})
|
||||
|
||||
const isExporting = ref(false)
|
||||
|
||||
// 选中的零件集合
|
||||
const selectedParts = ref(new Set())
|
||||
|
||||
@ -437,6 +447,179 @@ const updateSelection = (event) => {
|
||||
}
|
||||
}
|
||||
|
||||
const exportReport = () => {
|
||||
if (isExporting.value) return
|
||||
isExporting.value = true
|
||||
|
||||
try {
|
||||
const reportDate = analysisTime.value
|
||||
let tableRows = ''
|
||||
|
||||
allParts.value.forEach(part => {
|
||||
const rec = getDeletionRecommendationText(part.deletion_recommendation)
|
||||
const recClass = getDeletionRecommendationClass(part.deletion_recommendation)
|
||||
let scoreClass = 'low'
|
||||
if (recClass === 'recommended') scoreClass = 'medium'
|
||||
if (recClass === 'safe') scoreClass = 'high'
|
||||
|
||||
tableRows += `
|
||||
<tr>
|
||||
<td>${part.id}</td>
|
||||
<td>
|
||||
<strong>${part.name}</strong><br/>
|
||||
<span style="font-size:12px;color:#999;font-family:'Courier New', monospace;">${part.partPath || 'N/A'}</span>
|
||||
</td>
|
||||
<td>${(part.volumeReduction || 0).toFixed(6)}%</td>
|
||||
<td>${formatPercent(part.confidence * 100)}%</td>
|
||||
<td>${part.reason}</td>
|
||||
<td class="score ${scoreClass}">${rec}</td>
|
||||
</tr>
|
||||
`
|
||||
})
|
||||
|
||||
const htmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>智能薄壳化分析结果报告</title>
|
||||
<style>
|
||||
:root {
|
||||
--primary-color: #4361ee;
|
||||
--success-color: #2ecc71;
|
||||
--warning-color: #f39c12;
|
||||
--danger-color: #e74c3c;
|
||||
--text-main: #2b2b2b;
|
||||
--text-light: #7f8c8d;
|
||||
--bg-color: #f8f9fa;
|
||||
--card-bg: #ffffff;
|
||||
--border-color: #e9ecef;
|
||||
}
|
||||
body {
|
||||
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||
background-color: var(--bg-color);
|
||||
color: var(--text-main);
|
||||
margin: 0;
|
||||
padding: 40px 20px;
|
||||
}
|
||||
.container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
background: var(--card-bg);
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 10px 30px rgba(0,0,0,0.05);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #4361ee, #3a0ca3);
|
||||
color: white;
|
||||
padding: 40px;
|
||||
text-align: center;
|
||||
}
|
||||
.header h1 {
|
||||
margin: 0 0 10px 0;
|
||||
font-size: 32px;
|
||||
}
|
||||
.content { padding: 40px; }
|
||||
.summary-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.summary-card {
|
||||
background: #f8f9fc;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 10px;
|
||||
padding: 24px;
|
||||
text-align: center;
|
||||
}
|
||||
.summary-value {
|
||||
font-size: 36px;
|
||||
font-weight: 700;
|
||||
color: var(--primary-color);
|
||||
}
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 20px;
|
||||
}
|
||||
th, td {
|
||||
padding: 16px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
th { background-color: #f1f3f5; }
|
||||
.score.high { color: var(--danger-color); font-weight: bold;}
|
||||
.score.medium { color: var(--warning-color); font-weight: bold;}
|
||||
.score.low { color: var(--success-color); font-weight: bold;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>智能薄壳化分析结果报告</h1>
|
||||
<p>生成时间: ${reportDate}</p>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="summary-grid">
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${allParts.value.length}</div>
|
||||
<div class="summary-label">总零件数</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${analysisResults.value.estimatedReduction.volumeReduction}</div>
|
||||
<div class="summary-label">体积减少</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${analysisResults.value.estimatedReduction.fileSizeReduction}</div>
|
||||
<div class="summary-label">文件大小减少</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-value">${analysisResults.value.estimatedReduction.performanceImprovement}</div>
|
||||
<div class="summary-label">性能提升</div>
|
||||
</div>
|
||||
</div>
|
||||
<h2>薄壳化详细数据</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="50">ID</th>
|
||||
<th width="300">零件信息</th>
|
||||
<th>体积减少</th>
|
||||
<th>置信度</th>
|
||||
<th>原因</th>
|
||||
<th>删除建议</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>${tableRows}</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const blob = new Blob([htmlContent], { type: 'text/html;charset=utf-8' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = `智能薄壳化分析结果报告_${new Date().getTime()}.html`
|
||||
document.body.appendChild(a)
|
||||
a.click()
|
||||
document.body.removeChild(a)
|
||||
URL.revokeObjectURL(url)
|
||||
|
||||
ElMessageBox.success('报告导出成功')
|
||||
} catch (error) {
|
||||
console.error('导出报告失败', error)
|
||||
ElMessageBox.error('导出报告失败,请重试')
|
||||
} finally {
|
||||
isExporting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 删除选中的组件
|
||||
const deleteSelectedComponents = async () => {
|
||||
@ -494,9 +677,12 @@ const deleteSelectedComponents = async () => {
|
||||
|
||||
.page-header {
|
||||
margin-bottom: var(--spacing-2xl);
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.page-header h2 {
|
||||
.header-title h2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-md);
|
||||
@ -506,15 +692,44 @@ const deleteSelectedComponents = async () => {
|
||||
margin: 0 0 var(--spacing-sm) 0;
|
||||
}
|
||||
|
||||
.page-header h2 i {
|
||||
.header-title h2 i {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
|
||||
.page-header p {
|
||||
.header-title p {
|
||||
color: var(--color-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.export-report-btn {
|
||||
background: var(--color-primary);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
border-radius: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 12px rgba(67, 97, 238, 0.2);
|
||||
}
|
||||
|
||||
.export-report-btn:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 16px rgba(67, 97, 238, 0.3);
|
||||
background: #3651d4;
|
||||
}
|
||||
|
||||
.export-report-btn:disabled {
|
||||
background: #aab8f8;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@ -62,7 +62,7 @@ class PdmsApiService {
|
||||
const url = buildApiUrl(this.softwareName, 'simplify')
|
||||
|
||||
return await apiClient.post(url, params, {
|
||||
timeout: 600000, // 超时600s
|
||||
timeout: 660000, // 超时660s
|
||||
operationContext: {
|
||||
software: 'PDMS',
|
||||
operation: '模型简化处理'
|
||||
@ -133,7 +133,7 @@ class PdmsApiService {
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出为IFC格式
|
||||
* 导出为RVM格式(与后台exportIfc接口对应)
|
||||
* @param {Object} params - 导出参数 { ExportPath, FileName }
|
||||
* @returns {Promise<{success: boolean, data?: any, error?: string}>}
|
||||
*/
|
||||
@ -141,10 +141,10 @@ class PdmsApiService {
|
||||
const url = buildApiUrl(this.softwareName, 'exportIfc')
|
||||
|
||||
return await apiClient.post(url, params || {}, {
|
||||
timeout: 600000, // 导出可能需要较长时间
|
||||
timeout: 600000,
|
||||
operationContext: {
|
||||
software: 'PDMS',
|
||||
operation: '导出IFC格式'
|
||||
operation: '模型导出'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user