category: schema title: YSS项目Parse Server数据范式 subtitle: 映三色设计师项目管理系统完整数据表结构 name: 'yss-schemas'
本文档定义了映三色(YSS)设计师项目管理系统的完整Parse Server数据范式。系统采用多租户架构,以Company为核心,支持客服、设计师、组长等多角色协作的全流程项目管理。
核心特性:
Department 项目组(部门)
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(company, Pointer→Company)
FIELD(userId, String)
FIELD(role, 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(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, String)
FIELD(fileUrl, String)
FIELD(reviewStatus, String)
FIELD(data, Object)
FIELD(isDeleted, Boolean)
}
TABLE(ProjectFile, "ProjectFile\n项目文件表") {
FIELD(objectId, String)
FIELD(project, Pointer→Project)
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(Communication, "Communication\n沟通记录表") {
FIELD(objectId, String)
FIELD(project, Pointer→Project)
FIELD(sender, Pointer→Profile/ContactInfo)
FIELD(content, String)
FIELD(communicationType, String)
FIELD(relatedStage, 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" 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" Communication : 沟通记录
' 群聊关系
GroupChat "n" --> "1" Company : 所属企业
GroupChat "n" --> "1" Project : 关联项目(可选)
@enduml
用途: 多租户系统的核心,所有数据通过 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 |
data字段扩展示例:
{
"settings": {
"timezone": "Asia/Shanghai",
"currency": "CNY",
"workingHours": { "start": "09:00", "end": "18:00" }
},
"modules": ["project", "crm", "finance", "hr"],
"wxwork": {
"agentId": "1000002",
"secret": "***"
}
}
索引建议:
objectId
(主键)corpId
name
用途: 存储企业员工档案信息,统一管理客服、设计师、组长等所有角色。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "prof001" |
name | String | 是 | 员工姓名 | "张三" |
mobile | String | 否 | 手机号 | "13800138000" |
company | Pointer | 是 | 所属企业 | → Company |
userId | String | 否 | 企微UserID | "zhangsan" |
role | 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 枚举值:
客服
: 客户服务人员,负责接单、跟进组员
: 设计师,负责具体设计工作组长
: 团队负责人,负责审核、分配财务
: 财务人员人事
: 人事人员管理员
: 系统管理员data字段扩展示例:
{
"avatar": "https://...",
"email": "zhangsan@example.com",
"department": "设计一组",
"position": "高级设计师",
"skills": ["建模", "渲染", "软装"],
"workload": {
"currentProjects": 5,
"maxCapacity": 8,
"utilizationRate": 0.625
},
"performance": {
"completedProjects": 120,
"averageRating": 4.8,
"onTimeRate": 0.95
}
}
使用场景:
// 获取当前登录员工
const profileId = localStorage.getItem("Parse/ProfileId");
const query = new Parse.Query("Profile");
const profile = await query.get(profileId);
// 查询设计师列表
const designerQuery = new Parse.Query("Profile");
designerQuery.equalTo("company", companyId);
designerQuery.equalTo("role", "组员");
designerQuery.notEqualTo("isDeleted", true);
const designers = await designerQuery.find();
// 查询客服人员
const csQuery = new Parse.Query("Profile");
csQuery.equalTo("role", "客服");
csQuery.equalTo("company", companyId);
索引建议:
company + isDeleted
userId + company
role + company
mobile
用途: 统一管理所有客户信息,支持企微外部联系人同步。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
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 |
source 枚举值:
朋友圈
: 微信朋友圈引流信息流
: 广告投放转介绍
: 老客户推荐其他
: 其他渠道data字段扩展示例:
{
"avatar": "https://...",
"wechat": "lisi_wx",
"type": "new",
"tags": {
"needType": "全案",
"preference": "现代简约",
"colorAtmosphere": "明亮温馨",
"budget": { "min": 50000, "max": 100000 }
},
"demandType": "价格敏感",
"preferenceTags": ["环保材料", "智能家电", "大窗户"],
"followUpStatus": "待报价",
"remark": "要求使用环保材料,对价格比较敏感",
"follow_user": [{
"userid": "zhangsan",
"remark": "李总",
"createtime": 1605171726,
"tags": [...]
}]
}
使用场景:
// 搜索客户
const searchQuery = new Parse.Query("ContactInfo");
searchQuery.equalTo("company", companyId);
searchQuery.matches("name", keyword, "i");
searchQuery.matches("mobile", keyword, "i");
// 同步企微外部联系人
const contactInfo = await wxwork.syncContact(externalContact);
// 查询客户的所有项目
const projectQuery = new Parse.Query("Project");
projectQuery.equalTo("customer", contactInfo.toPointer());
projectQuery.notEqualTo("isDeleted", true);
索引建议:
company + isDeleted
external_userid + company
mobile + company
source + company
用途: 存储企业微信群聊信息,支持与项目关联。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "group001" |
chat_id | String | 是 | 企微群聊ID | "wrxxx" |
name | String | 是 | 群聊名称 | "李总-现代简约全案" |
company | Pointer | 是 | 所属企业 | → Company |
project | Pointer | 否 | 关联项目 | → Project |
member_list | Array | 否 | 成员列表 | [{userid: "zhangsan", ...}] |
joinUrl | String | 否 | 入群链接 | "https://..." |
data | Object | 否 | 扩展数据 | { owner, notice, ... } |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
data字段扩展示例:
{
"owner": "zhangsan",
"notice": "本群为李总项目专属群,请及时沟通设计需求",
"member_version": "1234567890",
"joinQrcode": "https://...",
"create_time": 1605171726
}
与Project的关系:
使用场景:
// 从企微会话中获取群聊并同步
const { GroupChat } = await wxwork.getCurrentChatObject();
console.log("当前群聊:", GroupChat.get("name"));
console.log("关联项目:", GroupChat.get("project")?.id);
// 查询项目的所有群聊
const groupQuery = new Parse.Query("GroupChat");
groupQuery.equalTo("project", projectId);
groupQuery.notEqualTo("isDeleted", true);
const groups = await groupQuery.find();
// 创建项目群聊
const GroupChat = Parse.Object.extend("GroupChat");
const group = new GroupChat();
group.set("chat_id", chatId);
group.set("name", "项目群");
group.set("company", company.toPointer());
group.set("project", project.toPointer());
await group.save();
索引建议:
chat_id + company
(联合唯一)project + isDeleted
company + isDeleted
用途: 实现项目与群聊的多对多关系(高级场景)。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "pg001" |
project | Pointer | 是 | 关联项目 | → Project |
groupChat | Pointer | 是 | 关联群聊 | → GroupChat |
isPrimary | Boolean | 否 | 是否主群 | true |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
使用场景:
// 查询项目的所有群聊(通过中间表)
const pgQuery = new Parse.Query("ProjectGroup");
pgQuery.equalTo("project", projectId);
pgQuery.include("groupChat");
const pgs = await pgQuery.find();
const groups = pgs.map(pg => pg.get("groupChat"));
// 查询群聊关联的所有项目
const pgQuery2 = new Parse.Query("ProjectGroup");
pgQuery2.equalTo("groupChat", groupChatId);
pgQuery2.include("project");
const projects = (await pgQuery2.find()).map(pg => pg.get("project"));
索引建议:
project + groupChat
(联合唯一)groupChat
isPrimary
用途: 项目管理的核心表,记录设计项目的全生命周期信息。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
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 |
status 枚举值:
待分配
: 新建项目,等待分配设计师进行中
: 设计师已开始工作已完成
: 项目交付完成已暂停
: 客户要求暂停已延期
: 超过原定截止时间已取消
: 项目取消currentStage 枚举值:
订单分配
: 客服下单,待分配设计师需求沟通
: 设计师与客户沟通需求方案确认
: 设计方案等待客户确认
建模
: 3D建模阶段软装
: 软装设计阶段渲染
: 效果图渲染阶段后期
: 后期处理与优化尾款结算
: 等待客户支付尾款客户评价
: 客户评价阶段投诉处理
: 客户投诉处理data字段扩展示例:
{
"projectCode": "YSS-2024-001",
"estimatedCompletionDate": "2024-12-20T00:00:00.000Z",
"actualCompletionDate": null,
"customerServiceId": "prof002",
"priority": "high",
"tags": ["全案", "现代简约", "120平"],
"stageHistory": [
{
"stage": "订单分配",
"startTime": "2024-10-01T09:00:00.000Z",
"endTime": "2024-10-01T10:30:00.000Z",
"duration": 1.5,
"status": "completed",
"operator": { "id": "prof002", "name": "王客服", "role": "客服" }
}
],
"workflow": {
"overallProgress": 45,
"estimatedHours": 160,
"actualHours": 72
}
}
使用场景:
// 创建项目
const Project = Parse.Object.extend("Project");
const project = new Project();
project.set("title", "李总现代简约全案");
project.set("company", company.toPointer());
project.set("customer", customer.toPointer());
project.set("status", "待分配");
project.set("currentStage", "订单分配");
await project.save();
// 查询设计师的项目列表
const query = new Parse.Query("Project");
query.equalTo("assignee", profileId);
query.containedIn("status", ["待分配", "进行中"]);
query.notEqualTo("isDeleted", true);
query.include("customer", "assignee");
query.descending("updatedAt");
// 更新项目阶段
project.set("currentStage", "建模");
project.set("status", "进行中");
await project.save();
索引建议:
company + isDeleted
assignee + status
customer + isDeleted
currentStage + status
deadline
updatedAt
(降序)用途: 存储项目的详细需求信息,包括空间信息、设计需求、素材分析等。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "req001" |
project | Pointer | 是 | 所属项目 | → Project |
company | Pointer | 是 | 所属企业 | → Company |
spaces | Array | 否 | 空间信息 | [{name: "客厅", area: 40, ...}] |
designRequirements | Object | 否 | 设计需求 | { style: [...], color: "...", ... } |
materialAnalysis | Object | 否 | 素材分析结果 | { colorAnalysis: {...}, ... } |
data | Object | 否 | 扩展数据 | { functionalRequirements, ... } |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
spaces 结构示例:
[
{
"id": "space001",
"name": "客厅",
"area": 40,
"dimensions": {
"length": 8,
"width": 5,
"height": 2.8
},
"existingConditions": ["采光好", "南向"],
"requirements": ["需要大储物空间", "开放式设计"]
}
]
designRequirements 结构示例:
{
"style": ["现代简约", "北欧"],
"colorPreference": "明亮温馨",
"materialPreference": ["实木", "环保材料"],
"specialRequirements": ["智能家电", "宠物友好设计"]
}
materialAnalysis 结构示例:
{
"colorAnalysis": {
"primaryHue": 180,
"saturation": 45,
"temperature": "冷色调",
"colorDistribution": [
{ "hex": "#F5F5DC", "percentage": 40, "name": "米白色" },
{ "hex": "#8B4513", "percentage": 30, "name": "原木色" }
]
},
"formAnalysis": {
"lineType": "straight",
"complexity": 60,
"symmetry": "symmetric"
},
"textureAnalysis": {
"dominantTexture": "光滑",
"materials": ["实木", "大理石", "布艺"]
},
"lightingAnalysis": {
"naturalLight": "充足",
"lightColor": "暖白",
"lightIntensity": "中等"
}
}
索引建议:
project
(唯一)company + isDeleted
用途: 管理项目团队成员及其角色分工。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "team001" |
project | Pointer | 是 | 所属项目 | → Project |
profile | Pointer | 是 | 团队成员 | → Profile |
role | String | 是 | 项目角色 | "主设计师" / "建模师" / "渲染师" |
workload | Number | 否 | 工作量占比 | 0.6 |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 加入时间 | 2024-01-01T00:00:00.000Z |
role 枚举值:
主设计师
: 项目负责人建模师
: 负责3D建模渲染师
: 负责效果图渲染软装师
: 负责软装设计助理
: 辅助工作使用场景:
// 添加团队成员
const ProjectTeam = Parse.Object.extend("ProjectTeam");
const team = new ProjectTeam();
team.set("project", project.toPointer());
team.set("profile", designer.toPointer());
team.set("role", "建模师");
team.set("workload", 0.4);
await team.save();
// 查询项目团队
const teamQuery = new Parse.Query("ProjectTeam");
teamQuery.equalTo("project", projectId);
teamQuery.include("profile");
teamQuery.notEqualTo("isDeleted", true);
索引建议:
project + isDeleted
profile + project
(联合唯一)用途: 记录项目各阶段的交付物,如效果图、施工图等。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "deliv001" |
project | Pointer | 是 | 所属项目 | → Project |
company | Pointer | 是 | 所属企业 | → Company |
stage | String | 是 | 所属阶段 | "建模" / "渲染" / "后期" |
processType | String | 否 | 工序类型 | "modeling" / "rendering" |
space | String | 否 | 空间名称 | "客厅" / "主卧" |
fileUrl | String | 是 | 文件URL | "https://..." |
reviewStatus | String | 是 | 审核状态 | "pending" / "approved" |
data | Object | 否 | 扩展数据 | { thumbnailUrl, version, ... } |
quotation | Object | 否 | 产品报价 | { price, ... } |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
stage 枚举值: 与 Project.currentStage 一致
processType 枚举值:
modeling
: 建模softDecor
: 软装rendering
: 渲染postProcess
: 后期reviewStatus 枚举值:
pending
: 待审核approved
: 已通过rejected
: 已驳回revision_required
: 需要修改data字段扩展示例:
{
"fileName": "客厅效果图v2.jpg",
"fileSize": 2048576,
"fileType": "image",
"format": "jpg",
"thumbnailUrl": "https://...",
"uploadedBy": "prof001",
"version": 2,
"reviewNotes": "色调需要再暖一些",
"progress": 100
}
quotation字段扩展说明
Product.quotation 产品报价字段
**用途**: 记录项目报价信息和审批流程。
| 字段名 | 类型 | 必填 | 说明 | 示例值 |
|--------|------|------|------|--------|
| price | Number | 是 | 总金额 | 1200 |
| currency | String | 是 | 货币单位 | "CNY" |
| breakdown | Object | 否 | 费用明细 | { design: 30000, ... } |
| status | String | 是 | 审核状态 | "待审核" / "已通过" |
| approvedBy | Pointer | 否 | 审批人 | → Profile |
| data | Object | 否 | 扩展数据 | { discount, notes, ... } |
| isDeleted | Boolean | 否 | 软删除标记 | false |
| createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
| updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
**status 枚举值**:
- `待审核`: 等待财务或管理员审核
- `已通过`: 审核通过
- `已驳回`: 审核未通过
- `已修改`: 报价已修改,需重新审核
**breakdown 结构示例**:
``\`json
{
"design": 30000,
"modeling": 20000,
"rendering": 15000,
"softDecor": 10000,
"postProcessing": 5000
}
``\`
**data字段扩展示例**:
``\`json
{
"discount": 0.9,
"discountReason": "老客户优惠",
"notes": "含3次修改",
"validUntil": "2024-11-01T00:00:00.000Z",
"approvalHistory": [
{
"approver": "prof003",
"action": "approved",
"timestamp": "2024-10-15T10:00:00.000Z",
"comment": "价格合理"
}
]
}
``\`
**索引建议**:
- `project + isDeleted`
- `status + company`
- `approvedBy`
索引建议:
project + stage + isDeleted
project + space
reviewStatus + project
用途: 存储项目相关的所有文件,如CAD图纸、参考图等。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "file001" |
project | Pointer | 是 | 所属项目 | → Project |
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 |
fileType 枚举值:
cad
: CAD图纸reference
: 参考图片document
: 文档资料contract
: 合同文件voucher
: 付款凭证other
: 其他索引建议:
project + fileType + isDeleted
uploadedBy + project
用途: 记录项目分阶段结算信息。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "settle001" |
project | Pointer | 是 | 所属项目 | → Project |
company | Pointer | 是 | 所属企业 | → Company |
stage | String | 是 | 结算阶段 | "定金" / "进度款" / "尾款" |
amount | Number | 是 | 结算金额 | 24000 |
percentage | Number | 否 | 占总额百分比 | 0.3 |
status | String | 是 | 结算状态 | "待结算" / "已结算" |
dueDate | Date | 否 | 应付日期 | 2024-10-20T00:00:00.000Z |
settledAt | Date | 否 | 实际结算时间 | 2024-10-18T14:30:00.000Z |
data | Object | 否 | 扩展数据 | { paymentMethod, ... } |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
stage 枚举值:
定金
: 项目启动定金(通常30%)进度款
: 中期进度款(通常40%)尾款
: 项目完成尾款(通常30%)status 枚举值:
待结算
: 等待客户付款已结算
: 已收到款项逾期
: 超过应付日期未付款data字段扩展示例:
{
"paymentMethod": "微信转账",
"transactionId": "WX20241018143000",
"notes": "已收到定金",
"invoiceRequired": true,
"invoiceIssued": false
}
索引建议:
project + stage
status + company
dueDate
用途: 记录客户付款凭证及OCR识别结果。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "voucher001" |
settlement | Pointer | 是 | 关联结算记录 | → ProjectSettlement |
project | Pointer | 是 | 所属项目 | → Project |
amount | Number | 是 | 付款金额 | 24000 |
voucherUrl | String | 是 | 凭证图片URL | "https://..." |
recognizedInfo | Object | 否 | OCR识别结果 | { amount: 24000, ... } |
verifiedBy | Pointer | 否 | 核验人 | → Profile |
data | Object | 否 | 扩展数据 | { paymentTime, ... } |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
recognizedInfo 结构示例:
{
"amount": 24000,
"paymentTime": "2024-10-18 14:30:00",
"paymentMethod": "微信支付",
"transactionId": "WX20241018143000",
"payerName": "李四",
"confidence": 0.95
}
索引建议:
settlement + project
project + isDeleted
用途: 记录客户在各阶段的反馈和评价。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "feedback001" |
project | Pointer | 是 | 所属项目 | → Project |
customer | 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 |
feedbackType 枚举值:
suggestion
: 建议complaint
: 投诉praise
: 表扬question
: 疑问status 枚举值:
待处理
: 新反馈,待响应处理中
: 正在处理已解决
: 问题已解决已关闭
: 反馈已关闭data字段扩展示例:
{
"isSatisfied": false,
"problemLocation": "客厅沙发区",
"expectedEffect": "希望更温馨舒适",
"referenceCase": "case123",
"response": "已调整色调,请查看最新版本",
"respondedBy": "prof001",
"respondedAt": "2024-10-16T10:00:00.000Z",
"attachments": ["https://..."]
}
索引建议:
project + status + isDeleted
customer + project
feedbackType + stage
用途: 记录项目质量检查结果,如模型检查、效果图审核等。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "check001" |
project | Pointer | 是 | 所属项目 | → Project |
checkType | String | 是 | 检查类型 | "model" / "render" / "final" |
checkedBy | Pointer | 是 | 检查人 | → Profile |
checkedAt | Date | 是 | 检查时间 | 2024-10-15T10:00:00.000Z |
isPassed | Boolean | 是 | 是否通过 | true |
items | Array | 否 | 检查项目 | [{name: "尺寸准确性", passed: true}] |
data | Object | 否 | 扩展数据 | { notes, images, ... } |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
checkType 枚举值:
model
: 模型检查render
: 渲染效果检查final
: 最终交付检查items 结构示例:
[
{
"id": "item001",
"name": "尺寸准确性",
"category": "基础",
"isPassed": true,
"notes": "符合要求"
},
{
"id": "item002",
"name": "材质真实性",
"category": "渲染质量",
"isPassed": false,
"notes": "地板材质需要调整"
}
]
索引建议:
project + checkType + isDeleted
checkedBy + isPassed
用途: 记录项目执行过程中的异常情况。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "except001" |
project | Pointer | 是 | 所属项目 | → Project |
reportedBy | Pointer | 是 | 报告人 | → Profile |
exceptionType | String | 是 | 异常类型 | "failed" / "stuck" / "quality" |
severity | String | 是 | 严重程度 | "low" / "high" / "critical" |
description | String | 是 | 异常描述 | "建模软件崩溃导致进度延误" |
status | String | 是 | 处理状态 | "待处理" / "已解决" |
resolution | String | 否 | 解决方案 | "重新建模,延期2天" |
data | Object | 否 | 扩展数据 | { assignedTo, impact, ... } |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
exceptionType 枚举值:
failed
: 任务失败stuck
: 进度停滞quality
: 质量问题timeline
: 进度延期resource
: 资源不足other
: 其他severity 枚举值:
low
: 低,影响较小medium
: 中,需要关注high
: 高,严重影响进度critical
: 紧急,项目面临风险data字段扩展示例:
{
"assignedTo": "prof003",
"relatedStage": "建模",
"impact": "预计延期2天",
"preventiveMeasures": ["增加备份频率", "升级建模软件"],
"resolvedAt": "2024-10-16T15:00:00.000Z"
}
索引建议:
project + status + isDeleted
exceptionType + severity
reportedBy
用途: 记录项目相关的沟通历史。
字段名 | 类型 | 必填 | 说明 | 示例值 |
---|---|---|---|---|
objectId | String | 是 | 主键ID | "comm001" |
project | Pointer | 是 | 所属项目 | → Project |
sender | Pointer | 是 | 发送人 | → Profile / ContactInfo |
content | String | 是 | 沟通内容 | "客厅效果图已发送,请查收" |
communicationType | String | 是 | 沟通类型 | "message" / "call" / "meeting" |
relatedStage | String | 否 | 关联阶段 | "渲染" |
attachments | Array | 否 | 附件列表 | ["https://..."] |
data | Object | 否 | 扩展数据 | { isRead, priority, ... } |
isDeleted | Boolean | 否 | 软删除标记 | false |
createdAt | Date | 自动 | 创建时间 | 2024-01-01T00:00:00.000Z |
updatedAt | Date | 自动 | 更新时间 | 2024-01-01T00:00:00.000Z |
communicationType 枚举值:
message
: 文字消息call
: 电话沟通meeting
: 会议email
: 邮件feedback
: 客户反馈索引建议:
project + createdAt
sender + project
relatedStage
所有业务表都包含 company
字段,确保多租户数据隔离:
query.equalTo("company", companyId);
所有表都包含 isDeleted
字段,避免数据永久删除:
query.notEqualTo("isDeleted", true);
使用 data
Object 字段存储灵活的扩展数据,避免频繁修改表结构:
// 读取扩展数据
const extraData = project.get("data");
const workflow = extraData.workflow;
// 写入扩展数据
project.set("data", {
...project.get("data"),
workflow: { overallProgress: 50 }
});
使用 include
减少查询次数:
query.include("customer", "assignee", "project.customer");
company + isDeleted
必建复合索引updatedAt
/ createdAt
建立降序索引// 1. 从企微会话获取群聊
const { GroupChat } = await wxwork.getCurrentChatObject();
// 2. 直接获取关联项目
const project = GroupChat.get("project");
if (project) {
await project.fetch({ include: ["customer", "assignee"] });
console.log("项目:", project.get("title"));
console.log("客户:", project.get("customer").get("name"));
console.log("设计师:", project.get("assignee").get("name"));
}
// 1. 创建客户
const ContactInfo = Parse.Object.extend("ContactInfo");
const customer = new ContactInfo();
customer.set("name", "李总");
customer.set("mobile", "13900139000");
customer.set("company", company.toPointer());
await customer.save();
// 2. 创建项目
const Project = Parse.Object.extend("Project");
const project = new Project();
project.set("title", "李总现代简约全案");
project.set("company", company.toPointer());
project.set("customer", customer.toPointer());
project.set("status", "待分配");
project.set("currentStage", "订单分配");
await project.save();
// 3. 关联群聊
const groupChat = await wxwork.syncGroupChat(currentChat.group);
groupChat.set("project", project.toPointer());
await groupChat.save();
// 查询设计师当前进行中的项目
const query = new Parse.Query("Project");
query.equalTo("assignee", designerId);
query.containedIn("status", ["待分配", "进行中"]);
query.notEqualTo("isDeleted", true);
query.include("customer");
const projects = await query.find();
console.log(`当前负载: ${projects.length}个项目`);
// 统计各阶段项目数
const stageCount = {};
projects.forEach(p => {
const stage = p.get("currentStage");
stageCount[stage] = (stageCount[stage] || 0) + 1;
});
// 推进项目到下一阶段
const project = await new Parse.Query("Project").get(projectId);
const currentStage = project.get("currentStage");
const data = project.get("data") || {};
// 更新阶段历史
const stageHistory = data.stageHistory || [];
stageHistory.push({
stage: currentStage,
startTime: lastStartTime,
endTime: new Date(),
status: "completed",
operator: { id: profileId, name: "张设计师", role: "组员" }
});
// 更新当前阶段
project.set("currentStage", "渲染");
project.set("data", {
...data,
stageHistory
});
await project.save();
如果系统中已有 Contact
表(企微外部联系人),建议:
数据同步脚本:定期从 Contact 同步到 ContactInfo
// 同步脚本示例
const contacts = await new Parse.Query("Contact")
.equalTo("company", companyId)
.limit(1000)
.find();
for (const contact of contacts) {
// 查询或创建 ContactInfo
let contactInfo = await new Parse.Query("ContactInfo")
.equalTo("external_userid", contact.get("external_userid"))
.equalTo("company", companyId)
.first();
if (!contactInfo) {
contactInfo = new Parse.Object("ContactInfo");
contactInfo.set("company", company.toPointer());
contactInfo.set("external_userid", contact.get("external_userid"));
}
contactInfo.set("name", contact.get("name"));
contactInfo.set("mobile", contact.get("mobile"));
contactInfo.set("data", contact.get("data"));
await contactInfo.save();
}
本数据范式具有以下特点:
✅ 统一规范: Profile(员工)、ContactInfo(客户)统一管理 ✅ 灵活关联: Project ←→ GroupChat 支持简单和复杂场景 ✅ 角色清晰: role 字段区分客服/组员/组长 ✅ 扩展性强: data Object 字段支持灵活扩展 ✅ 多租户: company 字段确保租户隔离 ✅ 软删除: isDeleted 字段保护数据安全 ✅ 企微集成: 与企业微信深度集成
通过实施这个数据范式,可以实现:
文档版本: v1.0 最后更新: 2025-10-15 维护者: YSS Development Team