Commit 551fe50a44d0b6358cf3861f772ca223ea56f0e2

Authored by Vben
1 parent 745fcfc0

perf(table): the table fills the height according to the screen close #310

CHANGELOG.zh_CN.md
... ... @@ -9,6 +9,8 @@
9 9  
10 10 - 表格关闭分页时不再携带分页参数
11 11 - 登录页监听回车事件进行登录
  12 +- 当表格设置自适应大小时,根据屏幕来铺满了高度.
  13 +- Tree 滚动条优化
12 14  
13 15 ### 🐛 Bug Fixes
14 16  
... ...
package.json
... ... @@ -109,7 +109,7 @@
109 109 "vite-plugin-mock": "^2.2.0",
110 110 "vite-plugin-purge-icons": "^0.7.0",
111 111 "vite-plugin-pwa": "^0.5.6",
112   - "vite-plugin-style-import": "^0.7.6",
  112 + "vite-plugin-style-import": "^0.8.1",
113 113 "vite-plugin-svg-icons": "^0.2.1",
114 114 "vite-plugin-theme": "^0.4.8",
115 115 "vite-plugin-windicss": "0.6.10",
... ...
src/components/Page/src/PageWrapper.vue
1 1 <template>
2 2 <div :class="getClass">
3   - <PageHeader :ghost="ghost" v-bind="$attrs" ref="headerRef">
  3 + <PageHeader
  4 + :ghost="ghost"
  5 + v-bind="$attrs"
  6 + ref="headerRef"
  7 + v-if="content || $slots.headerContent"
  8 + >
4 9 <template #default>
5 10 <template v-if="content">
6 11 {{ content }}
... ... @@ -11,7 +16,11 @@
11 16 <slot :name="item" v-bind="data"></slot>
12 17 </template>
13 18 </PageHeader>
14   - <div :class="[`${prefixCls}-content`, $attrs.contentClass]" :style="getContentStyle">
  19 + <div
  20 + class="m-4 overflow-hidden"
  21 + :class="[`${prefixCls}-content`, contentClass]"
  22 + :style="getContentStyle"
  23 + >
15 24 <slot></slot>
16 25 </div>
17 26 <PageFooter v-if="getShowFooter" ref="footerRef">
... ... @@ -48,6 +57,8 @@
48 57 },
49 58 contentBackground: propTypes.bool,
50 59 contentFullHeight: propTypes.bool,
  60 + contentClass: propTypes.string,
  61 + fixedHeight: propTypes.bool,
51 62 },
52 63 setup(props, { slots }) {
53 64 const headerRef = ref<ComponentRef>(null);
... ... @@ -73,15 +84,17 @@
73 84  
74 85 const getContentStyle = computed(
75 86 (): CSSProperties => {
76   - const { contentBackground, contentFullHeight, contentStyle } = props;
  87 + const { contentBackground, contentFullHeight, contentStyle, fixedHeight } = props;
77 88 const bg = contentBackground ? { backgroundColor: '#fff' } : {};
78 89 if (!contentFullHeight) {
79 90 return { ...bg, ...contentStyle };
80 91 }
  92 + const height = `${unref(pageHeight)}px`;
81 93 return {
82 94 ...bg,
83 95 ...contentStyle,
84   - minHeight: `${unref(pageHeight)}px`,
  96 + minHeight: height,
  97 + ...(fixedHeight ? { height } : {}),
85 98 paddingBottom: `${unref(footerHeight)}px`,
86 99 };
87 100 }
... ... @@ -137,18 +150,11 @@
137 150 position: relative;
138 151  
139 152 .ant-page-header {
140   - // padding: 12px 16px;
141   -
142 153 &:empty {
143 154 padding: 0;
144 155 }
145 156 }
146 157  
147   - &-content {
148   - // padding: 12px;
149   - margin: 16px;
150   - }
151   -
152 158 &--dense {
153 159 .@{prefix-cls}-content {
154 160 margin: 0;
... ...
src/components/Table/src/BasicTable.vue
... ... @@ -3,6 +3,7 @@
3 3 ref="wrapRef"
4 4 :class="[
5 5 prefixCls,
  6 + $attrs.class,
6 7 {
7 8 [`${prefixCls}-form-container`]: getBindValues.useSearchForm,
8 9 [`${prefixCls}--inset`]: getBindValues.inset,
... ... @@ -211,6 +212,8 @@
211 212 propsData = omit(propsData, 'scroll');
212 213 }
213 214  
  215 + propsData = omit(propsData, 'class');
  216 +
214 217 return propsData;
215 218 });
216 219  
... ...
src/components/Table/src/hooks/useTableScroll.ts
... ... @@ -55,6 +55,7 @@ export function useTableScroll(
55 55 // No need to repeat queries
56 56 let paginationEl: HTMLElement | null;
57 57 let footerEl: HTMLElement | null;
  58 + let bodyEl: HTMLElement | null;
58 59  
59 60 async function calcTableHeight() {
60 61 const { resizeHeightOffset, pagination, maxHeight } = unref(propsRef);
... ... @@ -68,6 +69,7 @@ export function useTableScroll(
68 69 if (!tableEl) return;
69 70  
70 71 const headEl = tableEl.querySelector('.ant-table-thead ');
  72 +
71 73 if (!headEl) return;
72 74  
73 75 // Table height from bottom
... ... @@ -117,6 +119,11 @@ export function useTableScroll(
117 119  
118 120 height = (height > maxHeight! ? (maxHeight as number) : height) ?? height;
119 121 setHeight(height);
  122 +
  123 + if (!bodyEl) {
  124 + bodyEl = tableEl.querySelector('.ant-table-body');
  125 + }
  126 + bodyEl!.style.height = `${height}px`;
120 127 }
121 128  
122 129 useWindowSizeFn(calcTableHeight, 200);
... ...
src/components/Table/src/style/index.less
... ... @@ -4,12 +4,11 @@
4 4  
5 5 .@{prefix-cls} {
6 6 &-form-container {
7   - width: 100%;
8 7 padding: 16px;
9 8  
10 9 .ant-form {
11   - padding: 16px 16px 6px 12px;
12   - margin-bottom: 18px;
  10 + padding: 12px 10px 6px 10px;
  11 + margin-bottom: 16px;
13 12 background: #fff;
14 13 border-radius: 4px;
15 14 }
... ... @@ -74,40 +73,6 @@
74 73 }
75 74 }
76 75  
77   - // .ant-table-bordered .ant-table-header > table,
78   - // .ant-table-bordered .ant-table-body > table,
79   - // .ant-table-bordered .ant-table-fixed-left table,
80   - // .ant-table-bordered .ant-table-fixed-right table {
81   - // border: 1px solid @border-color !important;
82   - // }
83   -
84   - // .ant-table-thead {
85   - // tr {
86   - // border: none;
87   - // }
88   -
89   - // th {
90   - // border: none;
91   - // }
92   - // }
93   -
94   - // .ant-table-bordered .ant-table-tbody > tr > td {
95   - // border-bottom: 1px solid @border-color !important;
96   -
97   - // &:last-child {
98   - // border-right: none !important;
99   - // }
100   - // }
101   -
102   - // .ant-table.ant-table-bordered .ant-table-footer,
103   - // .ant-table.ant-table-bordered .ant-table-title {
104   - // border: 1px solid @border-color !important;
105   - // }
106   -
107   - // .ant-table-bordered.ant-table-empty .ant-table-placeholder {
108   - // border: 1px solid @border-color !important;
109   - // }
110   -
111 76 .ant-table-tbody > tr > td,
112 77 .ant-table-tbody > tr > th,
113 78 .ant-table-thead > tr > td,
... ... @@ -115,62 +80,10 @@
115 80 white-space: pre;
116 81 }
117 82  
118   - // .ant-table-row-cell-last {
119   - // border-right: none !important;
120   - // }
121   -
122   - // .ant-table-bordered .ant-table-thead > tr > th,
123   - // .ant-table-bordered .ant-table-tbody > tr > td {
124   - // border-right: 1px solid @border-color !important;
125   - // }
126   -
127 83 .ant-pagination {
128 84 margin: 10px 0 0 0;
129 85 }
130 86  
131   - // .ant-table-body {
132   - // overflow-x: auto !important;
133   - // overflow-y: scroll !important;
134   - // }
135   -
136   - // .ant-table-header {
137   - // margin-bottom: 0 !important;
138   - // overflow-x: hidden !important;
139   - // overflow-y: scroll !important;
140   - // }
141   -
142   - // .ant-table-fixed-right {
143   - // right: -1px;
144   -
145   - // .ant-table-header {
146   - // border-left: 1px solid @border-color !important;
147   -
148   - // .ant-table-fixed {
149   - // border-bottom: none;
150   -
151   - // .ant-table-thead th {
152   - // background: rgb(241, 243, 244);
153   - // }
154   - // }
155   - // }
156   - // }
157   -
158   - // .ant-table-fixed-left {
159   - // .ant-table-header {
160   - // overflow-y: hidden !important;
161   - // }
162   -
163   - // .ant-table-fixed {
164   - // border-bottom: none;
165   - // }
166   - // }
167   -
168   - // .ant-table-bordered .ant-table-thead > tr:not(:last-child) > th,
169   - // .ant-table-tbody > tr > td {
170   - // word-break: break-word;
171   - // // border-color: @border-color !important;
172   - // }
173   -
174 87 .ant-table-footer {
175 88 padding: 0;
176 89  
... ...
src/components/Tree/src/index.vue
1 1 <script lang="tsx">
2 2 import type { ReplaceFields, Keys, CheckKeys, TreeActionType, TreeItem } from './types';
3 3  
4   - import { defineComponent, reactive, computed, unref, ref, watchEffect, toRaw, watch } from 'vue';
5   - import { Tree } from 'ant-design-vue';
  4 + import {
  5 + defineComponent,
  6 + reactive,
  7 + computed,
  8 + unref,
  9 + ref,
  10 + watchEffect,
  11 + toRaw,
  12 + watch,
  13 + CSSProperties,
  14 + } from 'vue';
  15 + import { Tree, Empty } from 'ant-design-vue';
6 16 import { TreeIcon } from './TreeIcon';
7 17 import TreeHeader from './TreeHeader.vue';
  18 + import { ScrollContainer } from '/@/components/Container';
8 19 // import { DownOutlined } from '@ant-design/icons-vue';
9 20  
10 21 import { omit, get } from 'lodash-es';
... ... @@ -95,6 +106,11 @@
95 106 emit('update:value', rawVal);
96 107 },
97 108 onRightClick: handleRightClick,
  109 + // onSelect: (k, e) => {
  110 + // setTimeout(() => {
  111 + // emit('select', k, e);
  112 + // }, 16);
  113 + // },
98 114 };
99 115 propsData = omit(propsData, 'treeData', 'class');
100 116 return propsData;
... ... @@ -104,6 +120,10 @@
104 120 searchState.startSearch ? searchState.searchData : unref(treeDataRef)
105 121 );
106 122  
  123 + const getNotFound = computed((): boolean => {
  124 + return searchState.startSearch && searchState.searchData?.length === 0;
  125 + });
  126 +
107 127 const {
108 128 deleteNodeByKey,
109 129 insertNodeByKey,
... ... @@ -178,10 +198,10 @@
178 198 return;
179 199 }
180 200 searchState.startSearch = true;
  201 + const { title: titleField } = unref(getReplaceFields);
181 202  
182 203 searchState.searchData = filter(unref(treeDataRef), (node) => {
183   - const { title } = node;
184   - return title?.includes(searchValue) ?? false;
  204 + return node[titleField]?.includes(searchValue) ?? false;
185 205 });
186 206 }
187 207  
... ... @@ -284,7 +304,7 @@
284 304 title: () => (
285 305 <span
286 306 class={`${prefixCls}-title pl-2`}
287   - onClick={handleClickNode.bind(null, item.key, children)}
  307 + onClick={handleClickNode.bind(null, item[keyField], item[childrenField])}
288 308 >
289 309 {icon && <TreeIcon icon={icon} />}
290 310 <span
... ... @@ -304,9 +324,11 @@
304 324 }
305 325 return () => {
306 326 const { title, helpMessage, toolbar, search } = props;
  327 + const showTitle = title || toolbar || search;
  328 + const scrollStyle: CSSProperties = { height: 'calc(100% - 38px)' };
307 329 return (
308 330 <div class={[prefixCls, 'h-full bg-white', attrs.class]}>
309   - {(title || toolbar || search) && (
  331 + {showTitle && (
310 332 <TreeHeader
311 333 checkAll={checkAll}
312 334 expandAll={expandAll}
... ... @@ -318,13 +340,17 @@
318 340 onSearch={handleSearch}
319 341 />
320 342 )}
321   - <Tree {...unref(getBindValues)} showIcon={false}>
322   - {{
323   - // switcherIcon: () => <DownOutlined />,
324   - default: () => renderTreeNode({ data: unref(getTreeData), level: 1 }),
325   - ...extendSlots(slots),
326   - }}
327   - </Tree>
  343 + <ScrollContainer style={scrollStyle} v-show={!unref(getNotFound)}>
  344 + <Tree {...unref(getBindValues)} showIcon={false}>
  345 + {{
  346 + // switcherIcon: () => <DownOutlined />,
  347 + default: () => renderTreeNode({ data: unref(getTreeData), level: 1 }),
  348 + ...extendSlots(slots),
  349 + }}
  350 + </Tree>
  351 + </ScrollContainer>
  352 +
  353 + <Empty v-show={unref(getNotFound)} class="!mt-4" />
328 354 </div>
329 355 );
330 356 };
... ...
src/views/demo/system/account/DeptTree.vue 0 → 100644
  1 +<template>
  2 + <div class="bg-white m-4 mr-0 overflow-hidden">
  3 + <BasicTree
  4 + title="部门列表"
  5 + toolbar
  6 + search
  7 + :clickRowToExpand="false"
  8 + :treeData="treeData"
  9 + :replaceFields="{ key: 'id', title: 'deptName' }"
  10 + @select="handleSelect"
  11 + />
  12 + </div>
  13 +</template>
  14 +<script lang="ts">
  15 + import { defineComponent, onMounted, ref } from 'vue';
  16 +
  17 + import { BasicTree, TreeItem } from '/@/components/Tree';
  18 + import { getDeptList } from '/@/api/demo/system';
  19 +
  20 + export default defineComponent({
  21 + name: 'DeptTree',
  22 + components: { BasicTree },
  23 +
  24 + emits: ['select'],
  25 + setup(_, { emit }) {
  26 + const treeData = ref<TreeItem[]>([]);
  27 +
  28 + async function fetch() {
  29 + treeData.value = ((await getDeptList()) as unknown) as TreeItem[];
  30 + }
  31 +
  32 + function handleSelect(keys: string, e) {
  33 + emit('select', keys[0]);
  34 + console.log(keys, e);
  35 + }
  36 +
  37 + onMounted(() => {
  38 + fetch();
  39 + });
  40 + return { treeData, handleSelect };
  41 + },
  42 + });
  43 +</script>
... ...
src/views/demo/system/account/index.vue
1 1 <template>
2   - <div :class="[prefixCls]">
3   - <BasicTable @register="registerTable">
  2 + <PageWrapper dense contentFullHeight fixedHeight contentClass="flex">
  3 + <DeptTree class="w-1/4 xl:w-1/5" @select="handleSelect" />
  4 + <BasicTable @register="registerTable" class="w-3/4 xl:w-4/5">
4 5 <template #toolbar>
5 6 <a-button type="primary" @click="handleCreate"> 新增账号 </a-button>
6 7 </template>
... ... @@ -24,14 +25,15 @@
24 25 </template>
25 26 </BasicTable>
26 27 <AccountModal @register="registerModal" @success="handleSuccess" />
27   - </div>
  28 + </PageWrapper>
28 29 </template>
29 30 <script lang="ts">
30 31 import { defineComponent } from 'vue';
31 32  
32   - import { useDesign } from '/@/hooks/web/useDesign';
33 33 import { BasicTable, useTable, TableAction } from '/@/components/Table';
34 34 import { getAccountList } from '/@/api/demo/system';
  35 + import { PageWrapper } from '/@/components/Page';
  36 + import DeptTree from './DeptTree.vue';
35 37  
36 38 import { useModal } from '/@/components/Modal';
37 39 import AccountModal from './AccountModal.vue';
... ... @@ -40,10 +42,8 @@
40 42  
41 43 export default defineComponent({
42 44 name: 'AccountManagement',
43   - components: { BasicTable, AccountModal, TableAction },
  45 + components: { BasicTable, PageWrapper, DeptTree, AccountModal, TableAction },
44 46 setup() {
45   - const { prefixCls } = useDesign('account-management');
46   -
47 47 const [registerModal, { openModal }] = useModal();
48 48 const [registerTable, { reload }] = useTable({
49 49 title: '账号列表',
... ... @@ -86,22 +86,19 @@
86 86 reload();
87 87 }
88 88  
  89 + function handleSelect(deptId: string = '') {
  90 + reload({ searchInfo: { deptId } });
  91 + }
  92 +
89 93 return {
90   - prefixCls,
91 94 registerTable,
92 95 registerModal,
93 96 handleCreate,
94 97 handleEdit,
95 98 handleDelete,
96 99 handleSuccess,
  100 + handleSelect,
97 101 };
98 102 },
99 103 });
100 104 </script>
101   -<style lang="less" scoped>
102   - @prefix-cls: ~'@{namespace}-account-management';
103   -
104   - .@{prefix-cls} {
105   - display: flex;
106   - }
107   -</style>
... ...
yarn.lock
... ... @@ -3662,10 +3662,10 @@ es-module-lexer@^0.3.26:
3662 3662 resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.3.26.tgz#7b507044e97d5b03b01d4392c74ffeb9c177a83b"
3663 3663 integrity sha512-Va0Q/xqtrss45hWzP8CZJwzGSZJjDM5/MJRE3IXXnUCcVLElR9BRaE9F62BopysASyc4nM3uwhSW7FFB9nlWAA==
3664 3664  
3665   -es-module-lexer@^0.4.0:
3666   - version "0.4.0"
3667   - resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.0.tgz#21f4181cc8b7eee06855f1c59e6087c7bc4f77b0"
3668   - integrity sha512-iuEGihqqhKWFgh72Q/Jtch7V2t/ft8w8IPP2aEN8ArYKO+IWyo6hsi96hCdgyeEDQIV3InhYQ9BlwUFPGXrbEQ==
  3665 +es-module-lexer@^0.4.1:
  3666 + version "0.4.1"
  3667 + resolved "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz#dda8c6a14d8f340a24e34331e0fab0cb50438e0e"
  3668 + integrity sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==
3669 3669  
3670 3670 es-to-primitive@^1.2.1:
3671 3671 version "1.2.1"
... ... @@ -9120,15 +9120,15 @@ vite-plugin-pwa@^0.5.6:
9120 9120 pretty-bytes "^5.6.0"
9121 9121 workbox-build "^6.1.1"
9122 9122  
9123   -vite-plugin-style-import@^0.7.6:
9124   - version "0.7.6"
9125   - resolved "https://registry.npmjs.org/vite-plugin-style-import/-/vite-plugin-style-import-0.7.6.tgz#909a5402f3a915fb2512e2a039e9cdb360fd2882"
9126   - integrity sha512-EDjscCzMsmi6mJ0UbMLMkCGLo7LCdFsRJZdjO7sfUIB+2wsC1FjDJcIEGWg0Lzl+4gghv9rk+AP+WCibI83WNw==
  9123 +vite-plugin-style-import@^0.8.1:
  9124 + version "0.8.1"
  9125 + resolved "https://registry.npmjs.org/vite-plugin-style-import/-/vite-plugin-style-import-0.8.1.tgz#e098c633cba3abef9b5a156aaf47f001567ebbb9"
  9126 + integrity sha512-qZg73SA2+tbuEk7b0VjubjceUKVzHB6NwDYd3R9Hd6At4+sJ/85UIlTkzxSWHNgkTQh4sIOMQi1olXjkSF7tjg==
9127 9127 dependencies:
9128 9128 "@rollup/pluginutils" "^4.1.0"
9129 9129 change-case "^4.1.2"
9130 9130 debug "^4.3.2"
9131   - es-module-lexer "^0.4.0"
  9131 + es-module-lexer "^0.4.1"
9132 9132 magic-string "^0.25.7"
9133 9133  
9134 9134 vite-plugin-svg-icons@^0.2.1:
... ...