feat: 实现Creo几何复杂度分析结果页面UI

- 完全照抄参考项目的几何复杂度分析UI设计
- 实现分析摘要、零件列表表格、选择删除功能界面
- 添加几何复杂度专用CSS变量到theme.css统一管理
- 使用模拟数据展示6个零件的复杂度分析结果
- 支持全选/清空、复杂度等级颜色标识功能
- 完全复用现有系统CSS变量,保持主题一致性

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sladro 2025-09-17 13:37:54 +08:00
parent 7fdbb5791b
commit 653917eab3
2 changed files with 585 additions and 20 deletions

View File

@ -77,6 +77,17 @@
--color-text-red: rgb(255, 0, 0);
--color-text-blue: rgb(0, 100, 200);
/* 几何复杂度分析主题色 */
--color-complexity-base: 255, 140, 0; /* #FF8C00 */
--color-complexity: rgb(var(--color-complexity-base));
--color-complexity-bg-1: rgba(var(--color-complexity-base), 0.05);
--color-complexity-bg-2: rgba(var(--color-complexity-base), 0.08);
--color-complexity-bg-3: rgba(var(--color-complexity-base), 0.1);
--color-complexity-border-1: rgba(var(--color-complexity-base), 0.1);
--color-complexity-border-2: rgba(var(--color-complexity-base), 0.2);
--color-complexity-border-3: rgba(var(--color-complexity-base), 0.3);
--color-complexity-border-15: rgba(var(--color-complexity-base), 0.15);
/* ===== 优化透明度层级系统 ===== */
/* 主色调透明度变体 */

View File

@ -9,22 +9,301 @@
</div>
<div class="page-content">
<div class="result-placeholder">
<div class="placeholder-icon">
<i class="fas fa-hourglass-half"></i>
<!-- 分析统计摘要 -->
<div class="complexity-analysis-summary">
<div class="summary-header">
<h4><i class="fas fa-chart-pie"></i> 分析摘要</h4>
<div class="analysis-time">
<i class="fas fa-clock"></i>
完成时间: {{ analysisTime }}
</div>
</div>
<h3>分析结果页面</h3>
<p>此页面将展示几何复杂度分析的结果</p>
<div class="summary-stats">
<div class="stat-card">
<div class="stat-value">{{ mockData.length }}</div>
<div class="stat-label">总零件数</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ averageComplexity }}</div>
<div class="stat-label">平均复杂度</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ selectedParts.size }}</div>
<div class="stat-label">已选择零件</div>
</div>
<div class="stat-card">
<div class="stat-value">{{ highComplexityCount }}</div>
<div class="stat-label">高复杂度零件</div>
</div>
</div>
</div>
<!-- 零件列表区域 -->
<div class="complexity-parts-list">
<div class="complexity-parts-header">
<h4>
<i class="fas fa-list"></i>
几何复杂度分析结果 ({{ mockData.length }} 个零件)
</h4>
<div class="complexity-controls">
<button class="complexity-select-all" @click="selectAll">
<i class="fas fa-check-square"></i>
全选
</button>
<button class="complexity-clear-all" @click="clearAll">
<i class="far fa-square"></i>
清空
</button>
</div>
</div>
<div class="table-container">
<table class="complexity-parts-table">
<thead>
<tr>
<th width="50">选择</th>
<th width="60">ID</th>
<th width="200">零件名称</th>
<th width="80">表面数</th>
<th width="80">特征数</th>
<th width="80">曲面数</th>
<th width="60">孔数</th>
<th width="80">圆角数</th>
<th width="100">复杂度得分</th>
<th width="100">体积 (mm³)</th>
</tr>
</thead>
<tbody id="complexity-parts-tbody">
<tr
v-for="(part, index) in mockData"
:key="index"
class="complexity-part-row"
:class="{ selected: selectedParts.has(index + 1) }"
:data-part-id="index + 1"
>
<td>
<input
type="checkbox"
class="complexity-checkbox"
:data-part-id="index + 1"
:checked="selectedParts.has(index + 1)"
@change="updateSelection"
/>
</td>
<td>{{ index + 1 }}</td>
<td>
<div class="part-info">
<span class="complexity-part-name">{{ part.part_name }}</span>
<div class="complexity-part-path">{{ part.part_path }}</div>
<div class="complexity-file-size">{{ part.file_size }}</div>
</div>
</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>
<span
class="complexity-score"
:class="getComplexityClass(part.complexity_score)"
>
{{ part.complexity_score.toFixed(2) }}
</span>
</td>
<td>{{ formatVolume(part.volume) }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- 删除操作区域 -->
<div class="complexity-delete-section">
<div class="complexity-delete-header">
<h4>
<i class="fas fa-trash"></i>
删除操作
</h4>
<div class="complexity-selected-count" id="complexity-selected-count">
已选择: {{ selectedParts.size }} 个零件
</div>
</div>
<div class="complexity-delete-summary">
<p>选中的零件将从模型中删除请仔细检查选择的零件删除操作无法撤销</p>
</div>
<button
id="complexity-delete-btn"
class="complexity-delete-btn"
:disabled="selectedParts.size === 0"
@click="deleteSelected"
>
<i class="fas fa-trash"></i>
删除选中零件
</button>
</div>
</div>
</div>
</template>
<script setup>
//
import { ref, computed, onMounted } from 'vue'
//
const selectedParts = ref(new Set())
const analysisTime = ref('')
//
const mockData = ref([
{
part_name: 'HOUSING_ASSEMBLY_001',
part_path: '/PROJECT/ASSEMBLY/HOUSING_ASSEMBLY_001.PRT',
file_size: '2.4 MB',
surface_count: 142,
feature_count: 23,
curved_surface_count: 18,
hole_count: 8,
fillet_count: 15,
complexity_score: 8.5,
complexity_level: 'Very High',
volume: 125400.50
},
{
part_name: 'BRACKET_SUPPORT_V2',
part_path: '/PROJECT/ASSEMBLY/BRACKET_SUPPORT_V2.PRT',
file_size: '1.8 MB',
surface_count: 98,
feature_count: 18,
curved_surface_count: 12,
hole_count: 6,
fillet_count: 11,
complexity_score: 7.2,
complexity_level: 'High',
volume: 89230.25
},
{
part_name: 'CONNECTOR_PLATE_A',
part_path: '/PROJECT/ASSEMBLY/CONNECTOR_PLATE_A.PRT',
file_size: '0.9 MB',
surface_count: 54,
feature_count: 12,
curved_surface_count: 6,
hole_count: 4,
fillet_count: 8,
complexity_score: 5.8,
complexity_level: 'Medium',
volume: 42150.75
},
{
part_name: 'BASE_FRAME_MAIN',
part_path: '/PROJECT/ASSEMBLY/BASE_FRAME_MAIN.PRT',
file_size: '3.2 MB',
surface_count: 186,
feature_count: 31,
curved_surface_count: 24,
hole_count: 12,
fillet_count: 19,
complexity_score: 9.1,
complexity_level: 'Very High',
volume: 198750.00
},
{
part_name: 'GUIDE_RAIL_SET',
part_path: '/PROJECT/ASSEMBLY/GUIDE_RAIL_SET.PRT',
file_size: '1.2 MB',
surface_count: 76,
feature_count: 15,
curved_surface_count: 8,
hole_count: 5,
fillet_count: 9,
complexity_score: 6.4,
complexity_level: 'Medium',
volume: 67890.30
},
{
part_name: 'SIMPLE_WASHER_001',
part_path: '/PROJECT/ASSEMBLY/SIMPLE_WASHER_001.PRT',
file_size: '0.1 MB',
surface_count: 8,
feature_count: 3,
curved_surface_count: 2,
hole_count: 1,
fillet_count: 2,
complexity_score: 2.1,
complexity_level: 'Low',
volume: 1250.45
}
])
//
const averageComplexity = computed(() => {
const total = mockData.value.reduce((sum, part) => sum + part.complexity_score, 0)
return (total / mockData.value.length).toFixed(2)
})
const highComplexityCount = computed(() => {
return mockData.value.filter(part => part.complexity_score >= 7.0).length
})
//
const getComplexityClass = (score) => {
if (score >= 8.5) return 'very-high'
if (score >= 7.0) return 'high'
if (score >= 5.0) return 'medium'
if (score >= 3.0) return 'low'
return 'very-low'
}
const formatVolume = (volume) => {
return volume.toLocaleString('zh-CN', {
minimumFractionDigits: 2,
maximumFractionDigits: 2
})
}
const selectAll = () => {
selectedParts.value.clear()
for (let i = 1; i <= mockData.value.length; i++) {
selectedParts.value.add(i)
}
}
const clearAll = () => {
selectedParts.value.clear()
}
const updateSelection = (event) => {
const partId = parseInt(event.target.getAttribute('data-part-id'))
if (event.target.checked) {
selectedParts.value.add(partId)
} else {
selectedParts.value.delete(partId)
}
}
const deleteSelected = () => {
if (selectedParts.value.size === 0) {
alert('请先选择要删除的零件')
return
}
const confirmed = confirm(`确定要删除选中的 ${selectedParts.value.size} 个零件吗?`)
if (confirmed) {
alert('删除功能仅为UI演示未实现实际删除逻辑')
}
}
//
onMounted(() => {
analysisTime.value = new Date().toLocaleString('zh-CN')
})
</script>
<style scoped>
/* 页面基础样式 */
.geometry-complexity-result-page {
padding: var(--spacing-2xl);
height: 100%;
@ -45,7 +324,7 @@
}
.page-header h2 i {
color: var(--color-primary);
color: var(--color-complexity);
}
.page-header p {
@ -54,31 +333,306 @@
}
.page-content {
height: calc(100% - 100px);
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
gap: var(--spacing-xl);
}
.result-placeholder {
/* 分析统计摘要样式 */
.complexity-analysis-summary {
background: var(--color-bg-secondary);
border: 1px solid var(--color-complexity-border-1);
border-radius: var(--size-border-radius-card);
padding: var(--spacing-xl);
}
.summary-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-lg);
padding-bottom: var(--spacing-md);
border-bottom: 1px solid var(--color-complexity-border-2);
}
.summary-header h4 {
margin: 0;
color: var(--color-complexity);
font-size: var(--font-size-xl);
font-weight: var(--font-weight-semibold);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.analysis-time {
color: var(--color-text-muted);
font-size: var(--font-size-sm);
display: flex;
align-items: center;
gap: var(--spacing-xs);
}
.summary-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: var(--spacing-md);
}
.stat-card {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--color-complexity-border-15);
border-radius: var(--size-border-radius);
padding: var(--spacing-md);
text-align: center;
transition: all 0.2s ease;
}
.stat-card:hover {
background: var(--color-complexity-bg-2);
transform: translateY(-2px);
}
.stat-value {
font-size: var(--font-size-2xl);
font-weight: var(--font-weight-bold);
color: var(--color-complexity);
line-height: 1.2;
margin-bottom: var(--spacing-xs);
}
.stat-label {
font-size: var(--font-size-sm);
color: var(--color-text-muted);
font-weight: var(--font-weight-medium);
}
/* 零件列表样式 */
.complexity-parts-list {
background: var(--color-bg-secondary);
border-radius: var(--size-border-radius-card);
overflow: hidden;
}
.complexity-parts-header {
background: var(--color-complexity-border-15);
padding: var(--spacing-lg);
border-bottom: 1px solid var(--color-complexity-border-2);
display: flex;
justify-content: space-between;
align-items: center;
}
.complexity-parts-header h4 {
margin: 0;
color: var(--color-complexity);
font-size: var(--font-size-xl);
font-weight: var(--font-weight-semibold);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.complexity-controls {
display: flex;
gap: var(--spacing-sm);
align-items: center;
}
.complexity-select-all,
.complexity-clear-all {
background: var(--color-complexity-border-15);
border: 1px solid var(--color-complexity-border-3);
color: var(--color-complexity);
padding: var(--spacing-xs) var(--spacing-sm);
border-radius: var(--border-radius-sm);
cursor: pointer;
transition: all 0.2s ease;
font-size: var(--font-size-sm);
display: flex;
align-items: center;
gap: var(--spacing-xs);
}
.complexity-select-all:hover,
.complexity-clear-all:hover {
background: var(--color-complexity-border-2);
}
.table-container {
max-height: 400px;
overflow-y: auto;
}
.complexity-parts-table {
width: 100%;
border-collapse: collapse;
}
.complexity-parts-table th {
background: var(--color-complexity-bg-2);
color: var(--color-complexity);
padding: var(--spacing-sm) var(--spacing-md);
text-align: left;
font-weight: var(--font-weight-semibold);
border-bottom: 1px solid var(--color-complexity-border-2);
position: sticky;
top: 0;
z-index: 1;
}
.complexity-parts-table td {
padding: var(--spacing-sm) var(--spacing-md);
border-bottom: 1px solid var(--color-complexity-border-15);
color: var(--color-text-secondary);
}
.placeholder-icon {
font-size: 4rem;
margin-bottom: var(--spacing-lg);
.complexity-parts-table tr:hover {
background: var(--color-complexity-bg-1);
}
.complexity-parts-table tr.selected {
background: var(--color-complexity-bg-2);
border-left: 3px solid var(--color-complexity);
}
.complexity-checkbox {
width: 18px;
height: 18px;
accent-color: var(--color-complexity);
cursor: pointer;
}
.part-info {
display: flex;
flex-direction: column;
gap: var(--spacing-xs);
}
.complexity-part-name {
color: var(--color-primary);
font-weight: var(--font-weight-medium);
font-size: var(--font-size-sm);
}
.result-placeholder h3 {
font-size: var(--font-size-2xl);
color: var(--color-text-primary);
margin: 0 0 var(--spacing-md) 0;
.complexity-part-path {
color: #28a745;
font-size: var(--font-size-xs);
font-family: 'Courier New', monospace;
opacity: 0.8;
}
.result-placeholder p {
font-size: var(--font-size-lg);
.complexity-file-size {
color: var(--color-text-muted);
font-size: var(--font-size-xs);
font-weight: var(--font-weight-medium);
}
.complexity-score {
display: inline-block;
padding: var(--spacing-xs) var(--spacing-sm);
border-radius: var(--border-radius-sm);
font-weight: var(--font-weight-semibold);
font-size: var(--font-size-sm);
}
.complexity-score.very-high {
background: rgba(139, 0, 0, 0.1);
color: #8B0000;
font-weight: var(--font-weight-bold);
}
.complexity-score.high {
background: rgba(220, 53, 69, 0.1);
color: #dc3545;
font-weight: var(--font-weight-semibold);
}
.complexity-score.medium {
background: rgba(255, 193, 7, 0.1);
color: #ffc107;
}
.complexity-score.low {
background: rgba(40, 167, 69, 0.1);
color: #28a745;
}
.complexity-score.very-low {
background: rgba(34, 139, 34, 0.1);
color: #228B22;
}
/* 删除操作区域 */
.complexity-delete-section {
background: var(--color-complexity-bg-1);
border: 1px solid var(--color-complexity-border-2);
border-radius: var(--size-border-radius-card);
padding: var(--spacing-xl);
}
.complexity-delete-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--spacing-md);
}
.complexity-delete-header h4 {
margin: 0;
color: var(--color-complexity);
font-size: var(--font-size-lg);
font-weight: var(--font-weight-semibold);
display: flex;
align-items: center;
gap: var(--spacing-sm);
}
.complexity-selected-count {
background: var(--color-complexity-border-15);
color: var(--color-complexity);
padding: var(--spacing-xs) var(--spacing-sm);
border-radius: var(--border-radius-full);
font-size: var(--font-size-sm);
font-weight: var(--font-weight-semibold);
}
.complexity-delete-summary {
margin-bottom: var(--spacing-lg);
padding: var(--spacing-sm) var(--spacing-md);
background: var(--color-complexity-bg-2);
border-radius: var(--size-border-radius);
border-left: 4px solid var(--color-complexity);
color: var(--color-text-secondary);
font-size: var(--font-size-sm);
}
.complexity-delete-btn {
background: linear-gradient(135deg, #dc3545, #c82333);
border: none;
color: white;
padding: var(--spacing-sm) var(--spacing-lg);
border-radius: var(--size-border-radius);
cursor: pointer;
font-size: var(--font-size-base);
font-weight: var(--font-weight-semibold);
display: flex;
align-items: center;
gap: var(--spacing-sm);
transition: all 0.2s ease;
box-shadow: 0 2px 8px rgba(220, 53, 69, 0.3);
}
.complexity-delete-btn:hover:not(:disabled) {
background: linear-gradient(135deg, #c82333, #a71e2a);
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(220, 53, 69, 0.4);
}
.complexity-delete-btn:disabled {
background: rgba(108, 117, 125, 0.5);
cursor: not-allowed;
box-shadow: none;
transform: none;
}
</style>