# 销售机会对象建模及表单
在前面的步骤中,我们已经定义了客户模型,并创建了它的列表、新建和编辑表单。现在我们来定义销售机会,以及与它关联的互动记录和任务。
参考 CRM 系统设计文档,三个模型的字段如下。
# 模型定义
# 互动记录 (InteractionRecords)
| 字段名 | 类型 | 是否可为空 | 可选项 | 备注 |
|---|---|---|---|---|
| name | STRING | 否 | 无 | 互动主题 |
| interactionType | STRING | 否 | 电话、会议、邮件、现场拜访、视频会议、其他 | 互动类型 |
| interactionDate | LOCAL_DATE | 否 | 无 | 互动日期 |
| notes | STRING | 是 | 无 | 备注 |
# 任务 (Tasks)
| 字段名 | 类型 | 是否可为空 | 可选项 | 备注 |
|---|---|---|---|---|
| name | STRING | 否 | 无 | 任务名称 |
| description | STRING | 否 | 无 | 任务描述 |
| dueDate | LOCAL_DATE | 否 | 无 | 截止日期 |
| status | STRING | 否 | 待处理、进行中、已完成、已取消 | 任务状态 |
# 销售机会 (SalesOpportunities)
| 字段名 | 类型 | 是否可为空 | 可选项 | 关联对象类型 | 备注 |
|---|---|---|---|---|---|
| name | STRING | 否 | 无 | 无 | 机会名称 |
| customer | DOMAIN_OBJECT | 否 | 无 | Customers | 关联客户 |
| stage | STRING | 否 | 初步接触、需求分析、方案设计、投标、谈判、成交、失效 | 无 | 机会阶段 |
| expectedAmount | BIG_DECIMAL | 否 | 无 | 无 | 预期金额 |
| expectedCloseDate | LOCAL_DATE | 否 | 无 | 无 | 预计关闭日期 |
| interactionRecords | DOMAIN_OBJECT_LIST | 是 | 无 | InteractionRecords | 互动记录 |
| tasks | DOMAIN_OBJECT_LIST | 是 | 无 | Tasks | 任务 |
说明:
customer字段关联到第 1 步定义的客户模型,类型为DOMAIN_OBJECT,referenceDomain.shortName填Customers。- 销售机会与互动记录、任务是一对多关系,这种关系使用
DOMAIN_OBJECT_LIST配置。平台默认以子表的形式在销售机会的表单中维护它们。
# 用 CSV 创建模型
在第 1 步的两个 CSV 文件中追加以下内容。
DomainClass_crm.csv(完整内容):
shortName(*),extInfo,createRoleRequirement.name,readRoleRequirement.name,updateRoleRequirement.name,deleteRoleRequirement.name
;; CRM 教程:客户、销售机会、互动记录、任务
Customers,,USER,USER,USER,
InteractionRecords,,USER,USER,USER,USER
Tasks,,USER,USER,USER,USER
SalesOpportunities,,USER,USER,USER,
2
3
4
5
6
互动记录和任务要在子表中新建、修改、删除,所以四项权限都开放给 USER;销售机会的删除权限与客户一样,留到第 4 步。
DomainClassField_crm.csv(在客户字段之后追加):
;; 互动记录
InteractionRecords,name,STRING,,false,true,,
InteractionRecords,interactionType,STRING,,false,true,,"[""电话"",""会议"",""邮件"",""现场拜访"",""视频会议"",""其他""]"
InteractionRecords,interactionDate,LOCAL_DATE,,false,true,,
InteractionRecords,notes,STRING,,true,true,,
;; 任务
Tasks,name,STRING,,false,true,,
Tasks,description,STRING,,false,true,,
Tasks,dueDate,LOCAL_DATE,,false,true,,
Tasks,status,STRING,,false,true,,"[""待处理"",""进行中"",""已完成"",""已取消""]"
;; 销售机会
SalesOpportunities,name,STRING,,false,true,,
SalesOpportunities,customer,DOMAIN_OBJECT,Customers,false,true,,
SalesOpportunities,stage,STRING,,false,true,,"[""初步接触"",""需求分析"",""方案设计"",""投标"",""谈判"",""成交"",""失效""]"
SalesOpportunities,expectedAmount,BIG_DECIMAL,,false,true,,
SalesOpportunities,expectedCloseDate,LOCAL_DATE,,false,true,,
SalesOpportunities,interactionRecords,DOMAIN_OBJECT_LIST,InteractionRecords,true,true,,
SalesOpportunities,tasks,DOMAIN_OBJECT_LIST,Tasks,true,true,,
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
被引用的模型(Customers、InteractionRecords、Tasks)由 DomainClass_crm.csv 创建,而 DomainClass 总是先于 DomainClassField 导入,所以字段文件中行的先后顺序没有要求。
重启后端服务后,「开发定制 > 领域模型」中出现三个新模型:
# 表单定义
与第 2 步相同,在「开发配置 > 表单 > 表单」中为销售机会创建三个表单:
| 类型 | 名称 | 显示名称 | 关联对象类型 |
|---|---|---|---|
| LIST | List of SalesOpportunities | 销售机会列表 | Sales Opportunities |
| CREATE | Create SalesOpportunities | 新建销售机会 | Sales Opportunities |
| UPDATE | Update SalesOpportunities | 编辑销售机会 | Sales Opportunities |
提示
「关联对象类型」下拉框中显示的是模型的显示名称。动态模型创建时,显示名称由模型名按驼峰拆分生成,所以 SalesOpportunities 显示为 Sales Opportunities,InteractionRecords 显示为 Interaction Records。
再在「开发配置 > 界面显示 > 菜单」中创建一级菜单:名称 SalesOpportunities,类型 Form,显示名称「销售机会」,图标 FundOutlined,关联表单 List of SalesOpportunities,显示顺序 6。
# 使用子表维护关联数据
互动记录、任务与销售机会是一对多关系,在销售机会的新建和编辑表单中以子表形式显示。子表的列取自子对象的 LIST 表单;子对象没有 LIST 表单时,子表区域会一直显示加载状态。
所以还需要为互动记录和任务各创建表单(本教程同时创建了 CREATE、UPDATE 表单,方便以后单独维护这两类数据):
| 类型 | 名称 | 显示名称 | 关联对象类型 |
|---|---|---|---|
| LIST | List of InteractionRecords | 互动记录列表 | Interaction Records |
| CREATE | Create InteractionRecords | 新建互动记录 | Interaction Records |
| UPDATE | Update InteractionRecords | 编辑互动记录 | Interaction Records |
| LIST | List of Tasks | 任务列表 | Tasks |
| CREATE | Create Tasks | 新建任务 | Tasks |
| UPDATE | Update Tasks | 编辑任务 | Tasks |
最后,把本步新建的 9 个表单追加到 DynamicForm_crm.csv 中设置访问权限(加上第 2 步的 3 行,文件共 12 行),然后重启后端服务:
name(*),accessRequirement.name
;; CRM 教程:为界面上创建的表单补充访问权限(界面上没有该字段)
List of Customers,USER
Create Customers,USER
Update Customers,USER
List of SalesOpportunities,USER
Create SalesOpportunities,USER
Update SalesOpportunities,USER
List of InteractionRecords,USER
Create InteractionRecords,USER
Update InteractionRecords,USER
List of Tasks,USER
Create Tasks,USER
Update Tasks,USER
2
3
4
5
6
7
8
9
10
11
12
13
14
提示
这个文件用 name(*) 按名称查找已有的表单,accessRequirement.name 按名称引用角色要求。如果某个表单还没在界面上创建,这一行会导入失败(CSV 中没有表单类型等必填字段,无法新建),这个文件的导入状态不是成功,下次重启时会整个文件重新导入。请先建表单,再改 CSV。
现在点击左侧的「销售机会」,再点「创建」。子表上方有「创建」按钮,点击后在子表中新增一行,填写后点该行的「保存」:
图中子表每一行操作列末尾多出的「0」是当前版本的界面问题,不影响使用;「customer」下拉框显示的是客户的 ID,下文会说明原因。
点击「保存并关闭」,销售机会和子表中的互动记录、任务一起保存。
# 优化关联客户的显示
保存后回到列表,会发现「customer」一列显示的是客户的 ID,而不是客户姓名;新建表单中选择客户的下拉框,选项也是 ID:
这是因为平台不知道用客户的哪个字段来代表一个客户。领域模型的扩展信息(extInfo)中的 labelField 用来指定这个字段。
1.0.0-beta18 已知问题:先不要做下面的修改
在 1.0.0-beta18 中,给动态模型设置 labelField 后,引用它的列表页(这里是「销售机会」)加载数据时后端会陷入无限递归,列表一直停留在加载状态。在该问题修复前,请暂不要给被其他动态模型引用的模型设置 labelField;已经设置了的,把 extInfo 一格改为 NULL 并重新导入即可清除。本教程后续截图中客户仍显示为 ID。
该问题修复后,把 DomainClass_crm.csv 中 Customers 一行的 extInfo 改为下面的值,客户就会显示为姓名:
Customers,"{""labelField"": ""name""}",USER,USER,USER,
也可以在「开发定制 > 领域模型」中点击 Customers 行的「修改」,在「扩展信息」中填入 {"labelField": "name"}。
提示
同一条数据如果既在界面上改过、又在 CSV 中改过,导入时会被判定为冲突,不会覆盖界面上的修改,详见 数据导入 中的「冲突检测与覆盖」。因此同一个配置项最好固定在一处维护:要么只用 CSV,要么只用界面。
# 进一步阅读
下一步,我们将为客户和销售机会开放删除权限,并绑定批量删除动作,继续查看对象删除权限章节。
我们的平台是牧言低代码平台,专为帮助用户快速构建信息化系统而设计。了解更多关于我们平台的信息,请访问 牧言低代码平台 (opens new window)。