需求确认阶段包含"需求沟通"和"方案确认"两个子环节,是连接订单分配与交付执行的关键桥梁。该阶段通过AI辅助分析工具深入理解客户需求,并将抽象需求转化为可执行的设计方案。
graph TD
A[订单分配完成] --> B{是否多产品设计项目?}
B -->|否| C[单产品设计需求管理流程]
B -->|是| D[多产品设计需求管理流程]
D --> E[产品设计需求识别]
D --> F[全局需求定义]
D --> G[跨产品关系分析]
E --> H[各产品设计独立需求采集]
F --> I[整体风格和预算约束]
G --> J[产品间依赖和一致性]
H --> K[需求一致性检查]
I --> K
J --> K
K --> L{一致性检查通过?}
L -->|是| M[生成多产品设计方案]
L -->|否| N[需求调整和协调]
N --> E
M --> O[客户确认方案]
O --> P[推进到交付执行]
style C fill:#e8f5e9
style D fill:#fff3e0
style P fill:#e3f2fd
interface Product {
// 产品基本信息
objectId: string;
project: Pointer<Project>;
profile: Pointer<Profile>;
productName: string; // "李总主卧设计"
productType: string; // "bedroom"
// 空间信息字段 (Product.space)
space: {
spaceName: string; // "主卧"
area: number; // 18.5
dimensions: {
length: number;
width: number;
height: number;
};
features: string[]; // ["朝南", "飘窗", "独立卫浴"]
constraints: string[]; // ["承重墙不可动"]
priority: string; // "high"
complexity: string; // "medium"
};
// 产品需求字段 (Product.requirements)
requirements: {
// 色彩需求
colorRequirement: {
primaryHue: number;
saturation: number;
temperature: string; // "暖色调"
colorDistribution: Array<{
hex: string;
percentage: number;
name: string;
}>;
};
// 材质需求
materialRequirement: {
preferred: string[]; // ["实木", "环保材料"]
avoid: string[]; // ["塑料", "合成材料"]
budget: {
min: number;
max: number;
};
};
// 照明需求
lightingRequirement: {
naturalLight: string; // "充足"
lightColor: string; // "暖白"
specialRequirements: string[]; // ["床头阅读灯", "氛围灯"]
};
// 具体需求
specificRequirements: string[]; // ["需要大储物空间", "独立卫浴"]
// 参考图片
referenceImages: string[];
// 约束条件
constraints: {
structural: string[];
budget: number;
timeline: number;
};
};
// 产品报价字段 (Product.quotation)
quotation: {
price: number;
currency: string; // "CNY"
breakdown: {
design: number;
modeling: number;
rendering: number;
softDecor: number;
};
status: string; // "pending" | "approved"
validUntil: Date;
};
// 产品状态
status: 'not_started' | 'in_progress' | 'awaiting_review' | 'completed';
}
class ProductRequirementService {
// 创建产品设计需求
async createProductRequirement(
projectId: string,
designerId: string,
requirementData: ProductRequirementData
): Promise<Product> {
const product = new Parse.Object("Product");
product.set("project", { __type: "Pointer", className: "Project", objectId: projectId });
product.set("profile", { __type: "Pointer", className: "Profile", objectId: designerId });
product.set("productName", requirementData.productName);
product.set("productType", requirementData.productType);
// 设置空间信息
product.set("space", requirementData.space);
// 设置需求信息
product.set("requirements", requirementData.requirements);
// 设置初始报价
product.set("quotation", this.generateInitialQuotation(requirementData));
await product.save();
return product;
}
// 需求一致性检查
async checkRequirementConsistency(
products: Product[]
): Promise<ConsistencyCheckResult> {
const result: ConsistencyCheckResult = {
isConsistent: true,
conflicts: [],
recommendations: []
};
// 检查跨产品风格一致性
const styleConflicts = this.checkStyleConsistency(products);
if (styleConflicts.length > 0) {
result.isConsistent = false;
result.conflicts.push(...styleConflicts);
}
// 检查预算约束
const budgetConflicts = this.checkBudgetConstraints(products);
if (budgetConflicts.length > 0) {
result.isConsistent = false;
result.conflicts.push(...budgetConflicts);
}
// 检查时间约束
const timelineConflicts = this.checkTimelineConstraints(products);
if (timelineConflicts.length > 0) {
result.isConsistent = false;
result.conflicts.push(...timelineConflicts);
}
return result;
}
// AI需求分析
async analyzeRequirement(
customerDescription: string,
referenceImages: string[]
): Promise<RequirementAnalysisResult> {
// 调用AI服务分析客户描述
const aiAnalysis = await this.aiService.analyzeDesignRequirement({
description: customerDescription,
images: referenceImages,
context: "home_design"
});
return {
colorPreference: aiAnalysis.colorPreference,
materialPreference: aiAnalysis.materialPreference,
stylePreference: aiAnalysis.stylePreference,
spaceRequirements: aiAnalysis.spaceRequirements,
confidence: aiAnalysis.confidence,
suggestedQuestions: aiAnalysis.suggestedQuestions
};
}
}
// React 组件示例
const ProductRequirementPanel = ({ projectId, onRequirementUpdate }) => {
const [products, setProducts] = useState<Product[]>([]);
const [selectedProduct, setSelectedProduct] = useState<Product | null>(null);
const [consistencyResult, setConsistencyResult] = useState<ConsistencyCheckResult | null>(null);
// 加载项目的产品列表
useEffect(() => {
loadProjectProducts();
}, [projectId]);
const loadProjectProducts = async () => {
const query = new Parse.Query("Product");
query.equalTo("project", { __type: "Pointer", className: "Project", objectId: projectId });
query.include("profile");
const results = await query.find();
setProducts(results);
};
// 需求一致性检查
const checkConsistency = async () => {
if (products.length > 1) {
const result = await requirementService.checkRequirementConsistency(products);
setConsistencyResult(result);
}
};
return (
<div className="product-requirement-panel">
{/* 产品列表 */}
<div className="product-list">
<h3>空间设计产品</h3>
{products.map(product => (
<ProductRequirementCard
key={product.id}
product={product}
onSelect={setSelectedProduct}
onUpdate={loadProjectProducts}
/>
))}
</div>
{/* 需求编辑器 */}
{selectedProduct && (
<RequirementEditor
product={selectedProduct}
onSave={async (updatedRequirements) => {
selectedProduct.set("requirements", updatedRequirements);
await selectedProduct.save();
loadProjectProducts();
onRequirementUpdate();
}}
/>
)}
{/* 一致性检查结果 */}
{consistencyResult && (
<ConsistencyCheckResult result={consistencyResult} />
)}
</div>
);
};
class ConsistencyRules {
// 风格一致性检查
checkStyleConsistency(products: Product[]): Conflict[] {
const conflicts: Conflict[] = [];
const styleMap = new Map<string, Product[]>();
// 收集所有产品的风格信息
products.forEach(product => {
const style = this.extractStyleFromRequirements(product.requirements);
if (!styleMap.has(style)) {
styleMap.set(style, []);
}
styleMap.get(style)!.push(product);
});
// 检查风格冲突
if (styleMap.size > 1) {
conflicts.push({
type: "style_conflict",
description: "发现风格不一致的产品设计",
affectedProducts: products,
recommendation: "建议统一整体风格或明确各产品的风格定位"
});
}
return conflicts;
}
// 预算约束检查
checkBudgetConstraints(products: Product[]): Conflict[] {
const conflicts: Conflict[] = [];
const totalBudget = products.reduce((sum, product) => {
return sum + (product.quotation?.price || 0);
}, 0);
// 获取项目总预算约束
const projectBudget = this.getProjectBudget(products[0].project);
if (totalBudget > projectBudget) {
conflicts.push({
type: "budget_exceeded",
description: `总预算${totalBudget}超过项目预算${projectBudget}`,
affectedProducts: products,
recommendation: "建议调整产品报价或增加项目预算"
});
}
return conflicts;
}
// 时间约束检查
checkTimelineConstraints(products: Product[]): Conflict[] {
const conflicts: Conflict[] = [];
const totalTimeline = products.reduce((sum, product) => {
return sum + (product.requirements?.constraints?.timeline || 0);
}, 0);
// 检查产品间的时间依赖
const dependencies = this.analyzeProductDependencies(products);
dependencies.forEach(dep => {
if (dep.conflict) {
conflicts.push({
type: "timeline_conflict",
description: `产品${dep.fromProduct.productName}与${dep.toProduct.productName}存在时间冲突`,
affectedProducts: [dep.fromProduct, dep.toProduct],
recommendation: "建议调整产品执行顺序或时间安排"
});
}
});
return conflicts;
}
}
class DesignProposalService {
// 基于需求生成设计方案
async generateDesignProposal(
products: Product[],
customerRequirements: CustomerRequirement
): Promise<DesignProposal> {
const proposal: DesignProposal = {
id: generateId(),
projectId: products[0].project.id,
products: [],
overallDesign: {},
timeline: {},
budget: {},
status: "draft"
};
// 为每个产品生成设计方案
for (const product of products) {
const productDesign = await this.generateProductDesign(product, customerRequirements);
proposal.products.push(productDesign);
}
// 生成整体设计方案
proposal.overallDesign = await this.generateOverallDesign(products, customerRequirements);
// 生成时间计划
proposal.timeline = this.generateTimeline(proposal.products);
// 生成预算方案
proposal.budget = this.generateBudget(proposal.products);
return proposal;
}
// 客户确认方案
async confirmProposal(
proposalId: string,
customerFeedback: CustomerFeedback
): Promise<ProposalConfirmationResult> {
const proposal = await this.getProposal(proposalId);
if (customerFeedback.approved) {
// 方案确认通过,更新产品状态
await this.updateProductStatus(proposal.products, "in_progress");
return {
success: true,
message: "方案已确认,项目进入执行阶段"
};
} else {
// 方案需要修改
await this.handleProposalRevision(proposal, customerFeedback);
return {
success: false,
message: "方案需要修改,请根据客户反馈调整设计"
};
}
}
}
<!-- 产品需求管理主界面 -->
<div class="requirement-confirmation-container">
<!-- 头部导航 -->
<div class="requirement-header">
<h2>需求确认 - {{ project.title }}</h2>
<div class="progress-indicator">
<div class="step active">需求沟通</div>
<div class="step">方案确认</div>
<div class="step">客户确认</div>
</div>
</div>
<!-- 产品列表 -->
<div class="product-section">
<h3>空间设计产品列表</h3>
<div class="product-grid">
<div v-for="product in products" :key="product.id"
class="product-card"
:class="{ active: selectedProduct?.id === product.id }"
@click="selectProduct(product)">
<div class="product-header">
<h4>{{ product.productName }}</h4>
<span class="product-type">{{ getProductTypeLabel(product.productType) }}</span>
</div>
<div class="product-info">
<div class="space-info">
<span class="area">{{ product.space.area }}㎡</span>
<span class="complexity">{{ product.space.complexity }}</span>
</div>
<div class="designer-info">
<img :src="product.profile.avatar" class="designer-avatar" />
<span>{{ product.profile.name }}</span>
</div>
</div>
<div class="requirement-summary">
<div class="requirement-item">
<label>风格:</label>
<span>{{ getStyleLabel(product.requirements.colorRequirement.temperature) }}</span>
</div>
<div class="requirement-item">
<label>材质:</label>
<span>{{ product.requirements.materialRequirement.preferred.join(', ') }}</span>
</div>
</div>
<div class="product-status">
<span class="status-badge" :class="product.status">
{{ getStatusLabel(product.status) }}
</span>
</div>
</div>
</div>
</div>
<!-- 需求编辑器 -->
<div class="requirement-editor" v-if="selectedProduct">
<h3>产品需求编辑 - {{ selectedProduct.productName }}</h3>
<div class="requirement-tabs">
<div class="tab"
v-for="tab in requirementTabs"
:key="tab.key"
:class="{ active: activeTab === tab.key }"
@click="activeTab = tab.key">
{{ tab.label }}
</div>
</div>
<!-- 色彩需求 -->
<div class="tab-content" v-show="activeTab === 'color'">
<ColorRequirementEditor
:requirement="selectedProduct.requirements.colorRequirement"
@update="updateColorRequirement" />
</div>
<!-- 材质需求 -->
<div class="tab-content" v-show="activeTab === 'material'">
<MaterialRequirementEditor
:requirement="selectedProduct.requirements.materialRequirement"
@update="updateMaterialRequirement" />
</div>
<!-- 照明需求 -->
<div class="tab-content" v-show="activeTab === 'lighting'">
<LightingRequirementEditor
:requirement="selectedProduct.requirements.lightingRequirement"
@update="updateLightingRequirement" />
</div>
<!-- 具体需求 -->
<div class="tab-content" v-show="activeTab === 'specific'">
<SpecificRequirementEditor
:requirement="selectedProduct.requirements.specificRequirements"
@update="updateSpecificRequirement" />
</div>
</div>
<!-- 一致性检查 -->
<div class="consistency-check" v-if="products.length > 1">
<h3>跨产品一致性检查</h3>
<button class="check-button" @click="checkConsistency">
执行一致性检查
</button>
<div class="check-results" v-if="consistencyResult">
<div class="result-item"
v-for="result in consistencyResult.conflicts"
:key="result.type"
:class="result.type">
<div class="conflict-header">
<span class="conflict-type">{{ getConflictTypeLabel(result.type) }}</span>
<span class="conflict-severity">{{ result.severity }}</span>
</div>
<div class="conflict-description">{{ result.description }}</div>
<div class="conflict-recommendation">{{ result.recommendation }}</div>
</div>
</div>
</div>
<!-- 方案预览 -->
<div class="proposal-preview">
<h3>设计方案预览</h3>
<button class="generate-button" @click="generateProposal">
生成设计方案
</button>
<div class="proposal-content" v-if="designProposal">
<div class="proposal-overview">
<h4>整体设计概览</h4>
<p>{{ designProposal.overallDesign.description }}</p>
</div>
<div class="proposal-budget">
<h4>预算方案</h4>
<div class="budget-breakdown">
<div v-for="item in designProposal.budget.breakdown" :key="item.type">
<span class="budget-type">{{ item.type }}:</span>
<span class="budget-amount">¥{{ item.amount.toLocaleString() }}</span>
</div>
<div class="budget-total">
<span>总计: ¥{{ designProposal.budget.total.toLocaleString() }}</span>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 需求确认流程界面 -->
<div class="requirement-confirmation-flow">
<!-- 步骤指示器 -->
<div class="flow-steps">
<div class="step"
v-for="(step, index) in confirmationSteps"
:key="index"
:class="{
active: currentStep === index,
completed: currentStep > index
}">
<div class="step-number">{{ index + 1 }}</div>
<div class="step-label">{{ step.label }}</div>
<div class="step-description">{{ step.description }}</div>
</div>
</div>
<!-- 步骤内容 -->
<div class="step-content">
<!-- 需求沟通步骤 -->
<div v-if="currentStep === 0" class="communication-step">
<CommunicationInterface
:products="products"
@requirement-collected="handleRequirementCollected"
@communication-completed="handleCommunicationCompleted" />
</div>
<!-- 方案确认步骤 -->
<div v-if="currentStep === 1" class="proposal-step">
<ProposalInterface
:products="products"
:requirements="collectedRequirements"
@proposal-generated="handleProposalGenerated"
@proposal-confirmed="handleProposalConfirmed" />
</div>
<!-- 客户确认步骤 -->
<div v-if="currentStep === 2" class="confirmation-step">
<CustomerConfirmationInterface
:proposal="generatedProposal"
@customer-approved="handleCustomerApproved"
@customer-rejected="handleCustomerRejected" />
</div>
</div>
<!-- 操作按钮 -->
<div class="flow-actions">
<button v-if="currentStep > 0"
class="prev-button"
@click="previousStep">
上一步
</button>
<button v-if="currentStep < confirmationSteps.length - 1"
class="next-button"
:disabled="!canProceedToNext"
@click="nextStep">
下一步
</button>
<button v-if="currentStep === confirmationSteps.length - 1"
class="complete-button"
:disabled="!canCompleteFlow"
@click="completeConfirmation">
完成需求确认
</button>
</div>
</div>
文档版本: v3.0 (Product表统一空间管理) 最后更新: 2025-10-20 维护者: YSS Development Team