|
@@ -362,10 +362,10 @@
|
|
<div class="detail-section">
|
|
<div class="detail-section">
|
|
<div class="section-header">
|
|
<div class="section-header">
|
|
<h4>材质规格与分类</h4>
|
|
<h4>材质规格与分类</h4>
|
|
- <span class="section-count">{{ proposalAnalysis?.materials?.length || 0 }} 类材质</span>
|
|
|
|
|
|
+ <span class="section-count">{{ (proposalAnalysis && proposalAnalysis.materials ? proposalAnalysis.materials.length : 0) }} 类材质</span>
|
|
</div>
|
|
</div>
|
|
<div class="materials-grid">
|
|
<div class="materials-grid">
|
|
- @for (material of proposalAnalysis?.materials || []; track material.category) {
|
|
|
|
|
|
+ @for (material of (proposalAnalysis && proposalAnalysis.materials ? proposalAnalysis.materials : []); track material.category) {
|
|
<div class="material-card" [class]="material.usage.priority">
|
|
<div class="material-card" [class]="material.usage.priority">
|
|
<div class="material-header">
|
|
<div class="material-header">
|
|
<h5>{{ material.category }}</h5>
|
|
<h5>{{ material.category }}</h5>
|
|
@@ -398,10 +398,10 @@
|
|
<div class="detail-section">
|
|
<div class="detail-section">
|
|
<div class="section-header">
|
|
<div class="section-header">
|
|
<h4>设计风格特征</h4>
|
|
<h4>设计风格特征</h4>
|
|
- <span class="style-name">{{ proposalAnalysis?.designStyle?.primaryStyle || '未定义' }}</span>
|
|
|
|
|
|
+ <span class="style-name">{{ (proposalAnalysis && proposalAnalysis.designStyle ? proposalAnalysis.designStyle.primaryStyle : null) || '未定义' }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="style-elements">
|
|
<div class="style-elements">
|
|
- @for (element of proposalAnalysis?.designStyle?.styleElements || []; track element.element) {
|
|
|
|
|
|
+ @for (element of (proposalAnalysis && proposalAnalysis.designStyle && proposalAnalysis.designStyle.styleElements ? proposalAnalysis.designStyle.styleElements : []); track element.element) {
|
|
<div class="style-element">
|
|
<div class="style-element">
|
|
<div class="element-header">
|
|
<div class="element-header">
|
|
<span class="element-name">{{ element.element }}</span>
|
|
<span class="element-name">{{ element.element }}</span>
|
|
@@ -415,7 +415,7 @@
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="style-characteristics">
|
|
<div class="style-characteristics">
|
|
- @for (char of proposalAnalysis?.designStyle?.characteristics || []; track char.feature) {
|
|
|
|
|
|
+ @for (char of (proposalAnalysis && proposalAnalysis.designStyle && proposalAnalysis.designStyle.characteristics ? proposalAnalysis.designStyle.characteristics : []); track char.feature) {
|
|
<div class="characteristic-item" [class]="char.importance">
|
|
<div class="characteristic-item" [class]="char.importance">
|
|
<span class="char-feature">{{ char.feature }}</span>
|
|
<span class="char-feature">{{ char.feature }}</span>
|
|
<span class="char-value">{{ char.value }}</span>
|
|
<span class="char-value">{{ char.value }}</span>
|
|
@@ -428,10 +428,10 @@
|
|
<div class="detail-section">
|
|
<div class="detail-section">
|
|
<div class="section-header">
|
|
<div class="section-header">
|
|
<h4>色彩搭配方案及占比分析</h4>
|
|
<h4>色彩搭配方案及占比分析</h4>
|
|
- <span class="harmony-type">{{ proposalAnalysis?.colorScheme?.harmony?.type || '未定义' }}</span>
|
|
|
|
|
|
+ <span class="harmony-type">{{ (proposalAnalysis && proposalAnalysis.colorScheme && proposalAnalysis.colorScheme.harmony ? proposalAnalysis.colorScheme.harmony.type : null) || '未定义' }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="color-palette">
|
|
<div class="color-palette">
|
|
- @for (color of proposalAnalysis?.colorScheme?.palette || []; track color.hex) {
|
|
|
|
|
|
+ @for (color of (proposalAnalysis && proposalAnalysis.colorScheme && proposalAnalysis.colorScheme.palette ? proposalAnalysis.colorScheme.palette : []); track color.hex) {
|
|
<div class="color-item" [class]="color.role">
|
|
<div class="color-item" [class]="color.role">
|
|
<div class="color-swatch" [style.background-color]="color.hex"></div>
|
|
<div class="color-swatch" [style.background-color]="color.hex"></div>
|
|
<div class="color-info">
|
|
<div class="color-info">
|
|
@@ -449,11 +449,11 @@
|
|
<div class="color-psychology">
|
|
<div class="color-psychology">
|
|
<div class="psychology-item">
|
|
<div class="psychology-item">
|
|
<span class="label">氛围营造</span>
|
|
<span class="label">氛围营造</span>
|
|
- <span class="value">{{ proposalAnalysis?.colorScheme?.psychology?.mood || '未定义' }}</span>
|
|
|
|
|
|
+ <span class="value">{{ (proposalAnalysis && proposalAnalysis.colorScheme && proposalAnalysis.colorScheme.psychology ? proposalAnalysis.colorScheme.psychology.mood : null) || '未定义' }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="psychology-item">
|
|
<div class="psychology-item">
|
|
<span class="label">空间感受</span>
|
|
<span class="label">空间感受</span>
|
|
- <span class="value">{{ proposalAnalysis?.colorScheme?.psychology?.atmosphere || '未定义' }}</span>
|
|
|
|
|
|
+ <span class="value">{{ (proposalAnalysis && proposalAnalysis.colorScheme && proposalAnalysis.colorScheme.psychology ? proposalAnalysis.colorScheme.psychology.atmosphere : null) || '未定义' }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@@ -462,28 +462,28 @@
|
|
<div class="detail-section">
|
|
<div class="detail-section">
|
|
<div class="section-header">
|
|
<div class="section-header">
|
|
<h4>空间尺寸数据及功能分区</h4>
|
|
<h4>空间尺寸数据及功能分区</h4>
|
|
- <span class="total-area">总面积 {{ proposalAnalysis?.spaceLayout?.dimensions?.area || 0 }}㎡</span>
|
|
|
|
|
|
+ <span class="total-area">总面积 {{ (proposalAnalysis && proposalAnalysis.spaceLayout && proposalAnalysis.spaceLayout.dimensions ? proposalAnalysis.spaceLayout.dimensions.area : 0) || 0 }}㎡</span>
|
|
</div>
|
|
</div>
|
|
<div class="space-dimensions">
|
|
<div class="space-dimensions">
|
|
<div class="dimension-item">
|
|
<div class="dimension-item">
|
|
<span class="dim-label">长度</span>
|
|
<span class="dim-label">长度</span>
|
|
- <span class="dim-value">{{ proposalAnalysis?.spaceLayout?.dimensions?.length || 0 }}m</span>
|
|
|
|
|
|
+ <span class="dim-value">{{ (proposalAnalysis && proposalAnalysis.spaceLayout && proposalAnalysis.spaceLayout.dimensions ? proposalAnalysis.spaceLayout.dimensions.length : 0) || 0 }}m</span>
|
|
</div>
|
|
</div>
|
|
<div class="dimension-item">
|
|
<div class="dimension-item">
|
|
<span class="dim-label">宽度</span>
|
|
<span class="dim-label">宽度</span>
|
|
- <span class="dim-value">{{ proposalAnalysis?.spaceLayout?.dimensions?.width || 0 }}m</span>
|
|
|
|
|
|
+ <span class="dim-value">{{ (proposalAnalysis && proposalAnalysis.spaceLayout && proposalAnalysis.spaceLayout.dimensions ? proposalAnalysis.spaceLayout.dimensions.width : 0) || 0 }}m</span>
|
|
</div>
|
|
</div>
|
|
<div class="dimension-item">
|
|
<div class="dimension-item">
|
|
<span class="dim-label">层高</span>
|
|
<span class="dim-label">层高</span>
|
|
- <span class="dim-value">{{ proposalAnalysis?.spaceLayout?.dimensions?.height || 0 }}m</span>
|
|
|
|
|
|
+ <span class="dim-value">{{ (proposalAnalysis && proposalAnalysis.spaceLayout && proposalAnalysis.spaceLayout.dimensions ? proposalAnalysis.spaceLayout.dimensions.height : 0) || 0 }}m</span>
|
|
</div>
|
|
</div>
|
|
<div class="dimension-item">
|
|
<div class="dimension-item">
|
|
<span class="dim-label">体积</span>
|
|
<span class="dim-label">体积</span>
|
|
- <span class="dim-value">{{ proposalAnalysis?.spaceLayout?.dimensions?.volume || 0 }}m³</span>
|
|
|
|
|
|
+ <span class="dim-value">{{ (proposalAnalysis && proposalAnalysis.spaceLayout && proposalAnalysis.spaceLayout.dimensions ? proposalAnalysis.spaceLayout.dimensions.volume : 0) || 0 }}m³</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="functional-zones">
|
|
<div class="functional-zones">
|
|
- @for (zone of proposalAnalysis?.spaceLayout?.functionalZones || []; track zone.zone) {
|
|
|
|
|
|
+ @for (zone of (proposalAnalysis && proposalAnalysis.spaceLayout && proposalAnalysis.spaceLayout.functionalZones ? proposalAnalysis.spaceLayout.functionalZones : []); track zone.zone) {
|
|
<div class="zone-card">
|
|
<div class="zone-card">
|
|
<div class="zone-header">
|
|
<div class="zone-header">
|
|
<h5>{{ zone.zone }}</h5>
|
|
<h5>{{ zone.zone }}</h5>
|
|
@@ -517,10 +517,10 @@
|
|
<div class="detail-section">
|
|
<div class="detail-section">
|
|
<div class="section-header">
|
|
<div class="section-header">
|
|
<h4>预算与时间线</h4>
|
|
<h4>预算与时间线</h4>
|
|
- <span class="total-budget">总预算 ¥{{ (proposalAnalysis?.budget?.total || 0).toLocaleString() }}</span>
|
|
|
|
|
|
+ <span class="total-budget">总预算 ¥{{ ((proposalAnalysis && proposalAnalysis.budget ? proposalAnalysis.budget.total : 0) || 0).toLocaleString() }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="budget-breakdown">
|
|
<div class="budget-breakdown">
|
|
- @for (item of proposalAnalysis?.budget?.breakdown || []; track item.category) {
|
|
|
|
|
|
+ @for (item of (proposalAnalysis && proposalAnalysis.budget && proposalAnalysis.budget.breakdown ? proposalAnalysis.budget.breakdown : []); track item.category) {
|
|
<div class="budget-item">
|
|
<div class="budget-item">
|
|
<div class="budget-category">{{ item.category }}</div>
|
|
<div class="budget-category">{{ item.category }}</div>
|
|
<div class="budget-amount">¥{{ item.amount.toLocaleString() }}</div>
|
|
<div class="budget-amount">¥{{ item.amount.toLocaleString() }}</div>
|
|
@@ -532,7 +532,7 @@
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
<div class="timeline">
|
|
<div class="timeline">
|
|
- @for (phase of proposalAnalysis?.timeline || []; track phase.phase) {
|
|
|
|
|
|
+ @for (phase of (proposalAnalysis && proposalAnalysis.timeline ? proposalAnalysis.timeline : []); track phase.phase) {
|
|
<div class="timeline-item">
|
|
<div class="timeline-item">
|
|
<div class="phase-name">{{ phase.phase }}</div>
|
|
<div class="phase-name">{{ phase.phase }}</div>
|
|
<div class="phase-duration">{{ phase.duration }}天</div>
|
|
<div class="phase-duration">{{ phase.duration }}天</div>
|
|
@@ -673,28 +673,28 @@
|
|
</div>
|
|
</div>
|
|
<div class="settlement-automation">
|
|
<div class="settlement-automation">
|
|
<div class="automation-features">
|
|
<div class="automation-features">
|
|
- <div class="feature-card">
|
|
|
|
|
|
+ <div class="feature-card clickable" (click)="showFeatureDetail('自动触发流程', '技术验收完成后,系统会自动创建尾款结算记录,并通知客服跟进。整个流程无需人工干预,提高结算效率。')">
|
|
<div class="feature-icon">🤖</div>
|
|
<div class="feature-icon">🤖</div>
|
|
<div class="feature-content">
|
|
<div class="feature-content">
|
|
<h4>自动触发流程</h4>
|
|
<h4>自动触发流程</h4>
|
|
<p>技术验收完成后自动发起尾款结算申请</p>
|
|
<p>技术验收完成后自动发起尾款结算申请</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- <div class="feature-card">
|
|
|
|
|
|
+ <div class="feature-card clickable" (click)="showFeatureDetail('自动解密发送', '客户通过小程序完成支付后,系统自动解锁渲染大图,并一键发送给客户,无需手动操作。')">
|
|
<div class="feature-icon">🔓</div>
|
|
<div class="feature-icon">🔓</div>
|
|
<div class="feature-content">
|
|
<div class="feature-content">
|
|
<h4>自动解密发送</h4>
|
|
<h4>自动解密发送</h4>
|
|
<p>小程序支付自动解密并发送大图给客户</p>
|
|
<p>小程序支付自动解密并发送大图给客户</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- <div class="feature-card">
|
|
|
|
|
|
+ <div class="feature-card clickable" (click)="showFeatureDetail('凭证智能识别', '上传微信或支付宝支付截图后,AI自动识别支付金额、支付方式和支付时间,提高录入效率。')">
|
|
<div class="feature-icon">📱</div>
|
|
<div class="feature-icon">📱</div>
|
|
<div class="feature-content">
|
|
<div class="feature-content">
|
|
<h4>凭证智能识别</h4>
|
|
<h4>凭证智能识别</h4>
|
|
<p>上传微信/支付宝截图自动提取金额和支付方式</p>
|
|
<p>上传微信/支付宝截图自动提取金额和支付方式</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- <div class="feature-card">
|
|
|
|
|
|
+ <div class="feature-card clickable" (click)="showFeatureDetail('自动通知', '支付完成后,系统自动向客户和相关人员发送通知,告知尾款已到账、大图已解锁,确保信息及时传达。')">
|
|
<div class="feature-icon">🔔</div>
|
|
<div class="feature-icon">🔔</div>
|
|
<div class="feature-content">
|
|
<div class="feature-content">
|
|
<h4>自动通知</h4>
|
|
<h4>自动通知</h4>
|
|
@@ -710,10 +710,19 @@
|
|
<button
|
|
<button
|
|
class="primary-btn automation-btn"
|
|
class="primary-btn automation-btn"
|
|
(click)="initiateAutoSettlement()"
|
|
(click)="initiateAutoSettlement()"
|
|
- [disabled]="isAutoSettling">
|
|
|
|
- @if (isAutoSettling) { <span class="loading-spinner"></span> 自动化处理中... } @else { 🚀 启动自动化结算 }
|
|
|
|
|
|
+ [disabled]="isAutoSettling"
|
|
|
|
+ type="button">
|
|
|
|
+ @if (isAutoSettling) {
|
|
|
|
+ <span class="loading-spinner"></span>
|
|
|
|
+ <span>自动化处理中...</span>
|
|
|
|
+ } @else {
|
|
|
|
+ <span>🚀 启动自动化结算</span>
|
|
|
|
+ }
|
|
|
|
+ </button>
|
|
|
|
+ <button class="secondary-btn" (click)="uploadPaymentProof()" type="button">
|
|
|
|
+ <span class="upload-icon">📎</span>
|
|
|
|
+ <span>上传支付凭证</span>
|
|
</button>
|
|
</button>
|
|
- <button class="secondary-btn" (click)="uploadPaymentProof()"><span class="upload-icon">📎</span> 上传支付凭证</button>
|
|
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
@@ -727,21 +736,21 @@
|
|
</div>
|
|
</div>
|
|
<div class="panoramic-synthesis">
|
|
<div class="panoramic-synthesis">
|
|
<div class="panoramic-features">
|
|
<div class="panoramic-features">
|
|
- <div class="feature-card">
|
|
|
|
|
|
+ <div class="feature-card clickable" (click)="showFeatureDetail('KR Panel集成', '系统集成了专业的KR Panel全景图合成工具,支持高质量全景图生成,确保最终效果达到行业标准。')">
|
|
<div class="feature-icon">🖥️</div>
|
|
<div class="feature-icon">🖥️</div>
|
|
<div class="feature-content">
|
|
<div class="feature-content">
|
|
<h4>KR Panel集成</h4>
|
|
<h4>KR Panel集成</h4>
|
|
<p>集成专业全景图合成工具,确保合成质量</p>
|
|
<p>集成专业全景图合成工具,确保合成质量</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- <div class="feature-card">
|
|
|
|
|
|
+ <div class="feature-card clickable" (click)="showFeatureDetail('智能空间标注', '技术人员上传图片时,系统会智能识别文件名中的空间信息(如「客厅-角度1.jpg」),自动完成空间分类和标注。')">
|
|
<div class="feature-icon">📸</div>
|
|
<div class="feature-icon">📸</div>
|
|
<div class="feature-content">
|
|
<div class="feature-content">
|
|
<h4>智能空间标注</h4>
|
|
<h4>智能空间标注</h4>
|
|
<p>技术上传图片并标注空间名称(如"客厅-角度1")</p>
|
|
<p>技术上传图片并标注空间名称(如"客厅-角度1")</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- <div class="feature-card">
|
|
|
|
|
|
+ <div class="feature-card clickable" (click)="showFeatureDetail('自动生成链接', '全景图合成完成后,系统自动生成可分享的漫游链接,客户可以通过链接在线浏览360度全景效果。')">
|
|
<div class="feature-icon">🔗</div>
|
|
<div class="feature-icon">🔗</div>
|
|
<div class="feature-content">
|
|
<div class="feature-content">
|
|
<h4>自动生成链接</h4>
|
|
<h4>自动生成链接</h4>
|
|
@@ -765,8 +774,12 @@
|
|
</div>
|
|
</div>
|
|
@if (canEditSection('aftercare')) {
|
|
@if (canEditSection('aftercare')) {
|
|
<div class="panoramic-actions">
|
|
<div class="panoramic-actions">
|
|
- <button class="primary-btn" (click)="startPanoramicSynthesis()">开始合成</button>
|
|
|
|
- <button class="secondary-btn" (click)="viewPanoramicGallery()">查看全景图库</button>
|
|
|
|
|
|
+ <button class="primary-btn" (click)="startPanoramicSynthesis()" type="button">
|
|
|
|
+ <span>🎨 开始合成</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button class="secondary-btn" (click)="viewPanoramicGallery()" type="button">
|
|
|
|
+ <span>📁 查看全景图库</span>
|
|
|
|
+ </button>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
@@ -792,8 +805,12 @@
|
|
</div>
|
|
</div>
|
|
@if (canEditSection('aftercare')) {
|
|
@if (canEditSection('aftercare')) {
|
|
<div class="review-actions">
|
|
<div class="review-actions">
|
|
- <button class="primary-btn" (click)="confirmCustomerReview()">✅ 确认评价完成</button>
|
|
|
|
- <button class="secondary-btn" (click)="generateReviewLink()">🔗 生成评价链接</button>
|
|
|
|
|
|
+ <button class="primary-btn" (click)="generateReviewLink()" type="button">
|
|
|
|
+ <span>🔗 生成评价链接</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button class="secondary-btn" (click)="confirmCustomerReview()" type="button">
|
|
|
|
+ <span>✅ 确认评价完成</span>
|
|
|
|
+ </button>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
@@ -841,9 +858,15 @@
|
|
</div>
|
|
</div>
|
|
@if (canEditSection('aftercare')) {
|
|
@if (canEditSection('aftercare')) {
|
|
<div class="complaint-actions">
|
|
<div class="complaint-actions">
|
|
- <button class="primary-btn" (click)="createComplaintManually()">📝 人工创建投诉</button>
|
|
|
|
- <button class="secondary-btn" (click)="setupKeywordMonitoring()">⚙️ 设置关键词监测</button>
|
|
|
|
- <button class="primary-btn" (click)="confirmComplaint()">✅ 确认投诉处理完成</button>
|
|
|
|
|
|
+ <button class="primary-btn" (click)="createComplaintManually()" type="button">
|
|
|
|
+ <span>📝 人工创建投诉</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button class="secondary-btn" (click)="setupKeywordMonitoring()" type="button">
|
|
|
|
+ <span>⚙️ 设置关键词监测</span>
|
|
|
|
+ </button>
|
|
|
|
+ <button class="success-btn" (click)="confirmComplaint()" type="button">
|
|
|
|
+ <span>✅ 确认投诉处理完成</span>
|
|
|
|
+ </button>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
@@ -1359,8 +1382,8 @@
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
-
|
|
|
|
- <!-- 串式流程:10个阶段横向排列(保持) -->
|
|
|
|
|
|
+
|
|
|
|
+ <!-- 串式流程:10个阶段横向排列(保持) -->
|
|
<div class="stage-progress-container">
|
|
<div class="stage-progress-container">
|
|
@for (stage of getVisibleStages(); track stage) {
|
|
@for (stage of getVisibleStages(); track stage) {
|
|
<div class="vertical-stage-block" [attr.id]="stageToAnchor(stage)" [class.active]="getStageStatus(stage) === 'active'">
|
|
<div class="vertical-stage-block" [attr.id]="stageToAnchor(stage)" [class.active]="getStageStatus(stage) === 'active'">
|
|
@@ -1398,10 +1421,10 @@
|
|
<h3 class="form-title">客户信息(已同步)</h3>
|
|
<h3 class="form-title">客户信息(已同步)</h3>
|
|
<div class="customer-info-display">
|
|
<div class="customer-info-display">
|
|
<div class="info-row">
|
|
<div class="info-row">
|
|
- <div class="info-item">
|
|
|
|
|
|
+ <div class="info-item">
|
|
<label>客户姓名:</label>
|
|
<label>客户姓名:</label>
|
|
<span>{{ orderCreationData.customerInfo.name || '未填写' }}</span>
|
|
<span>{{ orderCreationData.customerInfo.name || '未填写' }}</span>
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
<div class="info-item">
|
|
<div class="info-item">
|
|
<label>联系电话:</label>
|
|
<label>联系电话:</label>
|
|
<span>{{ orderCreationData.customerInfo.phone || '未填写' }}</span>
|
|
<span>{{ orderCreationData.customerInfo.phone || '未填写' }}</span>
|
|
@@ -1519,22 +1542,22 @@
|
|
<!-- 报价明细组件 -->
|
|
<!-- 报价明细组件 -->
|
|
<section class="quotation-section">
|
|
<section class="quotation-section">
|
|
<h3 class="form-title">报价明细</h3>
|
|
<h3 class="form-title">报价明细</h3>
|
|
- <app-quotation-details
|
|
|
|
- [initialData]="quotationData"
|
|
|
|
- (dataChange)="onQuotationDataChange($event)"
|
|
|
|
- ></app-quotation-details>
|
|
|
|
|
|
+ <app-quotation-details
|
|
|
|
+ [initialData]="quotationData"
|
|
|
|
+ (dataChange)="onQuotationDataChange($event)"
|
|
|
|
+ ></app-quotation-details>
|
|
</section>
|
|
</section>
|
|
|
|
|
|
<!-- 设计师分配组件 -->
|
|
<!-- 设计师分配组件 -->
|
|
<section class="designer-assignment-section">
|
|
<section class="designer-assignment-section">
|
|
<h3 class="form-title">设计师分配</h3>
|
|
<h3 class="form-title">设计师分配</h3>
|
|
<div class="designer-assignment-container">
|
|
<div class="designer-assignment-container">
|
|
- <app-designer-assignment
|
|
|
|
- [quotationItems]="quotationData.items"
|
|
|
|
- [initialAssignment]="designerAssignmentData"
|
|
|
|
- (assignmentChange)="onDesignerAssignmentChange($event)"
|
|
|
|
- (designerClick)="onDesignerClick($event)"
|
|
|
|
- ></app-designer-assignment>
|
|
|
|
|
|
+ <app-designer-assignment
|
|
|
|
+ [quotationItems]="quotationData.items"
|
|
|
|
+ [initialAssignment]="designerAssignmentData"
|
|
|
|
+ (assignmentChange)="onDesignerAssignmentChange($event)"
|
|
|
|
+ (designerClick)="onDesignerClick($event)"
|
|
|
|
+ ></app-designer-assignment>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</section>
|
|
|
|
|
|
@@ -1742,14 +1765,14 @@
|
|
<div class="space-list-container">
|
|
<div class="space-list-container">
|
|
<div class="space-list-header">
|
|
<div class="space-list-header">
|
|
<h4>空间列表</h4>
|
|
<h4>空间列表</h4>
|
|
- @if (canEditSection('delivery')) {
|
|
|
|
|
|
+ @if (canEditSection('delivery')) {
|
|
<button class="add-space-btn"
|
|
<button class="add-space-btn"
|
|
(click)="showAddSpaceInput['modeling'] = true">
|
|
(click)="showAddSpaceInput['modeling'] = true">
|
|
<span class="add-icon">+</span>
|
|
<span class="add-icon">+</span>
|
|
<span>添加空间</span>
|
|
<span>添加空间</span>
|
|
- </button>
|
|
|
|
|
|
+ </button>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 添加空间输入框 -->
|
|
<!-- 添加空间输入框 -->
|
|
@if (showAddSpaceInput['modeling']) {
|
|
@if (showAddSpaceInput['modeling']) {
|
|
@@ -1764,8 +1787,8 @@
|
|
<button class="confirm-btn" (click)="addSpace('modeling')">确认</button>
|
|
<button class="confirm-btn" (click)="addSpace('modeling')">确认</button>
|
|
<button class="cancel-btn" (click)="cancelAddSpace('modeling')">取消</button>
|
|
<button class="cancel-btn" (click)="cancelAddSpace('modeling')">取消</button>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
- }
|
|
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
|
|
<!-- 空间卡片列表 -->
|
|
<!-- 空间卡片列表 -->
|
|
<div class="space-cards">
|
|
<div class="space-cards">
|
|
@@ -1777,7 +1800,7 @@
|
|
<span class="space-progress">{{ getSpaceProgress('modeling', space.id) }}%</span>
|
|
<span class="space-progress">{{ getSpaceProgress('modeling', space.id) }}%</span>
|
|
</div>
|
|
</div>
|
|
<div class="space-actions">
|
|
<div class="space-actions">
|
|
- @if (canEditSection('delivery')) {
|
|
|
|
|
|
+ @if (canEditSection('delivery')) {
|
|
<button class="delete-space-btn"
|
|
<button class="delete-space-btn"
|
|
(click)="$event.stopPropagation(); removeSpace('modeling', space.id)"
|
|
(click)="$event.stopPropagation(); removeSpace('modeling', space.id)"
|
|
title="删除空间">
|
|
title="删除空间">
|
|
@@ -1788,15 +1811,15 @@
|
|
</button>
|
|
</button>
|
|
}
|
|
}
|
|
<span class="expand-arrow" [class.expanded]="space.isExpanded">▼</span>
|
|
<span class="expand-arrow" [class.expanded]="space.isExpanded">▼</span>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
|
|
@if (space.isExpanded) {
|
|
@if (space.isExpanded) {
|
|
<div class="space-content">
|
|
<div class="space-content">
|
|
<!-- 图片上传区域 -->
|
|
<!-- 图片上传区域 -->
|
|
- <div class="upload-section">
|
|
|
|
- @if (canEditSection('delivery')) {
|
|
|
|
- <div class="upload-dropzone"
|
|
|
|
|
|
+ <div class="upload-section">
|
|
|
|
+ @if (canEditSection('delivery')) {
|
|
|
|
+ <div class="upload-dropzone"
|
|
(click)="triggerSpaceFileInput('modeling', space.id)"
|
|
(click)="triggerSpaceFileInput('modeling', space.id)"
|
|
(dragover)="onDragOver($event)"
|
|
(dragover)="onDragOver($event)"
|
|
(dragleave)="onDragLeave($event)"
|
|
(dragleave)="onDragLeave($event)"
|
|
@@ -1810,35 +1833,35 @@
|
|
支持 JPG、PNG 格式,单个文件最大 10MB
|
|
支持 JPG、PNG 格式,单个文件最大 10MB
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- } @else {
|
|
|
|
- <div class="uploaded-images-grid">
|
|
|
|
|
|
+ } @else {
|
|
|
|
+ <div class="uploaded-images-grid">
|
|
@for (img of getSpaceImages('modeling', space.id); track img.id) {
|
|
@for (img of getSpaceImages('modeling', space.id); track img.id) {
|
|
- <div class="uploaded-image-item" (click)="previewImage(img)">
|
|
|
|
- <img [src]="img.url" [alt]="img.name" />
|
|
|
|
- <div class="image-overlay">
|
|
|
|
- <div class="image-name">{{ img.name }}</div>
|
|
|
|
- <div class="image-actions">
|
|
|
|
- <button class="preview-btn" (click)="$event.stopPropagation(); previewImage(img)">
|
|
|
|
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
|
|
|
|
+ <div class="uploaded-image-item" (click)="previewImage(img)">
|
|
|
|
+ <img [src]="img.url" [alt]="img.name" />
|
|
|
|
+ <div class="image-overlay">
|
|
|
|
+ <div class="image-name">{{ img.name }}</div>
|
|
|
|
+ <div class="image-actions">
|
|
|
|
+ <button class="preview-btn" (click)="$event.stopPropagation(); previewImage(img)">
|
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
|
|
+ </svg>
|
|
|
|
+ </button>
|
|
@if (canEditSection('delivery')) {
|
|
@if (canEditSection('delivery')) {
|
|
<button class="delete-btn" (click)="$event.stopPropagation(); removeSpaceImage('modeling', space.id, img.id)">
|
|
<button class="delete-btn" (click)="$event.stopPropagation(); removeSpaceImage('modeling', space.id, img.id)">
|
|
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
|
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<polyline points="3,6 5,6 21,6"></polyline>
|
|
<polyline points="3,6 5,6 21,6"></polyline>
|
|
<path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
|
|
<path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
|
|
+ </svg>
|
|
|
|
+ </button>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
</div>
|
|
</div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="readonly-images">
|
|
<div class="readonly-images">
|
|
@if (getSpaceImages('modeling', space.id).length > 0) {
|
|
@if (getSpaceImages('modeling', space.id).length > 0) {
|
|
@@ -1848,38 +1871,38 @@
|
|
<img [src]="img.url" [alt]="img.name" />
|
|
<img [src]="img.url" [alt]="img.name" />
|
|
<div class="image-overlay">
|
|
<div class="image-overlay">
|
|
<div class="image-name">{{ img.name }}</div>
|
|
<div class="image-name">{{ img.name }}</div>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="empty-tip">暂无上传的图片</div>
|
|
<div class="empty-tip">暂无上传的图片</div>
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 备注区域 -->
|
|
<!-- 备注区域 -->
|
|
<div class="notes-section">
|
|
<div class="notes-section">
|
|
<label class="notes-label">备注</label>
|
|
<label class="notes-label">备注</label>
|
|
- @if (canEditSection('delivery')) {
|
|
|
|
|
|
+ @if (canEditSection('delivery')) {
|
|
<textarea #modelingNotes
|
|
<textarea #modelingNotes
|
|
class="notes-textarea"
|
|
class="notes-textarea"
|
|
placeholder="请输入备注信息..."
|
|
placeholder="请输入备注信息..."
|
|
[value]="getSpaceNotes('modeling', space.id)"
|
|
[value]="getSpaceNotes('modeling', space.id)"
|
|
(blur)="updateSpaceNotes('modeling', space.id, modelingNotes.value || '')">
|
|
(blur)="updateSpaceNotes('modeling', space.id, modelingNotes.value || '')">
|
|
</textarea>
|
|
</textarea>
|
|
- } @else {
|
|
|
|
|
|
+ } @else {
|
|
<div class="notes-readonly">
|
|
<div class="notes-readonly">
|
|
{{ getSpaceNotes('modeling', space.id) || '暂无备注' }}
|
|
{{ getSpaceNotes('modeling', space.id) || '暂无备注' }}
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
|
|
+ }
|
|
</div>
|
|
</div>
|
|
- }
|
|
|
|
- </div>
|
|
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
} @else if (stage === '软装') {
|
|
} @else if (stage === '软装') {
|
|
@@ -1928,7 +1951,7 @@
|
|
<span class="space-progress">{{ getSpaceProgress('softDecor', space.id) }}%</span>
|
|
<span class="space-progress">{{ getSpaceProgress('softDecor', space.id) }}%</span>
|
|
</div>
|
|
</div>
|
|
<div class="space-actions">
|
|
<div class="space-actions">
|
|
- @if (canEditSection('delivery')) {
|
|
|
|
|
|
+ @if (canEditSection('delivery')) {
|
|
<button class="delete-space-btn"
|
|
<button class="delete-space-btn"
|
|
(click)="$event.stopPropagation(); removeSpace('softDecor', space.id)"
|
|
(click)="$event.stopPropagation(); removeSpace('softDecor', space.id)"
|
|
title="删除空间">
|
|
title="删除空间">
|
|
@@ -1939,15 +1962,15 @@
|
|
</button>
|
|
</button>
|
|
}
|
|
}
|
|
<span class="expand-arrow" [class.expanded]="space.isExpanded">▼</span>
|
|
<span class="expand-arrow" [class.expanded]="space.isExpanded">▼</span>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
|
|
@if (space.isExpanded) {
|
|
@if (space.isExpanded) {
|
|
<div class="space-content">
|
|
<div class="space-content">
|
|
<!-- 图片上传区域 -->
|
|
<!-- 图片上传区域 -->
|
|
- <div class="upload-section">
|
|
|
|
- @if (canEditSection('delivery')) {
|
|
|
|
- <div class="upload-dropzone"
|
|
|
|
|
|
+ <div class="upload-section">
|
|
|
|
+ @if (canEditSection('delivery')) {
|
|
|
|
+ <div class="upload-dropzone"
|
|
(click)="triggerSpaceFileInput('softDecor', space.id)"
|
|
(click)="triggerSpaceFileInput('softDecor', space.id)"
|
|
(dragover)="onDragOver($event)"
|
|
(dragover)="onDragOver($event)"
|
|
(dragleave)="onDragLeave($event)"
|
|
(dragleave)="onDragLeave($event)"
|
|
@@ -1961,35 +1984,35 @@
|
|
建议 ≤1MB 的 JPG/PNG 小图
|
|
建议 ≤1MB 的 JPG/PNG 小图
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- } @else {
|
|
|
|
- <div class="uploaded-images-grid">
|
|
|
|
|
|
+ } @else {
|
|
|
|
+ <div class="uploaded-images-grid">
|
|
@for (img of getSpaceImages('softDecor', space.id); track img.id) {
|
|
@for (img of getSpaceImages('softDecor', space.id); track img.id) {
|
|
- <div class="uploaded-image-item" (click)="previewImage(img)">
|
|
|
|
- <img [src]="img.url" [alt]="img.name" />
|
|
|
|
- <div class="image-overlay">
|
|
|
|
- <div class="image-name">{{ img.name }}</div>
|
|
|
|
- <div class="image-actions">
|
|
|
|
- <button class="preview-btn" (click)="$event.stopPropagation(); previewImage(img)">
|
|
|
|
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
|
|
|
|
+ <div class="uploaded-image-item" (click)="previewImage(img)">
|
|
|
|
+ <img [src]="img.url" [alt]="img.name" />
|
|
|
|
+ <div class="image-overlay">
|
|
|
|
+ <div class="image-name">{{ img.name }}</div>
|
|
|
|
+ <div class="image-actions">
|
|
|
|
+ <button class="preview-btn" (click)="$event.stopPropagation(); previewImage(img)">
|
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
|
|
+ </svg>
|
|
|
|
+ </button>
|
|
@if (canEditSection('delivery')) {
|
|
@if (canEditSection('delivery')) {
|
|
<button class="delete-btn" (click)="$event.stopPropagation(); removeSpaceImage('softDecor', space.id, img.id)">
|
|
<button class="delete-btn" (click)="$event.stopPropagation(); removeSpaceImage('softDecor', space.id, img.id)">
|
|
- <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
|
|
|
|
+ <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<polyline points="3,6 5,6 21,6"></polyline>
|
|
<polyline points="3,6 5,6 21,6"></polyline>
|
|
<path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
|
|
<path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
|
|
- </svg>
|
|
|
|
- </button>
|
|
|
|
|
|
+ </svg>
|
|
|
|
+ </button>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
</div>
|
|
</div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="readonly-images">
|
|
<div class="readonly-images">
|
|
@if (getSpaceImages('softDecor', space.id).length > 0) {
|
|
@if (getSpaceImages('softDecor', space.id).length > 0) {
|
|
@@ -1999,16 +2022,16 @@
|
|
<img [src]="img.url" [alt]="img.name" />
|
|
<img [src]="img.url" [alt]="img.name" />
|
|
<div class="image-overlay">
|
|
<div class="image-overlay">
|
|
<div class="image-name">{{ img.name }}</div>
|
|
<div class="image-name">{{ img.name }}</div>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- } @else {
|
|
|
|
- <div class="empty-tip">暂无上传的图片</div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
|
|
+ } @else {
|
|
|
|
+ <div class="empty-tip">暂无上传的图片</div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 备注区域 -->
|
|
<!-- 备注区域 -->
|
|
<div class="notes-section">
|
|
<div class="notes-section">
|
|
@@ -2023,23 +2046,23 @@
|
|
} @else {
|
|
} @else {
|
|
<div class="notes-readonly">
|
|
<div class="notes-readonly">
|
|
{{ getSpaceNotes('softDecor', space.id) || '暂无备注' }}
|
|
{{ getSpaceNotes('softDecor', space.id) || '暂无备注' }}
|
|
- </div>
|
|
|
|
- }
|
|
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
} @else if (stage === '渲染') {
|
|
} @else if (stage === '渲染') {
|
|
<!-- 渲染阶段:直接显示渲染相关内容 -->
|
|
<!-- 渲染阶段:直接显示渲染相关内容 -->
|
|
<div class="rendering-stage-panel">
|
|
<div class="rendering-stage-panel">
|
|
<div class="stage-description">
|
|
<div class="stage-description">
|
|
<h4>渲染阶段</h4>
|
|
<h4>渲染阶段</h4>
|
|
<p>上传渲染大图,满足4K标准</p>
|
|
<p>上传渲染大图,满足4K标准</p>
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
<!-- 空间列表 -->
|
|
<!-- 空间列表 -->
|
|
<div class="space-list-container">
|
|
<div class="space-list-container">
|
|
<div class="space-list-header">
|
|
<div class="space-list-header">
|
|
@@ -2050,8 +2073,8 @@
|
|
<span class="add-icon">+</span>
|
|
<span class="add-icon">+</span>
|
|
<span>添加空间</span>
|
|
<span>添加空间</span>
|
|
</button>
|
|
</button>
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 添加空间输入框 -->
|
|
<!-- 添加空间输入框 -->
|
|
@if (showAddSpaceInput['rendering']) {
|
|
@if (showAddSpaceInput['rendering']) {
|
|
@@ -2077,7 +2100,7 @@
|
|
<div class="space-info">
|
|
<div class="space-info">
|
|
<span class="space-name">{{ space.name }}</span>
|
|
<span class="space-name">{{ space.name }}</span>
|
|
<span class="space-progress">{{ getSpaceProgress('rendering', space.id) }}%</span>
|
|
<span class="space-progress">{{ getSpaceProgress('rendering', space.id) }}%</span>
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
<div class="space-actions">
|
|
<div class="space-actions">
|
|
@if (canEditSection('delivery')) {
|
|
@if (canEditSection('delivery')) {
|
|
<button class="delete-space-btn"
|
|
<button class="delete-space-btn"
|
|
@@ -2090,8 +2113,8 @@
|
|
</button>
|
|
</button>
|
|
}
|
|
}
|
|
<span class="expand-arrow" [class.expanded]="space.isExpanded">▼</span>
|
|
<span class="expand-arrow" [class.expanded]="space.isExpanded">▼</span>
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
|
|
|
|
@if (space.isExpanded) {
|
|
@if (space.isExpanded) {
|
|
<div class="space-content">
|
|
<div class="space-content">
|
|
@@ -2110,8 +2133,8 @@
|
|
<div class="upload-text">点击上传或拖拽文件到此处</div>
|
|
<div class="upload-text">点击上传或拖拽文件到此处</div>
|
|
<div class="upload-hint">
|
|
<div class="upload-hint">
|
|
需满足4K标准(最长边 ≥ 4000px)
|
|
需满足4K标准(最长边 ≥ 4000px)
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="uploaded-images-grid">
|
|
<div class="uploaded-images-grid">
|
|
@for (img of getSpaceImages('rendering', space.id); track img.id) {
|
|
@for (img of getSpaceImages('rendering', space.id); track img.id) {
|
|
@@ -2125,22 +2148,22 @@
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
</svg>
|
|
</svg>
|
|
- </button>
|
|
|
|
|
|
+ </button>
|
|
@if (canEditSection('delivery')) {
|
|
@if (canEditSection('delivery')) {
|
|
<button class="delete-btn" (click)="$event.stopPropagation(); removeSpaceImage('rendering', space.id, img.id)">
|
|
<button class="delete-btn" (click)="$event.stopPropagation(); removeSpaceImage('rendering', space.id, img.id)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<polyline points="3,6 5,6 21,6"></polyline>
|
|
<polyline points="3,6 5,6 21,6"></polyline>
|
|
<path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
|
|
<path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
|
|
</svg>
|
|
</svg>
|
|
- </button>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ </button>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="readonly-images">
|
|
<div class="readonly-images">
|
|
@if (getSpaceImages('rendering', space.id).length > 0) {
|
|
@if (getSpaceImages('rendering', space.id).length > 0) {
|
|
@@ -2150,16 +2173,16 @@
|
|
<img [src]="img.url" [alt]="img.name" />
|
|
<img [src]="img.url" [alt]="img.name" />
|
|
<div class="image-overlay">
|
|
<div class="image-overlay">
|
|
<div class="image-name">{{ img.name }}</div>
|
|
<div class="image-name">{{ img.name }}</div>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="empty-tip">暂无上传的图片</div>
|
|
<div class="empty-tip">暂无上传的图片</div>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 备注区域 -->
|
|
<!-- 备注区域 -->
|
|
<div class="notes-section">
|
|
<div class="notes-section">
|
|
@@ -2174,23 +2197,23 @@
|
|
} @else {
|
|
} @else {
|
|
<div class="notes-readonly">
|
|
<div class="notes-readonly">
|
|
{{ getSpaceNotes('rendering', space.id) || '暂无备注' }}
|
|
{{ getSpaceNotes('rendering', space.id) || '暂无备注' }}
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
} @else if (stage === '后期') {
|
|
} @else if (stage === '后期') {
|
|
<!-- 后期阶段:直接显示后期相关内容 -->
|
|
<!-- 后期阶段:直接显示后期相关内容 -->
|
|
<div class="post-production-stage-panel">
|
|
<div class="post-production-stage-panel">
|
|
<div class="stage-description">
|
|
<div class="stage-description">
|
|
<h4>后期阶段</h4>
|
|
<h4>后期阶段</h4>
|
|
<p>上传后期处理图片,进行最终调整</p>
|
|
<p>上传后期处理图片,进行最终调整</p>
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
<!-- 空间列表 -->
|
|
<!-- 空间列表 -->
|
|
<div class="space-list-container">
|
|
<div class="space-list-container">
|
|
<div class="space-list-header">
|
|
<div class="space-list-header">
|
|
@@ -2200,9 +2223,9 @@
|
|
(click)="showAddSpaceInput['postProduction'] = true">
|
|
(click)="showAddSpaceInput['postProduction'] = true">
|
|
<span class="add-icon">+</span>
|
|
<span class="add-icon">+</span>
|
|
<span>添加空间</span>
|
|
<span>添加空间</span>
|
|
- </button>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ </button>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 添加空间输入框 -->
|
|
<!-- 添加空间输入框 -->
|
|
@if (showAddSpaceInput['postProduction']) {
|
|
@if (showAddSpaceInput['postProduction']) {
|
|
@@ -2216,8 +2239,8 @@
|
|
<div class="input-actions">
|
|
<div class="input-actions">
|
|
<button class="confirm-btn" (click)="addSpace('postProduction')">确认</button>
|
|
<button class="confirm-btn" (click)="addSpace('postProduction')">确认</button>
|
|
<button class="cancel-btn" (click)="cancelAddSpace('postProduction')">取消</button>
|
|
<button class="cancel-btn" (click)="cancelAddSpace('postProduction')">取消</button>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
}
|
|
}
|
|
|
|
|
|
<!-- 空间卡片列表 -->
|
|
<!-- 空间卡片列表 -->
|
|
@@ -2228,7 +2251,7 @@
|
|
<div class="space-info">
|
|
<div class="space-info">
|
|
<span class="space-name">{{ space.name }}</span>
|
|
<span class="space-name">{{ space.name }}</span>
|
|
<span class="space-progress">{{ getSpaceProgress('postProduction', space.id) }}%</span>
|
|
<span class="space-progress">{{ getSpaceProgress('postProduction', space.id) }}%</span>
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
<div class="space-actions">
|
|
<div class="space-actions">
|
|
@if (canEditSection('delivery')) {
|
|
@if (canEditSection('delivery')) {
|
|
<button class="delete-space-btn"
|
|
<button class="delete-space-btn"
|
|
@@ -2241,8 +2264,8 @@
|
|
</button>
|
|
</button>
|
|
}
|
|
}
|
|
<span class="expand-arrow" [class.expanded]="space.isExpanded">▼</span>
|
|
<span class="expand-arrow" [class.expanded]="space.isExpanded">▼</span>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
|
|
@if (space.isExpanded) {
|
|
@if (space.isExpanded) {
|
|
<div class="space-content">
|
|
<div class="space-content">
|
|
@@ -2261,8 +2284,8 @@
|
|
<div class="upload-text">点击上传或拖拽文件到此处</div>
|
|
<div class="upload-text">点击上传或拖拽文件到此处</div>
|
|
<div class="upload-hint">
|
|
<div class="upload-hint">
|
|
支持 JPG、PNG 格式,后期处理图片
|
|
支持 JPG、PNG 格式,后期处理图片
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="uploaded-images-grid">
|
|
<div class="uploaded-images-grid">
|
|
@for (img of getSpaceImages('postProduction', space.id); track img.id) {
|
|
@for (img of getSpaceImages('postProduction', space.id); track img.id) {
|
|
@@ -2276,22 +2299,22 @@
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<circle cx="11" cy="11" r="8"></circle>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
<path d="m21 21-4.35-4.35"></path>
|
|
</svg>
|
|
</svg>
|
|
- </button>
|
|
|
|
|
|
+ </button>
|
|
@if (canEditSection('delivery')) {
|
|
@if (canEditSection('delivery')) {
|
|
<button class="delete-btn" (click)="$event.stopPropagation(); removeSpaceImage('postProduction', space.id, img.id)">
|
|
<button class="delete-btn" (click)="$event.stopPropagation(); removeSpaceImage('postProduction', space.id, img.id)">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor">
|
|
<polyline points="3,6 5,6 21,6"></polyline>
|
|
<polyline points="3,6 5,6 21,6"></polyline>
|
|
<path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
|
|
<path d="m19,6v14a2,2 0 0,1 -2,2H7a2,2 0 0,1 -2,-2V6m3,0V4a2,2 0 0,1 2,-2h4a2,2 0 0,1 2,2v2"></path>
|
|
</svg>
|
|
</svg>
|
|
- </button>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ </button>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="readonly-images">
|
|
<div class="readonly-images">
|
|
@if (getSpaceImages('postProduction', space.id).length > 0) {
|
|
@if (getSpaceImages('postProduction', space.id).length > 0) {
|
|
@@ -2301,16 +2324,16 @@
|
|
<img [src]="img.url" [alt]="img.name" />
|
|
<img [src]="img.url" [alt]="img.name" />
|
|
<div class="image-overlay">
|
|
<div class="image-overlay">
|
|
<div class="image-name">{{ img.name }}</div>
|
|
<div class="image-name">{{ img.name }}</div>
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
} @else {
|
|
} @else {
|
|
<div class="empty-tip">暂无上传的图片</div>
|
|
<div class="empty-tip">暂无上传的图片</div>
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
|
|
<!-- 备注区域 -->
|
|
<!-- 备注区域 -->
|
|
<div class="notes-section">
|
|
<div class="notes-section">
|
|
@@ -2325,27 +2348,27 @@
|
|
} @else {
|
|
} @else {
|
|
<div class="notes-readonly">
|
|
<div class="notes-readonly">
|
|
{{ getSpaceNotes('postProduction', space.id) || '暂无备注' }}
|
|
{{ getSpaceNotes('postProduction', space.id) || '暂无备注' }}
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
|
|
+ </div>
|
|
} @else if (stage === '尾款结算') {
|
|
} @else if (stage === '尾款结算') {
|
|
<!-- 原尾款结算售后 tab 容器已移除,根据用户要求不再使用 -->
|
|
<!-- 原尾款结算售后 tab 容器已移除,根据用户要求不再使用 -->
|
|
}
|
|
}
|
|
- </div>
|
|
|
|
- </div>
|
|
|
|
- }
|
|
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
- </div>
|
|
|
|
|
|
+ }
|
|
|
|
+ </div>
|
|
</div>
|
|
</div>
|
|
|
|
+ </div>
|
|
|
|
|
|
-
|
|
|
|
|
|
+
|
|
<!-- 项目人员标签页 -->
|
|
<!-- 项目人员标签页 -->
|
|
@if (isActiveTab('members')) {
|
|
@if (isActiveTab('members')) {
|
|
<div class="members-tab-content">
|
|
<div class="members-tab-content">
|