Commit 17b6b5b102accd7ecebe3bada627449d1c698dfb

Authored by ww
1 parent ec57584d

perf: 优化数据看板分页界面

@@ -15,6 +15,8 @@ export interface UpdateDataBoardParams extends AddDataBoardParams { @@ -15,6 +15,8 @@ export interface UpdateDataBoardParams extends AddDataBoardParams {
15 export interface GetDataBoardParams { 15 export interface GetDataBoardParams {
16 page?: number; 16 page?: number;
17 pageSize?: number; 17 pageSize?: number;
  18 + name?: string;
  19 + organizationId?: string;
18 orderFiled?: string; 20 orderFiled?: string;
19 orderType?: string; 21 orderType?: string;
20 } 22 }
@@ -47,7 +49,9 @@ export interface DataBoardRecord { @@ -47,7 +49,9 @@ export interface DataBoardRecord {
47 layout: Layout[]; 49 layout: Layout[];
48 defaultConfig: string; 50 defaultConfig: string;
49 tenantStatus: string; 51 tenantStatus: string;
  52 + componentNum?: number;
50 publicId: string; 53 publicId: string;
  54 + organizationId?: string;
51 accessCredentials?: string; 55 accessCredentials?: string;
52 } 56 }
53 57
@@ -96,7 +96,7 @@ @@ -96,7 +96,7 @@
96 }, 96 },
97 }, 97 },
98 rowKey: unref(getRowKey), 98 rowKey: unref(getRowKey),
99 - }; 99 + } as ListProps;
100 }); 100 });
101 101
102 watch(cardListLayout, () => { 102 watch(cardListLayout, () => {
@@ -122,7 +122,7 @@ @@ -122,7 +122,7 @@
122 122
123 <template> 123 <template>
124 <main class="basic-card-list p-4 flex flex-col w-full h-full"> 124 <main class="basic-card-list p-4 flex flex-col w-full h-full">
125 - <section class="w-full bg-light-50 dark:bg-dark-900 p-4 mb-4"> 125 + <section v-if="getProps.useSearchForm" class="w-full bg-light-50 dark:bg-dark-900 p-4 mb-4">
126 <BasicForm 126 <BasicForm
127 @register="registerForm" 127 @register="registerForm"
128 v-bind="getFormProps" 128 v-bind="getFormProps"
@@ -141,8 +141,10 @@ @@ -141,8 +141,10 @@
141 <template #header> 141 <template #header>
142 <section class="flex justify-between items-center"> 142 <section class="flex justify-between items-center">
143 <div> 143 <div>
144 - <span v-if="title"></span>  
145 - <slot v-else name="name"></slot> 144 + <span v-if="getProps.title" class="font-bold text-base px-4">
  145 + {{ getProps.title }}
  146 + </span>
  147 + <slot v-else name="title"></slot>
146 </div> 148 </div>
147 <div class="flex flex-auto justify-end mr-4"> 149 <div class="flex flex-auto justify-end mr-4">
148 <slot name="toolbar"></slot> 150 <slot name="toolbar"></slot>
@@ -126,7 +126,6 @@ export function useCardListData( @@ -126,7 +126,6 @@ export function useCardListData(
126 ...(useSearchForm ? getFieldsValue() : {}), 126 ...(useSearchForm ? getFieldsValue() : {}),
127 ...searchInfo, 127 ...searchInfo,
128 }; 128 };
129 -  
130 if (beforeFetch && isFunction(beforeFetch)) { 129 if (beforeFetch && isFunction(beforeFetch)) {
131 params = (await beforeFetch(params)) || params; 130 params = (await beforeFetch(params)) || params;
132 } 131 }
1 -import { Ref, computed, reactive, unref } from 'vue'; 1 +import { Ref, computed, reactive, unref, watch } from 'vue';
2 import { BasicCardListPropsType, ListGridType } from '../types'; 2 import { BasicCardListPropsType, ListGridType } from '../types';
3 import { getListGridByColumn } from '../utils'; 3 import { getListGridByColumn } from '../utils';
4 import { screenMap, sizeEnum } from '/@/enums/breakpointEnum'; 4 import { screenMap, sizeEnum } from '/@/enums/breakpointEnum';
@@ -16,6 +16,13 @@ export function useListGrid(getProps: Ref<BasicCardListPropsType>) { @@ -16,6 +16,13 @@ export function useListGrid(getProps: Ref<BasicCardListPropsType>) {
16 } as ListGridType; 16 } as ListGridType;
17 }); 17 });
18 18
  19 + watch(
  20 + () => unref(getProps).baseLayout,
  21 + () => {
  22 + Object.assign(cardListLayout, unref(getProps).baseLayout);
  23 + }
  24 + );
  25 +
19 function getScreenSize() { 26 function getScreenSize() {
20 const width = document.body.clientWidth; 27 const width = document.body.clientWidth;
21 const xs = screenMap.get(sizeEnum.XS)!; 28 const xs = screenMap.get(sizeEnum.XS)!;
@@ -25,6 +25,7 @@ export interface BasicCardListPropsType<T = Recordable> { @@ -25,6 +25,7 @@ export interface BasicCardListPropsType<T = Recordable> {
25 rowKey?: (item: T) => string | number; 25 rowKey?: (item: T) => string | number;
26 immediate?: boolean; 26 immediate?: boolean;
27 handleSearchInfoFn?: Fn; 27 handleSearchInfoFn?: Fn;
  28 + baseLayout?: Record<'row' | 'col', number>;
28 } 29 }
29 30
30 export type ListGridType = Record<'column' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', number> & { 31 export type ListGridType = Record<'column' | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl', number> & {
@@ -11,6 +11,9 @@ export const formSchema: FormSchema[] = [ @@ -11,6 +11,9 @@ export const formSchema: FormSchema[] = [
11 component: 'Input', 11 component: 'Input',
12 // colProps: { span: 10 }, 12 // colProps: { span: 10 },
13 colProps: useGridLayout(2, 3, 4) as unknown as ColEx, 13 colProps: useGridLayout(2, 3, 4) as unknown as ColEx,
  14 + componentProps: {
  15 + placeholder: '请输入看板名称',
  16 + },
14 }, 17 },
15 { 18 {
16 field: 'organizationId', 19 field: 'organizationId',
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { List, Card, Statistic, Button, Tooltip, Spin } from 'ant-design-vue';  
3 - import { onMounted, ref, unref } from 'vue';  
4 - import { PageWrapper } from '/@/components/Page'; 2 + import { Card, Statistic, Button, Tooltip } from 'ant-design-vue';
  3 + import { unref, computed } from 'vue';
5 import { MoreOutlined, ShareAltOutlined } from '@ant-design/icons-vue'; 4 import { MoreOutlined, ShareAltOutlined } from '@ant-design/icons-vue';
6 import { useMessage } from '/@/hooks/web/useMessage'; 5 import { useMessage } from '/@/hooks/web/useMessage';
7 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue'; 6 import Dropdown from '/@/components/Dropdown/src/Dropdown.vue';
@@ -13,12 +12,8 @@ @@ -13,12 +12,8 @@
13 import { DataBoardRecord } from '/@/api/dataBoard/model'; 12 import { DataBoardRecord } from '/@/api/dataBoard/model';
14 import { ViewType } from './config/panelDetail'; 13 import { ViewType } from './config/panelDetail';
15 import { useRouter } from 'vue-router'; 14 import { useRouter } from 'vue-router';
16 - import { getBoundingClientRect } from '/@/utils/domUtils';  
17 - import Authority from '/@/components/Authority/src/Authority.vue';  
18 - import { computed } from '@vue/reactivity';  
19 import { usePermission } from '/@/hooks/web/usePermission'; 15 import { usePermission } from '/@/hooks/web/usePermission';
20 import { encode } from './config/config'; 16 import { encode } from './config/config';
21 - import { useForm, BasicForm } from '/@/components/Form';  
22 import { formSchema } from './config/searchForm'; 17 import { formSchema } from './config/searchForm';
23 import { ShareModal } from '/@/views/common/ShareModal'; 18 import { ShareModal } from '/@/views/common/ShareModal';
24 import { ModalParamsType } from '/#/utils'; 19 import { ModalParamsType } from '/#/utils';
@@ -26,62 +21,23 @@ @@ -26,62 +21,23 @@
26 import { useRole } from '/@/hooks/business/useRole'; 21 import { useRole } from '/@/hooks/business/useRole';
27 import { useClipboard } from '@vueuse/core'; 22 import { useClipboard } from '@vueuse/core';
28 import { DATA_BOARD_SHARE_URL } from '../palette'; 23 import { DATA_BOARD_SHARE_URL } from '../palette';
  24 + import { BasicCardList, useCardList } from '/@/components/CardList';
29 25
30 - const ListItem = List.Item;  
31 const router = useRouter(); 26 const router = useRouter();
32 27
33 const { createMessage, createConfirm } = useMessage(); 28 const { createMessage, createConfirm } = useMessage();
34 29
35 - const listEL = ref();  
36 - const loading = ref(false);  
37 - const dataBoardList = ref<DataBoardRecord[]>([]);  
38 -  
39 - const [searchFormRegister, searchFormMethod] = useForm({  
40 - schemas: formSchema,  
41 - labelWidth: 80,  
42 - layout: 'inline',  
43 - submitButtonOptions: {  
44 - loading: loading as unknown as boolean,  
45 - },  
46 - submitFunc: async () => {  
47 - try {  
48 - const params = searchFormMethod.getFieldsValue();  
49 - await getDatasource(params);  
50 - } catch (error) {}  
51 - },  
52 - resetFunc: async () => {  
53 - try {  
54 - await getDatasource();  
55 - } catch (error) {} 30 + const [registerCardList, { reload }] = useCardList({
  31 + title: '数据看板',
  32 + api: getDataBoardList,
  33 + baseLayout: { col: 3, row: 3 },
  34 + useSearchForm: true,
  35 + formConfig: {
  36 + schemas: formSchema,
  37 + labelWidth: 80,
56 }, 38 },
57 }); 39 });
58 40
59 - // about pagination  
60 - const page = ref(1);  
61 - const pageSize = ref(10);  
62 - const total = ref(0);  
63 - const paginationProp = ref({  
64 - showSizeChanger: false,  
65 - showQuickJumper: true,  
66 - pageSize,  
67 - current: page,  
68 - size: 'small',  
69 - total,  
70 - showTotal: (total) => `总 ${total} 条`,  
71 - onChange: pageChange,  
72 - onShowSizeChange: pageSizeChange,  
73 - });  
74 -  
75 - function pageChange(p, pz) {  
76 - page.value = p;  
77 - pageSize.value = pz;  
78 - getDatasource();  
79 - }  
80 - function pageSizeChange(_current, size) {  
81 - pageSize.value = size;  
82 - getDatasource();  
83 - }  
84 -  
85 const createShareUrl = (record: DataBoardRecord) => { 41 const createShareUrl = (record: DataBoardRecord) => {
86 const { origin } = location; 42 const { origin } = location;
87 const { id, publicId } = record; 43 const { id, publicId } = record;
@@ -124,22 +80,6 @@ @@ -124,22 +80,6 @@
124 return basicMenu; 80 return basicMenu;
125 }); 81 });
126 82
127 - const getDatasource = async (params: Recordable = {}) => {  
128 - try {  
129 - loading.value = true;  
130 - const { total, items } = await getDataBoardList({  
131 - page: unref(paginationProp).current,  
132 - pageSize: unref(paginationProp).pageSize,  
133 - ...params,  
134 - });  
135 - dataBoardList.value = items;  
136 - paginationProp.value.total = total;  
137 - } catch (error) {  
138 - } finally {  
139 - loading.value = false;  
140 - }  
141 - };  
142 -  
143 const handleOpenShareModal = (record: DataBoardRecord) => { 83 const handleOpenShareModal = (record: DataBoardRecord) => {
144 openShareModal(true, { 84 openShareModal(true, {
145 record, 85 record,
@@ -175,7 +115,7 @@ @@ -175,7 +115,7 @@
175 try { 115 try {
176 await deleteDataBoard([record.id]); 116 await deleteDataBoard([record.id]);
177 createMessage.success('删除成功'); 117 createMessage.success('删除成功');
178 - await getDatasource(); 118 + reload();
179 } catch (error) {} 119 } catch (error) {}
180 }; 120 };
181 121
@@ -188,106 +128,67 @@ @@ -188,106 +128,67 @@
188 if (hasDetailPermission) { 128 if (hasDetailPermission) {
189 const boardId = encode(record.id); 129 const boardId = encode(record.id);
190 const boardName = encode(record.name); 130 const boardName = encode(record.name);
191 - const organizationId = encode(record?.organizationId); 131 + const organizationId = encode(record!.organizationId!);
192 132
193 router.push(`/visual/board/detail/${boardId}/${boardName}/${organizationId}`); 133 router.push(`/visual/board/detail/${boardId}/${boardName}/${organizationId}`);
194 } else createMessage.warning('没有权限'); 134 } else createMessage.warning('没有权限');
195 }; 135 };
196 -  
197 - const handlePagenationPosition = () => {  
198 - const clientHeight = document.documentElement.clientHeight;  
199 - const rect = getBoundingClientRect(unref(listEL).$el!) as DOMRect;  
200 - const paginationHeight = 32 + 24 + 16;  
201 - const listContainerMarginBottom = 16;  
202 - const listContainerHeight =  
203 - clientHeight - rect.top - paginationHeight - listContainerMarginBottom;  
204 - const listContainerEl = (unref(listEL).$el as HTMLElement).querySelector(  
205 - '.ant-spin-container'  
206 - ) as HTMLElement;  
207 - listContainerEl &&  
208 - (listContainerEl.style.height = listContainerHeight + 'px') &&  
209 - (listContainerEl.style.overflowY = 'auto') &&  
210 - (listContainerEl.style.overflowX = 'hidden');  
211 - };  
212 -  
213 - onMounted(() => {  
214 - getDatasource();  
215 - handlePagenationPosition();  
216 - });  
217 </script> 136 </script>
218 137
219 <template> 138 <template>
220 - <PageWrapper>  
221 - <div class="flex items-center mb-3 bg-light-100 h-78px dark:text-gray-300 dark:bg-dark-900">  
222 - <div class="text-lg ml-30px mr-9px font-bold">自定义看板</div>  
223 - <Authority value="api:yt:data_board:add:post">  
224 - <Button v-if="!isCustomerUser" type="primary" @click="handleOpenDetailModal"  
225 - >创建看板</Button  
226 - >  
227 - </Authority>  
228 - </div>  
229 - <div class="bg-light-100 mb-6 w-full p-3 search-form dark:text-gray-300 dark:bg-dark-900">  
230 - <BasicForm class="flex-auto w-full" @register="searchFormRegister" />  
231 - </div>  
232 - <Spin :spinning="loading">  
233 - <List  
234 - ref="listEL"  
235 - :pagination="paginationProp"  
236 - :data-source="dataBoardList"  
237 - :grid="{ gutter: 20, column: 4, xs: 1, sm: 2, md: 2, lg: 3, xl: 3, xxl: 3 }"  
238 - class="data-board-list"  
239 - >  
240 - <template #renderItem="{ item }">  
241 - <ListItem>  
242 - <Card class="data-card cursor-pointer">  
243 - <template #title>  
244 - <div class="font-bold">{{ item.name }}</div>  
245 - </template>  
246 - <template #extra>  
247 - <Dropdown  
248 - v-if="!isCustomerUser && dropMenuList.length"  
249 - :trigger="['click']"  
250 - @menu-event="(event) => handleMenuEvent(event, item)"  
251 - :drop-menu-list="dropMenuList"  
252 - >  
253 - <MoreOutlined class="rotate-90 transform cursor-pointer" />  
254 - </Dropdown>  
255 - </template>  
256 - <section @click="handleViewBoard(item)">  
257 - <div class="flex data-card__info">  
258 - <div>  
259 - <div>组件数量</div>  
260 - <Statistic style="font-size: 22px" :value="item.componentNum">  
261 - <template #suffix>  
262 - <span class="text-sm">个</span>  
263 - </template>  
264 - </Statistic>  
265 - </div>  
266 - </div>  
267 - <div class="flex justify-between mt-4 text-sm" style="color: #999">  
268 - <div class="flex min-w-20 mr-3">  
269 - <span>  
270 - {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }}  
271 - </span>  
272 - <span v-if="item.viewType === ViewType.PUBLIC_VIEW">  
273 - <Tooltip title="点击复制分享链接">  
274 - <ShareAltOutlined class="ml-1" @click.stop="handleCopyShareUrl(item)" />  
275 - </Tooltip>  
276 - </span>  
277 - </div>  
278 - <Tooltip placement="topLeft" :title="item.createTime">  
279 - <div class="truncate">{{ item.createTime }}</div> 139 + <section>
  140 + <BasicCardList @register="registerCardList">
  141 + <template #toolbar>
  142 + <Button type="primary" @click="handleOpenDetailModal">新增看板</Button>
  143 + </template>
  144 + <template #renderItem="{ item }: CardListRenderItem<DataBoardRecord>">
  145 + <Card class="data-card cursor-pointer">
  146 + <template #title>
  147 + <div class="font-bold">{{ item.name }}</div>
  148 + </template>
  149 + <template #extra>
  150 + <Dropdown
  151 + v-if="!isCustomerUser && dropMenuList.length"
  152 + :trigger="['click']"
  153 + @menu-event="(event) => handleMenuEvent(event, item)"
  154 + :drop-menu-list="dropMenuList"
  155 + >
  156 + <MoreOutlined class="rotate-90 transform cursor-pointer" />
  157 + </Dropdown>
  158 + </template>
  159 + <section @click="handleViewBoard(item)">
  160 + <div class="flex data-card__info">
  161 + <div>
  162 + <div>组件数量</div>
  163 + <Statistic class="text-2xl" :value="item.componentNum">
  164 + <template #suffix>
  165 + <span class="text-sm">个</span>
  166 + </template>
  167 + </Statistic>
  168 + </div>
  169 + </div>
  170 + <div class="flex justify-between mt-4 text-sm" style="color: #999">
  171 + <div class="flex min-w-20 mr-3">
  172 + <span>
  173 + {{ item.viewType === ViewType.PRIVATE_VIEW ? '私有看板' : '公共看板' }}
  174 + </span>
  175 + <span v-if="item.viewType === ViewType.PUBLIC_VIEW">
  176 + <Tooltip title="点击复制分享链接">
  177 + <ShareAltOutlined class="ml-1" @click.stop="handleCopyShareUrl(item)" />
280 </Tooltip> 178 </Tooltip>
281 - </div>  
282 - </section>  
283 - </Card>  
284 - </ListItem>  
285 - </template>  
286 - </List>  
287 - </Spin>  
288 - <ShareModal @register="registerShareModal" :shareApi="shareBoard" @success="getDatasource" />  
289 - <PanelDetailModal @register="registerModal" @change="getDatasource" />  
290 - </PageWrapper> 179 + </span>
  180 + </div>
  181 + <Tooltip placement="topLeft" :title="item.createTime">
  182 + <div class="truncate">{{ item.createTime }}</div>
  183 + </Tooltip>
  184 + </div>
  185 + </section>
  186 + </Card>
  187 + </template>
  188 + </BasicCardList>
  189 + <ShareModal @register="registerShareModal" :shareApi="shareBoard" @success="reload()" />
  190 + <PanelDetailModal @register="registerModal" @change="reload()" />
  191 + </section>
291 </template> 192 </template>
292 193
293 <style scoped lang="less"> 194 <style scoped lang="less">