x
This commit is contained in:
+92
-70
@@ -1364,72 +1364,108 @@ optgroup {
|
|||||||
gap: var(--space-4);
|
gap: var(--space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mechanism-visual-grid {
|
.side-action-list {
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
|
||||||
gap: var(--space-4);
|
|
||||||
margin-top: var(--space-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mechanism-visual-card {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 220px minmax(0, 1fr);
|
|
||||||
gap: 0;
|
|
||||||
border: 1px solid var(--border-light);
|
|
||||||
border-radius: var(--radius-xl);
|
|
||||||
background: var(--bg-primary);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mechanism-visual-svg {
|
|
||||||
background: linear-gradient(180deg, #eff6ff 0%, #f8fafc 100%);
|
|
||||||
border-right: 1px solid var(--border-light);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
min-height: 180px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mechanism-svg {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mechanism-visual-body {
|
|
||||||
padding: var(--space-4);
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: var(--space-4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mechanism-kpis {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
||||||
gap: var(--space-3);
|
gap: var(--space-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mechanism-kpi {
|
.side-action-row {
|
||||||
padding: var(--space-3);
|
width: 100%;
|
||||||
border-radius: var(--radius-lg);
|
text-align: left;
|
||||||
background: var(--bg-secondary);
|
|
||||||
border: 1px solid var(--border-light);
|
border: 1px solid var(--border-light);
|
||||||
|
border-radius: var(--radius-xl);
|
||||||
|
padding: var(--space-4);
|
||||||
|
background: var(--bg-primary);
|
||||||
|
cursor: pointer;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-3);
|
||||||
|
transition: all var(--duration-fast) var(--ease-default);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mechanism-kpi-label {
|
.side-action-row:hover {
|
||||||
display: block;
|
border-color: var(--primary-200);
|
||||||
font-size: var(--text-xs);
|
box-shadow: var(--shadow-sm);
|
||||||
color: var(--text-tertiary);
|
transform: translateY(-1px);
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.04em;
|
|
||||||
margin-bottom: var(--space-1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mechanism-kpi-value {
|
.side-action-row-main {
|
||||||
display: block;
|
display: flex;
|
||||||
font-size: var(--text-sm);
|
flex-direction: column;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.side-action-row-title {
|
||||||
|
font-size: var(--text-base);
|
||||||
font-weight: var(--font-semibold);
|
font-weight: var(--font-semibold);
|
||||||
color: var(--text-primary);
|
color: var(--text-primary);
|
||||||
word-break: break-word;
|
}
|
||||||
|
|
||||||
|
.chip-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: var(--space-1) var(--space-3);
|
||||||
|
border-radius: var(--radius-full);
|
||||||
|
background: var(--bg-tertiary);
|
||||||
|
border: 1px solid var(--border-light);
|
||||||
|
font-size: var(--text-xs);
|
||||||
|
font-weight: var(--font-medium);
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.chip-risk {
|
||||||
|
background: #fff7ed;
|
||||||
|
border-color: #fde68a;
|
||||||
|
color: #9a3412;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
background: rgba(15, 23, 42, 0.35);
|
||||||
|
z-index: 2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-panel {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: min(520px, 92vw);
|
||||||
|
background: var(--bg-primary);
|
||||||
|
border-left: 1px solid var(--border-light);
|
||||||
|
box-shadow: var(--shadow-lg);
|
||||||
|
z-index: 2001;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: var(--space-5);
|
||||||
|
border-bottom: 1px solid var(--border-light);
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: var(--text-lg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.drawer-body {
|
||||||
|
padding: var(--space-5);
|
||||||
|
overflow-y: auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mechanism-card {
|
.mechanism-card {
|
||||||
@@ -1512,10 +1548,6 @@ optgroup {
|
|||||||
color: var(--primary-700);
|
color: var(--primary-700);
|
||||||
}
|
}
|
||||||
|
|
||||||
.mechanism-modal {
|
|
||||||
max-width: 860px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.single-scheme-grid {
|
.single-scheme-grid {
|
||||||
grid-template-columns: 1fr !important;
|
grid-template-columns: 1fr !important;
|
||||||
}
|
}
|
||||||
@@ -1548,18 +1580,8 @@ optgroup {
|
|||||||
.info-list {
|
.info-list {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
.drawer-panel {
|
||||||
.mechanism-visual-card {
|
width: 92vw;
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mechanism-visual-svg {
|
|
||||||
border-right: 0;
|
|
||||||
border-bottom: 1px solid var(--border-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mechanism-kpis {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+147
-114
@@ -1520,9 +1520,97 @@ const ResultView = {
|
|||||||
const sliderMechanisms = computed(() => selectedSideActions.value?.slider_mechanisms || []);
|
const sliderMechanisms = computed(() => selectedSideActions.value?.slider_mechanisms || []);
|
||||||
const lifterMechanisms = computed(() => selectedSideActions.value?.lifter_mechanisms || []);
|
const lifterMechanisms = computed(() => selectedSideActions.value?.lifter_mechanisms || []);
|
||||||
const sideActionRecommendations = computed(() => selectedSideActions.value?.recommendations || []);
|
const sideActionRecommendations = computed(() => selectedSideActions.value?.recommendations || []);
|
||||||
const allMechanisms = computed(() => {
|
const inferSliderDirectionKey = (vector) => {
|
||||||
const sliders = sliderMechanisms.value.map((item, index) => ({ type: 'slider', index, item }));
|
if (!Array.isArray(vector) || vector.length < 3) return null;
|
||||||
const lifters = lifterMechanisms.value.map((item, index) => ({ type: 'lifter', index, item }));
|
const values = vector.map(v => Number(v) || 0);
|
||||||
|
const abs = values.map(v => Math.abs(v));
|
||||||
|
const max = Math.max(...abs);
|
||||||
|
if (!max) return null;
|
||||||
|
const idx = abs.findIndex(v => v === max);
|
||||||
|
const axis = idx === 0 ? 'X' : idx === 1 ? 'Y' : 'Z';
|
||||||
|
const sign = values[idx] >= 0 ? '+' : '-';
|
||||||
|
return `${axis}${sign}`;
|
||||||
|
};
|
||||||
|
const demoldingDigest = computed(() => {
|
||||||
|
const sliders = sliderMechanisms.value.length;
|
||||||
|
const lifters = lifterMechanisms.value.length;
|
||||||
|
const total = sliders + lifters;
|
||||||
|
const hasHydraulic = Boolean(sideActionSummary.value?.has_hydraulic);
|
||||||
|
const complexity = sideActionSummary.value?.complexity || (total >= 6 ? 'very_complex' : total >= 4 ? 'complex' : total >= 2 ? 'moderate' : total === 1 ? 'simple' : 'none');
|
||||||
|
const directionKeys = new Set(
|
||||||
|
sliderMechanisms.value
|
||||||
|
.map(item => inferSliderDirectionKey(item.slide_direction))
|
||||||
|
.filter(Boolean)
|
||||||
|
);
|
||||||
|
const directionLabel = directionKeys.size <= 1 ? '单向' : '多向';
|
||||||
|
const riskLevel = hasHydraulic || total >= 5 ? '高' : total >= 3 ? '中' : total >= 1 ? '低' : '无';
|
||||||
|
const actions = (sideActionRecommendations.value || []).slice(0, 2);
|
||||||
|
return {
|
||||||
|
sliders,
|
||||||
|
lifters,
|
||||||
|
total,
|
||||||
|
hasHydraulic,
|
||||||
|
complexity,
|
||||||
|
directionLabel,
|
||||||
|
riskLevel,
|
||||||
|
actions
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const normalizeActuationLabel = (value) => {
|
||||||
|
const text = String(value || '').toLowerCase();
|
||||||
|
if (!text) return 'N/A';
|
||||||
|
if (text.includes('hydraulic')) return '液压';
|
||||||
|
if (text.includes('mechanical')) return '机械';
|
||||||
|
if (text.includes('spring')) return '弹簧';
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
const buildMechanismTags = (type, item = {}, totalCount = 0, hasHydraulic = false) => {
|
||||||
|
const tags = [];
|
||||||
|
const risks = [];
|
||||||
|
if (type === 'slider') {
|
||||||
|
if (item.slide_stroke != null) tags.push(`行程 ${Number(item.slide_stroke).toFixed(1)}mm`);
|
||||||
|
if (item.slide_angle != null) tags.push(`角度 ${Number(item.slide_angle).toFixed(1)}°`);
|
||||||
|
if (item.actuation) tags.push(`驱动 ${normalizeActuationLabel(item.actuation)}`);
|
||||||
|
if (item.slide_stroke != null && Number(item.slide_stroke) > 60) risks.push('行程偏大');
|
||||||
|
if (item.slide_angle != null && Number(item.slide_angle) > 25) risks.push('角度偏大');
|
||||||
|
} else if (type === 'lifter') {
|
||||||
|
if (item.lifter_angle != null) tags.push(`角度 ${Number(item.lifter_angle).toFixed(1)}°`);
|
||||||
|
if (item.lifter_stroke != null) tags.push(`行程 ${Number(item.lifter_stroke).toFixed(1)}mm`);
|
||||||
|
if (item.return_mechanism) tags.push(`回位 ${item.return_mechanism}`);
|
||||||
|
if (item.lifter_stroke != null && Number(item.lifter_stroke) > 60) risks.push('行程偏大');
|
||||||
|
if (item.lifter_angle != null && Number(item.lifter_angle) > 20) risks.push('角度偏大');
|
||||||
|
}
|
||||||
|
if (totalCount >= 5) risks.push('数量偏多');
|
||||||
|
if (hasHydraulic) risks.push('需液压评审');
|
||||||
|
return { tags, risks: risks.slice(0, 3) };
|
||||||
|
};
|
||||||
|
const mechanismRows = computed(() => {
|
||||||
|
const totalCount = demoldingDigest.value.total;
|
||||||
|
const hasHydraulic = demoldingDigest.value.hasHydraulic;
|
||||||
|
const sliders = sliderMechanisms.value.map((item, index) => {
|
||||||
|
const { tags, risks } = buildMechanismTags('slider', item, totalCount, hasHydraulic);
|
||||||
|
return {
|
||||||
|
id: `slider-${index}`,
|
||||||
|
type: 'slider',
|
||||||
|
index,
|
||||||
|
item,
|
||||||
|
title: `滑块 #${index + 1}`,
|
||||||
|
tags,
|
||||||
|
risks
|
||||||
|
};
|
||||||
|
});
|
||||||
|
const lifters = lifterMechanisms.value.map((item, index) => {
|
||||||
|
const { tags, risks } = buildMechanismTags('lifter', item, totalCount, hasHydraulic);
|
||||||
|
return {
|
||||||
|
id: `lifter-${index}`,
|
||||||
|
type: 'lifter',
|
||||||
|
index,
|
||||||
|
item,
|
||||||
|
title: `斜顶 #${index + 1}`,
|
||||||
|
tags,
|
||||||
|
risks
|
||||||
|
};
|
||||||
|
});
|
||||||
return [...sliders, ...lifters];
|
return [...sliders, ...lifters];
|
||||||
});
|
});
|
||||||
const dfmLevelSummary = computed(() => {
|
const dfmLevelSummary = computed(() => {
|
||||||
@@ -1568,7 +1656,7 @@ const ResultView = {
|
|||||||
{ id: 'candidate-schemes', label: '方案' },
|
{ id: 'candidate-schemes', label: '方案' },
|
||||||
{ id: 'preview-3d', label: '预览' },
|
{ id: 'preview-3d', label: '预览' },
|
||||||
{ id: 'engineering-summary', label: '工程摘要' },
|
{ id: 'engineering-summary', label: '工程摘要' },
|
||||||
{ id: 'side-actions', label: '抽芯建议' },
|
{ id: 'demolding-risk', label: '脱模风险' },
|
||||||
{ id: 'dfm-check', label: 'DFM' },
|
{ id: 'dfm-check', label: 'DFM' },
|
||||||
{ id: 'export-cam', label: '导出/CAM' },
|
{ id: 'export-cam', label: '导出/CAM' },
|
||||||
{ id: 'llm-report', label: '设计报告' }
|
{ id: 'llm-report', label: '设计报告' }
|
||||||
@@ -1640,53 +1728,10 @@ const ResultView = {
|
|||||||
return keys.map(key => `${key}:${Number(size[key]).toFixed(1)} mm`).join(' / ');
|
return keys.map(key => `${key}:${Number(size[key]).toFixed(1)} mm`).join(' / ');
|
||||||
};
|
};
|
||||||
const formatMechanismType = (type) => {
|
const formatMechanismType = (type) => {
|
||||||
if (type === 'slider') return '滑块抽芯';
|
if (type === 'slider') return '滑块';
|
||||||
if (type === 'lifter') return '斜顶抽芯';
|
if (type === 'lifter') return '斜顶';
|
||||||
return type || '机构';
|
return type || '机构';
|
||||||
};
|
};
|
||||||
const formatMechanismTypeShort = (type) => type === 'slider' ? '滑块' : type === 'lifter' ? '斜顶' : '机构';
|
|
||||||
const normalizeVector = (vector, fallback = [0.8, -0.6, 0.5]) => {
|
|
||||||
if (!Array.isArray(vector) || vector.length < 3) return fallback;
|
|
||||||
const values = vector.map(v => Number(v) || 0);
|
|
||||||
const length = Math.sqrt(values.reduce((acc, val) => acc + val * val, 0));
|
|
||||||
if (!length) return fallback;
|
|
||||||
return values.map(v => v / length);
|
|
||||||
};
|
|
||||||
const mechanismSchematicSvg = (type, item = {}) => {
|
|
||||||
const direction = normalizeVector(type === 'slider' ? item.slide_direction : item.location);
|
|
||||||
const location = normalizeVector(item.location, [0.3, 0.2, 0.5]);
|
|
||||||
const startX = 120 + (location[0] * 18);
|
|
||||||
const startY = 90 - (location[1] * 16);
|
|
||||||
const endX = startX + (direction[0] * 42);
|
|
||||||
const endY = startY - (direction[2] * 28) + (direction[1] * 12);
|
|
||||||
const mechanismColor = type === 'slider' ? '#2563eb' : '#7c3aed';
|
|
||||||
const label = type === 'slider' ? '滑块抽芯' : '斜顶抽芯';
|
|
||||||
return `
|
|
||||||
<svg viewBox="0 0 240 180" class="mechanism-svg" xmlns="http://www.w3.org/2000/svg" aria-label="${label}三维示意图">
|
|
||||||
<defs>
|
|
||||||
<linearGradient id="cubeTop" x1="0" y1="0" x2="1" y2="1">
|
|
||||||
<stop offset="0%" stop-color="#f8fafc" />
|
|
||||||
<stop offset="100%" stop-color="#dbeafe" />
|
|
||||||
</linearGradient>
|
|
||||||
<linearGradient id="cubeSide" x1="0" y1="0" x2="1" y2="1">
|
|
||||||
<stop offset="0%" stop-color="#cbd5e1" />
|
|
||||||
<stop offset="100%" stop-color="#94a3b8" />
|
|
||||||
</linearGradient>
|
|
||||||
<marker id="arrowHead" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse">
|
|
||||||
<path d="M 0 0 L 10 5 L 0 10 z" fill="${mechanismColor}" />
|
|
||||||
</marker>
|
|
||||||
</defs>
|
|
||||||
<rect x="22" y="24" width="196" height="132" rx="18" fill="#f8fafc" stroke="#dbeafe" />
|
|
||||||
<polygon points="72,60 132,38 184,62 124,84" fill="url(#cubeTop)" stroke="#94a3b8" />
|
|
||||||
<polygon points="124,84 184,62 184,118 124,140" fill="url(#cubeSide)" stroke="#94a3b8" />
|
|
||||||
<polygon points="72,60 124,84 124,140 72,116" fill="#e2e8f0" stroke="#94a3b8" />
|
|
||||||
<circle cx="${startX.toFixed(1)}" cy="${startY.toFixed(1)}" r="8" fill="${mechanismColor}" fill-opacity="0.92" />
|
|
||||||
<line x1="${startX.toFixed(1)}" y1="${startY.toFixed(1)}" x2="${endX.toFixed(1)}" y2="${endY.toFixed(1)}" stroke="${mechanismColor}" stroke-width="5" stroke-linecap="round" marker-end="url(#arrowHead)" />
|
|
||||||
<text x="28" y="42" fill="#0f172a" font-size="12" font-weight="700">${label}</text>
|
|
||||||
<text x="28" y="58" fill="#475569" font-size="11">基于机构方向与位置生成的三维示意</text>
|
|
||||||
</svg>
|
|
||||||
`;
|
|
||||||
};
|
|
||||||
const escapeHtml = (value) => String(value || '')
|
const escapeHtml = (value) => String(value || '')
|
||||||
.replace(/&/g, '&')
|
.replace(/&/g, '&')
|
||||||
.replace(/</g, '<')
|
.replace(/</g, '<')
|
||||||
@@ -1885,7 +1930,8 @@ const ResultView = {
|
|||||||
sliderMechanisms,
|
sliderMechanisms,
|
||||||
lifterMechanisms,
|
lifterMechanisms,
|
||||||
sideActionRecommendations,
|
sideActionRecommendations,
|
||||||
allMechanisms,
|
demoldingDigest,
|
||||||
|
mechanismRows,
|
||||||
dfmLevelSummary,
|
dfmLevelSummary,
|
||||||
llmReportHtml,
|
llmReportHtml,
|
||||||
stageTimingEntries,
|
stageTimingEntries,
|
||||||
@@ -1897,8 +1943,6 @@ const ResultView = {
|
|||||||
formatVector,
|
formatVector,
|
||||||
formatMechanismSize,
|
formatMechanismSize,
|
||||||
formatMechanismType,
|
formatMechanismType,
|
||||||
formatMechanismTypeShort,
|
|
||||||
mechanismSchematicSvg,
|
|
||||||
openMechanismDetail,
|
openMechanismDetail,
|
||||||
closeMechanismDetail,
|
closeMechanismDetail,
|
||||||
primaryRecommendation,
|
primaryRecommendation,
|
||||||
@@ -2291,84 +2335,73 @@ const ResultView = {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="side-actions" v-if="selectedSideActions && (sliderMechanisms.length || lifterMechanisms.length || sideActionRecommendations.length)" class="viewer-section">
|
<div id="demolding-risk" v-if="selectedSideActions && demoldingDigest.total" class="viewer-section">
|
||||||
<h3>倒扣与抽芯建议</h3>
|
<h3>脱模风险摘要</h3>
|
||||||
<div class="result-grid">
|
<div class="result-grid">
|
||||||
<div class="result-card">
|
<div class="result-card">
|
||||||
<h4>总体摘要</h4>
|
<h4>结论</h4>
|
||||||
<div class="info-list">
|
<div class="info-list">
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="info-label">倒扣面总数</span>
|
<span class="info-label">侧向机构</span>
|
||||||
<span class="info-value">{{ sideActionSummary.total_undercut_faces || getUndercutCount() }}</span>
|
<span class="info-value">滑块 {{ demoldingDigest.sliders }} / 斜顶 {{ demoldingDigest.lifters }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="info-label">滑块数量</span>
|
<span class="info-label">抽芯方向</span>
|
||||||
<span class="info-value">{{ sideActionSummary.total_slider_count || sliderMechanisms.length }}</span>
|
<span class="info-value">{{ demoldingDigest.directionLabel }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="info-label">斜顶数量</span>
|
<span class="info-label">复杂度</span>
|
||||||
<span class="info-value">{{ sideActionSummary.total_lifter_count || lifterMechanisms.length }}</span>
|
<span class="info-value">{{ demoldingDigest.complexity }}</span>
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">机构复杂度</span>
|
|
||||||
<span class="info-value">{{ sideActionSummary.complexity || 'N/A' }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
<span class="info-label">液压抽芯</span>
|
<span class="info-label">液压抽芯</span>
|
||||||
<span class="info-value">{{ sideActionSummary.has_hydraulic ? '需要' : '暂不需要' }}</span>
|
<span class="info-value">{{ demoldingDigest.hasHydraulic ? '需要' : '暂不需要' }}</span>
|
||||||
</div>
|
|
||||||
<div class="info-item">
|
|
||||||
<span class="info-label">建议动作</span>
|
|
||||||
<span class="info-value">{{ sideActionRecommendations[0] || '当前方案未返回额外抽芯建议' }}</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="inline-note">建议先用上方 3D 预览确认倒扣区域的空间位置,再查看侧向机构清单。</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="result-card">
|
||||||
|
<h4>风险与下一步</h4>
|
||||||
<div class="mechanism-visual-grid" v-if="allMechanisms.length">
|
<div class="recommendations-list">
|
||||||
<div class="mechanism-visual-card" v-for="mechanism in allMechanisms" :key="mechanism.type + '-' + mechanism.index">
|
<div class="recommendation-item high" v-if="demoldingDigest.riskLevel === '高'">
|
||||||
<div class="mechanism-visual-svg" v-html="mechanismSchematicSvg(mechanism.type, mechanism.item)"></div>
|
<div class="recommendation-text">侧向机构数量或液压抽芯提示较多,建议优先做结构优化与干涉评审,再进入制造准备。</div>
|
||||||
<div class="mechanism-visual-body">
|
|
||||||
<div class="mechanism-title">{{ formatMechanismType(mechanism.type) }} {{ mechanism.index + 1 }}</div>
|
|
||||||
<div class="mechanism-kpis">
|
|
||||||
<div class="mechanism-kpi">
|
|
||||||
<span class="mechanism-kpi-label">位置</span>
|
|
||||||
<span class="mechanism-kpi-value">{{ formatVector(mechanism.item.location) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="mechanism-kpi" v-if="mechanism.type === 'slider'">
|
|
||||||
<span class="mechanism-kpi-label">行程</span>
|
|
||||||
<span class="mechanism-kpi-value">{{ mechanism.item.slide_stroke || 'N/A' }} mm</span>
|
|
||||||
</div>
|
|
||||||
<div class="mechanism-kpi" v-if="mechanism.type === 'slider'">
|
|
||||||
<span class="mechanism-kpi-label">方向</span>
|
|
||||||
<span class="mechanism-kpi-value">{{ formatVector(mechanism.item.slide_direction) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="mechanism-kpi" v-if="mechanism.type === 'lifter'">
|
|
||||||
<span class="mechanism-kpi-label">角度</span>
|
|
||||||
<span class="mechanism-kpi-value">{{ mechanism.item.lifter_angle || 'N/A' }}°</span>
|
|
||||||
</div>
|
|
||||||
<div class="mechanism-kpi" v-if="mechanism.type === 'lifter'">
|
|
||||||
<span class="mechanism-kpi-label">行程</span>
|
|
||||||
<span class="mechanism-kpi-value">{{ mechanism.item.lifter_stroke || 'N/A' }} mm</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="mechanism-actions">
|
<div class="recommendation-item medium" v-else-if="demoldingDigest.riskLevel === '中'">
|
||||||
<button class="btn-sm btn-secondary" @click="openMechanismDetail(mechanism.type, mechanism.index, mechanism.item)">查看详情</button>
|
<div class="recommendation-text">侧向机构数量适中,建议结合 3D 预览复核抽芯方向与行程空间。</div>
|
||||||
|
</div>
|
||||||
|
<div class="recommendation-item low" v-else>
|
||||||
|
<div class="recommendation-text">侧向机构较少,可进入 DFM 复核与导出准备。</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="recommendations-list" v-if="demoldingDigest.actions.length">
|
||||||
</div>
|
<div class="recommendation-item medium" v-for="(rec, idx) in demoldingDigest.actions" :key="'demolding-action-' + idx">
|
||||||
|
<div class="recommendation-text">{{ rec }}</div>
|
||||||
<div class="result-card full-width" v-if="sideActionRecommendations.length">
|
</div>
|
||||||
<h4>总体建议</h4>
|
|
||||||
<div class="recommendations-list">
|
|
||||||
<div class="recommendation-item medium" v-for="(rec, idx) in sideActionRecommendations" :key="'side-rec-' + idx">
|
|
||||||
<div class="recommendation-text">{{ rec }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div class="inline-note" v-else>当前方案未返回额外侧向机构建议。</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<details id="side-action-list" v-if="mechanismRows.length" class="viewer-section diagnostic-panel compact-panel">
|
||||||
|
<summary>侧向机构清单(滑块 {{ demoldingDigest.sliders }} / 斜顶 {{ demoldingDigest.lifters }})</summary>
|
||||||
|
<div class="diagnostic-panel-body">
|
||||||
|
<div class="side-action-list">
|
||||||
|
<button class="side-action-row" v-for="row in mechanismRows" :key="row.id" @click="openMechanismDetail(row.type, row.index, row.item)">
|
||||||
|
<div class="side-action-row-main">
|
||||||
|
<div class="side-action-row-title">{{ row.title }}</div>
|
||||||
|
<div class="chip-row">
|
||||||
|
<span class="chip" v-for="(tag, tagIdx) in row.tags" :key="row.id + '-tag-' + tagIdx">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chip-row chip-row-risk" v-if="row.risks.length">
|
||||||
|
<span class="chip chip-risk" v-for="(tag, tagIdx) in row.risks" :key="row.id + '-risk-' + tagIdx">{{ tag }}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</details>
|
||||||
|
|
||||||
<div id="dfm-check" class="viewer-section">
|
<div id="dfm-check" class="viewer-section">
|
||||||
<h3>DFM 检查</h3>
|
<h3>DFM 检查</h3>
|
||||||
<div class="result-grid" v-if="selectedDfmViolations.length">
|
<div class="result-grid" v-if="selectedDfmViolations.length">
|
||||||
@@ -2400,7 +2433,7 @@ const ResultView = {
|
|||||||
<div class="recommendation-text">当前方案存在较高工艺风险,建议优先调整壁厚、倒扣或分型方式后再进入制造准备。</div>
|
<div class="recommendation-text">当前方案存在较高工艺风险,建议优先调整壁厚、倒扣或分型方式后再进入制造准备。</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="recommendation-item medium" v-else>
|
<div class="recommendation-item medium" v-else>
|
||||||
<div class="recommendation-text">当前方案未发现显著高风险项,可结合 3D 预览和抽芯建议继续做工程评审。</div>
|
<div class="recommendation-text">当前方案未发现显著高风险项,可结合 3D 预览与脱模风险摘要继续做工程评审。</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2416,7 +2449,7 @@ const ResultView = {
|
|||||||
<span class="priority-badge" :class="(item.level || 'medium').toLowerCase()">{{ getPriorityText((item.level || 'medium').toLowerCase()) }}</span>
|
<span class="priority-badge" :class="(item.level || 'medium').toLowerCase()">{{ getPriorityText((item.level || 'medium').toLowerCase()) }}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="dfm-card-message">{{ item.message || 'N/A' }}</div>
|
<div class="dfm-card-message">{{ item.message || 'N/A' }}</div>
|
||||||
<div class="dfm-card-hint">建议结合上方 3D 预览与抽芯示意定位具体风险区域。</div>
|
<div class="dfm-card-hint">建议结合上方 3D 预览与侧向机构清单定位具体风险区域。</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -2541,13 +2574,13 @@ const ResultView = {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="state.activeMechanismDetail" class="modal-overlay" @click.self="closeMechanismDetail">
|
<div v-if="state.activeMechanismDetail" class="drawer-overlay" @click.self="closeMechanismDetail">
|
||||||
<div class="modal-content mechanism-modal">
|
<div class="drawer-panel">
|
||||||
<div class="modal-header">
|
<div class="drawer-header">
|
||||||
<h3>{{ formatMechanismType(state.activeMechanismDetail.type) }} {{ state.activeMechanismDetail.index + 1 }}</h3>
|
<h3>{{ formatMechanismType(state.activeMechanismDetail.type) }} {{ state.activeMechanismDetail.index + 1 }}</h3>
|
||||||
<button class="modal-close" @click="closeMechanismDetail">×</button>
|
<button class="modal-close" @click="closeMechanismDetail">×</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="drawer-body">
|
||||||
<div class="result-card">
|
<div class="result-card">
|
||||||
<div class="info-list">
|
<div class="info-list">
|
||||||
<div class="info-item">
|
<div class="info-item">
|
||||||
|
|||||||
Reference in New Issue
Block a user