本文档定义了设计师端和客服端项目详情页面的统一数据范式,旨在实现数据结构的标准化、一致性和可扩展性。该范式涵盖了项目全生命周期的所有数据需求,支持多角色协作和实时数据同步。
// 统一项目数据模型
interface UnifiedProject {
// 基础信息
id: string;
name: string;
projectCode?: string; // 项目编号
// 客户信息
customer: {
id: string;
name: string;
phone: string;
wechat?: string;
avatar?: string;
type: 'new' | 'existing' | 'vip'; // 客户类型
source: '朋友圈' | '信息流' | '转介绍' | '其他'; // 来源渠道
tags: CustomerTag[];
remark?: string;
// 需求信息
demandType: 'price-sensitive' | 'value-sensitive' | 'comprehensive';
preferenceTags: string[];
followUpStatus: 'quotation' | 'confirm' | 'lost' | 'signed';
};
// 项目状态与阶段
status: ProjectStatus;
currentStage: ProjectStage;
stageHistory: StageHistoryItem[];
// 时间信息
createdAt: Date;
updatedAt: Date;
deadline: Date;
estimatedCompletionDate?: Date;
actualCompletionDate?: Date;
// 人员分配
assignee: {
designerId: string;
designerName: string;
assignedAt: Date;
skillsRequired: string[];
};
customerServiceId?: string;
customerServiceName?: string;
// 项目需求
requirements: ProjectRequirement;
// 工作流程数据
workflow: WorkflowData;
// 文件与交付物
deliverables: DeliverableData;
// 沟通记录
communications: CommunicationRecord[];
// 财务信息
financial: FinancialData;
// 质量控制
qualityControl: QualityControlData;
}
// 客户标签
interface CustomerTag {
source: '朋友圈' | '信息流';
needType: '硬装' | '软装' | '全案';
preference: '现代' | '宋式' | '欧式' | '北欧' | '中式' | '其他';
colorAtmosphere: string;
budget?: {
min: number;
max: number;
currency: 'CNY';
};
}
// 项目状态
type ProjectStatus = '待分配' | '进行中' | '已完成' | '已暂停' | '已延期' | '已取消';
// 项目阶段
type ProjectStage =
| '订单创建'
| '需求沟通'
| '方案确认'
| '建模'
| '软装'
| '渲染'
| '后期'
| '尾款结算'
| '客户评价'
| '投诉处理';
// 阶段历史记录
interface StageHistoryItem {
stage: ProjectStage;
startTime: Date;
endTime?: Date;
duration?: number; // 小时
status: 'completed' | 'current' | 'pending' | 'skipped';
operator: {
id: string;
name: string;
role: 'designer' | 'customer-service' | 'team-leader' | 'admin';
};
notes?: string;
}
// 项目需求
interface ProjectRequirement {
// 空间信息
spaces: SpaceInfo[];
// 设计需求
designRequirements: {
style: string[];
colorPreference: string;
materialPreference: string[];
specialRequirements: string[];
};
// 功能需求
functionalRequirements: string[];
// 高优先级需求
highPriorityNeeds: string[];
// 需求关键信息
keyInfo: {
colorAtmosphere: {
description: string;
mainColor: string;
colorTemp: string;
materials: string[];
};
spaceStructure: {
lineRatio: number;
blankRatio: number;
flowWidth: number;
aspectRatio: number;
ceilingHeight: number;
};
lightingLayout: {
naturalLight: string;
artificialLight: string[];
ambientRequirements: string;
};
};
}
// 空间信息
interface SpaceInfo {
id: string;
name: string; // 客厅、卧室、厨房等
area: number; // 平方米
dimensions: {
length: number;
width: number;
height: number;
};
existingConditions: string[];
requirements: string[];
}
// 工作流程数据
interface WorkflowData {
// 各阶段进度
stageProgress: Record<ProjectStage, {
progress: number; // 0-100
status: 'not_started' | 'in_progress' | 'completed' | 'on_hold';
startTime?: Date;
endTime?: Date;
estimatedDuration: number; // 小时
actualDuration?: number; // 小时
milestones: Milestone[];
}>;
// 交付执行详情
deliveryExecution: {
processes: DeliveryProcess[];
overallProgress: number;
};
}
// 里程碑
interface Milestone {
id: string;
title: string;
description: string;
dueDate: Date;
completedDate?: Date;
isCompleted: boolean;
priority: 'high' | 'medium' | 'low';
}
// 交付执行流程
interface DeliveryProcess {
id: string;
name: string; // 建模、软装、渲染、后期
type: 'modeling' | 'softDecor' | 'rendering' | 'postProcess';
spaces: DeliverySpace[];
isExpanded: boolean;
content: Record<string, {
images: DeliverableFile[];
progress: number;
status: 'pending' | 'in_progress' | 'completed' | 'approved';
notes: string;
lastUpdated: Date;
}>;
}
// 交付空间
interface DeliverySpace {
id: string;
name: string;
isExpanded: boolean;
order: number;
}
// 交付物数据
interface DeliverableData {
files: DeliverableFile[];
categories: Record<string, DeliverableFile[]>;
uploadHistory: UploadHistoryItem[];
}
// 交付文件
interface DeliverableFile {
id: string;
name: string;
type: 'image' | 'document' | 'video' | 'model' | 'other';
format: string; // jpg, png, pdf, dwg, etc.
size: number; // bytes
url: string;
thumbnailUrl?: string;
uploadedBy: string;
uploadedAt: Date;
stage: ProjectStage;
space?: string; // 关联空间
process?: string; // 关联流程
reviewStatus: 'pending' | 'approved' | 'rejected' | 'revision_required';
reviewNotes?: string;
version: number;
downloadCount: number;
metadata?: Record<string, any>;
}
// 上传历史
interface UploadHistoryItem {
id: string;
fileId: string;
action: 'upload' | 'replace' | 'delete';
operator: string;
timestamp: Date;
notes?: string;
}
// 沟通记录
interface CommunicationRecord {
id: string;
type: 'message' | 'call' | 'meeting' | 'email' | 'feedback';
participants: Participant[];
content: string;
attachments: DeliverableFile[];
timestamp: Date;
isRead: boolean;
priority: 'high' | 'medium' | 'low';
tags: string[];
relatedStage?: ProjectStage;
}
// 参与者
interface Participant {
id: string;
name: string;
role: 'customer' | 'designer' | 'customer-service' | 'team-leader';
avatar?: string;
}
// 财务数据
interface FinancialData {
totalAmount: number;
currency: 'CNY';
// 分阶段结算
settlements: Settlement[];
// 付款记录
payments: PaymentRecord[];
// 预算信息
budget: {
estimated: number;
actual: number;
breakdown: Record<string, number>;
};
}
// 结算记录
interface Settlement {
id: string;
stage: ProjectStage;
amount: number;
percentage: number;
status: '待结算' | '已结算' | '逾期';
dueDate: Date;
settledAt?: Date;
paymentMethod?: string;
notes?: string;
}
// 付款记录
interface PaymentRecord {
id: string;
settlementId: string;
amount: number;
paymentMethod: string;
transactionId?: string;
paidAt: Date;
status: 'pending' | 'completed' | 'failed' | 'refunded';
notes?: string;
}
// 质量控制数据
interface QualityControlData {
// 模型检查
modelChecks: ModelCheckItem[];
// 客户反馈
customerFeedbacks: CustomerFeedback[];
// 内部评审
internalReviews: InternalReview[];
// 异常记录
exceptions: ExceptionRecord[];
}
// 模型检查项
interface ModelCheckItem {
id: string;
name: string;
category: string;
isPassed: boolean;
checkedBy: string;
checkedAt: Date;
notes?: string;
images?: string[];
}
// 客户反馈
interface CustomerFeedback {
id: string;
content: string;
type: 'suggestion' | 'complaint' | 'praise' | 'question';
stage: ProjectStage;
rating?: number; // 1-5
isSatisfied: boolean;
problemLocation?: string;
expectedEffect?: string;
referenceCase?: string;
status: '待处理' | '处理中' | '已解决';
response?: string;
respondedBy?: string;
respondedAt?: Date;
createdAt: Date;
attachments?: DeliverableFile[];
}
// 内部评审
interface InternalReview {
id: string;
stage: ProjectStage;
reviewer: string;
reviewType: 'quality' | 'progress' | 'compliance';
score?: number;
comments: string;
recommendations: string[];
reviewedAt: Date;
status: 'passed' | 'failed' | 'conditional';
}
// 异常记录
interface ExceptionRecord {
id: string;
type: 'failed' | 'stuck' | 'quality' | 'timeline' | 'resource' | 'other';
severity: 'low' | 'medium' | 'high' | 'critical';
description: string;
stage: ProjectStage;
reportedBy: string;
reportedAt: Date;
status: '待处理' | '处理中' | '已解决' | '已关闭';
assignedTo?: string;
resolution?: string;
resolvedAt?: Date;
impact: string;
preventiveMeasures?: string[];
}
// 项目列表响应
interface ProjectListResponse {
data: ProjectListItem[];
pagination: {
page: number;
pageSize: number;
total: number;
totalPages: number;
};
filters: {
stages: ProjectStage[];
statuses: ProjectStatus[];
assignees: { id: string; name: string }[];
};
}
// 项目列表项
interface ProjectListItem {
id: string;
name: string;
customerName: string;
status: ProjectStatus;
currentStage: ProjectStage;
progress: number;
assigneeName: string;
createdAt: Date;
deadline: Date;
priority: 'high' | 'medium' | 'low';
isOverdue: boolean;
tags: string[];
}
// 项目详情响应
interface ProjectDetailResponse {
project: UnifiedProject;
permissions: UserPermissions;
relatedProjects?: ProjectListItem[];
statistics: ProjectStatistics;
}
// 用户权限
interface UserPermissions {
canEdit: boolean;
canDelete: boolean;
canAssign: boolean;
canViewFinancial: boolean;
canUploadFiles: boolean;
canReviewFiles: boolean;
canCommunicate: boolean;
canManageStages: boolean;
}
// 项目统计
interface ProjectStatistics {
totalDuration: number; // 小时
completionRate: number; // 百分比
customerSatisfaction?: number; // 1-5
fileCount: number;
communicationCount: number;
exceptionCount: number;
onTimeDeliveryRate: number; // 百分比
}
// 文件上传请求
interface FileUploadRequest {
projectId: string;
stage: ProjectStage;
space?: string;
process?: string;
files: File[];
notes?: string;
replaceFileId?: string; // 替换现有文件
}
// 文件上传响应
interface FileUploadResponse {
success: boolean;
files: DeliverableFile[];
errors?: string[];
warnings?: string[];
}
// 阶段推进请求
interface StageProgressRequest {
projectId: string;
fromStage: ProjectStage;
toStage: ProjectStage;
notes?: string;
attachments?: string[]; // 文件ID列表
skipValidation?: boolean;
}
// 阶段推进响应
interface StageProgressResponse {
success: boolean;
newStage: ProjectStage;
validationResults?: ValidationResult[];
warnings?: string[];
nextActions?: string[];
}
// 验证结果
interface ValidationResult {
type: 'error' | 'warning' | 'info';
message: string;
field?: string;
code?: string;
}
// 数据同步配置
interface SyncConfiguration {
// 实时同步的数据类型
realTimeSync: ('progress' | 'files' | 'communications' | 'status')[];
// 同步间隔(毫秒)
syncInterval: number;
// 冲突解决策略
conflictResolution: 'server-wins' | 'client-wins' | 'merge' | 'manual';
// 离线支持
offlineSupport: boolean;
// 数据缓存策略
cacheStrategy: {
maxAge: number; // 毫秒
maxSize: number; // MB
priority: ('recent' | 'frequent' | 'important')[];
};
}
// 数据变更事件
interface DataChangeEvent {
type: 'create' | 'update' | 'delete';
entity: 'project' | 'file' | 'communication' | 'stage' | 'feedback';
entityId: string;
changes: Record<string, any>;
timestamp: Date;
userId: string;
userRole: string;
}
// 插件接口
interface ProjectPlugin {
id: string;
name: string;
version: string;
// 数据扩展
extendProjectData?: (project: UnifiedProject) => Record<string, any>;
// UI扩展
renderCustomTabs?: () => CustomTab[];
renderCustomActions?: () => CustomAction[];
// 事件处理
onStageChange?: (event: StageChangeEvent) => void;
onFileUpload?: (event: FileUploadEvent) => void;
}
// 自定义标签页
interface CustomTab {
id: string;
title: string;
icon?: string;
component: any;
permissions?: string[];
}
// 自定义操作
interface CustomAction {
id: string;
title: string;
icon?: string;
handler: () => void;
permissions?: string[];
context: ('project' | 'stage' | 'file')[];
}
CREATE TABLE projects (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(255) NOT NULL,
project_code VARCHAR(50) UNIQUE,
customer_id VARCHAR(36) NOT NULL,
status ENUM('待分配', '进行中', '已完成', '已暂停', '已延期', '已取消'),
current_stage ENUM('订单创建', '需求沟通', '方案确认', '建模', '软装', '渲染', '后期', '尾款结算', '客户评价', '投诉处理'),
assignee_id VARCHAR(36),
customer_service_id VARCHAR(36),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deadline TIMESTAMP,
estimated_completion_date TIMESTAMP,
actual_completion_date TIMESTAMP,
INDEX idx_status (status),
INDEX idx_current_stage (current_stage),
INDEX idx_assignee (assignee_id),
INDEX idx_customer (customer_id)
);
CREATE TABLE customers (
id VARCHAR(36) PRIMARY KEY,
name VARCHAR(100) NOT NULL,
phone VARCHAR(20) UNIQUE,
wechat VARCHAR(50),
avatar VARCHAR(255),
type ENUM('new', 'existing', 'vip'),
source ENUM('朋友圈', '信息流', '转介绍', '其他'),
demand_type ENUM('price-sensitive', 'value-sensitive', 'comprehensive'),
follow_up_status ENUM('quotation', 'confirm', 'lost', 'signed'),
remark TEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_phone (phone),
INDEX idx_type (type),
INDEX idx_source (source)
);
CREATE TABLE deliverable_files (
id VARCHAR(36) PRIMARY KEY,
project_id VARCHAR(36) NOT NULL,
name VARCHAR(255) NOT NULL,
type ENUM('image', 'document', 'video', 'model', 'other'),
format VARCHAR(10),
size BIGINT,
url VARCHAR(500) NOT NULL,
thumbnail_url VARCHAR(500),
uploaded_by VARCHAR(36) NOT NULL,
uploaded_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
stage ENUM('订单创建', '需求沟通', '方案确认', '建模', '软装', '渲染', '后期', '尾款结算', '客户评价', '投诉处理'),
space VARCHAR(100),
process VARCHAR(100),
review_status ENUM('pending', 'approved', 'rejected', 'revision_required'),
review_notes TEXT,
version INT DEFAULT 1,
download_count INT DEFAULT 0,
metadata JSON,
INDEX idx_project (project_id),
INDEX idx_stage (stage),
INDEX idx_type (type),
INDEX idx_uploaded_by (uploaded_by),
FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
);
复合索引:
(project_id, stage)
- 用于按项目和阶段查询文件(customer_id, status)
- 用于按客户查询项目状态(assignee_id, current_stage)
- 用于设计师工作台查询全文索引:
分区策略:
数据迁移:
兼容性处理:
缓存策略:
查询优化:
数据权限:
API 安全:
本数据范式提供了一个完整、统一的项目管理数据模型,具有以下特点:
通过实施这个数据范式,可以实现:
建议在实施过程中分阶段进行,先实现核心功能,再逐步扩展高级特性,确保系统的稳定性和可维护性。