feat(demo->BasicTable): add TableSelectionBar and enable checkbox rowSelection demo (#3477)
* feat: add TableSelectionBar * feat: enable TableSelectionBar for checkbox rowSelection demo
This commit is contained in:
parent
00b8d169cb
commit
816553bfcd
|
|
@ -53,7 +53,7 @@
|
|||
import { BasicForm, useForm } from '@/components/Form';
|
||||
import { PageWrapperFixedHeightKey } from '@/enums/pageEnum';
|
||||
import HeaderCell from './components/HeaderCell.vue';
|
||||
import { InnerHandlers } from './types/table';
|
||||
import { InnerHandlers, InnerMethods } from './types/table';
|
||||
import { usePagination } from './hooks/usePagination';
|
||||
import { useColumns } from './hooks/useColumns';
|
||||
import { useDataSource } from './hooks/useDataSource';
|
||||
|
|
@ -221,7 +221,12 @@
|
|||
},
|
||||
};
|
||||
|
||||
const { getHeaderProps } = useTableHeader(getProps, slots, handlers);
|
||||
const methods: InnerMethods = {
|
||||
clearSelectedRowKeys,
|
||||
getSelectRowKeys,
|
||||
};
|
||||
|
||||
const { getHeaderProps } = useTableHeader(getProps, slots, handlers, methods);
|
||||
|
||||
const { getFooterProps } = useTableFooter(getProps, getScrollRef, tableElRef, getDataSourceRef);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@
|
|||
<div v-if="$slots.headerTop" style="margin: 5px">
|
||||
<slot name="headerTop"></slot>
|
||||
</div>
|
||||
<div v-if="showSelectionBar" style="margin: 5px">
|
||||
<TableSelectionBar :clearSelectedRowKeys="props.clearSelectedRowKeys!" :count="props.count" />
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<slot name="tableTitle" v-if="$slots.tableTitle"></slot>
|
||||
<TableTitle
|
||||
|
|
@ -23,16 +26,17 @@
|
|||
</div>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import type { TableSetting, ColumnChangeParam } from '../types/table';
|
||||
import type { TableSetting, ColumnChangeParam, TableActionType } from '../types/table';
|
||||
import type { PropType } from 'vue';
|
||||
import { Divider } from 'ant-design-vue';
|
||||
import TableSettingComponent from './settings/index.vue';
|
||||
import TableTitle from './TableTitle.vue';
|
||||
import { useDesign } from '@/hooks/web/useDesign';
|
||||
import TableSelectionBar from '../components/TableSelectionBar.vue';
|
||||
|
||||
defineOptions({ name: 'BasicTableHeader' });
|
||||
|
||||
defineProps({
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: [Function, String] as PropType<string | ((data) => string)>,
|
||||
},
|
||||
|
|
@ -46,6 +50,18 @@
|
|||
type: [String, Array] as PropType<string | string[]>,
|
||||
default: '',
|
||||
},
|
||||
//
|
||||
clearSelectedRowKeys: {
|
||||
type: Function as PropType<TableActionType['clearSelectedRowKeys']>,
|
||||
},
|
||||
count: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
showSelectionBar: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
const emit = defineEmits(['columns-change']);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
<template>
|
||||
<a-alert type="info" showIcon :class="[prefixCls]">
|
||||
<template #message>
|
||||
<span v-if="props.count > 0">
|
||||
{{ t('component.table.selectionBarTips', { count: props.count }) }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ t('component.table.selectionBarEmpty') }}
|
||||
</span>
|
||||
<a-button type="link" @click="clearSelectedRowKeys" size="small" v-show="props.count > 0">
|
||||
{{ t('component.table.selectionBarClear') }}
|
||||
</a-button>
|
||||
</template>
|
||||
</a-alert>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/hooks/web/useI18n';
|
||||
import { useDesign } from '@/hooks/web/useDesign';
|
||||
|
||||
import type { TableActionType } from '../types/table';
|
||||
import { Alert as AAlert } from 'ant-design-vue';
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const { prefixCls } = useDesign('table-select-bar');
|
||||
|
||||
defineOptions({
|
||||
name: 'TableSelectBar',
|
||||
});
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
count?: number;
|
||||
//
|
||||
clearSelectedRowKeys: TableActionType['clearSelectedRowKeys'];
|
||||
}>(),
|
||||
{
|
||||
count: () => 0,
|
||||
},
|
||||
);
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@prefix-cls: ~'@{namespace}-table-select-bar';
|
||||
|
||||
.@{prefix-cls} {
|
||||
flex-grow: 1;
|
||||
padding: 2px 8px;
|
||||
|
||||
:deep(.ant-btn-link) {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -83,7 +83,12 @@ export function useRowSelection(
|
|||
}
|
||||
|
||||
function setSelectedRows(rows: Recordable[]) {
|
||||
const { rowKey } = unref(propsRef);
|
||||
selectedRowRef.value = rows;
|
||||
selectedRowKeysRef.value = selectedRowRef.value.map((o) => {
|
||||
const key = (isFunction(rowKey) ? rowKey(o) : rowKey) || 'key';
|
||||
return o[key];
|
||||
});
|
||||
}
|
||||
|
||||
function clearSelectedRowKeys() {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ComputedRef, Slots } from 'vue';
|
||||
import type { BasicTableProps, InnerHandlers } from '../types/table';
|
||||
import type { BasicTableProps, InnerHandlers, InnerMethods } from '../types/table';
|
||||
import { unref, computed, h } from 'vue';
|
||||
import TableHeader from '../components/TableHeader.vue';
|
||||
import { isString } from '@/utils/is';
|
||||
|
|
@ -9,9 +9,12 @@ export function useTableHeader(
|
|||
propsRef: ComputedRef<BasicTableProps>,
|
||||
slots: Slots,
|
||||
handlers: InnerHandlers,
|
||||
//
|
||||
methods: InnerMethods,
|
||||
) {
|
||||
const getHeaderProps = computed((): Recordable => {
|
||||
const { title, showTableSetting, titleHelpMessage, tableSetting } = unref(propsRef);
|
||||
const { title, showTableSetting, titleHelpMessage, tableSetting, showSelectionBar } =
|
||||
unref(propsRef);
|
||||
const hideTitle = !slots.tableTitle && !title && !slots.toolbar && !showTableSetting;
|
||||
if (hideTitle && !isString(title)) {
|
||||
return {};
|
||||
|
|
@ -29,6 +32,10 @@ export function useTableHeader(
|
|||
showTableSetting,
|
||||
tableSetting,
|
||||
onColumnsChange: handlers.onColumnsChange,
|
||||
//
|
||||
clearSelectedRowKeys: methods.clearSelectedRowKeys,
|
||||
count: methods.getSelectRowKeys().length,
|
||||
showSelectionBar,
|
||||
} as Recordable,
|
||||
{
|
||||
...(slots.toolbar
|
||||
|
|
|
|||
|
|
@ -105,6 +105,7 @@ export const basicProps = {
|
|||
type: Object as PropType<TableRowSelection | null>,
|
||||
default: null,
|
||||
},
|
||||
showSelectionBar: propTypes.bool,
|
||||
title: {
|
||||
type: [String, Function] as PropType<string | ((data: Recordable) => string)>,
|
||||
default: null,
|
||||
|
|
|
|||
|
|
@ -312,6 +312,12 @@ export interface BasicTableProps<T = any> {
|
|||
*/
|
||||
rowSelection?: TableRowSelection;
|
||||
|
||||
/**
|
||||
* Show table selection bar(显示多选状态栏)
|
||||
* @type boolean
|
||||
*/
|
||||
showSelectionBar?: boolean;
|
||||
|
||||
/**
|
||||
* Set horizontal or vertical scrolling, can also be used to specify the width and height of the scroll area.
|
||||
* It is recommended to set a number for x, if you want to set it to true,
|
||||
|
|
@ -489,6 +495,11 @@ export interface InnerHandlers {
|
|||
onColumnsChange: (data: ColumnChangeParam[]) => void;
|
||||
}
|
||||
|
||||
export interface InnerMethods {
|
||||
clearSelectedRowKeys: TableActionType['clearSelectedRowKeys'];
|
||||
getSelectRowKeys: TableActionType['getSelectRowKeys'];
|
||||
}
|
||||
|
||||
export interface ColumnOptionsType {
|
||||
value: string;
|
||||
label: string;
|
||||
|
|
|
|||
|
|
@ -67,7 +67,10 @@
|
|||
"settingFixedRight": "Fixed Right",
|
||||
"settingFullScreen": "Full Screen",
|
||||
"index": "Index",
|
||||
"total": "total of {total}"
|
||||
"total": "total of {total}",
|
||||
"selectionBarTips": "{count} records selected.",
|
||||
"selectionBarClear": "Clear",
|
||||
"selectionBarEmpty": "No records selected."
|
||||
},
|
||||
"time": {
|
||||
"before": " ago",
|
||||
|
|
|
|||
|
|
@ -67,7 +67,10 @@
|
|||
"settingFixedRight": "固定到右侧",
|
||||
"settingFullScreen": "全屏",
|
||||
"index": "序号",
|
||||
"total": "共 {total} 条数据"
|
||||
"total": "共 {total} 条数据",
|
||||
"selectionBarTips": "已选择{count}条记录",
|
||||
"selectionBarClear": "清空",
|
||||
"selectionBarEmpty": "未选中任何记录"
|
||||
},
|
||||
"time": {
|
||||
"before": "前",
|
||||
|
|
|
|||
|
|
@ -137,6 +137,7 @@
|
|||
dataIndex: 'action',
|
||||
// slots: { customRender: 'action' },
|
||||
},
|
||||
showSelectionBar: true, // 显示多选状态栏
|
||||
});
|
||||
function handleEdit(record: Recordable) {
|
||||
console.log('点击了编辑', record);
|
||||
|
|
|
|||
|
|
@ -36,5 +36,6 @@
|
|||
summaryFunc: handleSummary,
|
||||
scroll: { x: 2000 },
|
||||
canResize: false,
|
||||
showSelectionBar: true, // 显示多选状态栏
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,102 +1,18 @@
|
|||
<template>
|
||||
<BasicTable @register="registerTable" @fetch-success="checkedRecordsUpdate">
|
||||
<BasicTable @register="registerTable">
|
||||
<template #form-custom> custom-slot </template>
|
||||
<template #headerTop>
|
||||
<Alert type="info" show-icon>
|
||||
<template #message>
|
||||
<template v-if="checkedRecords.length > 0">
|
||||
<span>已选中{{ checkedRecords.length }}条记录(可跨页)</span>
|
||||
<a-button type="link" @click="tableSelectBarClear" size="small">清空</a-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span>未选中任何项目</span>
|
||||
</template>
|
||||
</template>
|
||||
</Alert>
|
||||
</template>
|
||||
<template #toolbar>
|
||||
<a-button type="primary" @click="getFormValues">获取表单数据</a-button>
|
||||
</template>
|
||||
</BasicTable>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ref, nextTick } from 'vue';
|
||||
import { BasicTable, useTable } from '@/components/Table';
|
||||
import { getBasicColumns, getFormConfig } from './tableData';
|
||||
import { Alert } from 'ant-design-vue';
|
||||
import type { Key } from 'ant-design-vue/lib/table/interface';
|
||||
import type { TableRowSelection } from '@/components/Table/src/types/table';
|
||||
|
||||
import { demoListApi } from '@/api/demo/table';
|
||||
|
||||
const checkedRecords = ref<Key[]>([]);
|
||||
const checkedPageRecords = ref<Key[]>([]);
|
||||
|
||||
const rowSelectionOnChange: TableRowSelection['onChange'] = (selectedRowKeys) => {
|
||||
// 本页新出现的
|
||||
const adds = selectedRowKeys.filter((key) => !checkedPageRecords.value.includes(key));
|
||||
// 本页已消失的
|
||||
const removes = checkedPageRecords.value.filter((key) => !selectedRowKeys.includes(key));
|
||||
|
||||
// 添加/更新到全部
|
||||
for (const k of adds) {
|
||||
const index = checkedRecords.value.findIndex((key) => key === k);
|
||||
if (index > -1) {
|
||||
checkedRecords.value.splice(index, 1, k);
|
||||
} else {
|
||||
checkedRecords.value.push(k);
|
||||
}
|
||||
}
|
||||
|
||||
// 从全部删除
|
||||
for (const k of removes) {
|
||||
const index = checkedRecords.value.findIndex((key) => key === k);
|
||||
if (index > -1) {
|
||||
checkedRecords.value.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新本页记录
|
||||
checkedPageRecords.value = [...selectedRowKeys];
|
||||
};
|
||||
|
||||
// 清空选择
|
||||
const tableSelectBarClear = () => {
|
||||
checkedRecords.value = [];
|
||||
setSelectedRowKeys([]);
|
||||
};
|
||||
|
||||
// 移除记录(如果存在删除记录的操作)
|
||||
// const checkedRecordsRemove = (ids: (string | number)[]) => {
|
||||
// for (const id of ids) {
|
||||
// const index = checkedRecords.value.findIndex((o) => o.id === id);
|
||||
// if (index > -1) {
|
||||
// checkedRecords.value.splice(index, 1);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
const checkedRecordsUpdate = () => {
|
||||
// 当前页数据
|
||||
const dataSourceKeys = getDataSource().map((o) => o.id) as Array<Key>;
|
||||
for (const record of getDataSource()) {
|
||||
const index = checkedRecords.value.findIndex((key) => key === record.id);
|
||||
if (index > -1) {
|
||||
// 如果全部里存在,就更新它
|
||||
checkedRecords.value.splice(index, 1, record.id as Key);
|
||||
}
|
||||
}
|
||||
// 当前页存在全部里的
|
||||
const pageRecords = checkedRecords.value.filter((key) => dataSourceKeys.includes(key));
|
||||
// 刷新
|
||||
checkedPageRecords.value = pageRecords;
|
||||
nextTick(() => {
|
||||
// 选中
|
||||
setSelectedRowKeys(pageRecords);
|
||||
});
|
||||
};
|
||||
|
||||
const [registerTable, { getForm, setSelectedRowKeys, getDataSource }] = useTable({
|
||||
const [registerTable, { getForm }] = useTable({
|
||||
title: '开启搜索区域',
|
||||
api: demoListApi,
|
||||
columns: getBasicColumns(),
|
||||
|
|
@ -108,8 +24,8 @@
|
|||
rowKey: 'id',
|
||||
rowSelection: {
|
||||
type: 'checkbox',
|
||||
onChange: rowSelectionOnChange,
|
||||
},
|
||||
showSelectionBar: true, // 显示多选状态栏
|
||||
});
|
||||
|
||||
function getFormValues() {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
:columns="columns"
|
||||
rowKey="id"
|
||||
:rowSelection="{ type: 'checkbox' }"
|
||||
showSelectionBar
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -60,7 +61,6 @@
|
|||
rowSelection: {
|
||||
type: 'checkbox',
|
||||
},
|
||||
showIndexColumn: true,
|
||||
});
|
||||
}
|
||||
function reloadTable() {
|
||||
|
|
@ -69,7 +69,6 @@
|
|||
rowSelection: {
|
||||
type: 'checkbox',
|
||||
},
|
||||
showIndexColumn: true,
|
||||
});
|
||||
|
||||
getTableAction().reload({
|
||||
|
|
|
|||
|
|
@ -32,5 +32,6 @@
|
|||
columns: getBasicColumns(),
|
||||
dataSource: getTreeTableData(),
|
||||
rowKey: 'id',
|
||||
showSelectionBar: true, // 显示多选状态栏
|
||||
});
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@
|
|||
onColumnsChange: (data: ColumnChangeParam[]) => {
|
||||
console.log('ColumnsChanged', data);
|
||||
},
|
||||
showSelectionBar: true, // 显示多选状态栏
|
||||
});
|
||||
|
||||
function changeLoading() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue