Skip to content

Commit

Permalink
feat(grid-select): [grid-select] add grid select component and implem…
Browse files Browse the repository at this point in the history
…ent single/multiple select features (#2509)

* feat(grid-select): add basic grid-select

* feat(grid-select): add single/multiple select
  • Loading branch information
kagol authored Nov 11, 2024
1 parent 43723c1 commit a3e30c3
Show file tree
Hide file tree
Showing 18 changed files with 495 additions and 1 deletion.
84 changes: 84 additions & 0 deletions examples/sites/demos/apis/grid-select.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
export default {
mode: ['pc'],
apis: [
{
name: 'grid-select',
type: 'component',
props: [
{
name: 'grid-op',
typeAnchorName: 'IGridOption',
type: 'IGridOption',
defaultValue: '',
desc: {
'zh-CN': '下拉表格时,内置表格组件的配置,用法同 Grid 组件。',
'en-US': ''
},
mode: ['pc'],
pcDemo: 'basic-usage'
},
{
name: 'modelValue / v-model',
type: 'string | number | Array<string|number>',
defaultValue: '',
desc: {
'zh-CN': '绑定值',
'en-US': 'Bind value'
},
mode: ['pc'],
pcDemo: 'basic-usage'
},
{
name: 'multiple',
type: 'boolean',
defaultValue: 'false',
desc: {
'zh-CN': '是否允许选择多个选项',
'en-US': 'Allow multiple options to be selected'
},
mode: ['pc'],
pcDemo: 'multiple'
},
{
name: 'text-field',
type: 'string',
defaultValue: "''",
desc: {
'zh-CN': '显示值字段',
'en-US': 'Show Value Fields'
},
mode: ['pc'],
pcDemo: 'basic-usage'
},
{
name: 'value-field',
type: 'string',
defaultValue: "''",
desc: {
'zh-CN': '绑定值字段',
'en-US': 'Bind Value Field'
},
mode: ['pc'],
pcDemo: 'basic-usage'
}
]
}
],
types: [
{
name: 'IGridOption',
type: 'interface',
code: `
interface IGridOption {
data: Record<string, any>
columns: {
type: string
field: string
title: string
width: number
}[] // 表格列数据,用法同 Grid
}
`
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<template>
<tiny-grid-select v-model="value" :grid-op="gridOpSingle" value-field="id" text-field="city"></tiny-grid-select>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { TinyGridSelect } from '@opentiny/vue'
const value = ref('')
const gridOpSingle = reactive({
data: [
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
],
columns: [
{ type: 'radio', title: '' },
{ field: 'area', title: '区域', width: 90 },
{ field: 'province', title: '省份', width: 60 },
{ field: 'city', title: '城市', width: 60 }
]
})
</script>

<style scoped>
.tiny-grid-select {
width: 280px;
}
</style>
25 changes: 25 additions & 0 deletions examples/sites/demos/pc/app/grid-select/basic-usage.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { expect, test } from '@playwright/test'

test('测试下拉表格单选', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('grid-select#basic-usage')

const wrap = page.locator('#basic-usage')
const select = wrap.locator('.tiny-grid-select').nth(0)
const input = select.locator('.tiny-input__inner')
const dropdown = page.locator('body > .tiny-select-dropdown')
const suffixSvg = select.locator('.tiny-base-select__caret')
const row = dropdown.getByRole('row')

await expect(suffixSvg).toHaveCount(1)
await expect(suffixSvg).toBeVisible()

await input.click()
await expect(dropdown).toBeVisible()
await expect(row).toHaveCount(6)

await row.nth(1).getByRole('cell').first().click()
await expect(input).toHaveValue('广州市')
await input.click()
await expect(row.filter({ hasText: '广州市' })).toHaveClass(/tiny-grid-body__row row__radio/)
})
39 changes: 39 additions & 0 deletions examples/sites/demos/pc/app/grid-select/basic-usage.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<tiny-grid-select v-model="value" :grid-op="gridOpSingle" value-field="id" text-field="city"></tiny-grid-select>
</template>

<script>
import { TinyGridSelect } from '@opentiny/vue'
export default {
components: {
TinyGridSelect
},
data() {
return {
value: '',
gridOpSingle: {
data: [
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
],
columns: [
{ type: 'radio', title: '' },
{ field: 'area', title: '区域', width: 90 },
{ field: 'province', title: '省份', width: 60 },
{ field: 'city', title: '城市', width: 60 }
]
}
}
}
}
</script>

<style scoped>
.tiny-grid-select {
width: 280px;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<template>
<tiny-grid-select
v-model="value"
multiple
:grid-op="gridOpMulti"
value-field="id"
text-field="city"
></tiny-grid-select>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { GridSelect as TinyGridSelect } from '@opentiny/vue'
const value = ref('')
const gridOpMulti = reactive({
data: [
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
],
columns: [
{ type: 'selection', title: '' },
{ field: 'area', title: '区域', width: 90 },
{ field: 'province', title: '省份', width: 60 },
{ field: 'city', title: '城市', width: 60 }
]
})
</script>

<style scoped>
.tiny-grid-select {
width: 280px;
}
</style>
45 changes: 45 additions & 0 deletions examples/sites/demos/pc/app/grid-select/multiple.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<template>
<tiny-grid-select
v-model="value"
multiple
:grid-op="gridOpMulti"
value-field="id"
text-field="city"
></tiny-grid-select>
</template>

<script>
import { TinyGridSelect } from '@opentiny/vue'
export default {
components: {
TinyGridSelect
},
data() {
return {
value: '',
treeOp: {
data: [
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
{ id: '005', area: '华南区', province: '广东省', city: '中山市' }
],
columns: [
{ type: 'selection', title: '' },
{ field: 'area', title: '区域', width: 90 },
{ field: 'province', title: '省份', width: 60 },
{ field: 'city', title: '城市', width: 60 }
]
}
}
}
}
</script>

<style scoped>
.tiny-grid-select {
width: 280px;
}
</style>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: GridSelect 下拉表格选择器
---

# GridSelect 下拉表格选择器

结合了 BaseSelect 和 Grid 组件的选择器,用于从一个下拉表格中选择一个或多个选项。
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
title: GridSelect
---

# GridSelect

A selector that combines the BaseSelect and Grid components to select one or more options from a drop-down table.
35 changes: 35 additions & 0 deletions examples/sites/demos/pc/app/grid-select/webdoc/grid-select.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
export default {
column: '2',
owner: '',
meta: {
experimental: '3.20.0'
},
demos: [
{
demoId: 'basic-usage',
name: {
'zh-CN': '基本用法',
'en-US': 'Basic Usage'
},
desc: {
'zh-CN':
'<p>最基础的用法,通过 <code>grid-op</code> 设置下拉表格的数据源,<code>v-model</code> 设置绑定值。</p>',
'en-US': ''
},
codeFiles: ['basic-usage.vue']
},
{
demoId: 'multiple',
name: {
'zh-CN': '多选',
'en-US': 'Multiple'
},
desc: {
'zh-CN':
'<p>通过 <code>multiple</code> 属性启用多选功能,此时 <code>v-model</code> 的值为当前选中值所组成的数组,默认选中值会以标签形式展示。</p>',
'en-US': ''
},
codeFiles: ['multiple.vue']
}
]
}
8 changes: 8 additions & 0 deletions examples/sites/demos/pc/menus.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ export const cmpMenus = [
{ 'nameCn': '文件上传', 'name': 'FileUpload', 'key': 'file-upload' },
{ 'nameCn': '富文本', 'name': 'FluentEditor', 'key': 'fluent-editor' },
{ 'nameCn': '表单', 'name': 'Form', 'key': 'form' },
{
'nameCn': '下拉表格选择器',
'name': 'GridSelect',
'key': 'grid-select',
'meta': {
'experimental': '3.20.0'
}
},
{ 'nameCn': '输入框', 'name': 'Input', 'key': 'input' },
{ 'nameCn': ' IP地址输入框', 'name': 'IpAddress', 'key': 'ip-address' },
{ 'nameCn': '数字输入框', 'name': 'Numeric', 'key': 'numeric' },
Expand Down
2 changes: 1 addition & 1 deletion examples/sites/src/views/components/cmp-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const faqMdConfig = {
}

const getWebdocPath = (path) => {
if (path?.startsWith('grid-')) {
if (path?.startsWith('grid-') && path !== 'grid-select') {
return 'grid'
} else if (path?.startsWith('chart-')) {
return 'chart'
Expand Down
6 changes: 6 additions & 0 deletions packages/modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -1322,6 +1322,12 @@
"type": "component",
"exclude": false
},
"GridSelect": {
"path": "vue/src/grid-select/index.ts",
"type": "component",
"exclude": false,
"mode": ["pc"]
},
"GridToolbar": {
"path": "vue/src/grid-toolbar/index.ts",
"type": "component",
Expand Down
38 changes: 38 additions & 0 deletions packages/renderless/src/grid-select/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
export const radioChange =
({ props, vm, emit }) =>
({ row }) => {
if (!props.multiple) {
vm.$refs.baseSelectRef.updateSelectedData({
...row,
currentLabel: row[props.textField],
value: row[props.valueField],
state: {
currentLabel: row[props.textField]
}
})

vm.$refs.baseSelectRef.hidePanel()

emit('update:modelValue', row)
emit('change', row)
}
}

export const selectChange =
({ props, vm, emit }) =>
({ $table, selection, checked, row }) => {
if (props.multiple) {
vm.$refs.baseSelectRef.updateSelectedData(
selection.map((node) => {
return {
...node,
currentLabel: node[props.textField],
value: node[props.valueField]
}
})
)

emit('update:modelValue', selection)
emit('change', selection)
}
}
Loading

0 comments on commit a3e30c3

Please sign in to comment.