本文档针对需求沟通阶段的确认需求功能模块进行全面分析和优化建议。该模块位于设计师项目详情页面中,是整个项目流程中的关键环节。
src/app/shared/components/requirements-confirm-card/requirements-confirm-card.ts
src/app/shared/components/requirements-confirm-card/requirements-confirm-card.html
src/app/shared/components/requirements-confirm-card/requirements-confirm-card.scss
src/app/pages/designer/project-detail/project-detail.ts
确认需求模块采用四标签页架构:
功能模块 | 需求文档要求 | 当前实现状态 | 优先级 | 完成度 |
---|---|---|---|---|
素材分析 | ||||
色彩分析 | 补充色轮图标,完整展示色彩信息 | 有基础数据,缺少可视化 | 🔴 高 | 60% |
形体分析 | 整体形体+软装形体选择 | 只有分析数据,无选择功能 | 🔴 高 | 40% |
质感分析 | 质感、材质、亮光/哑光对比 | 有材质分类,展示不直观 | 🟡 中 | 50% |
纹理分析 | 图案可视化展示 | 只有文字标签 | 🟡 中 | 40% |
灯光分析 | 光色、光比、光质、光占比 | 有光色和光质,缺光比和光占比 | 🔴 高 | 50% |
完全展示所有信息 | 核心要求 | 信息折叠,展示简化 | 🔴 高 | 50% |
需求映射 | ||||
功能定位 | 隐藏功能,后台自动生成 | 独立标签页,用户可见 | 🟡 中 | 需调整 |
协作验证 | ||||
五维度验证 | 色彩、形体、质感、纹理、灯光分类 | 通用需求列表 | 🔴 高 | 20% |
素材关联 | 关联参考图、CAD、文字说明 | 无关联机制 | 🔴 高 | 0% |
选择和标注 | 交互式标注工具 | 无标注功能 | 🔴 高 | 0% |
区域细分 | 支持不同区域(客厅、婴儿房等) | 只有整体方案 | 🔴 高 | 0% |
分工人员 | 不同区域分配不同人员 | 只有角色标识 | 🟡 中 | 10% |
1. 交互式色轮可视化组件
// 新建组件:src/app/shared/components/color-wheel-visualizer/
interface ColorWheelConfig {
colors: Array<{
hue: number; // 色调角度 0-360
saturation: number; // 饱和度 0-100
brightness: number; // 亮度 0-100
percentage: number; // 占比
hex: string;
}>;
interactive: boolean; // 是否可交互
}
功能特性:
2. 色彩详情卡片
<div class="color-analysis-detail">
<div class="color-wheel-container">
<app-color-wheel-visualizer
[colors]="material.analysis.enhancedColorAnalysis.colorWheel.colorDistribution"
[interactive]="true">
</app-color-wheel-visualizer>
</div>
<div class="color-info-grid">
<!-- 主色调信息 -->
<div class="color-metric">
<span class="label">主色调</span>
<div class="hue-indicator" [style.background]="getHueColor()"></div>
<span class="value">{{ primaryHue }}°</span>
</div>
<!-- 饱和度 -->
<div class="color-metric">
<span class="label">饱和度</span>
<div class="saturation-bar">
<div class="fill" [style.width.%]="saturation"></div>
</div>
<span class="value">{{ saturation }}%</span>
</div>
<!-- 色温 -->
<div class="color-metric">
<span class="label">色温</span>
<div class="temperature-indicator" [class]="temperatureClass"></div>
<span class="value">{{ temperature }}K ({{ temperatureDesc }})</span>
</div>
<!-- 色彩心理学 -->
<div class="color-psychology">
<h6>色彩心理学</h6>
<div class="mood-tags">
<span class="mood-tag primary">{{ primaryMood }}</span>
<span class="atmosphere-tag">{{ atmosphere }}</span>
</div>
<ul class="effects-list">
<li *ngFor="let effect of psychologicalEffects">{{ effect }}</li>
</ul>
</div>
</div>
</div>
3. 技术实施细节
1. 形体分类展示
interface FormCategory {
overall: {
lineType: 'straight' | 'curved' | 'mixed'; // 直线/曲线/混合
complexity: number; // 复杂度 0-100
symmetry: 'symmetric' | 'asymmetric'; // 对称/不对称
};
furniture: {
dominant: string[]; // 主要家具形体
style: string; // 风格(简约、古典、现代等)
proportion: number; // 占比
};
}
2. 软装形体选择器
<div class="form-analysis-section">
<h6>形体分析</h6>
<!-- 整体形体 -->
<div class="overall-form">
<div class="form-type-selector">
<label>线条类型:</label>
<div class="type-options">
<button class="type-btn"
[class.active]="formType === 'straight'"
(click)="selectFormType('straight')">
<svg><!-- 直线图标 --></svg>
直线条
</button>
<button class="type-btn"
[class.active]="formType === 'curved'"
(click)="selectFormType('curved')">
<svg><!-- 曲线图标 --></svg>
曲线条
</button>
<button class="type-btn"
[class.active]="formType === 'mixed'"
(click)="selectFormType('mixed')">
<svg><!-- 混合图标 --></svg>
混合型
</button>
</div>
</div>
<!-- 对称性 -->
<div class="symmetry-indicator">
<span class="label">对称性:</span>
<div class="symmetry-visual">
<svg><!-- 对称性可视化图标 --></svg>
</div>
<span class="value">{{ symmetryType }}</span>
</div>
</div>
<!-- 软装形体选择 -->
<div class="furniture-form-selector">
<h6>软装形体选择</h6>
<div class="furniture-grid">
<div class="furniture-item"
*ngFor="let item of furnitureItems"
[class.selected]="item.selected"
(click)="toggleFurniture(item)">
<img [src]="item.preview" [alt]="item.name">
<span class="name">{{ item.name }}</span>
<span class="form-tag">{{ item.formType }}</span>
</div>
</div>
</div>
<!-- 形体比例分析 -->
<div class="proportion-analysis">
<h6>形体比例分析</h6>
<div class="proportion-chart">
<!-- 使用ECharts绘制比例图 -->
</div>
</div>
</div>
3. 数据模型扩展
interface FurnitureFormItem {
id: string;
name: string;
category: 'sofa' | 'table' | 'chair' | 'cabinet' | 'bed' | 'decoration';
formType: 'geometric' | 'organic' | 'linear' | 'curved';
preview: string;
selected: boolean;
dominance: number; // 视觉主导性
}
1. 亮光/哑光对比卡片
<div class="texture-analysis-section">
<h6>质感分析</h6>
<!-- 光泽度对比 -->
<div class="glossiness-comparison">
<div class="gloss-card matte" [class.active]="glossType === 'matte'">
<div class="gloss-preview matte-texture">
<span class="label">哑光</span>
<div class="gloss-level">{{ matteLevel }}/10</div>
</div>
<div class="gloss-properties">
<span>柔和 · 低反射 · 温暖</span>
</div>
</div>
<div class="gloss-card glossy" [class.active]="glossType === 'glossy'">
<div class="gloss-preview glossy-texture">
<span class="label">亮光</span>
<div class="gloss-level">{{ glossyLevel }}/10</div>
</div>
<div class="gloss-properties">
<span>明亮 · 高反射 · 现代</span>
</div>
</div>
</div>
<!-- 材质属性详情 -->
<div class="material-properties">
<div class="property-row">
<span class="label">粗糙度</span>
<div class="property-bar">
<div class="fill roughness" [style.width.%]="roughness"></div>
<span class="value">{{ roughnessLevel }}</span>
</div>
</div>
<div class="property-row">
<span class="label">反射率</span>
<div class="property-bar">
<div class="fill reflectivity" [style.width.%]="reflectivity"></div>
<span class="value">{{ reflectivity }}%</span>
</div>
</div>
<div class="property-row">
<span class="label">质感层次</span>
<div class="texture-layers">
<span class="layer" *ngFor="let layer of textureLayers">{{ layer }}</span>
</div>
</div>
</div>
<!-- 材质分类 -->
<div class="material-classification">
<h6>材质类型</h6>
<div class="material-tags">
<span class="material-tag primary">{{ primaryMaterial }}</span>
<span class="material-tag" *ngFor="let mat of secondaryMaterials">
{{ mat.name }} ({{ mat.percentage }}%)
</span>
</div>
</div>
</div>
2. 质感预览组件
使用3D渲染或高质量图片展示不同质感效果:
1. 纹理图案可视化
<div class="pattern-analysis-section">
<h6>纹理分析</h6>
<!-- 图案预览 -->
<div class="pattern-preview-grid">
<div class="pattern-item" *ngFor="let pattern of recognizedPatterns">
<div class="pattern-visual">
<!-- 截取参考图中的纹理区域显示 -->
<img [src]="pattern.sampleImage" [alt]="pattern.type">
<div class="pattern-overlay">
<span class="pattern-type">{{ pattern.type }}</span>
<span class="coverage">{{ pattern.coverage }}%</span>
</div>
</div>
<div class="pattern-info">
<span class="complexity">复杂度: {{ pattern.complexity }}</span>
<span class="scale">尺度: {{ pattern.scale }}</span>
</div>
</div>
</div>
<!-- 重复规律分析 -->
<div class="repetition-analysis">
<h6>重复规律</h6>
<div class="repetition-visual">
<svg>
<!-- 绘制网格或重复单元 -->
</svg>
</div>
<div class="repetition-info">
<div class="info-row">
<span class="label">重复类型:</span>
<span class="value">{{ repetitionType }}</span>
</div>
<div class="info-row">
<span class="label">间距:</span>
<span class="value">横向 {{ spacingH }}mm · 纵向 {{ spacingV }}mm</span>
</div>
<div class="info-row">
<span class="label">对称性:</span>
<span class="value">{{ symmetryType }} (强度 {{ symmetryStrength }}%)</span>
</div>
</div>
</div>
<!-- 纹理族 -->
<div class="texture-family">
<h6>纹理族系</h6>
<div class="family-tags">
<span class="family-tag primary">{{ primaryFamily }}</span>
<span class="family-tag">{{ subcategory }}</span>
</div>
<div class="suggested-materials">
<span class="label">建议材质:</span>
<span class="material" *ngFor="let mat of suggestedMaterials">{{ mat }}</span>
</div>
</div>
</div>
2. 技术实施
1. 完整的灯光分析面板
interface CompleteLightingAnalysis {
// 现有数据
lightSource: {
type: string;
intensity: number;
mood: string;
};
// 新增:光比
lightingRatio: {
keyToFill: number; // 主光与补光比例 (如 3:1)
contrast: number; // 明暗对比度
description: string; // 高反差/低反差/中等
};
// 新增:光占比
lightDistribution: {
natural: number; // 自然光占比 %
artificial: number; // 人工光占比 %
ambient: number; // 环境光占比 %
direct: number; // 直射光占比 %
indirect: number; // 间接光占比 %
};
// 光质
lightQuality: {
softness: number; // 柔和度
diffusion: number; // 漫射度
directionality: number; // 方向性
};
}
2. 灯光分析UI
<div class="lighting-analysis-section">
<h6>灯光分析</h6>
<!-- 光源识别 -->
<div class="light-sources">
<div class="source-item" *ngFor="let source of lightSources">
<div class="source-icon" [class]="source.type">
<svg><!-- 光源图标 --></svg>
</div>
<div class="source-info">
<span class="type">{{ source.subtype }}</span>
<span class="intensity">强度 {{ source.intensity }}%</span>
</div>
</div>
</div>
<!-- 光比分析 NEW -->
<div class="lighting-ratio">
<h6>光比分析</h6>
<div class="ratio-visual">
<div class="ratio-bars">
<div class="key-light-bar" [style.height.%]="keyLightRatio">
<span>主光</span>
<span class="value">{{ keyLightRatio }}%</span>
</div>
<div class="fill-light-bar" [style.height.%]="fillLightRatio">
<span>补光</span>
<span class="value">{{ fillLightRatio }}%</span>
</div>
</div>
<div class="ratio-description">
<span class="ratio-value">{{ keyToFillRatio }}</span>
<span class="contrast-level">{{ contrastDescription }}</span>
</div>
</div>
</div>
<!-- 光占比饼图 NEW -->
<div class="light-distribution">
<h6>光占比</h6>
<div class="distribution-chart">
<!-- 使用ECharts绘制饼图 -->
<canvas id="lightDistributionChart"></canvas>
</div>
<div class="distribution-legend">
<div class="legend-item">
<span class="color natural"></span>
<span class="label">自然光</span>
<span class="value">{{ naturalLight }}%</span>
</div>
<div class="legend-item">
<span class="color artificial"></span>
<span class="label">人工光</span>
<span class="value">{{ artificialLight }}%</span>
</div>
<div class="legend-item">
<span class="color ambient"></span>
<span class="label">环境光</span>
<span class="value">{{ ambientLight }}%</span>
</div>
</div>
</div>
<!-- 光质分析 -->
<div class="light-quality">
<h6>光质</h6>
<div class="quality-metrics">
<div class="metric-item">
<span class="label">柔和度</span>
<div class="metric-bar">
<div class="fill" [style.width.%]="softness"></div>
</div>
<span class="value">{{ softness }}%</span>
</div>
<div class="metric-item">
<span class="label">漫射度</span>
<div class="metric-bar">
<div class="fill" [style.width.%]="diffusion"></div>
</div>
<span class="value">{{ diffusion }}%</span>
</div>
<div class="metric-item">
<span class="label">方向性</span>
<div class="metric-bar">
<div class="fill" [style.width.%]="directionality"></div>
</div>
<span class="value">{{ directionality }}%</span>
</div>
</div>
</div>
<!-- 色温与情绪 -->
<div class="color-temperature-mood">
<div class="temperature">
<span class="label">色温</span>
<div class="temp-bar" [style.background]="tempGradient"></div>
<span class="value">{{ colorTemp }}K</span>
</div>
<div class="mood">
<span class="label">灯光情绪</span>
<span class="mood-tag">{{ lightingMood }}</span>
</div>
</div>
</div>
3. 服务层扩展
修改 src/app/shared/services/lighting-analysis.service.ts
:
// 新增光比计算方法
calculateLightingRatio(image: File): Observable<LightingRatioResult> {
// 分析图像的亮度分布
// 识别主光源和补光源
// 计算光比
}
// 新增光占比计算方法
calculateLightDistribution(lightingData: any): LightDistribution {
// 根据光源识别结果计算各类光源占比
}
1. 展开/折叠控制
<div class="materials-list">
<div class="list-header">
<h5>已上传素材</h5>
<div class="view-controls">
<button class="btn-ghost"
[class.active]="viewMode === 'compact'"
(click)="setViewMode('compact')">
精简视图
</button>
<button class="btn-ghost"
[class.active]="viewMode === 'expanded'"
(click)="setViewMode('expanded')">
完整展示
</button>
<button class="btn-ghost" (click)="expandAll()">全部展开</button>
<button class="btn-ghost" (click)="collapseAll()">全部折叠</button>
</div>
</div>
<div class="material-cards" [class]="viewMode">
<!-- 素材卡片 -->
</div>
</div>
2. 完整展示模式布局
.material-cards.expanded {
.material-card {
.analysis-section {
display: block !important; // 强制展开所有分析部分
.color-wheel-visualizer,
.form-analysis-section,
.texture-analysis-section,
.pattern-analysis-section,
.lighting-analysis-section {
max-height: none;
overflow: visible;
}
}
}
}
3. 打印/导出功能
// 新增导出分析报告功能
exportAnalysisReport(materialId: string, format: 'pdf' | 'excel' | 'json') {
const material = this.materials.find(m => m.id === materialId);
// 生成完整的分析报告
}
// 批量导出所有素材
exportAllMaterials() {
// 导出所有素材的完整分析数据
}
1. 移除"需求映射"标签页
修改 requirements-confirm-card.html
:
<!-- 移除需求映射标签按钮 -->
<div class="tab-navigation">
<button class="tab-button" [class.active]="activeTab === 'materials'">素材解析</button>
<!-- <button class="tab-button" [class.active]="activeTab === 'mapping'">需求映射</button> -->
<!-- 移除此标签 -->
<button class="tab-button" [class.active]="activeTab === 'collaboration'">协作验证</button>
<button class="tab-button" [class.active]="activeTab === 'progress'">进度管理</button>
</div>
2. 自动触发映射机制
// 在素材分析完成后自动触发
private onMaterialAnalysisComplete(material: MaterialFile): void {
// 检查是否所有素材都已分析完成
const allAnalyzed = this.materials.every(m => m.analysis);
if (allAnalyzed) {
console.log('所有素材分析完成,自动触发需求映射');
this.triggerBackgroundMapping();
}
}
// 后台映射生成
private triggerBackgroundMapping(): void {
this.isGeneratingMapping = true;
// 收集所有分析结果
const analysisResults = this.materials
.filter(m => m.type === 'image')
.map(m => this.convertToColorAnalysisResult(m));
// 自动生成需求映射(不显示给用户)
this.requirementMappingService.generateRequirementMapping(
this.mergeAnalysisResults(analysisResults),
SceneTemplate.LIVING_ROOM_MODERN
).subscribe({
next: (mapping) => {
this.requirementMapping = mapping;
this.isGeneratingMapping = false;
// 静默保存,不弹窗提示
console.log('需求映射已自动生成:', mapping);
// 发送映射数据到父组件(用于方案确认阶段展示)
this.emitMappingDataUpdate();
},
error: (error) => {
console.error('自动映射生成失败:', error);
this.isGeneratingMapping = false;
}
});
}
3. 保留数据接口
// 保留映射数据的访问接口,供其他模块使用
public getMappingData(): RequirementMapping | null {
return this.requirementMapping;
}
// 提供重新生成映射的方法(调试用)
public regenerateMapping(): void {
this.triggerBackgroundMapping();
}
4. 在开发模式下保留可见性(可选)
// 环境配置
showMappingTab = environment.production ? false : true;
<button class="tab-button"
*ngIf="showMappingTab"
[class.active]="activeTab === 'mapping'">
需求映射 (调试)
</button>
这是最重要的优化模块,需要完全重构当前的协作验证功能。
1. 数据模型重构
// 新建接口:src/app/models/collaboration-verification.interface.ts
export interface DimensionVerification {
id: string;
dimension: 'color' | 'form' | 'texture' | 'pattern' | 'lighting';
dimensionName: string;
status: 'pending' | 'in-review' | 'confirmed' | 'rejected';
// 关联的素材
linkedMaterials: LinkedMaterial[];
// 验证项
verificationItems: VerificationItem[];
// 标注
annotations: Annotation[];
// 协作信息
assignedTo?: string;
comments: Comment[];
// 区域(如果是区域细分)
areaId?: string;
lastUpdated: Date;
}
export interface LinkedMaterial {
materialId: string;
materialType: 'image' | 'cad' | 'text';
materialName: string;
relevance: number; // 相关度 0-100
highlightAreas?: Array<{x: number; y: number; width: number; height: number}>;
}
export interface VerificationItem {
id: string;
title: string;
description: string;
status: 'pending' | 'confirmed' | 'rejected';
priority: 'high' | 'medium' | 'low';
tags: string[];
}
export interface Annotation {
id: string;
type: 'text' | 'arrow' | 'highlight' | 'circle' | 'rectangle';
content?: string;
position: {x: number; y: number};
size?: {width: number; height: number};
color: string;
author: string;
timestamp: Date;
linkedMaterialId: string;
}
2. 五维验证UI布局
<div class="collaboration-section-redesign">
<div class="section-header">
<h5>协作验证</h5>
<div class="dimension-selector">
<button class="dimension-tab"
*ngFor="let dim of dimensions"
[class.active]="activeDimension === dim.key"
(click)="selectDimension(dim.key)">
<svg [innerHTML]="dim.icon"></svg>
<span>{{ dim.name }}</span>
<span class="status-badge" [class]="getDimensionStatus(dim.key)">
{{ getDimensionStatusText(dim.key) }}
</span>
</button>
</div>
</div>
<!-- 当前维度的验证内容 -->
<div class="dimension-content" [ngSwitch]="activeDimension">
<!-- 色彩验证 -->
<div *ngSwitchCase="'color'" class="color-verification">
<app-dimension-verification
[dimension]="'color'"
[materials]="getColorRelatedMaterials()"
[verificationData]="colorVerificationData"
(materialLinked)="onMaterialLinked($event)"
(annotationAdded)="onAnnotationAdded($event)"
(statusChanged)="onVerificationStatusChanged($event)">
</app-dimension-verification>
</div>
<!-- 形体验证 -->
<div *ngSwitchCase="'form'" class="form-verification">
<app-dimension-verification
[dimension]="'form'"
[materials]="getFormRelatedMaterials()"
[verificationData]="formVerificationData">
</app-dimension-verification>
</div>
<!-- 质感验证 -->
<div *ngSwitchCase="'texture'" class="texture-verification">
<app-dimension-verification
[dimension]="'texture'"
[materials]="getTextureRelatedMaterials()"
[verificationData]="textureVerificationData">
</app-dimension-verification>
</div>
<!-- 纹理验证 -->
<div *ngSwitchCase="'pattern'" class="pattern-verification">
<app-dimension-verification
[dimension]="'pattern'"
[materials]="getPatternRelatedMaterials()"
[verificationData]="patternVerificationData">
</app-dimension-verification>
</div>
<!-- 灯光验证 -->
<div *ngSwitchCase="'lighting'" class="lighting-verification">
<app-dimension-verification
[dimension]="'lighting'"
[materials]="getLightingRelatedMaterials()"
[verificationData]="lightingVerificationData">
</app-dimension-verification>
</div>
</div>
</div>
3. 新建维度验证组件
创建 src/app/shared/components/dimension-verification/
@Component({
selector: 'app-dimension-verification',
templateUrl: './dimension-verification.component.html',
styleUrls: ['./dimension-verification.component.scss']
})
export class DimensionVerificationComponent implements OnInit {
@Input() dimension!: 'color' | 'form' | 'texture' | 'pattern' | 'lighting';
@Input() materials: MaterialFile[] = [];
@Input() verificationData?: DimensionVerification;
@Output() materialLinked = new EventEmitter<LinkedMaterial>();
@Output() annotationAdded = new EventEmitter<Annotation>();
@Output() statusChanged = new EventEmitter<{dimension: string; status: string}>();
// 组件逻辑...
}
1. 拖拽关联
<div class="material-linking-panel">
<div class="source-materials">
<h6>素材库</h6>
<div class="material-list"
cdkDropList
#materialList="cdkDropList"
[cdkDropListData]="availableMaterials"
[cdkDropListConnectedTo]="[linkedList]">
<div class="material-item"
*ngFor="let material of availableMaterials"
cdkDrag>
<img [src]="material.url" [alt]="material.name">
<span>{{ material.name }}</span>
</div>
</div>
</div>
<div class="linked-materials">
<h6>已关联素材 - {{ dimensionName }}</h6>
<div class="linked-list"
cdkDropList
#linkedList="cdkDropList"
[cdkDropListData]="linkedMaterials"
[cdkDropListConnectedTo]="[materialList]"
(cdkDropListDropped)="onMaterialDropped($event)">
<div class="linked-item"
*ngFor="let linked of linkedMaterials"
cdkDrag>
<img [src]="linked.materialUrl" [alt]="linked.materialName">
<div class="linked-info">
<span class="name">{{ linked.materialName }}</span>
<span class="relevance">相关度: {{ linked.relevance }}%</span>
</div>
<button class="btn-remove" (click)="unlinkMaterial(linked.id)">
<svg><!-- 删除图标 --></svg>
</button>
</div>
</div>
</div>
</div>
2. 下拉选择关联
<div class="material-selector">
<label>关联参考图:</label>
<select (change)="linkMaterial($event.target.value)">
<option value="">-- 选择素材 --</option>
<option *ngFor="let material of availableMaterials"
[value]="material.id">
{{ material.name }}
</option>
</select>
</div>
3. 关联逻辑实现
onMaterialDropped(event: CdkDragDrop<MaterialFile[]>) {
if (event.previousContainer === event.container) {
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
} else {
transferArrayItem(
event.previousContainer.data,
event.container.data,
event.previousIndex,
event.currentIndex
);
// 创建关联
const material = event.container.data[event.currentIndex];
this.createMaterialLink(material);
}
}
private createMaterialLink(material: MaterialFile): void {
const linked: LinkedMaterial = {
materialId: material.id,
materialType: material.type,
materialName: material.name,
relevance: this.calculateRelevance(material), // 自动计算相关度
highlightAreas: []
};
this.materialLinked.emit(linked);
}
// 计算素材与当前维度的相关度
private calculateRelevance(material: MaterialFile): number {
// 根据维度和素材分析结果计算相关度
switch(this.dimension) {
case 'color':
return material.analysis?.enhancedColorAnalysis ? 90 : 50;
case 'form':
return material.analysis?.formAnalysis ? 85 : 40;
case 'texture':
return material.analysis?.textureAnalysis ? 88 : 45;
case 'pattern':
return material.analysis?.patternAnalysis ? 82 : 35;
case 'lighting':
return material.analysis?.lightingAnalysis ? 92 : 50;
default:
return 50;
}
}
1. 标注工具栏
<div class="annotation-toolbar">
<button class="tool-btn"
[class.active]="activeTool === 'text'"
(click)="selectTool('text')">
<svg><!-- 文本图标 --></svg>
文字
</button>
<button class="tool-btn"
[class.active]="activeTool === 'arrow'"
(click)="selectTool('arrow')">
<svg><!-- 箭头图标 --></svg>
箭头
</button>
<button class="tool-btn"
[class.active]="activeTool === 'highlight'"
(click)="selectTool('highlight')">
<svg><!-- 高亮图标 --></svg>
高亮
</button>
<button class="tool-btn"
[class.active]="activeTool === 'circle'"
(click)="selectTool('circle')">
<svg><!-- 圆圈图标 --></svg>
圆圈
</button>
<button class="tool-btn"
[class.active]="activeTool === 'rectangle'"
(click)="selectTool('rectangle')">
<svg><!-- 矩形图标 --></svg>
矩形
</button>
<div class="color-picker">
<input type="color"
[(ngModel)]="annotationColor"
title="标注颜色">
</div>
<button class="tool-btn" (click)="clearAnnotations()">
<svg><!-- 清除图标 --></svg>
清除全部
</button>
</div>
2. 标注画布
<div class="annotation-canvas-container">
<div class="canvas-wrapper">
<!-- 底层:原始图片 -->
<img [src]="selectedMaterial.url"
class="base-image"
#baseImage>
<!-- 中层:SVG标注层 -->
<svg class="annotation-layer"
[attr.width]="canvasWidth"
[attr.height]="canvasHeight"
(mousedown)="startAnnotation($event)"
(mousemove)="continueAnnotation($event)"
(mouseup)="finishAnnotation($event)">
<!-- 已有标注 -->
<g *ngFor="let annotation of annotations"
[attr.data-id]="annotation.id"
class="annotation-item"
(click)="selectAnnotation(annotation)">
<!-- 文字标注 -->
<text *ngIf="annotation.type === 'text'"
[attr.x]="annotation.position.x"
[attr.y]="annotation.position.y"
[attr.fill]="annotation.color">
{{ annotation.content }}
</text>
<!-- 箭头标注 -->
<line *ngIf="annotation.type === 'arrow'"
[attr.x1]="annotation.start.x"
[attr.y1]="annotation.start.y"
[attr.x2]="annotation.end.x"
[attr.y2]="annotation.end.y"
[attr.stroke]="annotation.color"
stroke-width="2"
marker-end="url(#arrowhead)">
</line>
<!-- 高亮标注 -->
<rect *ngIf="annotation.type === 'highlight'"
[attr.x]="annotation.position.x"
[attr.y]="annotation.position.y"
[attr.width]="annotation.size.width"
[attr.height]="annotation.size.height"
[attr.fill]="annotation.color"
opacity="0.3">
</rect>
<!-- 圆圈标注 -->
<circle *ngIf="annotation.type === 'circle'"
[attr.cx]="annotation.position.x"
[attr.cy]="annotation.position.y"
[attr.r]="annotation.radius"
[attr.stroke]="annotation.color"
stroke-width="2"
fill="none">
</circle>
<!-- 矩形标注 -->
<rect *ngIf="annotation.type === 'rectangle'"
[attr.x]="annotation.position.x"
[attr.y]="annotation.position.y"
[attr.width]="annotation.size.width"
[attr.height]="annotation.size.height"
[attr.stroke]="annotation.color"
stroke-width="2"
fill="none">
</rect>
</g>
<!-- 箭头标记定义 -->
<defs>
<marker id="arrowhead" markerWidth="10" markerHeight="10"
refX="5" refY="5" orient="auto">
<polygon points="0 0, 10 5, 0 10" [attr.fill]="annotationColor" />
</marker>
</defs>
</svg>
</div>
<!-- 标注列表 -->
<div class="annotation-list">
<h6>标注列表</h6>
<div class="annotation-item-list">
<div class="list-item"
*ngFor="let annotation of annotations"
[class.selected]="selectedAnnotation?.id === annotation.id"
(click)="selectAnnotation(annotation)">
<span class="type-icon">{{ getAnnotationIcon(annotation.type) }}</span>
<span class="content">{{ annotation.content || annotation.type }}</span>
<span class="author">{{ annotation.author }}</span>
<button class="btn-delete" (click)="deleteAnnotation(annotation.id)">
<svg><!-- 删除图标 --></svg>
</button>
</div>
</div>
</div>
</div>
3. 标注逻辑实现
export class AnnotationToolComponent {
activeTool: 'text' | 'arrow' | 'highlight' | 'circle' | 'rectangle' | null = null;
annotationColor = '#FF0000';
annotations: Annotation[] = [];
isDrawing = false;
currentAnnotation: Partial<Annotation> | null = null;
startAnnotation(event: MouseEvent): void {
if (!this.activeTool) return;
this.isDrawing = true;
const rect = (event.target as HTMLElement).getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
this.currentAnnotation = {
id: this.generateId(),
type: this.activeTool,
position: { x, y },
color: this.annotationColor,
author: this.getCurrentUser(),
timestamp: new Date()
};
}
continueAnnotation(event: MouseEvent): void {
if (!this.isDrawing || !this.currentAnnotation) return;
const rect = (event.target as HTMLElement).getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
// 根据工具类型更新标注
if (this.activeTool === 'arrow') {
this.currentAnnotation.end = { x, y };
} else if (['highlight', 'rectangle'].includes(this.activeTool!)) {
this.currentAnnotation.size = {
width: x - this.currentAnnotation.position!.x,
height: y - this.currentAnnotation.position!.y
};
} else if (this.activeTool === 'circle') {
const dx = x - this.currentAnnotation.position!.x;
const dy = y - this.currentAnnotation.position!.y;
this.currentAnnotation.radius = Math.sqrt(dx * dx + dy * dy);
}
}
finishAnnotation(event: MouseEvent): void {
if (!this.isDrawing || !this.currentAnnotation) return;
this.isDrawing = false;
// 如果是文字工具,弹出输入框
if (this.activeTool === 'text') {
const text = prompt('请输入标注内容:');
if (text) {
this.currentAnnotation.content = text;
this.annotations.push(this.currentAnnotation as Annotation);
this.annotationAdded.emit(this.currentAnnotation as Annotation);
}
} else {
this.annotations.push(this.currentAnnotation as Annotation);
this.annotationAdded.emit(this.currentAnnotation as Annotation);
}
this.currentAnnotation = null;
}
deleteAnnotation(id: string): void {
const index = this.annotations.findIndex(a => a.id === id);
if (index !== -1) {
this.annotations.splice(index, 1);
}
}
clearAnnotations(): void {
if (confirm('确定清除所有标注吗?')) {
this.annotations = [];
}
}
}
1. 区域管理面板
<div class="area-management-panel">
<div class="panel-header">
<h5>区域细分管理</h5>
<button class="btn-primary" (click)="addNewArea()">
<svg><!-- 添加图标 --></svg>
新增区域
</button>
</div>
<!-- 整体方案 -->
<div class="overall-plan"
[class.active]="selectedArea === null"
(click)="selectArea(null)">
<div class="area-header">
<svg><!-- 整体图标 --></svg>
<h6>整体方案</h6>
<span class="area-status" [class]="overallStatus">{{ getStatusText(overallStatus) }}</span>
</div>
<div class="area-summary">
<span>默认统一风格设计</span>
</div>
</div>
<!-- 细分区域列表 -->
<div class="area-list">
<div class="area-item"
*ngFor="let area of areas"
[class.active]="selectedArea?.id === area.id"
(click)="selectArea(area)">
<div class="area-header">
<div class="area-icon" [style.background]="area.color">
{{ area.icon }}
</div>
<div class="area-info">
<h6>{{ area.name }}</h6>
<span class="area-style">{{ area.styleDescription }}</span>
</div>
<span class="area-status" [class]="area.status">
{{ getStatusText(area.status) }}
</span>
</div>
<div class="area-details">
<div class="detail-item">
<span class="label">责任人:</span>
<span class="value">{{ area.assignedTo || '未分配' }}</span>
</div>
<div class="detail-item">
<span class="label">五维验证:</span>
<span class="value">{{ getCompletedDimensions(area) }}/5</span>
</div>
</div>
<div class="area-actions">
<button class="btn-ghost btn-xs" (click)="editArea(area); $event.stopPropagation()">
编辑
</button>
<button class="btn-ghost btn-xs" (click)="deleteArea(area.id); $event.stopPropagation()">
删除
</button>
</div>
</div>
</div>
</div>
2. 区域数据模型
export interface Area {
id: string;
name: string;
icon: string; // emoji或图标
color: string; // 区域标识颜色
styleDescription: string; // 风格描述
status: 'pending' | 'in-progress' | 'completed';
// 分工
assignedTo?: string; // 责任人ID
assignedRole?: string; // 角色
// 五维验证数据
dimensionVerifications: {
color?: DimensionVerification;
form?: DimensionVerification;
texture?: DimensionVerification;
pattern?: DimensionVerification;
lighting?: DimensionVerification;
};
// 特殊需求
specialRequirements?: string[];
// 参考素材(区域专属)
dedicatedMaterials?: string[]; // 素材ID列表
createdAt: Date;
updatedAt: Date;
}
3. 区域添加/编辑对话框
<div class="area-dialog-overlay" *ngIf="showAreaDialog">
<div class="area-dialog">
<div class="dialog-header">
<h5>{{ editingArea ? '编辑区域' : '新增区域' }}</h5>
<button class="btn-close" (click)="closeAreaDialog()">×</button>
</div>
<div class="dialog-body">
<form [formGroup]="areaForm">
<!-- 区域名称 -->
<div class="form-group">
<label>区域名称</label>
<input type="text"
formControlName="name"
placeholder="如:客厅、婴儿房、主卧等">
</div>
<!-- 预设选择 -->
<div class="form-group">
<label>选择预设</label>
<div class="preset-grid">
<button type="button"
class="preset-btn"
*ngFor="let preset of areaPresets"
[class.selected]="selectedPreset?.id === preset.id"
(click)="applyPreset(preset)">
<span class="preset-icon">{{ preset.icon }}</span>
<span class="preset-name">{{ preset.name }}</span>
</button>
</div>
</div>
<!-- 风格描述 -->
<div class="form-group">
<label>风格描述</label>
<textarea formControlName="styleDescription"
rows="3"
placeholder="如:黑白灰很酷的现代风格 或 色彩更儿童化的温馨空间"></textarea>
</div>
<!-- 标识颜色 -->
<div class="form-group">
<label>标识颜色</label>
<input type="color" formControlName="color">
</div>
<!-- 责任人分配 -->
<div class="form-group">
<label>责任人</label>
<select formControlName="assignedTo">
<option value="">-- 未分配 --</option>
<option *ngFor="let user of availableUsers" [value]="user.id">
{{ user.name }} ({{ user.role }})
</option>
</select>
</div>
<!-- 特殊需求 -->
<div class="form-group">
<label>特殊需求</label>
<div class="requirement-tags">
<input type="text"
#requirementInput
placeholder="按Enter添加需求标签"
(keyup.enter)="addRequirement(requirementInput.value); requirementInput.value = ''">
<div class="tags-list">
<span class="tag" *ngFor="let req of specialRequirements; let i = index">
{{ req }}
<button class="remove" (click)="removeRequirement(i)">×</button>
</span>
</div>
</div>
</div>
</form>
</div>
<div class="dialog-footer">
<button class="btn-secondary" (click)="closeAreaDialog()">取消</button>
<button class="btn-primary" (click)="saveArea()">保存</button>
</div>
</div>
</div>
4. 区域预设配置
const areaPresets: AreaPreset[] = [
{
id: 'living-room',
name: '客厅',
icon: '🛋️',
color: '#4A90E2',
styleDescription: '现代简约,明亮开阔',
defaultRequirements: ['开放式布局', '充足采光', '舒适氛围']
},
{
id: 'baby-room',
name: '婴儿房',
icon: '👶',
color: '#FFB6C1',
styleDescription: '色彩丰富,童趣温馨',
defaultRequirements: ['安全环保', '柔和色彩', '储物充足', '易于清洁']
},
{
id: 'master-bedroom',
name: '主卧',
icon: '🛏️',
color: '#9B59B6',
styleDescription: '宁静优雅,私密舒适',
defaultRequirements: ['隔音效果', '柔和灯光', '收纳空间']
},
{
id: 'kitchen',
name: '厨房',
icon: '🍳',
color: '#E67E22',
styleDescription: '实用高效,易于清洁',
defaultRequirements: ['动线合理', '台面充足', '通风良好', '防油防水']
},
{
id: 'bathroom',
name: '卫生间',
icon: '🚿',
color: '#3498DB',
styleDescription: '清新明亮,干湿分离',
defaultRequirements: ['防水防滑', '通风除湿', '储物空间']
},
{
id: 'study',
name: '书房',
icon: '📚',
color: '#27AE60',
styleDescription: '安静专注,书香氛围',
defaultRequirements: ['采光充足', '隔音效果', '书柜充足']
},
{
id: 'dining',
name: '餐厅',
icon: '🍽️',
color: '#F39C12',
styleDescription: '温馨舒适,聚餐氛围',
defaultRequirements: ['空间适中', '照明充足', '易于清洁']
},
{
id: 'custom',
name: '自定义',
icon: '✏️',
color: '#95A5A6',
styleDescription: '',
defaultRequirements: []
}
];
5. 区域切换与对比视图
<div class="area-comparison-view">
<div class="comparison-header">
<h5>区域参数对比</h5>
<button class="btn-ghost" (click)="exportComparison()">导出对比表</button>
</div>
<table class="comparison-table">
<thead>
<tr>
<th>维度/区域</th>
<th *ngFor="let area of areas">{{ area.name }}</th>
</tr>
</thead>
<tbody>
<tr>
<td>色彩</td>
<td *ngFor="let area of areas">
<span class="status-badge" [class]="area.dimensionVerifications.color?.status">
{{ getStatusText(area.dimensionVerifications.color?.status) }}
</span>
</td>
</tr>
<tr>
<td>形体</td>
<td *ngFor="let area of areas">
<span class="status-badge" [class]="area.dimensionVerifications.form?.status">
{{ getStatusText(area.dimensionVerifications.form?.status) }}
</span>
</td>
</tr>
<tr>
<td>质感</td>
<td *ngFor="let area of areas">
<span class="status-badge" [class]="area.dimensionVerifications.texture?.status">
{{ getStatusText(area.dimensionVerifications.texture?.status) }}
</span>
</td>
</tr>
<tr>
<td>纹理</td>
<td *ngFor="let area of areas">
<span class="status-badge" [class]="area.dimensionVerifications.pattern?.status">
{{ getStatusText(area.dimensionVerifications.pattern?.status) }}
</span>
</td>
</tr>
<tr>
<td>灯光</td>
<td *ngFor="let area of areas">
<span class="status-badge" [class]="area.dimensionVerifications.lighting?.status">
{{ getStatusText(area.dimensionVerifications.lighting?.status) }}
</span>
</td>
</tr>
</tbody>
</table>
</div>
1. 人员角色定义
export interface CollaborationUser {
id: string;
name: string;
role: 'designer' | 'customer-service' | 'team-leader' | 'client';
avatar?: string;
permissions: {
canEditColor: boolean;
canEditForm: boolean;
canEditTexture: boolean;
canEditPattern: boolean;
canEditLighting: boolean;
canApprove: boolean;
};
}
2. 分工面板
<div class="collaboration-assignment-panel">
<h6>分工管理</h6>
<!-- 按维度分工 -->
<div class="dimension-assignments">
<div class="assignment-row" *ngFor="let dimension of dimensions">
<span class="dimension-name">{{ dimension.name }}</span>
<select [(ngModel)]="dimensionAssignments[dimension.key]"
(change)="updateAssignment(dimension.key, $event.target.value)">
<option value="">-- 未分配 --</option>
<option *ngFor="let user of eligibleUsers[dimension.key]"
[value]="user.id">
{{ user.name }} ({{ user.role }})
</option>
</select>
<span class="assignment-status">
{{ getAssignmentStatus(dimension.key) }}
</span>
</div>
</div>
<!-- 按区域分工 -->
<div class="area-assignments" *ngIf="areas.length > 0">
<h6>区域责任人</h6>
<div class="assignment-row" *ngFor="let area of areas">
<span class="area-name">{{ area.name }}</span>
<select [(ngModel)]="area.assignedTo"
(change)="updateAreaAssignment(area.id, $event.target.value)">
<option value="">-- 未分配 --</option>
<option *ngFor="let user of availableUsers"
[value]="user.id">
{{ user.name }} ({{ user.role }})
</option>
</select>
</div>
</div>
<!-- 协作状态跟踪 -->
<div class="collaboration-tracking">
<h6>协作状态</h6>
<div class="tracking-grid">
<div class="tracking-item" *ngFor="let user of activeUsers">
<div class="user-avatar">
<img [src]="user.avatar || defaultAvatar" [alt]="user.name">
<span class="online-indicator" *ngIf="user.isOnline"></span>
</div>
<div class="user-info">
<span class="name">{{ user.name }}</span>
<span class="role">{{ getRoleName(user.role) }}</span>
</div>
<div class="user-tasks">
<span class="task-count">{{ getUserTaskCount(user.id) }} 项任务</span>
<span class="completion">{{ getUserCompletion(user.id) }}% 完成</span>
</div>
</div>
</div>
</div>
</div>
3. 审批流程
<div class="approval-workflow">
<h6>审批流程</h6>
<div class="workflow-steps">
<div class="step"
*ngFor="let step of approvalSteps; let i = index"
[class.completed]="step.status === 'completed'"
[class.active]="step.status === 'in-progress'">
<div class="step-number">{{ i + 1 }}</div>
<div class="step-content">
<h6>{{ step.title }}</h6>
<p>{{ step.description }}</p>
<div class="step-assignee">
<span class="label">审批人:</span>
<span class="value">{{ step.assignee?.name || '待分配' }}</span>
</div>
<div class="step-actions" *ngIf="step.status === 'in-progress' && canApprove(step)">
<button class="btn-success btn-sm" (click)="approveStep(step.id)">
通过
</button>
<button class="btn-danger btn-sm" (click)="rejectStep(step.id)">
驳回
</button>
</div>
<div class="step-result" *ngIf="step.status === 'completed'">
<span class="result-badge" [class]="step.result">
{{ step.result === 'approved' ? '已通过' : '已驳回' }}
</span>
<span class="result-time">{{ step.completedAt | date:'MM-dd HH:mm' }}</span>
</div>
</div>
</div>
</div>
</div>
4. 审批逻辑
interface ApprovalStep {
id: string;
title: string;
description: string;
assignee?: CollaborationUser;
status: 'pending' | 'in-progress' | 'completed';
result?: 'approved' | 'rejected';
completedAt?: Date;
comments?: string;
}
const approvalSteps: ApprovalStep[] = [
{
id: 'dimension-verification',
title: '五维验证审核',
description: '设计师完成五个维度的验证',
status: 'pending'
},
{
id: 'customer-service-review',
title: '客服审核',
description: '客服确认需求理解正确',
status: 'pending'
},
{
id: 'team-leader-approval',
title: '组长审批',
description: '组长审批整体方案',
status: 'pending'
},
{
id: 'client-confirmation',
title: '客户确认',
description: '客户最终确认',
status: 'pending'
}
];
approveStep(stepId: string): void {
const step = this.approvalSteps.find(s => s.id === stepId);
if (step) {
step.status = 'completed';
step.result = 'approved';
step.completedAt = new Date();
// 自动启动下一步
const nextStepIndex = this.approvalSteps.indexOf(step) + 1;
if (nextStepIndex < this.approvalSteps.length) {
this.approvalSteps[nextStepIndex].status = 'in-progress';
}
// 检查是否所有步骤都完成
const allApproved = this.approvalSteps.every(s => s.result === 'approved');
if (allApproved) {
this.onAllStepsApproved();
}
}
}
rejectStep(stepId: string): void {
const step = this.approvalSteps.find(s => s.id === stepId);
if (step) {
const reason = prompt('请输入驳回原因:');
if (reason) {
step.status = 'completed';
step.result = 'rejected';
step.comments = reason;
step.completedAt = new Date();
// 通知相关人员
this.notifyRejection(step);
}
}
}
src/app/shared/components/
├── color-wheel-visualizer/ # 色轮可视化组件
│ ├── color-wheel-visualizer.component.ts
│ ├── color-wheel-visualizer.component.html
│ └── color-wheel-visualizer.component.scss
│
├── dimension-verification/ # 维度验证组件
│ ├── dimension-verification.component.ts
│ ├── dimension-verification.component.html
│ └── dimension-verification.component.scss
│
├── annotation-tool/ # 标注工具组件
│ ├── annotation-tool.component.ts
│ ├── annotation-tool.component.html
│ └── annotation-tool.component.scss
│
├── area-management/ # 区域管理组件
│ ├── area-management.component.ts
│ ├── area-management.component.html
│ └── area-management.component.scss
│
├── furniture-form-selector/ # 软装形体选择器
│ ├── furniture-form-selector.component.ts
│ ├── furniture-form-selector.component.html
│ └── furniture-form-selector.component.scss
│
├── texture-comparison/ # 质感对比组件
│ ├── texture-comparison.component.ts
│ ├── texture-comparison.component.html
│ └── texture-comparison.component.scss
│
├── pattern-visualizer/ # 纹理可视化组件
│ ├── pattern-visualizer.component.ts
│ ├── pattern-visualizer.component.html
│ └── pattern-visualizer.component.scss
│
└── lighting-distribution-chart/ # 光占比图表组件
├── lighting-distribution-chart.component.ts
├── lighting-distribution-chart.component.html
└── lighting-distribution-chart.component.scss
1. requirements-confirm-card.ts
2. requirements-confirm-card.html
3. requirements-confirm-card.scss
新建接口文件:
src/app/models/
├── collaboration-verification.interface.ts # 协作验证相关接口
├── annotation.interface.ts # 标注相关接口
├── area-management.interface.ts # 区域管理相关接口
└── approval-workflow.interface.ts # 审批流程相关接口
// 需要后端提供的API接口
// 1. 灯光分析增强
POST /api/analysis/lighting/ratio // 计算光比
POST /api/analysis/lighting/distribution // 计算光占比
// 2. 标注管理
POST /api/annotations // 创建标注
GET /api/annotations/:projectId // 获取项目标注
PUT /api/annotations/:id // 更新标注
DELETE /api/annotations/:id // 删除标注
// 3. 区域管理
POST /api/areas // 创建区域
GET /api/areas/:projectId // 获取项目区域
PUT /api/areas/:id // 更新区域
DELETE /api/areas/:id // 删除区域
// 4. 分工管理
POST /api/assignments // 分配任务
GET /api/assignments/:projectId // 获取项目分工
PUT /api/assignments/:id // 更新分工
// 5. 审批流程
POST /api/approvals/:stepId/approve // 审批通过
POST /api/approvals/:stepId/reject // 审批驳回
GET /api/approvals/:projectId/status // 获取审批状态
优先级:高
任务清单:
验收标准:
优先级:中
任务清单:
验收标准:
优先级:高(核心)
子阶段3.1:五维验证模块(3-4天)
子阶段3.2:素材关联系统(2-3天)
子阶段3.3:标注工具集成(3-4天)
子阶段3.4:区域细分管理(2-3天)
子阶段3.5:分工和人员系统(2-3天)
验收标准:
素材分析模块:
协作验证模块:
系统集成:
交互体验:
视觉设计:
易用性:
性能要求:
技术风险:
色轮可视化性能 - 大量颜色数据可能影响渲染性能
标注工具复杂度 - SVG操作和状态管理复杂
拖拽关联稳定性 - CDK Drag&Drop可能有兼容性问题
业务风险:
区域细分粒度 - 过细可能导致操作复杂
审批流程僵化 - 固定流程可能不适合所有项目
性能优化:
用户体验优化:
扩展性建议:
本优化方案围绕三个核心目标:
素材分析完全展示 - 通过增强色彩、形体、质感、纹理、灯光五个维度的可视化和数据完整性,确保所有采集的参考信息都能充分展示。
需求映射后台化 - 将用户不需要直接操作的需求映射功能隐藏,改为自动触发,简化用户流程。
协作验证深度重构 - 这是最核心的改进,通过五维验证、素材关联、标注工具、区域细分、分工管理等功能,实现真正的协作式需求验证。
实施建议采用分阶段推进,优先完成素材分析增强和协作验证重构,这两个是高优先级且用户价值最大的功能。
如有疑问或需要进一步讨论,请联系:
文档版本: v1.0
创建日期: {{ currentDate }}
最后更新: {{ currentDate }}
状态: 待审核