mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
feat: Picker组件已选项支持限制最大展示数量
This commit is contained in:
parent
866d3412b6
commit
3efadbbfb6
@ -684,12 +684,520 @@ order: 35
|
||||
}
|
||||
```
|
||||
|
||||
## 限制标签最大展示数量
|
||||
|
||||
设置`overflowConfig`后可以限制标签的最大展示数量,该属性仅在多选模式开启后生效,包含以下几个配置项:
|
||||
- `maxTagCount`:最大展示数量,是范围为0 - 选项总数量的整数,超出数量的部分会收纳到 Popover 中。
|
||||
- `displayPosition`:收纳标签生效的位置,类型为字符串数组,未开启内嵌模式默认为**选择器**, 开启后默认为**选择器**和**CRUD 顶部**,可选值为`'select'`(选择器)、`'crud'`(增删改查)。
|
||||
- `overflowTagPopover`配置收纳标签 Popover 相关[属性](../tooltip#属性表)。
|
||||
- `overflowTagPopoverInCRUD`可以配置**CRUD 顶部**收纳标签的 Popover相关[属性](../tooltip#属性表)。
|
||||
|
||||
> `3.4.0` 及以上版本
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"debug": true,
|
||||
"body": [
|
||||
{
|
||||
"type": "picker",
|
||||
"overflowConfig": {
|
||||
"maxTagCount": 3,
|
||||
},
|
||||
"name": "maxTagCount1",
|
||||
"joinValues": true,
|
||||
"valueField": "id",
|
||||
"labelField": "engine",
|
||||
"label": "多选",
|
||||
"source": "/api/mock2/sample",
|
||||
"size": "lg",
|
||||
"value": "1,2,3,4,5,6,7",
|
||||
"multiple": true,
|
||||
"pickerSchema": {
|
||||
"mode": "table",
|
||||
"name": "thelist",
|
||||
"quickSaveApi": "/api/mock2/sample/bulkUpdate",
|
||||
"quickSaveItemApi": "/api/mock2/sample/$id",
|
||||
"draggable": true,
|
||||
"headerToolbar": {
|
||||
"wrapWithPanel": false,
|
||||
"type": "form",
|
||||
"className": "text-right",
|
||||
"target": "thelist",
|
||||
"mode": "inline",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "keywords",
|
||||
"addOn": {
|
||||
"type": "submit",
|
||||
"label": "搜索",
|
||||
"level": "primary",
|
||||
"icon": "fa fa-search pull-left"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"footerToolbar": [
|
||||
"statistics",
|
||||
{
|
||||
"type": "pagination",
|
||||
"showPageInput": true,
|
||||
"layout": "perPage,pager,go"
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine",
|
||||
"sortable": true,
|
||||
"searchable": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"label": "Browser",
|
||||
"sortable": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"label": "Platform(s)",
|
||||
"sortable": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"label": "Engine version",
|
||||
"quickEdit": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "grade",
|
||||
"label": "CSS grade",
|
||||
"quickEdit": {
|
||||
"mode": "inline",
|
||||
"type": "select",
|
||||
"options": [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"X"
|
||||
],
|
||||
"saveImmediately": true
|
||||
},
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"type": "operation",
|
||||
"label": "操作",
|
||||
"width": 100,
|
||||
"buttons": [
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-eye",
|
||||
"actionType": "dialog",
|
||||
"dialog": {
|
||||
"title": "查看",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"body": [
|
||||
{
|
||||
"type": "static",
|
||||
"name": "engine",
|
||||
"label": "Engine"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "browser",
|
||||
"label": "Browser"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "platform",
|
||||
"label": "Platform(s)"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "grade",
|
||||
"label": "CSS grade"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "html",
|
||||
"html": "<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-pencil",
|
||||
"actionType": "dialog",
|
||||
"dialog": {
|
||||
"position": "left",
|
||||
"size": "lg",
|
||||
"title": "编辑",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"name": "sample-edit-form",
|
||||
"api": "/api/mock2/sample/$id",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "engine",
|
||||
"label": "Engine",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "browser",
|
||||
"label": "Browser",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "platform",
|
||||
"label": "Platform(s)",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"name": "grade",
|
||||
"label": "CSS grade",
|
||||
"options": [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"X"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-times text-danger",
|
||||
"actionType": "ajax",
|
||||
"confirmText": "您确认要删除?",
|
||||
"api": "delete:/api/mock2/sample/$id"
|
||||
}
|
||||
],
|
||||
"toggled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
内嵌模式下
|
||||
|
||||
```schema: scope="body"
|
||||
{
|
||||
"type": "form",
|
||||
"api": "/api/mock2/form/saveForm",
|
||||
"debug": true,
|
||||
"body": [
|
||||
{
|
||||
"type": "picker",
|
||||
"overflowConfig": {
|
||||
"maxTagCount": 3,
|
||||
"overflowTagPopoverInCRUD": {
|
||||
"placement": "top"
|
||||
}
|
||||
},
|
||||
"embed": true,
|
||||
"name": "maxTagCount2",
|
||||
"joinValues": true,
|
||||
"valueField": "id",
|
||||
"labelField": "engine",
|
||||
"label": "多选",
|
||||
"source": "/api/mock2/sample",
|
||||
"size": "lg",
|
||||
"value": "1,2,3,4,5,6,7",
|
||||
"multiple": true,
|
||||
"pickerSchema": {
|
||||
"mode": "table",
|
||||
"name": "thelist",
|
||||
"quickSaveApi": "/api/mock2/sample/bulkUpdate",
|
||||
"quickSaveItemApi": "/api/mock2/sample/$id",
|
||||
"draggable": true,
|
||||
"headerToolbar": {
|
||||
"wrapWithPanel": false,
|
||||
"type": "form",
|
||||
"className": "text-right",
|
||||
"target": "thelist",
|
||||
"mode": "inline",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "keywords",
|
||||
"addOn": {
|
||||
"type": "submit",
|
||||
"label": "搜索",
|
||||
"level": "primary",
|
||||
"icon": "fa fa-search pull-left"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"footerToolbar": [
|
||||
"statistics",
|
||||
{
|
||||
"type": "pagination",
|
||||
"showPageInput": true,
|
||||
"layout": "perPage,pager,go"
|
||||
}
|
||||
],
|
||||
"columns": [
|
||||
{
|
||||
"name": "engine",
|
||||
"label": "Rendering engine",
|
||||
"sortable": true,
|
||||
"searchable": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"label": "Browser",
|
||||
"sortable": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "platform",
|
||||
"label": "Platform(s)",
|
||||
"sortable": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "version",
|
||||
"label": "Engine version",
|
||||
"quickEdit": true,
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"name": "grade",
|
||||
"label": "CSS grade",
|
||||
"quickEdit": {
|
||||
"mode": "inline",
|
||||
"type": "select",
|
||||
"options": [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"X"
|
||||
],
|
||||
"saveImmediately": true
|
||||
},
|
||||
"type": "text",
|
||||
"toggled": true
|
||||
},
|
||||
{
|
||||
"type": "operation",
|
||||
"label": "操作",
|
||||
"width": 100,
|
||||
"buttons": [
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-eye",
|
||||
"actionType": "dialog",
|
||||
"dialog": {
|
||||
"title": "查看",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"body": [
|
||||
{
|
||||
"type": "static",
|
||||
"name": "engine",
|
||||
"label": "Engine"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "browser",
|
||||
"label": "Browser"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "platform",
|
||||
"label": "Platform(s)"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "static",
|
||||
"name": "grade",
|
||||
"label": "CSS grade"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "html",
|
||||
"html": "<p>添加其他 <span>Html 片段</span> 需要支持变量替换(todo).</p>"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-pencil",
|
||||
"actionType": "dialog",
|
||||
"dialog": {
|
||||
"position": "left",
|
||||
"size": "lg",
|
||||
"title": "编辑",
|
||||
"body": {
|
||||
"type": "form",
|
||||
"name": "sample-edit-form",
|
||||
"api": "/api/mock2/sample/$id",
|
||||
"body": [
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "engine",
|
||||
"label": "Engine",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "browser",
|
||||
"label": "Browser",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "platform",
|
||||
"label": "Platform(s)",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "input-text",
|
||||
"name": "version",
|
||||
"label": "Engine version"
|
||||
},
|
||||
{
|
||||
"type": "divider"
|
||||
},
|
||||
{
|
||||
"type": "select",
|
||||
"name": "grade",
|
||||
"label": "CSS grade",
|
||||
"options": [
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"X"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"icon": "fa fa-times text-danger",
|
||||
"actionType": "ajax",
|
||||
"confirmText": "您确认要删除?",
|
||||
"api": "delete:/api/mock2/sample/$id"
|
||||
}
|
||||
],
|
||||
"toggled": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 属性表
|
||||
|
||||
当做选择器表单项使用时,除了支持 [普通表单项属性表](./formitem#%E5%B1%9E%E6%80%A7%E8%A1%A8) 中的配置以外,还支持下面一些配置
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| 属性名 | 类型 | 默认值 | 说明 | 版本 |
|
||||
| ------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------- | --- |
|
||||
| options | `Array<object>`或`Array<string>` | | [选项组](./options#%E9%9D%99%E6%80%81%E9%80%89%E9%A1%B9%E7%BB%84-options) |
|
||||
| source | `string`或 [API](../../../docs/types/api) 或 [数据映射](../../../docs/concepts/data-mapping) | | [动态选项组](./options#%E5%8A%A8%E6%80%81%E9%80%89%E9%A1%B9%E7%BB%84-source) |
|
||||
| multiple | `boolean` | | 是否为多选。 |
|
||||
@ -703,6 +1211,17 @@ order: 35
|
||||
| modalMode | `string` | `"dialog"` | 设置 `dialog` 或者 `drawer`,用来配置弹出方式。 |
|
||||
| pickerSchema | `string` | `{mode: 'list', listItem: {title: '${label}'}}` | 即用 List 类型的渲染,来展示列表信息。更多配置参考 [CRUD](../crud) |
|
||||
| embed | `boolean` | `false` | 是否使用内嵌模式 |
|
||||
| overflowConfig | `OverflowConfig` | 参考[OverflowConfig](./#overflowconfig) | 开启最大标签展示数量的相关配置 | `3.4.0` |
|
||||
|
||||
### OverflowConfig
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| ------------ | -------------------------------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
||||
| maxTagCount | `number` | `-1` | 标签的最大展示数量,超出数量后以收纳浮层的方式展示,仅在多选模式开启后生效,默认为`-1` 不开启 | `3.4.0` |
|
||||
| displayPosition | `('select' \| 'crud')[]` | `['select', 'crud']` | 收纳标签生效的位置,未开启内嵌模式默认为选择器, 开启后默认为选择器和CRUD 顶部,可选值为`'select'`(选择器)、`'crud'`(增删改查) | `3.4.0` |
|
||||
| overflowTagPopover | `TooltipObject` | `{"placement": "top", "trigger": "hover", "showArrow": false, "offset": [0, -10]}` | 选择器内收纳标签的Popover配置,详细配置参考[Tooltip](../tooltip#属性表) | `3.4.0` |
|
||||
| overflowTagPopoverInCRUD | `TooltipObject` | `{"placement": "bottom", "trigger": "hover", "showArrow": false, "offset": [0, 10]}` | CRUD顶部内收纳标签的Popover配置,详细配置参考[Tooltip](../tooltip#属性表) | `3.4.0` |
|
||||
|
||||
|
||||
## 事件表
|
||||
|
||||
|
@ -40,3 +40,40 @@ export function numberFormatter(num: number | string, precision: number = 0) {
|
||||
}
|
||||
return ZERO.toFixed(precision);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断一个数字是否为整数,且在给定范围内
|
||||
*
|
||||
* @param num 要判断的数字
|
||||
* @param options 范围选项,包括 start、end、left、right
|
||||
* @param options.start 范围起始值
|
||||
* @param options.end 范围结束值
|
||||
* @param options.left 范围的左边界类型,默认为 'inclusive',可选值为 'inclusive'(闭区间) 或 'exclusive'(开区间)
|
||||
* @param options.right 范围的右边界类型,默认为 'inclusive',可选值为 'inclusive'(闭区间) 或 'exclusive'(开区间)
|
||||
* @returns 如果数字在给定范围内则返回 true,否则返回 false
|
||||
*/
|
||||
export function isIntegerInRange(
|
||||
num: number,
|
||||
options: {
|
||||
start: number;
|
||||
end: number;
|
||||
left: 'inclusive' | 'exclusive';
|
||||
right: 'inclusive' | 'exclusive';
|
||||
}
|
||||
) {
|
||||
const {start, end, left = 'inclusive', right = 'inclusive'} = options || {};
|
||||
|
||||
if (num == null || typeof num !== 'number' || !Number.isSafeInteger(num)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (left === 'exclusive' && right === 'exclusive') {
|
||||
return num > start && num < end;
|
||||
} else if (left === 'inclusive' && right === 'exclusive') {
|
||||
return num >= start && num < end;
|
||||
} else if (left === 'exclusive' && right === 'inclusive') {
|
||||
return num > start && num <= end;
|
||||
} else {
|
||||
return num >= start && num <= end;
|
||||
}
|
||||
}
|
||||
|
@ -3620,6 +3620,8 @@
|
||||
--Pick-base-value-icon-color: var(--colors-other-5);
|
||||
--Picker-iconColor: var(--Pick-base-icon-color);
|
||||
--Picker-onHover-iconColor: var(--icon-onHover-color);
|
||||
--Picker-tag-height: #{px2rem(24px)};
|
||||
--Picker-tag-marginBottom: var(--select-multiple-marginBottom);
|
||||
--Pick-status-hover-top-border-color: var(--colors-other-5);
|
||||
--Pick-status-hover-top-border-width: var(--borders-width-2);
|
||||
--Pick-status-hover-top-border-style: var(--borders-style-2);
|
||||
|
@ -616,3 +616,63 @@
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@mixin tag-item($component-prefix) {
|
||||
.#{$ns}#{$component-prefix}-value {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
line-height: calc(
|
||||
var(--Form-input-lineHeight) * var(--Form-input-fontSize) - #{px2rem(2px)}
|
||||
);
|
||||
display: inline-block;
|
||||
font-size: var(--Pick-base-value-fontSize);
|
||||
color: var(--Pick-base-value-color);
|
||||
font-weight: var(--Pick-base-value-fontWeight);
|
||||
background: var(--Pick-base-value-bgColor);
|
||||
border-width: var(--Pick-base-value-top-border-width)
|
||||
var(--Pick-base-value-right-border-width)
|
||||
var(--Pick-base-value-bottom-border-width)
|
||||
var(--Pick-base-value-left-border-width);
|
||||
border-style: var(--Pick-base-value-top-border-style)
|
||||
var(--Pick-base-value-right-border-style)
|
||||
var(--Pick-base-value-bottom-border-style)
|
||||
var(--Pick-base-value-left-border-style);
|
||||
border-color: var(--Pick-base-value-top-border-color)
|
||||
var(--Pick-base-value-right-border-color)
|
||||
var(--Pick-base-value-bottom-border-color)
|
||||
var(--Pick-base-value-left-border-color);
|
||||
border-radius: var(--Pick-base-top-left-border-radius)
|
||||
var(--Pick-base-top-right-border-radius)
|
||||
var(--Pick-base-bottom-right-border-radius)
|
||||
var(--Pick-base-bottom-left-border-radius);
|
||||
margin-right: var(--gap-xs);
|
||||
margin-bottom: var(--gap-xs);
|
||||
margin-top: var(--gap-xs);
|
||||
|
||||
&:hover {
|
||||
background: var(--Form-selectValue-onHover-bg);
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
pointer-events: none;
|
||||
opacity: var(--Button-onDisabled-opacity);
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}#{$component-prefix}-valueIcon {
|
||||
color: var(--Pick-base-value-icon-color);
|
||||
cursor: pointer;
|
||||
border-right: px2rem(1px) solid var(--Form-selectValue-borderColor);
|
||||
padding: 1px 5px;
|
||||
|
||||
&:hover {
|
||||
background: var(--Pick-base-value-hover-icon-color);
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}#{$component-prefix}-valueLabel {
|
||||
padding: 0 var(--gap-xs);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,25 @@
|
||||
|
||||
&-selection {
|
||||
margin-bottom: var(--gap-base);
|
||||
|
||||
&-overflow {
|
||||
&-wrapper {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
height: calc(
|
||||
(var(--Picker-tag-height) + var(--Picker-tag-marginBottom) * 4) * 3
|
||||
);
|
||||
max-height: calc(
|
||||
(var(--Picker-tag-height) + var(--Picker-tag-marginBottom)) * 5
|
||||
);
|
||||
|
||||
@include tag-item(Crud);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-selectionLabel {
|
||||
@ -17,61 +36,8 @@
|
||||
margin-top: var(--gap-xs);
|
||||
}
|
||||
|
||||
&-value {
|
||||
cursor: pointer;
|
||||
vertical-align: middle;
|
||||
user-select: none;
|
||||
line-height: calc(
|
||||
var(--Form-input-lineHeight) * var(--Form-input-fontSize) - #{px2rem(2px)}
|
||||
);
|
||||
display: inline-block;
|
||||
font-size: var(--Pick-base-value-fontSize);
|
||||
color: var(--Pick-base-value-color);
|
||||
font-weight: var(--Pick-base-value-fontWeight);
|
||||
background: var(--Pick-base-value-bgColor);
|
||||
border-width: var(--Pick-base-value-top-border-width)
|
||||
var(--Pick-base-value-right-border-width)
|
||||
var(--Pick-base-value-bottom-border-width)
|
||||
var(--Pick-base-value-left-border-width);
|
||||
border-style: var(--Pick-base-value-top-border-style)
|
||||
var(--Pick-base-value-right-border-style)
|
||||
var(--Pick-base-value-bottom-border-style)
|
||||
var(--Pick-base-value-left-border-style);
|
||||
border-color: var(--Pick-base-value-top-border-color)
|
||||
var(--Pick-base-value-right-border-color)
|
||||
var(--Pick-base-value-bottom-border-color)
|
||||
var(--Pick-base-value-left-border-color);
|
||||
border-radius: var(--Pick-base-top-left-border-radius)
|
||||
var(--Pick-base-top-right-border-radius)
|
||||
var(--Pick-base-bottom-right-border-radius)
|
||||
var(--Pick-base-bottom-left-border-radius);
|
||||
margin-right: var(--gap-xs);
|
||||
margin-top: var(--gap-xs);
|
||||
|
||||
&:hover {
|
||||
background: var(--Form-selectValue-onHover-bg);
|
||||
}
|
||||
|
||||
&.is-disabled {
|
||||
pointer-events: none;
|
||||
opacity: var(--Button-onDisabled-opacity);
|
||||
}
|
||||
}
|
||||
|
||||
&-valueIcon {
|
||||
color: var(--Pick-base-value-icon-color);
|
||||
cursor: pointer;
|
||||
border-right: px2rem(1px) solid var(--Form-selectValue-borderColor);
|
||||
padding: 1px 5px;
|
||||
|
||||
&:hover {
|
||||
background: var(--Form-selectValue-onHover-bg);
|
||||
}
|
||||
}
|
||||
|
||||
&-valueLabel {
|
||||
padding: 0 var(--gap-xs);
|
||||
}
|
||||
/* tag 样式 */
|
||||
@include tag-item(Crud);
|
||||
|
||||
&-selectionClear {
|
||||
display: inline-block;
|
||||
|
@ -115,53 +115,8 @@
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.#{$ns}Picker-value {
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
white-space: nowrap;
|
||||
vertical-align: middle;
|
||||
line-height: calc(
|
||||
var(--Form-input-lineHeight) * var(--Form-input-fontSize) - #{px2rem(2px)}
|
||||
);
|
||||
display: inline-block;
|
||||
font-size: var(--Pick-base-value-fontSize);
|
||||
color: var(--Pick-base-value-color);
|
||||
font-weight: var(--Pick-base-value-fontWeight);
|
||||
background: var(--Pick-base-value-bgColor);
|
||||
border-width: var(--Pick-base-value-top-border-width)
|
||||
var(--Pick-base-value-right-border-width)
|
||||
var(--Pick-base-value-bottom-border-width)
|
||||
var(--Pick-base-value-left-border-width);
|
||||
border-style: var(--Pick-base-value-top-border-style)
|
||||
var(--Pick-base-value-right-border-style)
|
||||
var(--Pick-base-value-bottom-border-style)
|
||||
var(--Pick-base-value-left-border-style);
|
||||
border-color: var(--Pick-base-value-top-border-color)
|
||||
var(--Pick-base-value-right-border-color)
|
||||
var(--Pick-base-value-bottom-border-color)
|
||||
var(--Pick-base-value-left-border-color);
|
||||
border-radius: var(--Pick-base-top-left-border-radius)
|
||||
var(--Pick-base-top-right-border-radius)
|
||||
var(--Pick-base-bottom-right-border-radius)
|
||||
var(--Pick-base-bottom-left-border-radius);
|
||||
margin-right: var(--gap-xs);
|
||||
margin-bottom: var(--gap-xs);
|
||||
}
|
||||
|
||||
.#{$ns}Picker-valueIcon {
|
||||
color: var(--Pick-base-value-icon-color);
|
||||
cursor: pointer;
|
||||
border-right: px2rem(1px) solid var(--Form-selectValue-borderColor);
|
||||
padding: 1px 5px;
|
||||
|
||||
&:hover {
|
||||
background: var(--Pick-base-value-hover-icon-color);
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}Picker-valueLabel {
|
||||
padding: 0 var(--gap-xs);
|
||||
}
|
||||
/* tag 样式 */
|
||||
@include tag-item(Picker);
|
||||
|
||||
&-btn {
|
||||
cursor: pointer;
|
||||
@ -198,6 +153,25 @@
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-overflow {
|
||||
&-wrapper {
|
||||
display: flex;
|
||||
flex-flow: column nowrap;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
height: calc(
|
||||
(var(--Picker-tag-height) + var(--Picker-tag-marginBottom) * 4) * 3
|
||||
);
|
||||
max-height: calc(
|
||||
(var(--Picker-tag-height) + var(--Picker-tag-marginBottom)) * 5
|
||||
);
|
||||
|
||||
@include tag-item(Picker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.#{$ns}PickerControl.is-inline {
|
||||
|
@ -12,8 +12,7 @@ import {
|
||||
render,
|
||||
fireEvent,
|
||||
cleanup,
|
||||
waitFor,
|
||||
getByText
|
||||
screen
|
||||
} from '@testing-library/react';
|
||||
import '../../src';
|
||||
import {render as amisRender} from '../../src';
|
||||
@ -25,7 +24,7 @@ afterEach(() => {
|
||||
clearStoresCache();
|
||||
});
|
||||
|
||||
test('Renderer:Picker base', async () => {
|
||||
test('1. Renderer:Picker base', async () => {
|
||||
const {container, rerender, getByText, getByPlaceholderText, baseElement} =
|
||||
render(
|
||||
amisRender({
|
||||
@ -73,7 +72,7 @@ test('Renderer:Picker base', async () => {
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('Renderer:Picker with pickerSchema & valueField & labelField & multiple & value & size', async () => {
|
||||
test('2. Renderer:Picker with pickerSchema & valueField & labelField & multiple & value & size', async () => {
|
||||
const fetcher = jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
@ -168,7 +167,7 @@ test('Renderer:Picker with pickerSchema & valueField & labelField & multiple & v
|
||||
});
|
||||
});
|
||||
|
||||
test('Renderer:Picker with embed', async () => {
|
||||
test('3. Renderer:Picker with embed', async () => {
|
||||
const fetcher = jest.fn().mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
@ -241,7 +240,7 @@ test('Renderer:Picker with embed', async () => {
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('Renderer:Picker with drawer modalMode', async () => {
|
||||
test('4. Renderer:Picker with drawer modalMode', async () => {
|
||||
const {container, rerender, getByText, getByPlaceholderText, baseElement} =
|
||||
render(
|
||||
amisRender({
|
||||
@ -274,3 +273,72 @@ test('Renderer:Picker with drawer modalMode', async () => {
|
||||
baseElement.querySelector('.cxd-Drawer .cxd-Crud')!
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe('5. Renderer:Picker with overflowConfig', () => {
|
||||
test('5-1. Renderer:Picker select', async () => {
|
||||
const {container, rerender, getByText, getByPlaceholderText, baseElement} =
|
||||
render(
|
||||
amisRender({
|
||||
type: 'picker',
|
||||
name: 'picker',
|
||||
label: 'picker',
|
||||
modalMode: 'dialog',
|
||||
placeholder: 'picker-placeholder',
|
||||
multiple: true,
|
||||
overflowConfig: {
|
||||
maxTagCount: 2
|
||||
},
|
||||
value: 'a,b,c',
|
||||
options: [
|
||||
{label: 'A', value: 'a'},
|
||||
{label: 'B', value: 'b'},
|
||||
{label: 'C', value: 'c'},
|
||||
{label: 'D', value: 'd'}
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
await wait(500);
|
||||
|
||||
const tags = container.querySelector('.cxd-Picker-values');
|
||||
|
||||
expect(tags).toBeInTheDocument();
|
||||
/** tag 元素数量正确 */
|
||||
expect(tags?.childElementCount).toEqual(3);
|
||||
/** 收纳标签文案正确 */
|
||||
expect(tags?.lastElementChild).toHaveTextContent('+ 1 ...');
|
||||
});
|
||||
|
||||
test('5-2. Renderer:Picker embeded', async () => {
|
||||
const {container, rerender, getByText, getByPlaceholderText, baseElement} =
|
||||
render(
|
||||
amisRender({
|
||||
type: 'picker',
|
||||
name: 'picker',
|
||||
label: 'picker',
|
||||
modalMode: 'dialog',
|
||||
placeholder: 'picker-placeholder',
|
||||
embed: true,
|
||||
multiple: true,
|
||||
overflowConfig: {
|
||||
maxTagCount: 2
|
||||
},
|
||||
value: 'a,b,c',
|
||||
options: [
|
||||
{label: 'A', value: 'a'},
|
||||
{label: 'B', value: 'b'},
|
||||
{label: 'C', value: 'c'},
|
||||
{label: 'D', value: 'd'}
|
||||
]
|
||||
})
|
||||
);
|
||||
|
||||
await wait(500);
|
||||
|
||||
const tags = container.querySelectorAll('.cxd-Crud-selection .cxd-Crud-value');
|
||||
/** tag 元素数量正确 */
|
||||
expect(tags?.length).toEqual(3);
|
||||
/** 收纳标签文案正确 */
|
||||
expect(tags[tags?.length - 1]).toHaveTextContent('+ 1 ...');
|
||||
});
|
||||
});
|
||||
|
@ -2721,8 +2721,6 @@ exports[`13. enderer: crud keepItemSelectionOnPageChange & maxKeepItemSelectionL
|
||||
>
|
||||
<span
|
||||
class="cxd-Crud-valueIcon"
|
||||
data-position="bottom"
|
||||
data-tooltip="删除"
|
||||
>
|
||||
×
|
||||
</span>
|
||||
@ -2741,8 +2739,6 @@ exports[`13. enderer: crud keepItemSelectionOnPageChange & maxKeepItemSelectionL
|
||||
>
|
||||
<span
|
||||
class="cxd-Crud-valueIcon"
|
||||
data-position="bottom"
|
||||
data-tooltip="删除"
|
||||
>
|
||||
×
|
||||
</span>
|
||||
@ -2761,8 +2757,6 @@ exports[`13. enderer: crud keepItemSelectionOnPageChange & maxKeepItemSelectionL
|
||||
>
|
||||
<span
|
||||
class="cxd-Crud-valueIcon"
|
||||
data-position="bottom"
|
||||
data-tooltip="删除"
|
||||
>
|
||||
×
|
||||
</span>
|
||||
@ -2781,8 +2775,6 @@ exports[`13. enderer: crud keepItemSelectionOnPageChange & maxKeepItemSelectionL
|
||||
>
|
||||
<span
|
||||
class="cxd-Crud-valueIcon"
|
||||
data-position="bottom"
|
||||
data-tooltip="删除"
|
||||
>
|
||||
×
|
||||
</span>
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Renderer:Picker base 1`] = `
|
||||
exports[`1. Renderer:Picker base 1`] = `
|
||||
<body
|
||||
class="is-modalOpened"
|
||||
style="width: calc(100% - 0px);"
|
||||
@ -222,7 +222,7 @@ exports[`Renderer:Picker base 1`] = `
|
||||
</body>
|
||||
`;
|
||||
|
||||
exports[`Renderer:Picker base 2`] = `
|
||||
exports[`1. Renderer:Picker base 2`] = `
|
||||
<div>
|
||||
<div
|
||||
class="cxd-Form-item cxd-Form-item--normal"
|
||||
@ -261,8 +261,6 @@ exports[`Renderer:Picker base 2`] = `
|
||||
>
|
||||
<span
|
||||
class="cxd-Picker-valueIcon"
|
||||
data-position="bottom"
|
||||
data-tooltip="删除"
|
||||
>
|
||||
×
|
||||
</span>
|
||||
|
@ -15,10 +15,11 @@ import {
|
||||
getVariable,
|
||||
qsstringify,
|
||||
qsparse,
|
||||
isArrayChildrenModified
|
||||
isArrayChildrenModified,
|
||||
isIntegerInRange
|
||||
} from 'amis-core';
|
||||
import {ScopedContext, IScopedContext} from 'amis-core';
|
||||
import {Button, SpinnerExtraProps} from 'amis-ui';
|
||||
import {Button, SpinnerExtraProps, TooltipWrapper} from 'amis-ui';
|
||||
import {Select} from 'amis-ui';
|
||||
import {getExprProperties} from 'amis-core';
|
||||
import pick from 'lodash/pick';
|
||||
@ -441,7 +442,9 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
'onSave',
|
||||
'onQuery',
|
||||
'formStore',
|
||||
'autoFillHeight'
|
||||
'autoFillHeight',
|
||||
'maxTagCount',
|
||||
'overflowTagPopover'
|
||||
];
|
||||
static defaultProps = {
|
||||
toolbarInline: true,
|
||||
@ -2221,9 +2224,8 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
return this.renderToolbar(footerToolbar, 0, childProps, toolbarRenderer);
|
||||
}
|
||||
|
||||
renderSelection(): React.ReactNode {
|
||||
renderTag(item: any, index: number) {
|
||||
const {
|
||||
store,
|
||||
classnames: cx,
|
||||
labelField,
|
||||
labelTpl,
|
||||
@ -2233,20 +2235,9 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
env
|
||||
} = this.props;
|
||||
|
||||
if (!store.selectedItems.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx('Crud-selection')}>
|
||||
<div className={cx('Crud-selectionLabel')}>
|
||||
{__('CRUD.selected', {total: store.selectedItems.length})}
|
||||
</div>
|
||||
{store.selectedItems.map((item, index) => (
|
||||
<div key={index} className={cx(`Crud-value`)}>
|
||||
<span
|
||||
data-tooltip={__('delete')}
|
||||
data-position="bottom"
|
||||
className={cx('Crud-valueIcon')}
|
||||
onClick={this.unSelectItem.bind(this, item, index)}
|
||||
>
|
||||
@ -2254,17 +2245,107 @@ export default class CRUD extends React.Component<CRUDProps, any> {
|
||||
</span>
|
||||
<span className={cx('Crud-valueLabel')}>
|
||||
{labelTpl ? (
|
||||
<Html
|
||||
html={filter(labelTpl, item)}
|
||||
filterHtml={env.filterHtml}
|
||||
/>
|
||||
<Html html={filter(labelTpl, item)} filterHtml={env.filterHtml} />
|
||||
) : (
|
||||
getVariable(item, labelField || 'label') ||
|
||||
getVariable(item, valueField || primaryField || 'id')
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
}
|
||||
|
||||
renderSelection(): React.ReactNode {
|
||||
const {
|
||||
store,
|
||||
classPrefix: ns,
|
||||
classnames: cx,
|
||||
labelField,
|
||||
labelTpl,
|
||||
primaryField,
|
||||
valueField,
|
||||
translate: __,
|
||||
env,
|
||||
popOverContainer,
|
||||
multiple,
|
||||
maxTagCount,
|
||||
overflowTagPopover
|
||||
} = this.props;
|
||||
|
||||
if (!store.selectedItems.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const totalCount = store.selectedItems.length;
|
||||
let tags: any[] = store.selectedItems;
|
||||
const enableOverflow =
|
||||
multiple !== false &&
|
||||
isIntegerInRange(maxTagCount, {
|
||||
start: 0,
|
||||
end: totalCount,
|
||||
left: 'inclusive',
|
||||
right: 'exclusive'
|
||||
});
|
||||
|
||||
if (enableOverflow) {
|
||||
tags = [
|
||||
...store.selectedItems.slice(0, maxTagCount),
|
||||
{label: `+ ${totalCount - maxTagCount} ...`, value: '__overflow_tag__'}
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cx('Crud-selection')}>
|
||||
<div className={cx('Crud-selectionLabel')}>
|
||||
{__('CRUD.selected', {total: store.selectedItems.length})}
|
||||
</div>
|
||||
{tags.map((item, index) => {
|
||||
if (enableOverflow && index === maxTagCount) {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
key={index}
|
||||
container={popOverContainer}
|
||||
tooltip={{
|
||||
placement: 'top',
|
||||
trigger: 'hover',
|
||||
showArrow: false,
|
||||
offset: [0, -10],
|
||||
tooltipClassName: cx(
|
||||
'Crud-selection-overflow',
|
||||
overflowTagPopover?.tooltipClassName
|
||||
),
|
||||
title: __('已选项'),
|
||||
...omit(overflowTagPopover, [
|
||||
'children',
|
||||
'content',
|
||||
'tooltipClassName'
|
||||
]),
|
||||
children: () => {
|
||||
return (
|
||||
<div
|
||||
className={cx(`${ns}Crud-selection-overflow-wrapper`)}
|
||||
>
|
||||
{store.selectedItems
|
||||
.slice(maxTagCount, totalCount)
|
||||
.map((overflowItem, rawIndex) => {
|
||||
const key = rawIndex + maxTagCount;
|
||||
|
||||
return this.renderTag(overflowItem, key);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div key={index} className={cx(`Crud-value`)}>
|
||||
<span className={cx('Crud-valueLabel')}>{item.label}</span>
|
||||
</div>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
return this.renderTag(item, index);
|
||||
})}
|
||||
<a onClick={this.clearSelection} className={cx('Crud-selectionClear')}>
|
||||
{__('clear')}
|
||||
</a>
|
||||
|
@ -4,6 +4,7 @@ import omit from 'lodash/omit';
|
||||
import find from 'lodash/find';
|
||||
import isEqual from 'lodash/isEqual';
|
||||
import findIndex from 'lodash/findIndex';
|
||||
import merge from 'lodash/merge';
|
||||
import {
|
||||
OptionsControl,
|
||||
OptionsControlProps,
|
||||
@ -20,13 +21,14 @@ import {
|
||||
resolveVariableAndFilter,
|
||||
isApiOutdated,
|
||||
isEffectiveApi,
|
||||
resolveEventData
|
||||
resolveEventData,
|
||||
isIntegerInRange
|
||||
} from 'amis-core';
|
||||
import {Html, Icon} from 'amis-ui';
|
||||
import {isMobile} from 'amis-core';
|
||||
import {Html, Icon, TooltipWrapper} from 'amis-ui';
|
||||
import {FormOptionsSchema, SchemaTpl} from '../../Schema';
|
||||
import intersectionWith from 'lodash/intersectionWith';
|
||||
import {PopUp} from 'amis-ui';
|
||||
import type {TooltipWrapperSchema} from '../TooltipWrapper';
|
||||
import type {Option} from 'amis-core';
|
||||
|
||||
/**
|
||||
* Picker
|
||||
@ -70,6 +72,31 @@ export interface PickerControlSchema extends FormOptionsSchema {
|
||||
* 内嵌模式,也就是说不弹框了。
|
||||
*/
|
||||
embed?: boolean;
|
||||
|
||||
/**
|
||||
* 开启最大标签展示数量的相关配置
|
||||
*/
|
||||
overflowConfig: {
|
||||
/**
|
||||
* 标签的最大展示数量,超出数量后以收纳浮层的方式展示,仅在多选模式开启后生效
|
||||
*/
|
||||
maxTagCount?: number;
|
||||
|
||||
/**
|
||||
* 开启最大标签展示数量后,收纳标签生效的位置,未开启内嵌模式默认为选择器, 开启后默认为选择器 + 模态框,可选值为'select'(选择器)、'crud'(增删改查)
|
||||
*/
|
||||
displayPosition?: ('select' | 'crud')[];
|
||||
|
||||
/**
|
||||
* 开启最大标签展示数量后,选择器内收纳标签的Popover配置
|
||||
*/
|
||||
overflowTagPopover?: TooltipWrapperSchema;
|
||||
|
||||
/**
|
||||
* 开启最大标签展示数量后,CRUD顶部内收纳标签的Popover配置
|
||||
*/
|
||||
overflowTagPopoverInCRUD?: TooltipWrapperSchema;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PickerProps extends OptionsControlProps {
|
||||
@ -115,7 +142,24 @@ export default class PickerControl extends React.PureComponent<
|
||||
title: '${label|raw}'
|
||||
}
|
||||
},
|
||||
embed: false
|
||||
embed: false,
|
||||
overflowConfig: {
|
||||
/** 默认值为-1,不开启 */
|
||||
maxTagCount: -1,
|
||||
displayPosition: ['select', 'crud'],
|
||||
overflowTagPopover: {
|
||||
placement: 'top',
|
||||
trigger: 'hover',
|
||||
showArrow: false,
|
||||
offset: [0, -10]
|
||||
},
|
||||
overflowTagPopoverInCRUD: {
|
||||
placement: 'bottom',
|
||||
trigger: 'hover',
|
||||
showArrow: false,
|
||||
offset: [0, 10]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
state: PickerState = {
|
||||
@ -398,10 +442,15 @@ export default class PickerControl extends React.PureComponent<
|
||||
onChange(resetValue !== void 0 ? resetValue : '');
|
||||
}
|
||||
|
||||
renderValues() {
|
||||
getOverflowConfig() {
|
||||
const {overflowConfig} = this.props;
|
||||
|
||||
return merge(PickerControl.defaultProps.overflowConfig, overflowConfig);
|
||||
}
|
||||
|
||||
renderTag(item: Option, index: number) {
|
||||
const {
|
||||
classPrefix: ns,
|
||||
selectedOptions,
|
||||
labelField,
|
||||
labelTpl,
|
||||
translate: __,
|
||||
@ -410,8 +459,6 @@ export default class PickerControl extends React.PureComponent<
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div className={`${ns}Picker-values`}>
|
||||
{selectedOptions.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={cx(`${ns}Picker-value`, {
|
||||
@ -419,8 +466,6 @@ export default class PickerControl extends React.PureComponent<
|
||||
})}
|
||||
>
|
||||
<span
|
||||
data-tooltip={__('delete')}
|
||||
data-position="bottom"
|
||||
className={`${ns}Picker-valueIcon`}
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
@ -437,10 +482,7 @@ export default class PickerControl extends React.PureComponent<
|
||||
}}
|
||||
>
|
||||
{labelTpl ? (
|
||||
<Html
|
||||
html={filter(labelTpl, item)}
|
||||
filterHtml={env.filterHtml}
|
||||
/>
|
||||
<Html html={filter(labelTpl, item)} filterHtml={env.filterHtml} />
|
||||
) : (
|
||||
`${
|
||||
getVariable(item, labelField || 'label') ||
|
||||
@ -449,7 +491,86 @@ export default class PickerControl extends React.PureComponent<
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
}
|
||||
|
||||
renderValues() {
|
||||
const {
|
||||
classPrefix: ns,
|
||||
selectedOptions,
|
||||
translate: __,
|
||||
disabled,
|
||||
multiple,
|
||||
popOverContainer
|
||||
} = this.props;
|
||||
const {maxTagCount, overflowTagPopover} = this.getOverflowConfig();
|
||||
const totalCount = selectedOptions.length;
|
||||
let tags = selectedOptions;
|
||||
const enableOverflow =
|
||||
multiple !== false &&
|
||||
isIntegerInRange(maxTagCount, {
|
||||
start: 0,
|
||||
end: totalCount,
|
||||
left: 'inclusive',
|
||||
right: 'exclusive'
|
||||
});
|
||||
|
||||
/** 多选且开启限制标签数量 */
|
||||
if (enableOverflow) {
|
||||
tags = [
|
||||
...selectedOptions.slice(0, maxTagCount),
|
||||
{label: `+ ${totalCount - maxTagCount} ...`, value: '__overflow_tag__'}
|
||||
];
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={`${ns}Picker-values`}>
|
||||
{tags.map((item, index) => {
|
||||
if (enableOverflow && index === maxTagCount) {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
key={index}
|
||||
container={popOverContainer}
|
||||
tooltip={{
|
||||
tooltipClassName: cx(
|
||||
'Picker-overflow',
|
||||
overflowTagPopover?.tooltipClassName
|
||||
),
|
||||
title: __('已选项'),
|
||||
...omit(overflowTagPopover, [
|
||||
'children',
|
||||
'content',
|
||||
'tooltipClassName'
|
||||
]),
|
||||
children: () => {
|
||||
return (
|
||||
<div className={cx(`${ns}Picker-overflow-wrapper`)}>
|
||||
{selectedOptions
|
||||
.slice(maxTagCount, totalCount)
|
||||
.map((overflowItem, rawIndex) => {
|
||||
const key = rawIndex + maxTagCount;
|
||||
|
||||
return this.renderTag(overflowItem, key);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div
|
||||
key={index}
|
||||
className={cx(`${ns}Picker-value`, {
|
||||
'is-disabled': disabled
|
||||
})}
|
||||
>
|
||||
<span className={`${ns}Picker-valueLabel`}>{item.label}</span>
|
||||
</div>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
return this.renderTag(item, index);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -466,6 +587,8 @@ export default class PickerControl extends React.PureComponent<
|
||||
source,
|
||||
strictMode
|
||||
} = this.props;
|
||||
const {maxTagCount, overflowTagPopoverInCRUD, displayPosition} =
|
||||
this.getOverflowConfig();
|
||||
|
||||
return render('modal-body', this.state.schema, {
|
||||
value: selectedOptions,
|
||||
@ -512,7 +635,11 @@ export default class PickerControl extends React.PureComponent<
|
||||
}
|
||||
: undefined,
|
||||
ref: this.crudRef,
|
||||
popOverContainer
|
||||
popOverContainer,
|
||||
...(embed ||
|
||||
(Array.isArray(displayPosition) && displayPosition.includes('crud'))
|
||||
? {maxTagCount, overflowTagPopover: overflowTagPopoverInCRUD}
|
||||
: {})
|
||||
}) as JSX.Element;
|
||||
}
|
||||
render() {
|
||||
|
Loading…
Reference in New Issue
Block a user