场景 1:单选
最基础的用法,通过 grid-op 设置下拉表格的数据源,v-model 设置绑定值。
通过 grid-op 设置表格列与数据,v-model 绑定选中值。
Configure the internal grid via grid-op and bind the selection with v-model.
通过 multiple 属性启用多选功能,此时 v-model 的值为当前选中值所组成的数组,默认选中值会以标签形式展示。
通过 radio-config / select-config 的 checkMethod 控制某些行不可选,并支持 trigger: row 开启整行点击。
Use radio-config / select-config with checkMethod to disable rows and enable row-click selection.
通过 filterable 设置是否可过滤,filter-method 设置自定义过滤逻辑。
配合 remote、remote-method 与 reserve-keyword 实现远程搜索,并分别展示单选与多选场景。
Demonstrates remote searching with remote, remote-method and keyword reservation for both single and multiple selection.
同时使用 remote 和 remote-method 和 filterable 3 个属性开启远程搜索。通过 remote-config 设置自动搜索和显示展开按钮。
在多选模式下,可通过 reserve-keyword 设置选中一个选项后依然保留搜索关键字。
利用 init-query 在远程模式下初始化表格数据,并展示单选与多选的默认值回显。
Loads remote data at startup via init-query and shows how default values are rendered for both modes.
通过 select-config (多选)或 radio-config (单选)属性的 checkMethod 自定义禁用逻辑,返回 true (启用) / false (禁用)。
配置 { trigger: "row" } 可以设置点击行选中数据。
通过 extra-query-params 将父级选择结果传递给子级下拉表格,实现级联查询与选项联动。
By customizing the disable logic through the select-config (multiple selection) or radio-config (single selection) attribute's checkMethod, return true (Enable) / false (disable).Configure {trigger: 'row'} to set the selected data in the click row.
Shows how extra-query-params passes parent selections to a child dropdown to build cascading queries.
一次性加载数百条记录,结合 Grid 的虚拟滚动仍可保持顺畅的选择体验。
', + 'en-US': + 'Loads hundreds of rows to illustrate how TinyGrid’s virtual scrolling keeps the dropdown responsive.
' + }, + codeFiles: ['radio-bigdata.vue'] } ] } diff --git a/examples/sites/demos/pc/menus.js b/examples/sites/demos/pc/menus.js index e7c6591c2d..a3bf89f1a2 100644 --- a/examples/sites/demos/pc/menus.js +++ b/examples/sites/demos/pc/menus.js @@ -163,14 +163,7 @@ 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' }, @@ -189,6 +182,14 @@ export const cmpMenus = [ 'nameCn': '树形选择器', 'name': 'TreeSelect', 'key': 'tree-select' + }, + { + 'nameCn': '下拉表格选择器', + 'name': 'GridSelect', + 'key': 'grid-select', + 'meta': { + 'experimental': '3.27.0' + } } ] }, diff --git a/packages/renderless/src/grid-select/index.ts b/packages/renderless/src/grid-select/index.ts index a320a0d14f..14beb8bcc0 100644 --- a/packages/renderless/src/grid-select/index.ts +++ b/packages/renderless/src/grid-select/index.ts @@ -1,3 +1,81 @@ +import { find } from '@opentiny/utils' + +const updateBaseSelect = ({ vm, props, data, label }: any) => { + if (!vm.$refs.baseSelectRef) { + return + } + + vm.$refs.baseSelectRef.updateSelectedData(data) + + if (!props.multiple) { + const baseState = vm.$refs.baseSelectRef.state + if (!baseState) { + return + } + + const currentLabel = + label ?? + (data && !Array.isArray(data) ? (data.state?.currentLabel ?? data.currentLabel ?? data[props.textField]) : '') + + baseState.selectedLabel = currentLabel || '' + + if (props.filterable || props.searchable) { + baseState.query = currentLabel || '' + } + } +} + +export const syncGridSelection = + ({ props, vm, state, nextTick }) => + () => { + if (!vm.$refs.gridRef) { + return + } + + // 使用 nextTick 确保表格已渲染 + nextTick(() => { + try { + const tableData = vm.$refs.gridRef.getTableData() + const fullData = tableData?.fullData || [] + + if (props.multiple) { + // 多选模式 + if (Array.isArray(state.modelValue) && state.modelValue.length > 0) { + const rowsToSelect = fullData.filter((row: any) => state.modelValue.indexOf(row[props.valueField]) !== -1) + vm.$refs.gridRef.clearSelection() + if (rowsToSelect.length > 0) { + vm.$refs.gridRef.setSelection(rowsToSelect, true) + } + } else { + vm.$refs.gridRef.clearSelection() + } + } else { + // 单选模式 + if (state.modelValue) { + const rowToSelect = fullData.find((row: any) => row[props.valueField] === state.modelValue) + vm.$refs.gridRef.clearRadioRow() + if (rowToSelect) { + vm.$refs.gridRef.setRadioRow(rowToSelect) + } + } else { + vm.$refs.gridRef.clearRadioRow() + } + } + } catch (e) { + // 如果表格还没有加载,忽略错误 + } + }) + } + +export const handleVisibleChange = + ({ api, state }) => + (visible: boolean) => { + // 面板打开时,同步表格选中状态 + if (visible && state.isMounted) { + api.syncGridSelection() + } + } + export const buildSelectConfig = ({ props, state }) => () => { @@ -38,16 +116,21 @@ export const filter = remoteMethod(value, props.extraQueryParams).then((data) => { // 多选时取远端数据与当前已选数据的并集 if (multiple) { - const selectedIds = state.selected.map((sel) => sel[valueField]) + const selectedIds = Array.isArray(state.selected) ? state.selected.map((sel: any) => sel[valueField]) : [] vm.$refs.gridRef.clearSelection() - vm.$refs.gridRef.setSelection( - data.filter((row) => ~selectedIds.indexOf(row[valueField])), - true - ) - state.remoteData = data.filter((row) => !~selectedIds.indexOf(row[valueField])).concat(state.selected) + // 设置表格中已选中的行 + const selectedRows = data.filter((row: any) => selectedIds.indexOf(row[valueField]) !== -1) + if (selectedRows.length > 0) { + vm.$refs.gridRef.setSelection(selectedRows, true) + } + // 合并远程数据和已选数据 + state.remoteData = data } else { vm.$refs.gridRef.clearRadioRow() - vm.$refs.gridRef.setRadioRow(find(data, (item) => props.modelValue === item[props.valueField])) + const selectedRow = find(data, (item: any) => props.modelValue === item[props.valueField]) + if (selectedRow) { + vm.$refs.gridRef.setRadioRow(selectedRow) + } state.remoteData = data } @@ -58,42 +141,480 @@ export const filter = } } +/** + * 多选,获取已选中的行 value 数组,用于初始化表格的勾选状态 + * @return 示例:[9, 6] + */ +export const getcheckedData = + ({ props, state }) => + () => { + const checkedKey: any[] = [] + + if (!Array.isArray(state.selected)) { + return props.modelValue + ? [props.modelValue] + : state.selected && state.selected[props.valueField] + ? [state.selected[props.valueField]] + : [] + } else { + state.selected.length > 0 && + state.selected.forEach((item: any) => { + checkedKey.push(item[props.valueField]) + }) + + return checkedKey + } + } + +/** + * 多选,获取匹配的表格行 + * @params value 表格行 value + * @return 完整的表格行数据 + */ +export const getPluginOption = + ({ api, props, state }) => + (value) => { + const isRemote = + (props.filterable || props.searchable) && + props.remote && + (typeof props.remoteMethod === 'function' || typeof props.initQuery === 'function') + const { textField, valueField } = props + const sourceData: any[] = isRemote + ? state.remoteData + : Array.isArray(state.gridData) + ? state.gridData + : state.gridData?.data || [] + const selNode = find(sourceData, (item: any) => item[valueField] === value) + const items: any[] = [] + + if (selNode) { + selNode.currentLabel = selNode[textField] + items.push(selNode) + } + + return items + } + +export const initQuery = + ({ props, state, vm }) => + (options: any = {}) => { + const { init } = options + const isRemote = + (props.filterable || props.searchable) && + props.remote && + (typeof props.remoteMethod === 'function' || typeof props.initQuery === 'function') + + let selected + if (isRemote && props.initQuery) { + let initData = props.initQuery(props.modelValue, props.extraQueryParams, !!init) + if (initData && initData.then) { + return new Promise((resolve) => { + initData.then((selected: any) => { + state.remoteData = selected + if (vm.$refs.gridRef) { + vm.$refs.gridRef.loadData(selected) + } + resolve(selected) + }) + }) + } + selected = initData + state.remoteData = selected + if (vm.$refs.gridRef) { + vm.$refs.gridRef.loadData(selected) + } + } + + return Promise.resolve(selected) + } + +export const mounted = + ({ api, state, props, vm, nextTick }) => + () => { + // 确保 gridRef 存在后再执行初始化 + const initSelected = () => { + if (!state.modelValue || (Array.isArray(state.modelValue) && state.modelValue.length === 0)) { + return + } + + if (props.multiple) { + let initialNodes: any[] = [] + if (Array.isArray(state.modelValue)) { + state.modelValue.forEach((value: any) => { + const option = api.getPluginOption(value) + initialNodes = initialNodes.concat(option) + }) + } + + const selected = initialNodes.map((node: any) => { + return { + ...node, + currentLabel: node[props.textField], + value: node[props.valueField] + } + }) + + updateBaseSelect({ vm, props, data: selected }) + state.selected = selected + + // 设置表格的选中状态 + if (vm.$refs.gridRef && selected.length > 0) { + vm.$refs.gridRef.clearSelection() + vm.$refs.gridRef.setSelection(selected, true) + } + } else { + const data = api.getPluginOption(state.modelValue)[0] + if (data) { + if (vm.$refs.baseSelectRef) { + updateBaseSelect({ + vm, + props, + data: { + ...data, + currentLabel: data[props.textField], + value: data[props.valueField], + state: { + currentLabel: data[props.textField] + } + } + }) + } + + state.selected = data + state.currentKey = data[props.valueField] + + // 设置表格的单选状态 + if (vm.$refs.gridRef) { + vm.$refs.gridRef.clearRadioRow() + vm.$refs.gridRef.setRadioRow(data) + } + } + } + } + + // 使用 nextTick 确保 DOM 已渲染完成 + nextTick(() => { + // 执行初始化查询,如果有的话 + const initQueryPromise = api.initQuery({ init: true }) + if (initQueryPromise && typeof initQueryPromise.then === 'function') { + initQueryPromise + .then(() => { + nextTick(() => { + initSelected() + }) + }) + .catch(() => { + // 如果 initQuery 失败,仍然尝试初始化选中状态 + nextTick(() => { + initSelected() + }) + }) + } else { + // 如果没有 initQuery 或返回的不是 Promise,直接初始化选中状态 + initSelected() + } + }) + } + +export const watchValue = + ({ api, props, vm, state }) => + (newValue: any, oldValue: any) => { + if (props.multiple) { + let initialNodes: any[] = [] + if (Array.isArray(newValue) && newValue.length > 0) { + // 从表格的完整数据中查找选中的行 + const isRemote = + (props.filterable || props.searchable) && + props.remote && + (typeof props.remoteMethod === 'function' || typeof props.initQuery === 'function') + const sourceData: any[] = isRemote + ? state.remoteData + : Array.isArray(state.gridData) + ? state.gridData + : state.gridData?.data || [] + + // 如果表格已加载,从表格的完整数据中查找 + if (vm.$refs.gridRef) { + try { + const tableData = vm.$refs.gridRef.getTableData() + const fullData = tableData?.fullData || sourceData + + newValue.forEach((value: any) => { + const foundRow = fullData.find((item: any) => item[props.valueField] === value) + if (foundRow) { + initialNodes.push(foundRow) + } else { + // 如果表格中没有找到,尝试从 state.selected 中查找 + const existing = state.selected.find((item: any) => item[props.valueField] === value) + if (existing) { + initialNodes.push(existing) + } + } + }) + } catch (e) { + // 如果表格还没有加载,从源数据中查找 + newValue.forEach((value: any) => { + const foundRow = sourceData.find((item: any) => item[props.valueField] === value) + if (foundRow) { + initialNodes.push(foundRow) + } else { + // 如果源数据中没有找到,尝试从 state.selected 中查找 + const existing = state.selected.find((item: any) => item[props.valueField] === value) + if (existing) { + initialNodes.push(existing) + } + } + }) + } + } else { + // 表格还没有加载,从源数据中查找 + newValue.forEach((value: any) => { + const foundRow = sourceData.find((item: any) => item[props.valueField] === value) + if (foundRow) { + initialNodes.push(foundRow) + } else { + // 如果源数据中没有找到,尝试从 state.selected 中查找 + const existing = state.selected.find((item: any) => item[props.valueField] === value) + if (existing) { + initialNodes.push(existing) + } + } + }) + } + } + + const selected = initialNodes.map((node: any) => { + return { + ...node, + currentLabel: node[props.textField], + value: node[props.valueField] + } + }) + + // 更新输入框中选中的标签 + if (vm.$refs.baseSelectRef) { + updateBaseSelect({ vm, props, data: selected }) + } + state.selected = selected + + // 更新下拉面板中选中的表格行(使用 nextTick 确保表格已渲染) + if (vm.$refs.gridRef) { + vm.$refs.gridRef.clearSelection() + if (selected.length > 0) { + // 从表格的完整数据中获取实际的行对象 + try { + const tableData = vm.$refs.gridRef.getTableData() + const fullData = tableData?.fullData || [] + const rowsToSelect = fullData.filter((row: any) => + selected.some((sel: any) => sel[props.valueField] === row[props.valueField]) + ) + if (rowsToSelect.length > 0) { + vm.$refs.gridRef.setSelection(rowsToSelect, true) + } + } catch (e) { + // 如果表格还没有加载,直接使用 selected + vm.$refs.gridRef.setSelection(selected, true) + } + } + } + } else { + if (!newValue) { + state.selected = {} + state.currentKey = '' + if (vm.$refs.gridRef) { + vm.$refs.gridRef.clearRadioRow() + } + if (vm.$refs.baseSelectRef) { + updateBaseSelect({ vm, props, data: null }) + } + return + } + + // 从表格的完整数据中查找选中的行 + const isRemote = + (props.filterable || props.searchable) && + props.remote && + (typeof props.remoteMethod === 'function' || typeof props.initQuery === 'function') + const sourceData: any[] = isRemote + ? state.remoteData + : Array.isArray(state.gridData) + ? state.gridData + : state.gridData?.data || [] + + let data = null + if (vm.$refs.gridRef) { + try { + const tableData = vm.$refs.gridRef.getTableData() + const fullData = tableData?.fullData || sourceData + data = fullData.find((item: any) => item[props.valueField] === newValue) + } catch (e) { + data = sourceData.find((item: any) => item[props.valueField] === newValue) + } + } else { + data = sourceData.find((item: any) => item[props.valueField] === newValue) + } + + // 如果表格中没有找到,尝试从 state.selected 中查找 + if ( + !data && + state.selected && + typeof state.selected === 'object' && + !Array.isArray(state.selected) && + state.selected[props.valueField] === newValue + ) { + data = state.selected + } + + if (data && typeof data === 'object' && !Array.isArray(data)) { + updateBaseSelect({ + vm, + props, + data: { + ...(data as any), + currentLabel: data[props.textField], + value: data[props.valueField], + state: { + currentLabel: data[props.textField] + } + } + }) + + state.selected = data + state.currentKey = data[props.valueField] + + // 更新下拉面板中选中的表格行 + if (vm.$refs.gridRef) { + vm.$refs.gridRef.clearRadioRow() + // 从表格的完整数据中获取实际的行对象 + try { + const tableData = vm.$refs.gridRef.getTableData() + const fullData = tableData?.fullData || [] + const rowToSelect = fullData.find((row: any) => row[props.valueField] === newValue) + if (rowToSelect) { + vm.$refs.gridRef.setRadioRow(rowToSelect) + } else { + vm.$refs.gridRef.setRadioRow(data) + } + } catch (e) { + vm.$refs.gridRef.setRadioRow(data) + } + } + } + } + } + export const radioChange = - ({ props, vm, emit }) => - ({ row }) => { + ({ props, vm, emit, state }) => + ({ row }: any) => { if (!props.multiple) { - vm.$refs.baseSelectRef.updateSelectedData({ - ...row, - currentLabel: row[props.textField], - value: row[props.valueField], - state: { - currentLabel: row[props.textField] + updateBaseSelect({ + vm, + props, + data: { + ...row, + currentLabel: row[props.textField], + value: row[props.valueField], + state: { + currentLabel: row[props.textField] + } } }) + state.selected = row + state.currentKey = row[props.valueField] + vm.$refs.baseSelectRef.hidePanel() - emit('update:modelValue', row) - emit('change', row) + emit('update:modelValue', row[props.valueField]) + emit('change', row[props.valueField]) } } export const selectChange = - ({ props, vm, emit }) => - ({ $table, selection, checked, row }) => { + ({ props, vm, emit, state, nextTick }) => + ({ $table, selection, checked, row }: any) => { if (props.multiple) { - vm.$refs.baseSelectRef.updateSelectedData( - selection.map((node) => { - return { - ...node, - currentLabel: node[props.textField], - value: node[props.valueField], - isGrid: true + const { textField, valueField } = props + const remoteItem = (row: any) => { + const removeItem = state.selected.find((item: any) => item[valueField] === row[valueField]) + if (removeItem) { + const index = state.selected.indexOf(removeItem) + state.selected.splice(index, 1) + } + } + + if (row) { + // 单行选择/取消 + if (checked) { + // 检查是否已存在 + const exists = state.selected.find((item: any) => item[valueField] === row[valueField]) + if (!exists) { + state.selected.push({ + ...row, + value: row[valueField], + currentLabel: row[textField] + }) } - }) - ) + } else { + remoteItem(row) + } + } else { + // 全选/取消全选 + if (checked) { + // 添加所有选中的行(排除已存在的) + selection.forEach((row: any) => { + const exists = state.selected.find((item: any) => item[valueField] === row[valueField]) + if (!exists) { + state.selected.push({ + ...row, + value: row[valueField], + currentLabel: row[textField] + }) + } + }) + } else { + // 取消全选:移除当前表格数据中的所有行 + const tableData = $table?.tableFullData || [] + tableData.forEach((row: any) => { + remoteItem(row) + }) + } + } + + // 更新显示的数据 + const selectedData = state.selected.map((node: any) => ({ + ...node, + currentLabel: node[textField], + value: node[valueField], + isGrid: true + })) + + updateBaseSelect({ vm, props, data: selectedData }) - emit('update:modelValue', selection) - emit('change', selection) + // 更新 modelValue(不触发 watchValue,因为表格选中状态已经正确) + const currentValue = state.selected.map((item: any) => item[valueField]) + // 直接更新 state.modelValue,避免触发 watchValue 导致重复更新 + state.modelValue = currentValue + emit('update:modelValue', currentValue) + emit('change', currentValue, state.selected) + + // 确保表格选中状态正确同步 + if (vm.$refs.gridRef) { + nextTick(() => { + try { + const tableData = vm.$refs.gridRef.getTableData() + const fullData = tableData?.fullData || [] + // 获取当前表格中应该选中的行 + const rowsToSelect = fullData.filter((row: any) => currentValue.indexOf(row[valueField]) !== -1) + // 清除所有选中,然后重新设置 + vm.$refs.gridRef.clearSelection() + if (rowsToSelect.length > 0) { + vm.$refs.gridRef.setSelection(rowsToSelect, true) + } + } catch (e) { + // 如果表格还没有加载,忽略错误 + } + }) + } } } diff --git a/packages/renderless/src/grid-select/vue.ts b/packages/renderless/src/grid-select/vue.ts index 383407cc90..f2112e5753 100644 --- a/packages/renderless/src/grid-select/vue.ts +++ b/packages/renderless/src/grid-select/vue.ts @@ -1,15 +1,60 @@ -import { buildRadioConfig, buildSelectConfig, filter, radioChange, selectChange } from './index' +import { + buildRadioConfig, + buildSelectConfig, + filter, + getcheckedData, + getPluginOption, + handleVisibleChange, + initQuery, + mounted, + radioChange, + selectChange, + syncGridSelection, + watchValue +} from './index' -export const api = ['state', 'buildRadioConfig', 'buildSelectConfig', 'filter', 'radioChange', 'selectChange'] +export const api = [ + 'state', + 'buildRadioConfig', + 'buildSelectConfig', + 'filter', + 'radioChange', + 'selectChange', + 'getcheckedData', + 'getPluginOption', + 'initQuery', + 'mounted', + 'syncGridSelection', + 'watchValue', + 'handleVisibleChange' +] -export const renderless = (props, { reactive, watch }, { vm, emit }) => { +export const renderless = (props, { reactive, computed, watch, onMounted, nextTick }, { vm, emit }) => { const api = {} + // 初始化 gridData,支持 { data: [], columns: [] } 格式 + const initGridData = () => { + if (props.gridOp) { + if (props.gridOp.data) { + return props.gridOp.data + } else if (Array.isArray(props.gridOp)) { + return props.gridOp + } else { + return props.gridOp + } + } + return { data: [], columns: [] } + } + const state = reactive({ value: props.modelValue, - gridData: props.gridOp.data, + gridData: initGridData(), remoteData: [], - selected: props.multiple ? [] : {} + selected: props.multiple ? [] : {}, + currentKey: props.multiple ? '' : props.modelValue, + previousQuery: null, + modelValue: props.multiple ? (Array.isArray(props.modelValue) ? [...props.modelValue] : []) : props.modelValue, + isMounted: false }) Object.assign(api, { @@ -17,15 +62,78 @@ export const renderless = (props, { reactive, watch }, { vm, emit }) => { buildRadioConfig: buildRadioConfig({ props, state }), buildSelectConfig: buildSelectConfig({ props, state }), filter: filter({ props, state, vm }), - radioChange: radioChange({ props, vm, emit }), - selectChange: selectChange({ props, vm, emit }) + getcheckedData: getcheckedData({ props, state }), + getPluginOption: getPluginOption({ api, props, state }), + initQuery: initQuery({ props, state, vm }), + mounted: mounted({ api, state, props, vm, nextTick }), + radioChange: radioChange({ props, vm, emit, state }), + selectChange: selectChange({ props, vm, emit, state, nextTick }), + syncGridSelection: syncGridSelection({ props, vm, state, nextTick }), + handleVisibleChange: handleVisibleChange({ api, state }), + watchValue: watchValue({ api, props, vm, state }) }) + // 计算属性:获取已选中的行 value 数组(需要在 api 对象创建之后) + state.gridCheckedData = computed(() => api.getcheckedData()) + + watch( + () => props.gridOp, + (gridOp) => { + if (gridOp) { + if (gridOp.data) { + // 格式:{ data: [], columns: [] } + state.gridData = gridOp.data + } else if (Array.isArray(gridOp)) { + // 格式:直接是数组 + state.gridData = gridOp + } else { + // 格式:{ data: [], columns: [] } 整体作为 gridData + state.gridData = gridOp + } + } + }, + { immediate: true, deep: true } + ) + watch( - () => props.gridOp.data, - (data) => data && (state.gridData = data), + () => props.modelValue, + () => { + if (props.multiple && Array.isArray(props.modelValue)) { + state.modelValue = [...props.modelValue] + } else { + state.modelValue = props.modelValue + } + }, { immediate: true, deep: true } ) + watch( + () => state.modelValue, + (newValue, oldValue) => { + // 只有在组件挂载后才执行 watchValue,避免初始化时的错误 + if (state.isMounted) { + api.watchValue(newValue, oldValue) + } + } + ) + + watch( + () => props.extraQueryParams, + () => { + if (props.remote) { + api.filter(state.previousQuery || '') + } + }, + { deep: true } + ) + + // 监听面板打开,同步表格选中状态(通过事件处理) + // 注意:这里不直接 watch visible,而是通过 visible-change 事件处理 + + onMounted(() => { + api.mounted() + state.isMounted = true + }) + return api } diff --git a/packages/vue/src/grid-select/src/pc.vue b/packages/vue/src/grid-select/src/pc.vue index e3ab4d56fa..71ab982757 100644 --- a/packages/vue/src/grid-select/src/pc.vue +++ b/packages/vue/src/grid-select/src/pc.vue @@ -2,10 +2,30 @@