--- category: schema title: YSS项目Parse Server数据范式 - 统一空间管理 subtitle: 映三色设计师项目管理系统完整数据表结构(统一空间管理版本) name: 'yss-schemas-unified-space' label: database --- # Parse Server 数据范式 - 映三色项目管理系统(统一空间管理) ## 概述 本文档定义了映三色(YSS)设计师项目管理系统的完整Parse Server数据范式。系统采用**多租户架构**,以Company为核心,支持客服、设计师、组长等多角色协作的全流程项目管理。 **核心特性**: - 🏢 多租户架构,以Company为核心租户隔离 - 👥 统一员工表(Profile)和客户表(ContactInfo) - 📋 项目与群聊灵活关联(Project ←→ GroupChat) - 🏠 **统一空间项目管理**:通过单一ProjectSpace表解决多空间项目管理问题 - 🎨 设计师项目全生命周期管理 - 💰 财务报价与结算流程 - 📊 质量控制与客户反馈 **空间管理优化**: - 🔄 **统一空间表**:ProjectSpace表统一管理所有空间相关功能 - 💰 **空间报价**:通过`.quotation`字段管理空间级别的报价 - 📁 **空间文件**:ProjectFile通过`.space`字段关联到具体空间 - 👥 **空间团队**:通过`.assignedTeam`字段管理空间团队成员 - 🎯 **空间需求**:通过`.requirements`字段管理空间详细需求 - 📸 **空间全景**:通过`.panorama`字段管理空间全景图信息 - ⭐ **空间评价**:通过`.reviews`字段管理空间评价和反馈 --- ## 数据表关系图 - Department 项目组(部门) - name String 项目组名称 - type "project" 项目组 - leader Pointer 组长 - company Pointer 指向当前帐套 ```plantuml @startuml !define TABLE(name,desc) class name as "desc" << (T,#FFAAAA) >> !define FIELD(name,type) name : type skinparam classAttributeIconSize 0 skinparam class { BackgroundColor LightYellow BorderColor Black ArrowColor Black } ' ============ 核心租户与人员 ============ TABLE(Company, "Company\n企业表") { FIELD(objectId, String) FIELD(name, String) FIELD(corpId, String) FIELD(data, Object) FIELD(isDeleted, Boolean) } TABLE(Profile, "Profile\n员工档案表") { FIELD(objectId, String) FIELD(name, String) FIELD(mobile, String) FIELD(department, Pointer→Department) FIELD(company, Pointer→Company) FIELD(userId, String) FIELD(roleName, String) FIELD(data, Object) FIELD(isDeleted, Boolean) } TABLE(ContactInfo, "ContactInfo\n客户信息表") { FIELD(objectId, String) FIELD(name, String) FIELD(mobile, String) FIELD(company, Pointer→Company) FIELD(external_userid, String) FIELD(source, String) FIELD(data, Object) FIELD(isDeleted, Boolean) } ' ============ 企微集成 ============ TABLE(GroupChat, "GroupChat\n企微群聊表") { FIELD(objectId, String) FIELD(chat_id, String) FIELD(name, String) FIELD(company, Pointer→Company) FIELD(project, Pointer→Project) FIELD(member_list, Array) FIELD(joinUrl, String) FIELD(data, Object) FIELD(isDeleted, Boolean) } TABLE(ProjectGroup, "ProjectGroup\n项目群组关联表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(groupChat, Pointer→GroupChat) FIELD(isPrimary, Boolean) FIELD(createdAt, Date) } ' ============ 项目模块 ============ TABLE(Project, "Project\n项目表") { FIELD(objectId, String) FIELD(title, String) FIELD(company, Pointer→Company) FIELD(customer, Pointer→ContactInfo) FIELD(assignee, Pointer→Profile) FIELD(status, String) FIELD(currentStage, String) FIELD(deadline, Date) FIELD(data, Object) FIELD(isDeleted, Boolean) } ' ============ 统一空间项目管理 ============ TABLE(ProjectSpace, "ProjectSpace\n统一项目空间表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(name, String) FIELD(type, String) FIELD(area, Number) FIELD(priority, Number) FIELD(status, String) FIELD(complexity, String) FIELD(metadata, Object) FIELD(quotation, Object) FIELD(panorama, Object) FIELD(assignedTeam, Array) FIELD(deliveryFiles, Array) FIELD(dependencies, Array) FIELD(requirements, Object) FIELD(reviews, Array) FIELD(estimatedBudget, Number) FIELD(estimatedDuration, Number) FIELD(order, Number) FIELD(isDeleted, Boolean) } TABLE(ProjectRequirement, "ProjectRequirement\n需求信息表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(company, Pointer→Company) FIELD(spaces, Array) FIELD(designRequirements, Object) FIELD(materialAnalysis, Object) FIELD(data, Object) FIELD(isDeleted, Boolean) } TABLE(ProjectTeam, "ProjectTeam\n项目团队表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(profile, Pointer→Profile) FIELD(role, String) FIELD(workload, Number) FIELD(isDeleted, Boolean) } ' ============ 交付物与文件 ============ TABLE(Product, "Product\n产品即交付物表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(company, Pointer→Company) FIELD(stage, String) FIELD(processType, String) FIELD(space, Pointer→ProjectSpace) FIELD(fileUrl, String) FIELD(reviewStatus, String) FIELD(data, Object) FIELD(isDeleted, Boolean) } ' NovaFile.id为Attachment.objectId TABLE(ProjectFile, "ProjectFile\n项目文件表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(space, Pointer→ProjectSpace) FIELD(attach, Attachment) FIELD(uploadedBy, Pointer→Profile) FIELD(fileType, String) FIELD(fileUrl, String) FIELD(fileName, String) FIELD(fileSize, Number) FIELD(stage, String) FIELD(data, Object) FIELD(isDeleted, Boolean) } ' ============ 财务模块 ============ TABLE(ProjectSettlement, "ProjectSettlement\n结算记录表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(company, Pointer→Company) FIELD(stage, String) FIELD(amount, Number) FIELD(percentage, Number) FIELD(status, String) FIELD(dueDate, Date) FIELD(settledAt, Date) FIELD(data, Object) FIELD(isDeleted, Boolean) } TABLE(ProjectVoucher, "ProjectVoucher\n付款凭证表") { FIELD(objectId, String) FIELD(settlement, Pointer→ProjectSettlement) FIELD(project, Pointer→Project) FIELD(amount, Number) FIELD(voucherUrl, String) FIELD(recognizedInfo, Object) FIELD(verifiedBy, Pointer→Profile) FIELD(data, Object) FIELD(isDeleted, Boolean) } ' ============ 质量与反馈 ============ TABLE(ProjectFeedback, "ProjectFeedback\n客户反馈表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(customer, Pointer→ContactInfo) FIELD(stage, String) FIELD(feedbackType, String) FIELD(content, String) FIELD(rating, Number) FIELD(status, String) FIELD(data, Object) FIELD(isDeleted, Boolean) } TABLE(ProductCheck, "ProductCheck\n产品质量检查表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(checkType, String) FIELD(checkedBy, Pointer→Profile) FIELD(checkedAt, Date) FIELD(isPassed, Boolean) FIELD(items, Array) FIELD(data, Object) FIELD(isDeleted, Boolean) } TABLE(ProjectIssue, "ProjectIssue\n异常记录表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(reportedBy, Pointer→Profile) FIELD(exceptionType, String) FIELD(severity, String) FIELD(description, String) FIELD(status, String) FIELD(resolution, String) FIELD(data, Object) FIELD(isDeleted, Boolean) } ' ============ 跟进记录 ============ TABLE(ContactFollow, "ContactFollow\n跟进记录表") { FIELD(objectId, String) FIELD(project, Pointer→Project) FIELD(sender, Pointer→Profile/ContactInfo) FIELD(content, String) FIELD(type, String) FIELD(stage, String) FIELD(attachments, Array) FIELD(data, Object) FIELD(isDeleted, Boolean) } ' ============ 关系连线 ============ ' Company 一对多关系 Company "1" --> "n" Profile : 企业员工 Company "1" --> "n" ContactInfo : 企业客户 Company "1" --> "n" Project : 企业项目 Company "1" --> "n" GroupChat : 企业群聊 ' 项目核心关系 Project "n" --> "1" Company : 所属企业 Project "n" --> "1" ContactInfo : 客户 Project "n" --> "1" Profile : 负责人(assignee) Project "1" --> "1" ProjectRequirement : 需求信息 Project "1" <--> "n" GroupChat : ProjectGroup\n群聊关联 Project "1" --> "n" ProjectTeam : 项目团队 ' 统一空间项目管理关系 Project "1" --> "n" ProjectSpace : 项目空间 ProjectSpace "1" --> "n" Product : 空间交付物 ProjectSpace "1" --> "n" ProjectFile : 空间文件 ' 交付与财务 Project "1" --> "n" Product : 交付物 Project "1" --> "n" ProjectFile : 项目文件 Project "1" --> "n" ProjectSettlement : 结算记录 ProjectSettlement "1" --> "n" ProjectVoucher : 付款凭证 ' 质量与沟通 Project "1" --> "n" ProjectFeedback : 客户反馈 Project "1" --> "n" ProductCheck : 质量检查 Project "1" --> "n" ProjectIssue : 异常记录 Project "1" --> "n" ContactFollow : 跟进记录 ' 群聊关系 GroupChat "n" --> "1" Company : 所属企业 GroupChat "n" --> "1" Project : 关联项目(可选) @enduml ``` --- ## 核心数据表详解 ### 1. Company(企业表) **用途**: 多租户系统的核心,所有数据通过 company 字段进行租户隔离。 | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "cDL6R1hgSi" | | name | String | 是 | 企业名称 | "映三色设计" | | corpId | String | 否 | 企业微信CorpID | "ww1234567890" | | data | Object | 否 | 扩展数据 | { settings: {...}, modules: [...] } | | isDeleted | Boolean | 否 | 软删除标记 | false | | createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z | | updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z | --- ### 2. Profile(员工档案表) **用途**: 存储企业员工档案信息,统一管理客服、设计师、组长等所有角色。 | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "prof001" | | name | String | 是 | 员工姓名 | "张三" | | mobile | String | 否 | 手机号 | "13800138000" | | department | Pointer | 是 | 所属小组 | → Department | | company | Pointer | 是 | 所属企业 | → Company | | userId | String | 否 | 企微UserID | "zhangsan" | | roleName | String | 是 | 员工角色 | "客服" / "组员" / "组长" | | data | Object | 否 | 扩展数据 | { avatar, department, skills, ... } | | isDeleted | Boolean | 否 | 软删除标记 | false | | createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z | | updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z | **role 枚举值**: - `客服`: 客户服务人员,负责接单、跟进 - `组员`: 设计师,负责具体设计工作 - `组长`: 团队负责人,负责审核、分配 - `财务`: 财务人员 - `人事`: 人事人员 - `管理员`: 系统管理员 --- ### 3. ContactInfo(客户信息表) **用途**: 统一管理所有客户信息,支持企微外部联系人同步。 | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "contact001" | | name | String | 是 | 客户姓名 | "李四" | | mobile | String | 否 | 手机号 | "13900139000" | | company | Pointer | 是 | 所属企业 | → Company | | external_userid | String | 否 | 企微外部联系人ID | "wmxxx" | | source | String | 否 | 来源渠道 | "朋友圈" / "信息流" / "转介绍" | | data | Object | 否 | 扩展数据 | { avatar, wechat, tags, ... } | | isDeleted | Boolean | 否 | 软删除标记 | false | | createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z | | updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z | --- ### 4. Project(项目表) **用途**: 项目管理的核心表,记录设计项目的全生命周期信息。 | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "proj001" | | title | String | 是 | 项目标题 | "李总现代简约全案" | | company | Pointer | 是 | 所属企业 | → Company | | customer | Pointer | 是 | 客户 | → ContactInfo | | assignee | Pointer | 否 | 负责设计师 | → Profile | | status | String | 是 | 项目状态 | "进行中" | | currentStage | String | 是 | 当前阶段 | "建模" | | deadline | Date | 否 | 截止时间 | 2024-12-31T00:00:00.000Z | | data | Object | 否 | 扩展数据 | { requirements, stageHistory, ... } | | isDeleted | Boolean | 否 | 软删除标记 | false | | createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z | | updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z | --- ### 5. ProjectSpace(统一项目空间表)⭐ **功能描述**: 统一管理项目空间的所有相关信息,包含报价、全景图、团队分配、需求等全生命周期数据。 **字段说明**: | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "space001" | | project | Pointer | 是 | 所属项目 | → Project | | name | String | 是 | 空间名称 | "主卧" | | type | String | 是 | 空间类型 | "bedroom" | | area | Number | 否 | 面积(平方米) | 18.5 | | priority | Number | 否 | 优先级(1-10) | 8 | | status | String | 否 | 状态 | "in_progress" | | complexity | String | 否 | 复杂度 | "medium" | | metadata | Object | 否 | 空间元数据 | {dimensions, features} | | **quotation** | **Object** | **否** | **空间报价信息** | **{price, breakdown}** | | **panorama** | **Object** | **否** | **全景图信息** | **{url, hotspots}** | | **assignedTeam** | **Array** | **否** | **分配团队** | **[{profile, role}]** | | **deliveryFiles** | **Array** | **否** | **交付文件列表** | **[{fileId, type}]** | | **dependencies** | **Array** | **否** | **空间依赖关系** | **[{fromSpace, type}]** | | **requirements** | **Object** | **否** | **空间详细需求** | **{color, material}** | | **reviews** | **Array** | **否** | **空间评价列表** | **[{rating, comments}]** | | estimatedBudget | Number | 否 | 预估预算 | 35000 | | estimatedDuration | Number | 否 | 预估工期(天) | 7 | | order | Number | 否 | 排序顺序 | 2 | | isDeleted | Boolean | 否 | 是否删除 | false | **type 枚举值**: - `living_room`: 客厅 - `bedroom`: 卧室 - `kitchen`: 厨房 - `bathroom`: 卫生间 - `dining_room`: 餐厅 - `study`: 书房 - `balcony`: 阳台 - `corridor`: 走廊 - `storage`: 储物间 - `entrance`: 玄关 - `other`: 其他 **status 枚举值**: - `not_started`: 未开始 - `in_progress`: 进行中 - `awaiting_review`: 待审核 - `completed`: 已完成 - `blocked`: 已阻塞 - `delayed`: 已延期 **quotation 字段结构示例**: ```json { "price": 35000, "currency": "CNY", "breakdown": { "design": 15000, "modeling": 10000, "rendering": 8000, "softDecor": 2000 }, "unitPrice": 1891, "estimatedDays": 7, "status": "approved", "approvedBy": {"__type": "Pointer", "className": "Profile", "objectId": "prof001"}, "validUntil": "2024-12-31T00:00:00.000Z" } ``` **panorama 字段结构示例**: ```json { "url": "https://...", "thumbnailUrl": "https://...", "previewImages": ["https://...", "https://..."], "hotspots": [ { "id": "hotspot001", "position": {"x": 0.5, "y": 0.3}, "type": "info", "title": "定制衣柜", "description": "实木定制衣柜,内部空间合理布局" } ], "resolution": {"width": 8192, "height": 4096}, "fileSize": 15728640, "renderTime": 1800, "status": "completed" } ``` **assignedTeam 字段结构示例**: ```json [ { "profile": {"__type": "Pointer", "className": "Profile", "objectId": "prof001"}, "profileName": "张设计师", "role": "primary_designer", "workload": 0.6, "assignedAt": "2024-10-01T10:00:00.000Z", "assignedBy": {"__type": "Pointer", "className": "Profile", "objectId": "prof002"}, "status": "active", "notes": "主要负责空间整体设计" }, { "profile": {"__type": "Pointer", "className": "Profile", "objectId": "prof003"}, "profileName": "李建模师", "role": "modeling_designer", "workload": 0.4, "assignedAt": "2024-10-02T09:00:00.000Z", "status": "active" } ] ``` **deliveryFiles 字段结构示例**: ```json [ { "fileId": {"__type": "Pointer", "className": "ProjectFile", "objectId": "file001"}, "fileName": "主卧效果图v2.jpg", "fileType": "rendering", "stage": "rendering", "uploadedAt": "2024-10-15T14:30:00.000Z", "uploadedBy": {"__type": "Pointer", "className": "Profile", "objectId": "prof001"}, "reviewStatus": "approved" } ] ``` **dependencies 字段结构示例**: ```json [ { "fromSpace": {"__type": "Pointer", "className": "ProjectSpace", "objectId": "space002"}, "fromSpaceName": "客厅", "type": "style_reference", "description": "需要与客厅风格保持一致", "priority": "high", "status": "active" } ] ``` **requirements 字段结构示例**: ```json { "colorRequirement": { "primaryHue": 180, "saturation": 45, "temperature": "暖色调", "colorDistribution": [ {"hex": "#F5F5DC", "percentage": 40, "name": "米白色"}, {"hex": "#8B4513", "percentage": 30, "name": "原木色"} ] }, "materialRequirement": { "preferred": ["实木", "环保材料"], "avoid": ["塑料", "合成材料"], "budget": { "min": 20000, "max": 40000 } }, "lightingRequirement": { "naturalLight": "充足", "lightColor": "暖白", "lightIntensity": "中等", "specialRequirements": ["床头阅读灯", "氛围灯"] }, "specificRequirements": [ "需要大储物空间", "独立卫浴", "飘窗设计" ], "referenceImages": ["https://...", "https://..."], "referenceFiles": ["file002", "file003"] } ``` **reviews 字段结构示例**: ```json [ { "reviewId": "review001", "satisfactionScore": 4.5, "spaceSpecificRatings": { "design": 5, "functionality": 4, "material": 4, "lighting": 5 }, "usageFeedback": { "positive": ["储物空间充足", "光线舒适"], "improvements": ["可以增加插座数量"] }, "comments": "整体设计很满意,储物功能强大", "afterPhotos": ["https://...", "https://..."], "submittedAt": "2024-11-15T10:00:00.000Z", "submittedBy": {"__type": "Pointer", "className": "ContactInfo", "objectId": "contact001"} } ] ``` **使用场景示例**: ```typescript // 创建空间 const ProjectSpace = Parse.Object.extend("ProjectSpace"); const space = new ProjectSpace(); space.set("project", project.toPointer()); space.set("name", "主卧"); space.set("type", "bedroom"); space.set("area", 18.5); // 设置空间报价 space.set("quotation", { price: 35000, currency: "CNY", breakdown: { design: 15000, modeling: 10000, rendering: 8000, softDecor: 2000 }, status: "pending" }); // 设置空间团队 space.set("assignedTeam", [ { profile: designer.toPointer(), profileName: designer.get("name"), role: "primary_designer", workload: 0.8, assignedAt: new Date() } ]); await space.save(); // 查询项目的所有空间 const spaceQuery = new Parse.Query("ProjectSpace"); spaceQuery.equalTo("project", projectId); spaceQuery.notEqualTo("isDeleted", true); spaceQuery.ascending("order"); const spaces = await spaceQuery.find(); // 查询设计师负责的空间 const designerSpaceQuery = new Parse.Query("ProjectSpace"); designerSpaceQuery.equalTo("project", projectId); designerSpaceQuery.equalTo("assignedTeam.profile", designerId); designerSpaceQuery.equalTo("assignedTeam.status", "active"); ``` --- ### 6. Product(交付物表) **用途**: 记录项目各阶段的交付物,如效果图、施工图等。**已更新支持空间关联**。 | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "deliv001" | | project | Pointer | 是 | 所属项目 | → Project | | company | Pointer | 是 | 所属企业 | → Company | | stage | String | 是 | 所属阶段 | "建模" / "渲染" / "后期" | | processType | String | 否 | 工序类型 | "modeling" / "rendering" | | **space** | **Pointer** | **否** | **所属空间** | **→ ProjectSpace** | | fileUrl | String | 是 | 文件URL | "https://..." | | reviewStatus | String | 是 | 审核状态 | "pending" / "approved" | | data | Object | 否 | 扩展数据 | { thumbnailUrl, version, ... } | | isDeleted | Boolean | 否 | 软删除标记 | false | | createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z | | updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z | --- ### 7. ProjectFile(项目文件表) **用途**: 存储项目相关的所有文件,如CAD图纸、参考图等。**已更新支持空间关联**。 | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "file001" | | project | Pointer | 是 | 所属项目 | → Project | | **space** | **Pointer** | **否** | **所属空间** | **→ ProjectSpace** | | attach | Pointer | 是 | 附件 | → Attachment | | uploadedBy | Pointer | 是 | 上传人 | → Profile | | fileType | String | 是 | 文件类型 | "cad" / "reference" / "document" | | fileUrl | String | 是 | 文件URL | "https://..." | | fileName | String | 是 | 文件名 | "户型图.dwg" | | fileSize | Number | 否 | 文件大小(字节) | 1024000 | | stage | String | 否 | 关联阶段 | "需求沟通" | | data | Object | 否 | 扩展数据 | { thumbnailUrl, ... } | | isDeleted | Boolean | 否 | 软删除标记 | false | | createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z | | updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z | **使用场景示例**: ```typescript // 上传空间相关文件 const ProjectFile = Parse.Object.extend("ProjectFile"); const file = new ProjectFile(); file.set("project", project.toPointer()); file.set("space", space.toPointer()); // 关联到具体空间 file.set("fileName", "主卧参考图.jpg"); file.set("fileType", "reference"); file.set("uploadedBy", profile.toPointer()); await file.save(); // 查询空间的所有文件 const fileQuery = new Parse.Query("ProjectFile"); fileQuery.equalTo("space", spaceId); fileQuery.notEqualTo("isDeleted", true); const spaceFiles = await fileQuery.find(); ``` --- ## 统一空间管理的优势 ### 1. 数据结构简化 - **减少表数量**: 从15个空间相关表简化为1个统一表 - **降低复杂度**: 消除复杂的表间关联关系 - **提高性能**: 减少JOIN查询操作 ### 2. 功能完整性 - **空间报价**: 通过`.quotation`字段实现空间级报价管理 - **空间全景**: 通过`.panorama`字段管理全景图和热点信息 - **团队协作**: 通过`.assignedTeam`字段管理空间团队成员 - **文件管理**: 通过`.deliveryFiles`字段管理空间交付物 - **需求跟踪**: 通过`.requirements`字段管理详细需求 - **评价反馈**: 通过`.reviews`字段管理空间评价 ### 3. 使用便利性 - **一次查询**: 获取空间所有相关信息 - **原子操作**: 空间信息可原子性更新 - **数据一致性**: 避免分布式数据一致性问题 - **扩展灵活**: Object字段支持灵活扩展 ### 4. 实现示例对比 **原有方式(多表操作)**: ```typescript // 需要多次查询 const space = await spaceQuery.get(spaceId); const quotation = await quotationQuery.equalTo("space", spaceId).first(); const team = await teamQuery.equalTo("space", spaceId).find(); const files = await fileQuery.equalTo("space", spaceId).find(); const reviews = await reviewQuery.equalTo("space", spaceId).find(); ``` **统一方式(单表操作)**: ```typescript // 一次查询获取所有信息 const space = await spaceQuery.get(spaceId); const quotation = space.get("quotation"); const team = space.get("assignedTeam"); const files = space.get("deliveryFiles"); const reviews = space.get("reviews"); ``` --- ## 数据迁移指南 ### 从多表结构迁移到统一ProjectSpace ```typescript // 1. 迁移空间报价数据 const oldQuotations = await new Parse.Query("SpaceQuotation").find(); for (const quotation of oldQuotations) { const space = await quotation.get("space"); space.set("quotation", { price: quotation.get("totalAmount"), currency: "CNY", breakdown: quotation.get("priceBreakdown"), status: "migrated" }); await space.save(); } // 2. 迁移空间团队数据 const oldAssignments = await new Parse.Query("SpaceAssignment").find(); for (const assignment of oldAssignments) { const space = await assignment.get("space"); const team = space.get("assignedTeam") || []; team.push({ profile: assignment.get("assigneeId"), profileName: assignment.get("assigneeName"), role: assignment.get("role"), workload: assignment.get("workload"), assignedAt: assignment.get("assignedAt"), assignedBy: assignment.get("assignedBy"), status: "migrated" }); space.set("assignedTeam", team); await space.save(); } // 3. 迁移空间需求 const oldRequirements = await new Parse.Query("SpaceRequirement").find(); for (const requirement of oldRequirements) { const space = await requirement.get("space"); space.set("requirements", { colorRequirement: requirement.get("colorRequirement"), materialRequirement: requirement.get("materialRequirement"), lightingRequirement: requirement.get("lightingRequirement"), specificRequirements: requirement.get("specificRequirements"), constraints: requirement.get("constraints"), referenceImages: requirement.get("referenceImages"), referenceFiles: requirement.get("referenceFiles") }); await space.save(); } ``` --- ## 总结 通过统一空间管理的重构,YSS项目管理系统实现了: ✅ **架构简化**: 从15个空间相关表简化为1个ProjectSpace表 ✅ **功能完整**: 保留所有空间管理功能,无缝迁移 ✅ **性能提升**: 减少查询复杂度,提高响应速度 ✅ **维护便利**: 降低数据模型维护成本 ✅ **扩展灵活**: Object字段支持未来功能扩展 ✅ **数据一致**: 避免多表数据一致性问题 这个统一的空间管理方案解决了多空间项目管理的复杂性,通过单一ProjectSpace表实现了报价、全景图、团队协作、文件管理、需求跟踪、评价反馈等全生命周期管理,大大简化了系统架构并提高了开发效率。 --- **文档版本**: v2.0(统一空间管理) **最后更新**: 2025-10-20 **维护者**: YSS Development Team