Skip to content

Commit

Permalink
perf(frontend): table 组件交互优化 TencentBlueKing#7818
Browse files Browse the repository at this point in the history
  • Loading branch information
hLinx committed Nov 7, 2024
1 parent 9abb62f commit 5d634df
Show file tree
Hide file tree
Showing 14 changed files with 788 additions and 2 deletions.
1 change: 1 addition & 0 deletions dbm-ui/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@blueking/login-modal": "^1.0.5",
"@blueking/notice-component": "2.0.5",
"@blueking/sub-saas": "0.0.0-beta.6",
"@blueking/vxe-table": "^4.8.0-beta.7.1",
"@icon-cool/bk-icon-bk-biz-components": "0.0.4",
"@vueuse/core": "^11.0.3",
"axios": "^1.7.7",
Expand Down
16 changes: 14 additions & 2 deletions dbm-ui/frontend/src/common/importComps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
* the specific language governing permissions and limitations under the License.
*/

import { Table } from 'bkui-vue';
import type { App } from 'vue';

import AuthButton from '@components/auth-component/button.vue';
Expand Down Expand Up @@ -39,6 +38,9 @@ import { ipSelector } from '@components/vue2/ip-selector';

import UserSelector from '@patch/user-selector/selector.vue';

import Table from './table/BkTable.vue';
import TableColumn from './table/BkTableColumn.vue';

export const setGlobalComps = (app: App<Element>) => {
app.component('DbCard', DbCard);
app.component('DbForm', DbForm);
Expand All @@ -63,5 +65,15 @@ export const setGlobalComps = (app: App<Element>) => {
app.component('AuthOption', AuthOption);
app.component('AuthSwitcher', AuthSwitch);
app.component('AuthRouterLink', AuthRouterLink);
app.component('BKTableColumn', Table.Column);
setTimeout(() => {
// eslint-disable-next-line
delete app._context.components.BkTable;
// eslint-disable-next-line
delete app._context.components.BkTableColumn;

app.component('BkTable', Table);
app.component('BkTableColumn', TableColumn);

console.dir(app);
});
};
186 changes: 186 additions & 0 deletions dbm-ui/frontend/src/common/table/BkTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<template>
<div class="bk-vxe-table">
<VxeTable
ref="table"
v-bind="realProps"
@filter-change="handleFilterChange"
@sort-change="handleSortChange">
<template v-if="isRowSelectEnable">
<VxeColumn
fixed="left"
:min-width="60"
:resizable="false"
:width="60">
<BkCheckbox />
</VxeColumn>
</template>
<slot />
<template
v-for="(columnItem, index) in columns"
:key="index">
<!-- @vue-ignore -->
<BkTableColumn v-bind="columnItem">
<!-- @vue-ignore -->
<template
v-if="columnItem.renderHead || _.isFunction(columnItem.label)"
#header>
<RenderHead
:column="columnItem"
:index="index" />
</template>
<!-- @vue-ignore -->
<template
v-if="columnItem.render"
#default="params">
<RenderCell
:column="columnItem"
:params="params" />
</template>
</BkTableColumn>
</template>
<!-- @vue-ignore -->
<template
v-if="slots.prepend"
#prepend>
<slot name="prepend" />
</template>
<!-- @vue-ignore -->
<template
v-if="false"
#settingColumn>
<SettingColumn :get-table="getTable" />
</template>
<template
v-if="slots.empty"
#empty>
<slot name="empty" />
</template>
</VxeTable>
</div>
</template>
<script setup lang="ts" generic="T extends Record<any, any>">
import _ from 'lodash';
import { computed, useTemplateRef, type VNode } from 'vue';
import {
VxeColumn,
type VxeGridProps,
type VxeGridPropTypes,
VxeTable,
type VxeTableDefines,
} from '@blueking/vxe-table';
import { tableConfig } from './adapter';
import BkTableColumn from './BkTableColumn.vue';
import RenderCell from './components/RenderCell';
import RenderHead from './components/RenderHead';
import SettingColumn from './components/setting-column/Index.vue';
import '@blueking/vxe-table/lib/style.css';
import 'vxe-pc-ui/lib/style.css';
/* eslint-disable vue/no-unused-properties */
interface Props {
rowClass?: (params: any) => string;
isRowSelectEnable?: boolean;
data: T[];
}
interface Emits {
(e: 'column-sort', params: { column: VxeGridPropTypes.Column; field: string; type: string | null }): void;
(e: 'sort-change', params: VxeTableDefines.SortChangeEventParams): void;
(e: 'column-filter', params: { column: VxeGridPropTypes.Column; field: string; checked: string[] }): void;
(e: 'filter-change', params: VxeTableDefines.FilterChangeEventParams): void;
}
interface Slots {
default?: () => VNode | VNode[];
prepend?: () => VNode;
empty?: () => VNode;
}
const props = withDefaults(defineProps<Props & VxeGridProps<T>>(), {
rowClass: undefined,
isRowSelectEnable: false,
align: 'left',
animat: true,
autoResize: true,
border: false,
columnKey: false,
columnConfig: () => ({
useKey: true,
isHover: true,
resizable: true,
width: undefined,
minWidth: 'auto',
}),
delayHover: 250,
emptyText: undefined,
filterConfig: () => ({
remote: true,
confirmButtonText: '确认',
resetButtonText: '重置',
}),
fit: true,
footerAlign: undefined,
headerAlign: 'left',
highlightCurrentColumn: undefined,
highlightCurrentRow: undefined,
highlightHoverColumn: undefined,
highlightHoverRow: undefined,
keepSource: undefined,
minHeight: undefined,
padding: true,
round: false,
rowConfig: () => ({
isHover: true,
}),
rowId: undefined,
showFooterOverflow: true,
showHeader: true,
showHeaderOverflow: true,
showOverflow: 'tooltip',
size: 'small',
sortConfig: () => ({
remote: true,
}),
stripe: false,
});
const emits = defineEmits<Emits>();
const slots = defineSlots<Slots>();
const tableRef = useTemplateRef('table');
const realProps = computed(() => tableConfig(props));
const getTable = () => tableRef.value;
const handleSortChange = (payload: VxeTableDefines.SortChangeEventParams) => {
emits('column-sort', {
column: payload.column,
field: payload.field,
type: payload.order,
});
emits('sort-change', payload);
};
const handleFilterChange = (payload: VxeTableDefines.FilterChangeEventParams) => {
emits('column-filter', {
column: Object.assign({}, payload.column, {
filter: {
list: payload.column.filters.map((item) => ({
text: item.label,
value: item.value,
})),
},
}),
field: payload.field,
checked: payload.values,
});
emits('filter-change', payload);
};
</script>
<style lang="less">
@import './style/vxe-table-path.less';
</style>
63 changes: 63 additions & 0 deletions dbm-ui/frontend/src/common/table/BkTableColumn.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<template>
<Column v-bind="realProps">
<template
v-if="slots.header"
#header>
<slot name="header" />
</template>
<template
v-if="slots.default"
#default="{ row }">
<slot v-bind="{ row }" />
</template>
</Column>
</template>
<script setup lang="ts">
import { computed, useAttrs, type VNode } from 'vue';
import { Column, type VxeGridPropTypes } from '@blueking/vxe-table';
import { columnConfig } from './adapter';
/* eslint-disable vue/no-unused-properties */
interface Props {
// label?: string | (() => any);
// sort?: boolean;
// filter?: any;
// textAlign?: string;
// align?: string;
}
interface Slot {
header?: () => VNode;
default?: (params: { row: any }) => VNode;
}
const props = withDefaults(defineProps<Props & VxeGridPropTypes.Column>(), {
// 兼容 BkTableColumn prop
sort: false,
filter: false,
textAlign: undefined,
label: undefined,
align: undefined,
// VxeColumn prop
visible: true,
resizable: true,
minWidth: 'auto',
showHeaderOverflow: 'tooltip',
showOverflow: 'tooltip',
width: undefined,
fit: true,
});
const slots = defineSlots<Slot>();
const attrs = useAttrs();
const realProps = computed(() =>
columnConfig({
...attrs,
...props,
}),
);
</script>
105 changes: 105 additions & 0 deletions dbm-ui/frontend/src/common/table/adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import _ from 'lodash';

import { makeMap } from './utils';

export const columnConfig = (bkColumnConfig: any) => {
const vxeColumnConfig = {
...bkColumnConfig,
slots: {},
};

if (bkColumnConfig.label) {
if (_.isString(bkColumnConfig.label)) {
vxeColumnConfig.title = bkColumnConfig.label;
} else if (_.isFunction(bkColumnConfig.label)) {
const renderLabel = bkColumnConfig.label;
Object.assign(vxeColumnConfig.slots, {
header: (payload: any) => {
const res = renderLabel({
column: payload.column,
index: payload.$rowIndex,
});

return res;
},
});
}
delete vxeColumnConfig.label;
}

if (_.has(bkColumnConfig, 'sort')) {
vxeColumnConfig.sortable = bkColumnConfig.sort;
delete vxeColumnConfig.sort;
}

if (bkColumnConfig.filter && bkColumnConfig.filter.list) {
const checkedMap = makeMap(bkColumnConfig.filter.checked || []);
vxeColumnConfig.filters = bkColumnConfig.filter.list.map((item: any) => ({
label: item.text,
value: item.value,
checked: Boolean(checkedMap[item.value]),
}));
vxeColumnConfig.filterMultiple = true;
delete vxeColumnConfig.filter;
}

if (bkColumnConfig.render) {
const cellRender = bkColumnConfig.render;
Object.assign(vxeColumnConfig.slots, {
default: (payload: any) =>
cellRender({
cell: payload.row[payload.column.field],
data: payload.row,
column: payload.column,
index: payload.$rowIndex,
rows: payload.data,
}),
});
delete vxeColumnConfig.render;
}

if (bkColumnConfig.renderHead) {
const headRender = bkColumnConfig.renderHead;
Object.assign(vxeColumnConfig.slots, {
header: (payload: any) =>
headRender({
column: payload.column,
index: payload.$rowIndex,
}),
});
delete vxeColumnConfig.renderHead;
}

delete vxeColumnConfig.label;
delete vxeColumnConfig.sort;
delete vxeColumnConfig.textAlign;

// 废弃属性
delete vxeColumnConfig.children;
delete vxeColumnConfig.titleHelp;

return vxeColumnConfig;
};

export const tableConfig = (bkTableConfig: any) => {
const bkTableConfigMemo = _.cloneDeep(bkTableConfig);
const vxeTableConfig = {
...bkTableConfig,
};

if (bkTableConfigMemo.columns) {
delete vxeTableConfig.columns;
}
if (bkTableConfigMemo.rowClass) {
if (typeof bkTableConfigMemo.rowClass === 'string') {
vxeTableConfig.rowClassName = bkTableConfigMemo.rowClas;
} else if (typeof bkTableConfigMemo.rowClass === 'function') {
const { rowClass } = bkTableConfigMemo;

vxeTableConfig.rowClassName = ({ row }: { row: any }) => rowClass(row);
}
delete vxeTableConfig.rowClass;
}

return vxeTableConfig;
};
Loading

0 comments on commit 5d634df

Please sign in to comment.