在CRM合同模块的添加页面中,有两个签约人字段都用到了selectPage下拉选择组件,但提交的数据类型却不一样:
- 客户签约人:提交的是联系人姓名(如"刘坤")
- 公司签约人:提交的是管理员ID(如"2")
两个字段配置看起来差不多,为什么提交结果不同?关键就在 data-field 和 data-primary-key 这两个属性上。
先看代码
客户签约人
<input type="text" name="contract[customer_signer]"
data-toggle="selectPage"
data-source="{:url('crm.customerContacts/selectpage')}"
data-field="contact"
data-primary-key="contact"
data-format-item="{contact}({phone})"
value="{$row['customer_signer']|default=''}">公司签约人
<input type="text" name="contract[company_signer]"
data-toggle="selectPage"
data-source="{:url('admin/selectpage')}"
data-field="username"
data-primary-key="admin_id"
data-format-item="{username}({realname})"
value="{$row['company_signer']|default=''}">核心结论:一句话记住
data-field管"看到什么",data-primary-key管"提交什么"。
就这么简单,别被其他属性搞混了。
详细拆解
1. 属性映射关系
selectPage组件初始化时,会把HTML的data属性映射成内部参数:
// selectpage.js 第215行
{data: 'source', keyField: 'primaryKey', showField: 'field', ...}对应关系:
| HTML属性 | 插件内部名 | 干什么用 |
|---|---|---|
data-field | showField | 选中后,输入框里显示哪个字段的值 |
data-primary-key | keyField | 选中后,隐藏表单字段写入哪个字段的值(就是最终提交给后端的) |
data-format-item | formatItem | 下拉列表里每条记录怎么格式化展示,比如 {contact}({phone}) |
2. 表单提交机制(这个很重要)
selectPage初始化的时候,会把原始的一个 <input> 拆成两个:
你写的: <input name="contract[company_signer]"> 插件拆成: <input type="hidden" name="contract[company_signer]"> ← 存keyField的值,跟着表单提交 <input type="text" name="contract[company_signer]_text"> ← 存showField的值,给用户看的
源码是这样的(selectpage.js 第568-582行):
// 隐藏input:保持原始name,存储实际提交的值
elem.hidden = $('<input type="hidden">').attr({ name: hidden_name }).val('');
// 可见input:name加"_text"后缀,存储显示的文本(不会被提交,因为name不一样)
elem.combo_input.attr({ name: input_name + '_text' });选中某项之后(selectpage.js 第738-742行):
var value = row[p.keyField]; // 取 data-primary-key 指定字段的值 → 写入隐藏input var text = row[p.showField]; // 取 data-field 指定字段的值 → 写入可见input self.elem.combo_input.val(text); // 用户看到文本 self.elem.hidden.val(value); // 表单提交的是这个值
3. 回到开头的两个字段
| 客户签约人 | 公司签约人 | |
|---|---|---|
data-field | contact | username |
data-primary-key | contact | admin_id |
| 用户看到的 | contact值,如"刘坤" | username值,如"admin" |
| 表单提交的 | contact值,如"刘坤" | admin_id值,如"2" |
客户签约人的 data-field 和 data-primary-key 都是 contact,所以看到的和提交的都是联系人姓名。
公司签约人的 data-field="username" 但 data-primary-key="admin_id",所以看到的是用户名,但实际提交给后端的是管理员ID。
4. data-format-item 的角色
这个属性只管下拉列表中每条记录的展示格式,不影响提交值。
data-format-item="{contact}({phone})"下拉列表里会显示:刘坤(13800138000)
但选中后输入框里只显示 data-field 对应的值(刘坤),除非在 easy-admin.js 中做了特殊处理(通过 eSelect 回调和 afterInit 重写来让输入框也用 formatItem 格式化显示)。
常见坑点
想让输入框也显示格式化内容:selectPage核心的
afterInit方法只用了showField,没用formatItem。easy-admin.js 里做了补丁处理,通过覆写afterInit和eSelect回调来实现格式化回显。后端接收到的值跟你以为的不一样:别只看输入框里显示什么,要看
data-primary-key配的是什么。如果data-primary-key="admin_id",后端收到的就是ID,不是用户名。编辑回显问题:如果
data-primary-key是ID,那value属性也要填ID值,不能填名称。比如公司签约人的value应该是{$row['company_signer']}(存的是admin_id),而不是人名。data-field和data-primary-key设成一样:完全没问题,客户签约人就是这么干的。这时候看到的和提交的是同一个字段的值。
速查表
┌──────────────────────────────────────────────────────────────────┐ │ 属性 │ 控制什么 │ 影响范围 │ ├──────────────────────────────────────────────────────────────────┤ │ data-field │ 输入框显示哪个字段 │ 用户看到的 │ │ data-primary-key │ 隐藏字段存哪个字段 │ 后端收到的 │ │ data-format-item │ 下拉列表每条怎么展示 │ 下拉选项文本 │ │ data-source │ 数据从哪个接口加载 │ 数据来源 │ │ data-params │ 额外的查询参数 │ 过滤条件 │ └──────────────────────────────────────────────────────────────────┘
相关文件
- selectPage组件源码:
public/static/plugs/lay-module/selectPage/selectpage.js - easy-admin集成层:
public/static/plugs/easy-admin/easy-admin.js(selectPage函数,约第2351行) - 合同添加页面:
app/admin/view/crm/contract/add.html - 后端selectpage方法:
app/admin/traits/Curd.php(selectpage方法)
给selectpage设置data-select-only="true"是不能输入,只有$('#selectPage').selectPageDisabled(true)不能点击下拉选...