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 12, 2024
1 parent 691e05d commit dbc25b9
Show file tree
Hide file tree
Showing 142 changed files with 1,443 additions and 802 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
1 change: 1 addition & 0 deletions dbm-ui/frontend/src/common/const/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './accountTypes';
export * from './clusterAffinity';
export * from './clusterInsStatus';
export * from './clusterTypeInfos';
export * from './clusterTypes';
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,8 +11,8 @@
* the specific language governing permissions and limitations under the License.
*/

import { Table } from 'bkui-vue';
import type { App } from 'vue';
import { VxeTooltip } from 'vxe-pc-ui';

import AuthButton from '@components/auth-component/button.vue';
import AuthTemplate from '@components/auth-component/component.vue';
Expand All @@ -39,6 +39,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 +66,14 @@ 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);
app.component('VxeTooltip', VxeTooltip);
});
};
257 changes: 257 additions & 0 deletions dbm-ui/frontend/src/common/table/BkTable.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
<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">
<VxeColgroup
v-if="columnItem.children"
:title="columnItem.label">
<template
v-for="(columnChildrenItem, childrenIndex) in columnItem.children"
:key="childrenIndex">
<BkTableColumn v-bind="columnChildrenItem" />
</template>
</VxeColgroup>
<BkTableColumn
v-else
v-bind="columnItem" />
</template>
<VxeColumn
fixed="right"
:min-width="60"
:resizable="false"
:width="60">
<template #header>
<SettingColumn :get-table="getTable" />
</template>
</VxeColumn>
<!-- @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 class="bk-vxe-table-pagination-wrapper">
<Pagination
v-bind="paginationConfig"
@change="handlePaginationChange"
@limit-change="handlePaginationLimitChange" />
</div>
</div>
</template>
<script setup lang="ts" generic="T extends Record<any, any>">
import { Pagination } from 'bkui-vue';
import { computed, reactive, useAttrs, useTemplateRef, type VNode } from 'vue';
import {
VxeColgroup,
VxeColumn,
type VxeGridProps,
type VxeGridPropTypes,
VxeTable,
type VxeTableDefines,
} from '@blueking/vxe-table';
import { tableConfig } from './adapter';
import BkTableColumn from './BkTableColumn.vue';
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 {
isRowSelectEnable?: boolean;
data: T[];
pagination?: {
current: number;
count: number;
limit?: number;
limitList?: number[];
showLimit?: boolean;
type?: 'default' | 'compact';
align?: 'left' | 'center' | 'right';
small?: boolean;
};
}
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;
(e: 'page-limit-change', params: number): void;
(e: 'page-value-change', params: number): void;
}
interface Slots {
default?: () => VNode | VNode[];
prepend?: () => VNode;
empty?: () => VNode;
}
const props = withDefaults(defineProps<Props & VxeGridProps<T>>(), {
pagination: 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>();
defineOptions({
name: 'BkVxeTable',
});
const attrs = useAttrs();
const tableRef = useTemplateRef('table');
const paginationConfig = reactive({
layout: ['total', 'limit', 'list'],
location: 'left',
count: 10,
align: 'left',
modelValue: 1,
});
const realProps = computed(() =>
tableConfig({
...props,
...attrs,
}),
);
const getTable = () => tableRef.value;
watch(
() => props.pagination,
() => {
if (!props.pagination) {
return;
}
Object.assign(paginationConfig, {
...props.pagination,
modelValue: props.pagination.current,
});
},
{
immediate: true,
deep: true,
},
);
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);
};
const handlePaginationChange = (value: number) => {
emits('page-value-change', value);
};
const handlePaginationLimitChange = (value: number) => {
emits('page-limit-change', value);
};
</script>
<style lang="less">
@import './style/vxe-table-path.less';
.bk-vxe-table-pagination-wrapper {
padding: 14px 16px;
background: #fff;
border: 1px solid #e8eaec;
border-top: none;
.bk-pagination-limit {
margin-right: auto;
}
}
</style>
68 changes: 68 additions & 0 deletions dbm-ui/frontend/src/common/table/BkTableColumn.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<template>
<Column v-bind="realProps">
<template
v-if="realProps.slots.header"
#header>
<RenderHead :column="realProps" />
</template>
<template
v-else-if="slots.header"
#header>
<slot name="header" />
</template>
<template
v-if="realProps.slots.default"
#default="payload">
<RenderCell
:column="realProps"
:params="payload" />
</template>
<template
v-else-if="slots.default"
#default="payload">
<slot
v-bind="{
...payload,
index: payload.columnIndex,
cell: payload.column.field ? payload.row[payload.column.field] : '',
data: payload.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';
import RenderCell from './components/RenderCell';
import RenderHead from './components/RenderHead';
interface Slot {
header?: () => VNode;
default?: (params: { row: any }) => VNode;
}
const props = withDefaults(defineProps<VxeGridPropTypes.Column>(), {
// 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>
Loading

0 comments on commit dbc25b9

Please sign in to comment.