# 销售机会对象建模及表单

在前面的步骤中,我们已经定义了客户模型,并创建了它的列表、新建和编辑表单。现在我们来定义销售机会,以及与它关联的互动记录和任务。

参考 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 任务

说明:

  1. customer 字段关联到第 1 步定义的客户模型,类型为 DOMAIN_OBJECT,referenceDomain.shortName 填 Customers。
  2. 销售机会与互动记录、任务是一对多关系,这种关系使用 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,
1
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,,
1
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 导入,所以字段文件中行的先后顺序没有要求。

重启后端服务后,「开发定制 > 领域模型」中出现三个新模型:

领域模型列表中的 CRM 模型

# 表单定义

与第 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14

提示

这个文件用 name(*) 按名称查找已有的表单,accessRequirement.name 按名称引用角色要求。如果某个表单还没在界面上创建,这一行会导入失败(CSV 中没有表单类型等必填字段,无法新建),这个文件的导入状态不是成功,下次重启时会整个文件重新导入。请先建表单,再改 CSV。

现在点击左侧的「销售机会」,再点「创建」。子表上方有「创建」按钮,点击后在子表中新增一行,填写后点该行的「保存」:

新建销售机会,并在子表中录入互动记录和任务

图中子表每一行操作列末尾多出的「0」是当前版本的界面问题,不影响使用;「customer」下拉框显示的是客户的 ID,下文会说明原因。

点击「保存并关闭」,销售机会和子表中的互动记录、任务一起保存。

# 优化关联客户的显示

保存后回到列表,会发现「customer」一列显示的是客户的 ID,而不是客户姓名;新建表单中选择客户的下拉框,选项也是 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,
1

也可以在「开发定制 > 领域模型」中点击 Customers 行的「修改」,在「扩展信息」中填入 {"labelField": "name"}。

提示

同一条数据如果既在界面上改过、又在 CSV 中改过,导入时会被判定为冲突,不会覆盖界面上的修改,详见 数据导入 中的「冲突检测与覆盖」。因此同一个配置项最好固定在一处维护:要么只用 CSV,要么只用界面。

# 进一步阅读

下一步,我们将为客户和销售机会开放删除权限,并绑定批量删除动作,继续查看对象删除权限章节。

我们的平台是牧言低代码平台,专为帮助用户快速构建信息化系统而设计。了解更多关于我们平台的信息,请访问 牧言低代码平台 (opens new window)。

Last Updated: 2026/9/24 14:27:35