Skip to content

Commit

Permalink
feat(grid-select): add single/multiple select
Browse files Browse the repository at this point in the history
  • Loading branch information
kagol committed Nov 11, 2024
1 parent 4e74df8 commit 317b23b
Show file tree
Hide file tree
Showing 10 changed files with 241 additions and 29 deletions.
58 changes: 51 additions & 7 deletions examples/sites/demos/apis/grid-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,50 @@ export default {
},
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'
}
]
}
Expand All @@ -25,14 +69,14 @@ export default {
name: 'IGridOption',
type: 'interface',
code: `
interface ITreeNode {
label: string // 默认树节点的文本字段
id: number|string // 树节点唯一标识
children: ITreeNode[] // 子节点
}
interface IGridOption {
data: ITreeNode[] // 树数据,用法同 Tree
data: Record<string, any>
columns: {
type: string
field: string
title: string
width: number
}[] // 表格列数据,用法同 Grid
}
`
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
<template>
<tiny-grid-select v-model="value" :grid-op="gridOp"></tiny-grid-select>
<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 { GridSelect as TinyGridSelect } from '@opentiny/vue'
import { TinyGridSelect } from '@opentiny/vue'
const value = ref('')
const gridOp = reactive({
const gridOpSingle = reactive({
data: [
{ id: '001', area: '华南区', province: '广东省', city: '深圳1' },
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
Expand Down
21 changes: 13 additions & 8 deletions examples/sites/demos/pc/app/grid-select/basic-usage.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
import { expect, test } from '@playwright/test'

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

const wrap = page.locator('#basic-usage')
const select = wrap.locator('.tiny-tree-select').nth(0)
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 treeNode = dropdown.locator('.tiny-tree-node')
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(treeNode).toHaveCount(7)
await expect(dropdown).toBeVisible()
await expect(row).toHaveCount(6)

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

<script>
import { GridSelect } from '@opentiny/vue'
import { TinyGridSelect } from '@opentiny/vue'
export default {
components: {
TinyGridSelect: GridSelect
TinyGridSelect
},
data() {
return {
value: '',
treeOp: {
gridOpSingle: {
data: [
{ id: '001', area: '华南区', province: '广东省', city: '深圳1' },
{ id: '001', area: '华南区', province: '广东省', city: '广州市' },
{ id: '002', area: '华南区', province: '广东省', city: '深圳市' },
{ id: '003', area: '华南区', province: '广东省', city: '珠海市' },
{ id: '004', area: '华南区', province: '广东省', city: '佛山市' },
Expand Down
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>
13 changes: 13 additions & 0 deletions examples/sites/demos/pc/app/grid-select/webdoc/grid-select.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ export default {
'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']
}
]
}
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)
}
}
10 changes: 7 additions & 3 deletions packages/renderless/src/grid-select/vue.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export const api = ['state']
import { radioChange, selectChange } from './index'

export const renderless = (props, { reactive }, { vm }) => {
export const api = ['state', 'radioChange', 'selectChange']

export const renderless = (props, { reactive }, { vm, emit }) => {
const api = {}

const state = reactive({
Expand All @@ -9,7 +11,9 @@ export const renderless = (props, { reactive }, { vm }) => {
})

Object.assign(api, {
state
state,
radioChange: radioChange({ props, vm, emit }),
selectChange: selectChange({ props, vm, emit })
})

return api
Expand Down
29 changes: 27 additions & 2 deletions packages/vue/src/grid-select/src/pc.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,19 @@
<template>
<tiny-base-select ref="baseSelectRef" class="tiny-grid-select" v-model="state.value">
<tiny-base-select ref="baseSelectRef" class="tiny-grid-select" v-model="state.value" :multiple="multiple">
<template #panel>
<tiny-grid ref="gridRef" v-bind="state.gridData"></tiny-grid>
<tiny-grid
ref="gridRef"
auto-resize
:row-id="valueField"
:highlight-current-row="true"
:columns="state.gridData.columns"
:data="state.gridData"
@select-all="selectChange"
@select-change="selectChange"
@radio-change="radioChange"
@mousedown.stop
v-bind="state.gridData"
></tiny-grid>
</template>
</tiny-base-select>
</template>
Expand All @@ -19,9 +31,22 @@ export default defineComponent({
TinyBaseSelect: BaseSelect
},
props: {
clearable: Boolean,
filterable: Boolean,
filterMethod: Function,
gridOp: {
type: Object,
default: () => ({})
},
modelValue: {},
multiple: Boolean,
textField: {
type: String,
default: 'label'
},
valueField: {
type: String,
default: 'value'
}
},
setup(props, context) {
Expand Down

0 comments on commit 317b23b

Please sign in to comment.