feat: 新增PDMS模型轻量化处理功能及相关分析工具页面和配置。
This commit is contained in:
parent
29904d4479
commit
d70a881bd3
@ -12,7 +12,11 @@
|
||||
:model-data="modelData"
|
||||
@page-change="(page) => $emit('page-change', page)"
|
||||
/>
|
||||
<div v-else-if="currentConnectedSoftware === 'pdms'" class="no-connection">PDMS分析功能开发中</div>
|
||||
<PdmsAnalysisDashboard
|
||||
v-else-if="currentConnectedSoftware === 'pdms'"
|
||||
:model-data="modelData"
|
||||
@page-change="(page) => $emit('page-change', page)"
|
||||
/>
|
||||
<div v-else class="no-connection">请先连接CAD软件</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -20,6 +24,7 @@
|
||||
<script setup>
|
||||
import CreoModelAnalysis from '@/components/pages/CreoModelAnalysis.vue'
|
||||
import RevitAnalysisDashboard from '@/components/pages/RevitAnalysisDashboard.vue'
|
||||
import PdmsAnalysisDashboard from '@/components/pages/PdmsAnalysisDashboard.vue'
|
||||
|
||||
defineProps({
|
||||
currentConnectedSoftware: {
|
||||
|
||||
327
src/components/pages/PdmsAnalysisDashboard.vue
Normal file
327
src/components/pages/PdmsAnalysisDashboard.vue
Normal file
@ -0,0 +1,327 @@
|
||||
<template>
|
||||
<div class="pdms-analysis-dashboard pdms-theme">
|
||||
<!-- 如果没有模型,显示欢迎界面 -->
|
||||
<div v-if="!hasModel" class="pdms-analysis-welcome pdms-theme">
|
||||
<div class="welcome-icon">
|
||||
<i class="fas fa-industry"></i>
|
||||
</div>
|
||||
<h2>PDMS 模型分析中心</h2>
|
||||
<p>专业的工厂设计模型处理工具,提供智能化轻量化和优化选项。请先打开或连接一个PDMS项目以开始分析。</p>
|
||||
<div class="welcome-actions">
|
||||
<button class="welcome-btn" @click="openProject">
|
||||
<i class="fas fa-folder-open"></i>
|
||||
打开项目
|
||||
</button>
|
||||
<button class="welcome-btn" @click="refreshConnection">
|
||||
<i class="fas fa-sync-alt"></i>
|
||||
刷新连接
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 如果有模型,显示分析仪表板 -->
|
||||
<div v-else>
|
||||
<div class="pdms-analysis-header">
|
||||
<h3>
|
||||
<i class="fas fa-industry"></i>
|
||||
PDMS 模型处理
|
||||
</h3>
|
||||
<p class="subtitle">{{ modelData?.ProjectInfo?.ProjectName || '当前连接的PDMS模型' }}</p>
|
||||
</div>
|
||||
|
||||
<div class="pdms-strategy-selector">
|
||||
<h4>
|
||||
<i class="fas fa-cogs"></i>
|
||||
模型处理工具选择
|
||||
</h4>
|
||||
<div class="pdms-strategy-grid">
|
||||
<div
|
||||
class="pdms-strategy-card"
|
||||
data-strategy="shrinkwrap"
|
||||
@click="openShrinkwrapPage"
|
||||
>
|
||||
<div class="strategy-icon">
|
||||
<i class="fas fa-compress-arrows-alt"></i>
|
||||
</div>
|
||||
<h5>模型轻量化处理 (Shrinkwrap)</h5>
|
||||
<p>
|
||||
对PDMS模型进行轮廓化处理,保留外部边缘,删除内部不需要的构件,从而大幅缩减模型体积。
|
||||
</p>
|
||||
<div class="features">
|
||||
<span>轮廓化</span>
|
||||
<span>缩小体积</span>
|
||||
<span>定制类型保留</span>
|
||||
</div>
|
||||
<div class="status-badge" style="background: var(--color-success)">新功能</div>
|
||||
</div>
|
||||
|
||||
<!-- 可以预留其他PDMS处理工具位置 -->
|
||||
<div class="pdms-strategy-card disabled" data-strategy="piping-analysis">
|
||||
<div class="strategy-icon" style="background: var(--color-border-primary);">
|
||||
<i class="fas fa-drafting-compass"></i>
|
||||
</div>
|
||||
<h5 style="color: var(--color-text-secondary);">管道专项分析 (开发中)</h5>
|
||||
<p style="color: var(--color-text-disabled);">
|
||||
针对管道模型进行碰撞检测及流体路径复杂性评估。
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { ElNotification } from 'element-plus'
|
||||
|
||||
const props = defineProps({
|
||||
modelData: {
|
||||
type: Object,
|
||||
default: null
|
||||
}
|
||||
})
|
||||
|
||||
const emit = defineEmits(['page-change'])
|
||||
|
||||
// 计算属性
|
||||
const hasModel = computed(() => {
|
||||
return props.modelData && Object.keys(props.modelData).length > 0
|
||||
})
|
||||
|
||||
// 方法
|
||||
const openProject = () => {
|
||||
emit('page-change', 'connection')
|
||||
}
|
||||
|
||||
const openShrinkwrapPage = () => {
|
||||
emit('page-change', 'pdms-shrinkwrap')
|
||||
}
|
||||
|
||||
const refreshConnection = () => {
|
||||
ElNotification({
|
||||
title: '刷新连接',
|
||||
message: '连接状态已刷新',
|
||||
type: 'info',
|
||||
position: 'top-right',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 仿照Revit的样式,颜色可以适当调整体现PDMS的工业感 */
|
||||
.pdms-analysis-welcome {
|
||||
background: linear-gradient(135deg, var(--color-bg-secondary) 0%, var(--color-bg-primary) 100%);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 16px;
|
||||
padding: 32px;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
animation: slideInUp 0.4s ease-out;
|
||||
}
|
||||
|
||||
.welcome-icon {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 24px auto;
|
||||
box-shadow: 0 8px 32px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
|
||||
.welcome-icon i {
|
||||
font-size: 32px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.pdms-analysis-welcome h2 {
|
||||
color: #10b981;
|
||||
font-size: 1.6em;
|
||||
font-weight: 600;
|
||||
margin: 0 0 16px 0;
|
||||
}
|
||||
|
||||
.pdms-analysis-welcome p {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.9em;
|
||||
margin: 0 0 32px 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.welcome-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.welcome-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 12px 24px;
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
font-size: 0.9em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
box-shadow: 0 4px 15px rgba(16, 185, 129, 0.4);
|
||||
}
|
||||
|
||||
.welcome-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 25px rgba(16, 185, 129, 0.6);
|
||||
}
|
||||
|
||||
.pdms-analysis-dashboard {
|
||||
background: linear-gradient(135deg, var(--color-bg-secondary) 0%, var(--color-bg-primary) 100%);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
animation: slideInUp 0.4s ease-out;
|
||||
}
|
||||
|
||||
.pdms-analysis-header {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.pdms-analysis-header h3 {
|
||||
color: #10b981;
|
||||
font-size: 1.6em;
|
||||
font-weight: 600;
|
||||
margin: 0 0 8px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.pdms-analysis-header .subtitle {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.9em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.pdms-strategy-selector {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.pdms-strategy-selector h4 {
|
||||
color: var(--color-text-primary);
|
||||
font-size: 1.3em;
|
||||
font-weight: 600;
|
||||
margin: 0 0 20px 0;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.pdms-strategy-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
|
||||
gap: 20px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.pdms-strategy-card {
|
||||
background: linear-gradient(135deg, var(--color-bg-secondary) 0%, var(--color-white-rgb-05) 100%);
|
||||
border: 2px solid transparent;
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
backdrop-filter: blur(10px);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pdms-strategy-card:hover {
|
||||
transform: translateY(-4px);
|
||||
border-color: #10b981;
|
||||
box-shadow: 0 8px 25px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
|
||||
.pdms-strategy-card.disabled {
|
||||
opacity: 0.6;
|
||||
cursor: not-allowed;
|
||||
border-color: var(--color-text-disabled);
|
||||
}
|
||||
|
||||
.pdms-strategy-card.disabled:hover {
|
||||
transform: none;
|
||||
border-color: var(--color-text-disabled);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.strategy-icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 12px;
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0 auto 16px auto;
|
||||
box-shadow: 0 4px 15px rgba(16, 185, 129, 0.4);
|
||||
}
|
||||
|
||||
.strategy-icon i {
|
||||
font-size: 24px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.pdms-strategy-card h5 {
|
||||
color: var(--color-text-primary);
|
||||
font-size: 1.2em;
|
||||
font-weight: 600;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.pdms-strategy-card p {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.9em;
|
||||
margin: 0 0 16px 0;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
position: absolute;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
background: var(--color-warning);
|
||||
color: white;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.7em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.features {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.features span {
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
color: #10b981;
|
||||
padding: 4px 8px;
|
||||
border-radius: 6px;
|
||||
font-size: 0.75em;
|
||||
font-weight: 500;
|
||||
}
|
||||
</style>
|
||||
565
src/components/pages/PdmsShrinkwrapPage.vue
Normal file
565
src/components/pages/PdmsShrinkwrapPage.vue
Normal file
@ -0,0 +1,565 @@
|
||||
<template>
|
||||
<div class="pdms-shrinkwrap pdms-theme">
|
||||
<div class="header-actions">
|
||||
<button class="icon-btn" @click="goBack" title="返回">
|
||||
<i class="fas fa-arrow-left"></i> 返回分析中心
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="optimization-header">
|
||||
<h2>
|
||||
<i class="fas fa-compress-arrows-alt"></i>
|
||||
PDMS模型轻量化处理
|
||||
</h2>
|
||||
<p class="subtitle">保留工厂建筑模型外部轮廓,删除多余内部细节,大幅缩减模型体积。</p>
|
||||
</div>
|
||||
|
||||
<!-- 任务参数设置区 -->
|
||||
<div class="settings-panel" v-if="taskStatus === 'idle' || taskStatus === 'failed'">
|
||||
<div class="setting-group checkbox-group">
|
||||
<label>保留类别 (Keep Types)</label>
|
||||
<div class="checkbox-options">
|
||||
<el-checkbox-group v-model="formData.keepTypes">
|
||||
<el-checkbox label="SITE">SITE (场地)</el-checkbox>
|
||||
<el-checkbox label="ZONE">ZONE (区域)</el-checkbox>
|
||||
<el-checkbox label="STRU">STRU (结构)</el-checkbox>
|
||||
<el-checkbox label="FRAME">FRAME (框架)</el-checkbox>
|
||||
<el-checkbox label="SHELL">SHELL (壳体)</el-checkbox>
|
||||
<el-checkbox label="PLAT">PLAT (平台)</el-checkbox>
|
||||
<el-checkbox label="WALL">WALL (墙体)</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-group parameters-group">
|
||||
<div class="param-item">
|
||||
<label>外壳内缩距离 (Padding)</label>
|
||||
<el-input-number v-model="formData.padding" :min="0" :step="100" />
|
||||
<p class="help-text">向内偏移判定距离,默认 500.0</p>
|
||||
</div>
|
||||
<div class="param-item">
|
||||
<label>内外判断容差 (Tolerance)</label>
|
||||
<el-input-number v-model="formData.touchTolerance" :min="0" :step="0.5" />
|
||||
<p class="help-text">判断模型是否相交的容差值,默认 1.0</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="setting-group">
|
||||
<label>区域过滤 (Zone Filters, 可选)</label>
|
||||
<el-input
|
||||
v-model="zoneFiltersInput"
|
||||
placeholder="输入要处理的ZONE路径(逗号分隔),为空则全量处理"
|
||||
></el-input>
|
||||
</div>
|
||||
|
||||
<div class="setting-group toggle-group">
|
||||
<label>安全设置</label>
|
||||
<div class="toggle-control">
|
||||
<span>开启模拟模式 (Dry Run)?仅模拟不真删</span>
|
||||
<el-switch v-model="formData.dryRun" active-color="#13ce66" inactive-color="#ff4949"></el-switch>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-bar">
|
||||
<button class="primary-btn" @click="startTask" :disabled="isStarting">
|
||||
<i class="fas" :class="isStarting ? 'fa-spinner fa-spin' : 'fa-play'"></i>
|
||||
{{ isStarting ? '正在处理...' : '执行轻量化' }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-if="errorMessage" class="error-message">
|
||||
<i class="fas fa-exclamation-triangle"></i> {{ errorMessage }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务执行中进度区 -->
|
||||
<div class="execution-panel" v-else-if="taskStatus === 'Processing'">
|
||||
<h3>
|
||||
<i class="fas fa-cog fa-spin"></i>
|
||||
正在处理PDMS模型,请耐心等待 (可能需要几分钟)...
|
||||
</h3>
|
||||
|
||||
<div class="progress-container">
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill active"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 任务结果区 -->
|
||||
<div class="result-panel" v-else-if="taskStatus === 'Completed' && taskResult">
|
||||
<div class="success-header">
|
||||
<i class="fas fa-check-circle success-icon"></i>
|
||||
<h3>模型轻量化完成</h3>
|
||||
<p v-if="taskResult.dryRun" style="color:var(--color-warning);">(本次为模拟运行模式,未真实删除模型)</p>
|
||||
</div>
|
||||
|
||||
<div class="metrics-grid">
|
||||
<div class="metric-card">
|
||||
<div class="metric-icon"><i class="fas fa-trash-alt"></i></div>
|
||||
<div class="metric-info">
|
||||
<div class="metric-value highlight">{{ taskResult.removedCount || 0 }}</div>
|
||||
<div class="metric-label">移除内部构件数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<div class="metric-icon"><i class="fas fa-check"></i></div>
|
||||
<div class="metric-info">
|
||||
<div class="metric-value">{{ taskResult.keptCount || 0 }}</div>
|
||||
<div class="metric-label">保留构件总数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-card">
|
||||
<div class="metric-icon"><i class="fas fa-search-plus"></i></div>
|
||||
<div class="metric-info">
|
||||
<div class="metric-value">{{ taskResult.totalVisited || 0 }}</div>
|
||||
<div class="metric-label">扫描构件总数</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="metric-card" v-if="taskResult.shellKeptCount !== undefined">
|
||||
<div class="metric-icon"><i class="fas fa-cube"></i></div>
|
||||
<div class="metric-info">
|
||||
<div class="metric-value">{{ taskResult.shellKeptCount }}</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.startedAt && taskResult.completedAt">
|
||||
执行时间: {{ formatTime(taskResult.startedAt) }} - {{ formatTime(taskResult.completedAt) }}
|
||||
</p>
|
||||
|
||||
<!-- Zone summaries -->
|
||||
<div v-if="taskResult.zoneSummaries && Object.keys(taskResult.zoneSummaries).length > 0">
|
||||
<h5 style="margin-top:20px; color: var(--color-text-primary);">Zone 处理汇总</h5>
|
||||
<ul>
|
||||
<li v-for="(count, zone) in taskResult.zoneSummaries" :key="zone">
|
||||
<span style="color:var(--color-primary)">{{ zone }}</span> : {{ count }} 个移除
|
||||
</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>
|
||||
<ul>
|
||||
<li v-for="(err, idx) in taskResult.errors.slice(0, 5)" :key="idx">{{ err }}</li>
|
||||
<li v-if="taskResult.errors.length > 5">...以及其他 {{ taskResult.errors.length - 5 }} 个错误</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="result-actions">
|
||||
<button class="primary-btn" @click="resetTask">
|
||||
<i class="fas fa-redo"></i> 再次处理
|
||||
</button>
|
||||
<button class="secondary-btn" @click="goBack">
|
||||
<i class="fas fa-home"></i> 返回分析中心
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue'
|
||||
import { ElNotification } from 'element-plus'
|
||||
import pdmsApi from '@/services/pdmsApi'
|
||||
|
||||
const emit = defineEmits(['page-change'])
|
||||
|
||||
// 状态定义
|
||||
// idle | Processing | Completed | failed
|
||||
const taskStatus = ref('idle')
|
||||
const isStarting = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const taskResult = ref(null)
|
||||
|
||||
const zoneFiltersInput = ref("")
|
||||
|
||||
// 表单数据
|
||||
const formData = reactive({
|
||||
dryRun: true,
|
||||
padding: 500.0,
|
||||
touchTolerance: 1.0,
|
||||
keepTypes: ["SITE", "ZONE", "STRU", "FRAME", "SHELL", "PLAT", "WALL"]
|
||||
})
|
||||
|
||||
// 返回函数
|
||||
const goBack = () => {
|
||||
emit('page-change', 'analysis-tools')
|
||||
}
|
||||
|
||||
// 重置状态
|
||||
const resetTask = () => {
|
||||
taskStatus.value = 'idle'
|
||||
taskResult.value = null
|
||||
errorMessage.value = ''
|
||||
}
|
||||
|
||||
// 时间格式化辅助
|
||||
const formatTime = (timeStr) => {
|
||||
if (!timeStr) return ""
|
||||
return new Date(timeStr).toLocaleString()
|
||||
}
|
||||
|
||||
// 启动任务
|
||||
const startTask = async () => {
|
||||
isStarting.value = true
|
||||
errorMessage.value = ''
|
||||
taskStatus.value = 'Processing'
|
||||
|
||||
try {
|
||||
const payload = {
|
||||
dryRun: formData.dryRun,
|
||||
padding: formData.padding,
|
||||
touchTolerance: formData.touchTolerance,
|
||||
zoneFilters: zoneFiltersInput.value ? zoneFiltersInput.value.split(',').map(s => s.trim()).filter(s => s) : [],
|
||||
keepTypes: formData.keepTypes
|
||||
}
|
||||
|
||||
const res = await pdmsApi.executeShrinkwrap(payload)
|
||||
if (res.success && res.data && res.data.code === 0) {
|
||||
taskStatus.value = 'Completed'
|
||||
taskResult.value = res.data.data
|
||||
ElNotification({
|
||||
title: '处理完成',
|
||||
message: 'PDMS模型轻量化处理执行完毕。',
|
||||
type: 'success'
|
||||
})
|
||||
} else {
|
||||
taskStatus.value = 'failed'
|
||||
errorMessage.value = (res.data && res.data.message) || res.error || '执行轻量化失败,返回数据异常。'
|
||||
ElNotification({
|
||||
title: '处理失败',
|
||||
message: errorMessage.value,
|
||||
type: 'error'
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
taskStatus.value = 'failed'
|
||||
errorMessage.value = err.message || '网络请求错误'
|
||||
ElNotification({
|
||||
title: '处理失败',
|
||||
message: errorMessage.value,
|
||||
type: 'error'
|
||||
})
|
||||
} finally {
|
||||
isStarting.value = false
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.pdms-shrinkwrap {
|
||||
background: linear-gradient(135deg, var(--color-bg-secondary) 0%, var(--color-bg-primary) 100%);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 16px;
|
||||
padding: 24px;
|
||||
backdrop-filter: blur(20px);
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
animation: slideInUp 0.4s ease-out;
|
||||
color: var(--color-text-primary);
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.icon-btn {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: #10b981;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
.icon-btn:hover {
|
||||
transform: translateX(-4px);
|
||||
color: #059669;
|
||||
}
|
||||
|
||||
.optimization-header {
|
||||
text-align: center;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.optimization-header h2 {
|
||||
color: #10b981;
|
||||
font-size: 1.8em;
|
||||
font-weight: 600;
|
||||
margin: 0 0 12px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.optimization-header .subtitle {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 1em;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 设定区 */
|
||||
.settings-panel {
|
||||
background: var(--color-bg-card);
|
||||
border-radius: 12px;
|
||||
padding: 32px;
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
border: 1px solid var(--color-border-primary);
|
||||
}
|
||||
|
||||
.setting-group {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.setting-group > label {
|
||||
display: block;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
margin-bottom: 16px;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.parameters-group {
|
||||
display: flex;
|
||||
gap: 32px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.param-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.param-item label {
|
||||
font-weight: 500;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.param-item .help-text {
|
||||
font-size: 0.8em;
|
||||
color: var(--color-text-secondary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.toggle-group {
|
||||
background: var(--color-bg-secondary);
|
||||
padding: 16px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.toggle-control {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action-bar {
|
||||
text-align: center;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
::v-deep(.el-checkbox-group) {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
::v-deep(.el-checkbox) {
|
||||
margin-right: 0;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.primary-btn {
|
||||
background: linear-gradient(135deg, #10b981 0%, #059669 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
padding: 14px 40px;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 4px 15px rgba(16, 185, 129, 0.4);
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.primary-btn:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(16, 185, 129, 0.6);
|
||||
}
|
||||
.primary-btn:disabled {
|
||||
opacity: 0.7;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.secondary-btn {
|
||||
background: var(--color-bg-secondary);
|
||||
color: var(--color-text-primary);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 8px;
|
||||
padding: 14px 40px;
|
||||
font-size: 1.1em;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
.secondary-btn:hover {
|
||||
background: var(--color-white-rgb-1);
|
||||
}
|
||||
|
||||
.error-message {
|
||||
margin-top: 20px;
|
||||
padding: 12px;
|
||||
background: rgba(255, 73, 73, 0.1);
|
||||
color: #ff4949;
|
||||
border-left: 4px solid #ff4949;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
/* 执行进度区 */
|
||||
.execution-panel {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
}
|
||||
|
||||
.execution-panel h3 {
|
||||
color: #10b981;
|
||||
font-size: 1.6em;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 8px;
|
||||
background: var(--color-border-primary);
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #10b981, #34d399);
|
||||
width: 50%;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.progress-fill.active {
|
||||
animation: progressIndeterminate 2s infinite ease-in-out;
|
||||
transform-origin: 0% 50%;
|
||||
}
|
||||
|
||||
@keyframes progressIndeterminate {
|
||||
0% { transform: translateX(-100%) scaleX(0.2); }
|
||||
50% { transform: translateX(0) scaleX(1); }
|
||||
100% { transform: translateX(200%) scaleX(0.2); }
|
||||
}
|
||||
|
||||
/* 结果区 */
|
||||
.result-panel {
|
||||
max-width: 900px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.success-header {
|
||||
text-align: center;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.success-icon {
|
||||
font-size: 64px;
|
||||
color: #10b981;
|
||||
margin-bottom: 16px;
|
||||
text-shadow: 0 4px 15px rgba(16, 185, 129, 0.3);
|
||||
}
|
||||
.success-header h3 {
|
||||
font-size: 1.8em;
|
||||
color: var(--color-text-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.metrics-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 24px;
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.metric-card {
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
.metric-icon {
|
||||
font-size: 32px;
|
||||
color: #10b981;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: rgba(16, 185, 129, 0.1);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
.metric-info {
|
||||
flex: 1;
|
||||
}
|
||||
.metric-value {
|
||||
font-size: 1.8em;
|
||||
font-weight: 700;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
.metric-value.highlight {
|
||||
color: #10b981;
|
||||
}
|
||||
.metric-label {
|
||||
color: var(--color-text-secondary);
|
||||
font-size: 0.9em;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.details-box {
|
||||
background: var(--color-bg-card);
|
||||
border: 1px solid var(--color-border-primary);
|
||||
border-radius: 12px;
|
||||
padding: 24px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.details-box h4 {
|
||||
margin: 0 0 20px 0;
|
||||
color: var(--color-text-primary);
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
.result-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 20px;
|
||||
}
|
||||
</style>
|
||||
@ -127,11 +127,12 @@ const CAD_SOFTWARE_DEFINITIONS = {
|
||||
apiVersion: 'v1',
|
||||
priority: 3,
|
||||
description: '工厂设计管理',
|
||||
features: ['status', 'piping'],
|
||||
features: ['status', 'piping', 'shrinkwrap'],
|
||||
endpoints: {
|
||||
connect: '/test',
|
||||
status: '/api/status/model',
|
||||
piping: '/api/v1/piping'
|
||||
piping: '/api/v1/piping',
|
||||
shrinkwrap: '/api/model/shrinkwrap'
|
||||
}
|
||||
},
|
||||
AUTOCAD: {
|
||||
|
||||
@ -13,7 +13,8 @@ export const PAGE_TYPES = {
|
||||
GEOMETRY_OPTIMIZATION_PARAMS: 'geometry-optimization-params',
|
||||
GEOMETRY_OPTIMIZATION_RESULT: 'geometry-optimization-result',
|
||||
FILE_MANAGEMENT: 'file-management',
|
||||
REVIT_ENVELOPE_OPTIMIZATION: 'revit-envelope-optimization'
|
||||
REVIT_ENVELOPE_OPTIMIZATION: 'revit-envelope-optimization',
|
||||
PDMS_SHRINKWRAP: 'pdms-shrinkwrap'
|
||||
}
|
||||
|
||||
// 需要CAD连接的页面
|
||||
@ -21,5 +22,6 @@ export const CAD_REQUIRED_PAGES = [
|
||||
PAGE_TYPES.MODEL_VIEWER,
|
||||
PAGE_TYPES.ANALYSIS_TOOLS,
|
||||
PAGE_TYPES.EXPORT_TOOLS,
|
||||
PAGE_TYPES.REVIT_ENVELOPE_OPTIMIZATION
|
||||
PAGE_TYPES.REVIT_ENVELOPE_OPTIMIZATION,
|
||||
PAGE_TYPES.PDMS_SHRINKWRAP
|
||||
]
|
||||
@ -35,6 +35,23 @@ class PdmsApiService {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行PDMS模型轻量化处理
|
||||
* @param {Object} params 轻量化参数
|
||||
* @returns {Promise<{success: boolean, data?: any, error?: string}>}
|
||||
*/
|
||||
async executeShrinkwrap(params) {
|
||||
const url = buildApiUrl(this.softwareName, 'shrinkwrap')
|
||||
|
||||
return await apiClient.post(url, params, {
|
||||
timeout: 600000, // 超时600s
|
||||
operationContext: {
|
||||
software: 'PDMS',
|
||||
operation: '模型轻量化处理'
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const pdmsApi = new PdmsApiService()
|
||||
|
||||
@ -66,6 +66,7 @@ import GeometryComplexityResult from '@/components/pages/GeometryComplexityResul
|
||||
import GeometryOptimizationParams from '@/components/pages/GeometryOptimizationParams.vue'
|
||||
import GeometryOptimizationResult from '@/components/pages/GeometryOptimizationResult.vue'
|
||||
import RevitEnvelopeOptimization from '@/components/pages/RevitEnvelopeOptimization.vue'
|
||||
import PdmsShrinkwrapPage from '@/components/pages/PdmsShrinkwrapPage.vue'
|
||||
import FileManagementPage from '@/components/pages/FileManagementPage.vue'
|
||||
import InfoManagementPanel from '@/components/layout/InfoManagementPanel.vue'
|
||||
import { PAGE_TYPES } from '@/config/pages'
|
||||
@ -112,7 +113,8 @@ const pageComponentMap = {
|
||||
[PAGE_TYPES.GEOMETRY_OPTIMIZATION_PARAMS]: GeometryOptimizationParams,
|
||||
[PAGE_TYPES.GEOMETRY_OPTIMIZATION_RESULT]: GeometryOptimizationResult,
|
||||
[PAGE_TYPES.FILE_MANAGEMENT]: FileManagementPage,
|
||||
[PAGE_TYPES.REVIT_ENVELOPE_OPTIMIZATION]: RevitEnvelopeOptimization
|
||||
[PAGE_TYPES.REVIT_ENVELOPE_OPTIMIZATION]: RevitEnvelopeOptimization,
|
||||
[PAGE_TYPES.PDMS_SHRINKWRAP]: PdmsShrinkwrapPage
|
||||
}
|
||||
|
||||
// 当前组件computed
|
||||
|
||||
Loading…
Reference in New Issue
Block a user