schemas.md 31 KB


category: schema title: YSS项目Parse Server数据范式 - Product表统一空间管理 subtitle: 映三色设计师项目管理系统完整数据表结构(基于Product表的空间管理版本) name: 'yss-schemas-product-space'

label: database

Parse Server 数据范式 - 映三色项目管理系统(Product表统一空间管理)

概述

本文档定义了映三色(YSS)设计师项目管理系统的完整Parse Server数据范式。系统采用多租户架构,以Company为核心,支持客服、设计师、组长等多角色协作的全流程项目管理。

核心特性

  • 🏢 多租户架构,以Company为核心租户隔离
  • 👥 统一员工表(Profile)和客户表(ContactInfo)
  • 📋 项目与群聊灵活关联(Project ←→ GroupChat)
  • 🏠 Product表统一空间管理:通过Product表实现多空间设计产品管理
  • 🎨 设计师项目全生命周期管理
  • 💰 财务报价与结算流程
  • 📊 质量控制与客户反馈

空间管理优化

  • 🎯 Product即空间:每个Product代表一个空间的设计产品
  • 💰 产品报价:通过Product的.quotation字段管理空间级报价
  • 📁 文件分类:ProjectFile通过.category区分panorama、delivery等类型
  • 👥 设计师分配:通过Product的.profile字段直接关联负责设计师
  • 🎯 产品需求:通过Product的.requirements字段管理空间需求
  • 产品评价:通过Product的.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(contact, Pointer→ContactInfo)
      FIELD(assignee, Pointer→Profile)
      FIELD(status, String)
      FIELD(currentStage, String)
      FIELD(deadline, Date)
      FIELD(data, Object)
      FIELD(isDeleted, Boolean)
      }
      
      ' ============ 核心创新:Product表统一空间管理 ============
      TABLE(Product, "Product\n空间设计产品表") {
      FIELD(objectId, String)
      FIELD(project, Pointer→Project)
      FIELD(company, Pointer→Company)
      FIELD(profile, Pointer→Profile)
      FIELD(stage, String)
      FIELD(processType, String)
      FIELD(productName, String)
      FIELD(productType, String)
      FIELD(status, String)
      FIELD(fileUrl, String)
      FIELD(reviewStatus, String)
      FIELD(space, Object)
      FIELD(quotation, Object)
      FIELD(requirements, Object)
      FIELD(reviews, Array)
      FIELD(estimatedBudget, Number)
      FIELD(estimatedDuration, Number)
      FIELD(order, Number)
      FIELD(data, Object)
      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(ProjectFile, "ProjectFile\n项目文件表") {
      FIELD(objectId, String)
      FIELD(project, Pointer→Project)
      FIELD(product, Pointer→Product)
      FIELD(attach, Pointer→Attachment) 
      FIELD(uploadedBy, Pointer→Profile)
      FIELD(stage, String)
      FIELD(data, Object)
      FIELD(isDeleted, Boolean)
      }
      
      ' ============ 财务模块 ============
      TABLE(ProjectPayment, "ProjectPayment\n项目付款表") {
      FIELD(objectId, String)
      FIELD(project, Pointer→Project)
      FIELD(company, Pointer→Company)
      FIELD(type, String)
      FIELD(stage, String)
      FIELD(method, String)
      FIELD(amount, Number)
      FIELD(currency, String)
      FIELD(percentage, Number)
      FIELD(paymentDate, Date)
      FIELD(dueDate, Date)
      FIELD(recordedDate, Date)
      FIELD(status, String)
      FIELD(voucherFile, Pointer→ProjectFile)
      FIELD(voucherUrl, String)
      FIELD(transactionId, String)
      FIELD(paymentReference, String)
      FIELD(paidBy, Pointer→ContactInfo)
      FIELD(recordedBy, Pointer→Profile)
      FIELD(verifiedBy, Pointer→Profile)
      FIELD(description, String)
      FIELD(notes, String)
      FIELD(relatedStage, String)
      FIELD(product, Pointer→Product)
      FIELD(autoReminderSent, Boolean)
      FIELD(reminderCount, Number)
      FIELD(data, Object)
      FIELD(isDeleted, Boolean)
      }
      
      ' ============ 质量与反馈 ============
      TABLE(ProjectFeedback, "ProjectFeedback\n客户反馈表") {
      FIELD(objectId, String)
      FIELD(project, Pointer→Project)
      FIELD(contact, Pointer→ContactInfo)
      FIELD(product, Pointer→Product)
      FIELD(stage, String)
      FIELD(feedbackType, String)
      FIELD(content, String)
      FIELD(rating, Number)
      FIELD(status, String)
      FIELD(data, Object)
      FIELD(isDeleted, Boolean)
      }
      
      TABLE(ProjectIssue, "ProjectIssue\n项目问题追踪表") {
      FIELD(objectId, String)
      FIELD(project, Pointer→Project)
      FIELD(product, Pointer→Product)
      FIELD(creator, Pointer→Profile)                  // 创建人
      FIELD(assignee, Pointer→Profile)                 // 责任人
      FIELD(title, String)                              // 问题标题
      FIELD(description, String)                       // 问题描述
      FIELD(relatedSpace, String)                       // 相关空间
      FIELD(relatedStage, String)                       // 相关阶段
      FIELD(relatedContentType, String)                 // 相关内容类型 (白模/软装/渲染/后期)
      FIELD(relatedFiles, Array)                        // 相关项目文件
      FIELD(priority, String)                           // 优先程度 (低/中/高/紧急)
      FIELD(issueType, String)                          // 问题类型 (投诉/建议/改图)
      FIELD(dueDate, Date)                              // 截止时间
      FIELD(status, String)                             // 状态 (待处理/处理中/已解决/已关闭)
      FIELD(resolution, String)                         // 解决方案
      FIELD(lastReminderAt, Date)                       // 最后催单时间
      FIELD(reminderCount, Number)                      // 催单次数
      FIELD(data, Object)                              // 扩展数据
      FIELD(isDeleted, Boolean)
      }
      
      ' ============ 跟进记录 ============
      TABLE(ContactFollow, "ContactFollow\n跟进记录表") {
      FIELD(objectId, String)
      FIELD(project, Pointer→Project)
      FIELD(product, Pointer→Product)
      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 : 项目团队
      
      ' Product表统一空间管理关系
      Project "1" --> "n" Product : 空间设计产品
      Product "n" --> "1" Profile : 负责设计师
      Product "1" --> "n" ProjectFile : 产品文件
      Product "1" --> "n" ProjectFeedback : 产品反馈
      Product "1" --> "n" ProjectIssue : 产品异常
      Product "1" --> "n" ContactFollow : 产品跟进
      
      ' 交付与财务
      Project "1" --> "n" ProjectFile : 项目文件
      Project "1" --> "n" ProjectPayment : 项目付款
      ProjectPayment "1" --> "1" ProjectFile : 付款凭证
      ProjectPayment "1" --> "1" ContactInfo : 付款人
      ProjectPayment "1" --> "1" Profile : 记录人/验证人
      Product "1" --> "n" ProjectPayment : 产品级付款
      
      ' 质量与沟通
      Project "1" --> "n" ProjectFeedback : 客户反馈
      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
    contact 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. Product(空间设计产品表)⭐

    功能描述: 核心创新 - 统一管理空间设计产品,每个Product代表一个空间的设计产品(如"李总主卧设计"、"王总客厅设计"),包含空间信息、报价、需求、评价等全生命周期数据。

    字段说明: | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "prod001" | | project | Pointer | 是 | 所属项目 | → Project | | company | Pointer | 是 | 所属企业 | → Company | | profile | Pointer | | 负责设计师 | → Profile | | stage | String | 是 | 设计阶段 | "建模" / "渲染" / "后期" | | processType | String | 否 | 工序类型 | "modeling" / "rendering" | | productName | String | | 产品名称 | "李总主卧设计" | | productType | String | | 空间类型 | "bedroom" | | status | String | 是 | 产品状态 | "进行中" | | fileUrl | String | 否 | 主要效果图URL | "https://..." | | reviewStatus | String | 是 | 审核状态 | "pending" / "approved" | | space | Object | | 空间信息 | {name, area, dimensions} | | quotation | Object | | 产品报价 | {price, breakdown} | | requirements | Object | | 设计需求 | {color, material} | | reviews | Array | | 产品评价 | [{rating, comments}] | | estimatedBudget | Number | 否 | 预估预算 | 35000 | | estimatedDuration | Number | 否 | 预估工期(天) | 7 | | order | Number | 否 | 排序顺序 | 1 | | data | Object | 否 | 扩展数据 | { version, progress, ... } | | isDeleted | Boolean | 否 | 软删除标记 | false |

    productType 枚举值:

    • living_room: 客厅
    • bedroom: 卧室
    • kitchen: 厨房
    • bathroom: 卫生间
    • dining_room: 餐厅
    • study: 书房
    • balcony: 阳台
    • corridor: 走廊
    • storage: 储物间
    • entrance: 玄关
    • other: 其他

    status 枚举值:

    • not_started: 未开始
    • in_progress: 进行中
    • awaiting_review: 待审核
    • completed: 已完成
    • blocked: 已阻塞
    • delayed: 已延期

    space 字段结构示例:

    {
      "spaceName": "主卧",
      "area": 18.5,
      "dimensions": {
        "length": 4.5,
        "width": 4.1,
        "height": 2.8
      },
      "features": ["朝南", "飘窗", "独立卫浴"],
      "constraints": ["承重墙不可动"],
      "priority": "high",
      "complexity": "medium"
    }
    

    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"
    }
    

    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": "暖白",
        "specialRequirements": ["床头阅读灯", "氛围灯"]
      },
      "specificRequirements": [
        "需要大储物空间",
        "独立卫浴",
        "飘窗设计"
      ],
      "referenceImages": ["https://...", "https://..."]
    }
    

    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 Product = Parse.Object.extend("Product");
    const product = new Product();
    product.set("project", project.toPointer());
    product.set("profile", designer.toPointer());
    product.set("productName", "李总主卧设计");
    product.set("productType", "bedroom");
    product.set("stage", "modeling");
    
    // 设置空间信息
    product.set("space", {
      spaceName: "主卧",
      area: 18.5,
      dimensions: { length: 4.5, width: 4.1, height: 2.8 },
      features: ["朝南", "飘窗", "独立卫浴"]
    });
    
    // 设置产品报价
    product.set("quotation", {
      price: 35000,
      currency: "CNY",
      breakdown: { design: 15000, modeling: 10000, rendering: 8000, softDecor: 2000 },
      status: "pending"
    });
    
    await product.save();
    
    // 查询项目的所有空间设计产品
    const productQuery = new Parse.Query("Product");
    productQuery.equalTo("project", projectId);
    productQuery.notEqualTo("isDeleted", true);
    productQuery.ascending("order");
    const products = await productQuery.find();
    
    // 查询设计师负责的空间产品
    const designerProductQuery = new Parse.Query("Product");
    designerProductQuery.equalTo("profile", designerId);
    designerProductQuery.equalTo("status", "in_progress");
    const designerProducts = await designerProductQuery.find();
    

    6. ProjectFile(项目文件表)

    用途: 存储项目相关的所有文件,简化设计,通过 .category 字段区分文件类型。

    字段名 类型 必填 说明 示例值
    objectId String 主键ID "file001"
    project Pointer 所属项目 → Project
    product Pointer 关联空间产品 → Product
    attach Pointer 附件 → Attachment
    uploadedBy Pointer 上传人 → Profile
    stage String 关联阶段 "需求沟通"
    category String 关联阶段 "需求沟通"
    data Object 扩展数据 { thumbnailUrl, ... }
    analysis Object 分析结果 详见下方 analysis.color 结构
    isDeleted Boolean 软删除标记 false
    createdAt Date 自动 创建时间 2024-01-01T00:00:00.000Z
    updatedAt Date 自动 更新时间 2024-01-01T00:00:00.000Z

    stage 枚举值

    • 订单分配: 'order'
    • 方案深化: 'requirements'
    • 交付执行: 'delivery'
    • 售后归档: 'aftercare'

    category 枚举值:

    • quotation: 财务凭据
    • panorama: 全景素材
    • delivery: 交付文件
    • reference: 参考文件
    • requirement: 需求文件

    analysis.color - 色彩分析结果结构

    用于存放“色彩分析插件(color-get)”生成的分析报告,并支持重新分析覆盖。该结构与组件内 ColorAnalysisReport 对齐,并补充元信息。

    {
      "version": "1.0",              // 结构版本,便于未来演进
      "source": "color-get",          // 生成来源(组件/脚本/服务)
      "pixelSize": 100,                // 马赛克像素块大小(用于重现)
      "createdAt": "2025-10-20T12:00:00.000Z", // 生成时间
    
      "palette": [                     // 主色卡(按占比降序,最多20)
        { "rgb": { "r": 240, "g": 200, "b": 160 }, "hex": "#F0C8A0", "percentage": 28.5 }
      ],
    
      "mosaicUrl": "data:image/png;base64,....", // 马赛克图(可选,dataURL 或存储链接)
    
      "metrics": {
        "warmCoolBalance": 12.0,       // 冷暖平衡:-100(冷) 到 100(暖)
        "averageBrightness": 56.0,     // 平均亮度:0-100
        "averageSaturation": 42.5,     // 平均饱和度:0-100
        "diversity": 18                // 色彩多样度(主色数量)
      },
    
      "histogram": {
        "brightnessBins": [0, 1, 3, 5, 8, 12, 9, 6, 3, 1],
        "saturationBins": [0, 0, 2, 4, 7, 10, 9, 5, 2, 1]
      },
    
      "splitPoints": [                 // 色彩拆分散点(冷暖/明暗/占比/色值)
        { "temp": 14.2, "brightness": 62.1, "size": 3.5, "color": "#F0C8A0" }
      ]
    }
    

    读写约定

    • 写入:将以上对象保存至 ProjectFile.analysis.color
    • 读取:若存在 analysis.color,组件直接使用并渲染(无需重复计算)。
    • 重新分析:覆盖同一字段,保留 versionsourcepixelSizecreatedAt 更新。
    • 存储位置:优先内嵌对象;如需持久化图像(大体积 mosaicUrl),可改为文件存储链接,并在此字段写入其URL。

    fileType 枚举值:

    • cad: CAD图纸
    • reference: 参考图片
    • document: 文档资料
    • contract: 合同文件
    • voucher: 付款凭证
    • other: 其他

    使用场景示例:

    // 上传空间产品相关的全景图文件
    const ProjectFile = Parse.Object.extend("ProjectFile");
    const file = new ProjectFile();
    file.set("project", project.toPointer());
    file.set("product", product.toPointer()); // 关联到具体空间产品
    file.set("category", "panorama"); // 标记为全景图文件
    file.set("fileName", "主卧720全景图.jpg");
    file.set("uploadedBy", profile.toPointer());
    await file.save();
    
    // 查询空间产品的所有全景图文件
    const panoramaQuery = new Parse.Query("ProjectFile");
    panoramaQuery.equalTo("product", productId);
    panoramaQuery.equalTo("category", "panorama");
    panoramaQuery.notEqualTo("isDeleted", true);
    const panoramaFiles = await panoramaQuery.find();
    
    // 查询空间产品的所有报价文件
    const quotationQuery = new Parse.Query("ProjectFile");
    quotationQuery.equalTo("product", productId);
    quotationQuery.equalTo("category", "quotation");
    const quotationFiles = await quotationQuery.find();
    

    7. ProjectPayment(项目付款表)⭐

    功能描述: 统一的项目付款管理表,整合了原有的 ProjectSettlement 和 ProjectVoucher 两张表的功能。每条记录代表一次具体的付款行为,包含付款类型、金额、方式、凭证等完整信息,支持项目级和产品级付款管理。

    字段说明: | 字段名 | 类型 | 必填 | 说明 | 示例值 | |--------|------|------|------|--------| | objectId | String | 是 | 主键ID | "payment001" | | project | Pointer | 是 | 所属项目 | → Project | | company | Pointer | 是 | 所属企业 | → Company | | type | String | | 付款类型 | "advance" / "milestone" / "final" / "refund" | | stage | String | | 付款阶段 | "order" / "requirements" / "delivery" / "aftercare" | | method | String | | 支付方式 | "cash" / "bank_transfer" / "alipay" / "wechat" | | amount | Number | | 付款金额 | 35000 | | currency | String | | 货币类型 | "CNY" | | percentage | Number | | 占总价百分比 | 30 | | paymentDate | Date | | 实际付款时间 | 2024-12-01T10:00:00.000Z | | dueDate | Date | | 应付款时间 | 2024-12-01T00:00:00.000Z | | recordedDate | Date | 自动 | 记录时间 | 2024-11-30T15:30:00.000Z | | status | String | | 付款状态 | "pending" / "paid" / "overdue" / "cancelled" | | voucherFile | Pointer | | 付款凭证文件 | → ProjectFile | | voucherUrl | String | | 凭证URL | "https://..." | | transactionId | String | | 第三方交易ID | "wx_123456789" | | paymentReference | String | | 付款参考号/发票号 | "INV-2024-001" | | paidBy | Pointer | | 付款人 | → ContactInfo | | recordedBy | Pointer | | 记录人 | → Profile | | verifiedBy | Pointer | | 验证人 | → Profile | | description | String | | 付款描述 | "首期款" | | notes | String | | 备注信息 | "客户通过银行转账付款" | | relatedStage | String | | 关联执行阶段 | "modeling" | | product | Pointer | | 关联产品 | → Product | | autoReminderSent | Boolean | | 是否已发送提醒 | false | | reminderCount | Number | | 提醒次数 | 0 | | data | Object | | 扩展数据 | {bankInfo, approvalFlow} | | isDeleted | Boolean | | 软删除标记 | false |

    type 枚举值:

    • advance: 预付款/定金
    • milestone: 里程碑付款
    • final: 尾款/结算款
    • refund: 退款

    stage 枚举值:

    • order: 订单分配阶段
    • requirements: 方案深化阶段
    • delivery: 交付执行阶段
    • aftercare: 售后归档阶段

    method 枚举值:

    • cash: 现金
    • bank_transfer: 银行转账
    • alipay: 支付宝
    • wechat: 微信支付
    • credit_card: 信用卡
    • other: 其他

    status 枚举值:

    • pending: 待付款
    • paid: 已付款
    • overdue: 逾期
    • cancelled: 已取消
    • refunded: 已退款

    data 字段结构示例:

    {
      "bankInfo": {
        "bankName": "中国工商银行",
        "accountNumber": "****1234",
        "accountName": "李四"
      },
      "approvalFlow": {
        "requestedBy": "客服小王",
        "approvedBy": "财务张三",
        "approvedAt": "2024-11-30T16:00:00.000Z",
        "comments": "款项已确认到账"
      },
      "automaticPayment": {
        "provider": "alipay",
        "gateway": "alipay_scan",
        "qrCodeUrl": "https://..."
      }
    }
    

    使用场景示例:

    // 创建项目付款记录
    const ProjectPayment = Parse.Object.extend("ProjectPayment");
    const payment = new ProjectPayment();
    payment.set("project", project.toPointer());
    payment.set("company", company.toPointer());
    payment.set("type", "advance");
    payment.set("stage", "order");
    payment.set("method", "bank_transfer");
    payment.set("amount", 35000);
    payment.set("currency", "CNY");
    payment.set("percentage", 30);
    payment.set("dueDate", new Date("2024-12-01"));
    payment.set("paidBy", contact.toPointer());
    payment.set("recordedBy", profile.toPointer());
    payment.set("status", "pending");
    payment.set("description", "项目首期款");
    await payment.save();
    
    // 上传付款凭证并关联
    const voucherFile = await uploadVoucherFile(file);
    payment.set("voucherFile", voucherFile.toPointer());
    payment.set("status", "paid");
    payment.set("paymentDate", new Date());
    await payment.save();
    
    // 查询项目的所有付款记录
    const paymentQuery = new Parse.Query("ProjectPayment");
    paymentQuery.equalTo("project", projectId);
    paymentQuery.include("voucherFile");
    paymentQuery.include("paidBy");
    paymentQuery.include("recordedBy");
    paymentQuery.descending("paymentDate");
    const payments = await paymentQuery.find();
    
    // 查询某个产品的付款记录
    const productPaymentQuery = new Parse.Query("ProjectPayment");
    productPaymentQuery.equalTo("product", { __type: "Pointer", className: "Product", objectId: productId });
    productPaymentQuery.equalTo("status", "paid");
    const productPayments = await productPaymentQuery.find();
    
    // 计算项目总付款金额
    const totalPaid = payments.reduce((sum, payment) => {
      return sum + (payment.get("status") === "paid" ? payment.get("amount") : 0);
    }, 0);
    

    8. ProjectFeedback(客户反馈表)

    用途: 记录客户在各阶段的反馈和评价。已更新支持产品关联

    字段名 类型 必填 说明 示例值
    objectId String 主键ID "feedback001"
    project Pointer 所属项目 → Project
    product Pointer 关联空间产品 → Product
    contact Pointer 反馈客户 → ContactInfo
    stage String 反馈阶段 "建模" / "渲染"
    feedbackType String 反馈类型 "suggestion" / "complaint"
    content String 反馈内容 "客厅颜色希望再暖一些"
    rating Number 评分(1-5) 4
    status String 处理状态 "待处理" / "已解决"
    data Object 扩展数据 { response, attachments, ... }
    isDeleted Boolean 软删除标记 false
    createdAt Date 自动 创建时间 2024-01-01T00:00:00.000Z
    updatedAt Date 自动 更新时间 2024-01-01T00:00:00.000Z

    Product表统一空间管理的优势

    1. 行业语义清晰

    • Product即空间设计产品:符合家装设计行业的业务理解
    • 产品化管理:每个空间都是一个独立的设计产品
    • 商业逻辑一致:报价、交付、评价都围绕产品展开

    2. 数据结构极简

    • 单表多能:Product表承载空间管理的所有核心功能
    • 文件分类管理:通过ProjectFile.category区分不同类型文件
    • 设计师直连:通过Product.profile直接关联负责设计师

    3. 使用场景优化

    • 产品清单:通过Product表直接获得项目的空间设计产品清单
    • 交付物管理:通过Product.fileUrl和ProjectFile管理交付物
    • 报价管理:通过Product.quotation管理产品级报价

    4. 实现示例对比

    原有方式(多表操作):

    // 需要查询多个表
    const spaces = await spaceQuery.equalTo("project", projectId).find();
    const quotations = await quotationQuery.equalTo("project", projectId).find();
    const panoramas = await panoramaQuery.equalTo("project", projectId).find();
    const deliveries = await deliveryQuery.equalTo("project", projectId).find();
    

    Product表方式(单表操作):

    // 一次查询获得所有空间设计产品
    const products = await productQuery.equalTo("project", projectId).find();
    // 每个product包含完整的space、quotation、requirements信息
    // 文件通过ProjectFile按category分类查询