schemas-unified.md 27 KB


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 指向当前帐套

      @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 字段结构示例:

    {
      "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 字段结构示例:

    {
      "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 字段结构示例:

    [
      {
        "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 字段结构示例:

    [
      {
        "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 字段结构示例:

    [
      {
        "fromSpace": {"__type": "Pointer", "className": "ProjectSpace", "objectId": "space002"},
        "fromSpaceName": "客厅",
        "type": "style_reference",
        "description": "需要与客厅风格保持一致",
        "priority": "high",
        "status": "active"
      }
    ]
    

    requirements 字段结构示例:

    {
      "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 字段结构示例:

    [
      {
        "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"}
      }
    ]
    

    使用场景示例:

    // 创建空间
    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

    使用场景示例:

    // 上传空间相关文件
    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. 实现示例对比

    原有方式(多表操作):

    // 需要多次查询
    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();
    

    统一方式(单表操作):

    // 一次查询获取所有信息
    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

    // 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