Commit bf667931225e146acd012da994a239cb2a0a4b7f

Authored by ww
1 parent 9a4aa30b

perf: 优化产品页面使用组件

@@ -43,120 +43,7 @@ export interface IDeviceConfigAddOrEditModel { @@ -43,120 +43,7 @@ export interface IDeviceConfigAddOrEditModel {
43 icon?: string; 43 icon?: string;
44 id?: string; 44 id?: string;
45 name?: string; 45 name?: string;
46 - profileData?: {  
47 - configuration: {};  
48 - transportConfiguration: {};  
49 - provisionConfiguration: {  
50 - provisionDeviceSecret: string;  
51 - };  
52 - //报警类型字段  
53 - alarms: [  
54 - {  
55 - id: 'highTemperatureAlarmID';  
56 - alarmType: 'High Temperature Alarm';  
57 - createRules: {  
58 - additionalProp1: {  
59 - condition: {  
60 - condition: [  
61 - {  
62 - key: {  
63 - type: 'TIME_SERIES';  
64 - key: 'temp';  
65 - };  
66 - valueType: 'NUMERIC';  
67 - value: {};  
68 - predicate: {};  
69 - }  
70 - ];  
71 - spec: {};  
72 - };  
73 - schedule: {  
74 - type: 'ANY_TIME';  
75 - };  
76 - alarmDetails: string;  
77 - dashboardId: {  
78 - id: '784f394c-42b6-435a-983c-b7beff2784f9';  
79 - entityType: 'DASHBOARD';  
80 - };  
81 - };  
82 - additionalProp2: {  
83 - condition: {  
84 - condition: [  
85 - {  
86 - key: {  
87 - type: 'TIME_SERIES';  
88 - key: 'temp';  
89 - };  
90 - valueType: 'NUMERIC';  
91 - value: {};  
92 - predicate: {};  
93 - }  
94 - ];  
95 - spec: {};  
96 - };  
97 - schedule: {  
98 - type: 'ANY_TIME';  
99 - };  
100 - alarmDetails: string;  
101 - dashboardId: {  
102 - id: '784f394c-42b6-435a-983c-b7beff2784f9';  
103 - entityType: 'DASHBOARD';  
104 - };  
105 - };  
106 - additionalProp3: {  
107 - condition: {  
108 - condition: [  
109 - {  
110 - key: {  
111 - type: 'TIME_SERIES';  
112 - key: 'temp';  
113 - };  
114 - valueType: 'NUMERIC';  
115 - value: {};  
116 - predicate: {};  
117 - }  
118 - ];  
119 - spec: {};  
120 - };  
121 - schedule: {  
122 - type: 'ANY_TIME';  
123 - };  
124 - alarmDetails: string;  
125 - dashboardId: {  
126 - id: '784f394c-42b6-435a-983c-b7beff2784f9';  
127 - entityType: 'DASHBOARD';  
128 - };  
129 - };  
130 - };  
131 - clearRule: {  
132 - condition: {  
133 - condition: [  
134 - {  
135 - key: {  
136 - type: 'TIME_SERIES';  
137 - key: 'temp';  
138 - };  
139 - valueType: 'NUMERIC';  
140 - value: {};  
141 - predicate: {};  
142 - }  
143 - ];  
144 - spec: {};  
145 - };  
146 - schedule: {  
147 - type: 'ANY_TIME';  
148 - };  
149 - alarmDetails: string;  
150 - dashboardId: {  
151 - id: '784f394c-42b6-435a-983c-b7beff2784f9';  
152 - entityType: 'DASHBOARD';  
153 - };  
154 - };  
155 - propagate: true;  
156 - propagateRelationTypes: [string];  
157 - }  
158 - ];  
159 - }; 46 + profileData?: ProfileData;
160 roleIds?: [string]; 47 roleIds?: [string];
161 tbProfileId?: string; 48 tbProfileId?: string;
162 tenantExpireTime?: '2021-12-15T02:17:26.645Z'; 49 tenantExpireTime?: '2021-12-15T02:17:26.645Z';
@@ -219,7 +106,7 @@ export interface ProfileData { @@ -219,7 +106,7 @@ export interface ProfileData {
219 configuration: Configuration; 106 configuration: Configuration;
220 transportConfiguration: TransportConfiguration; 107 transportConfiguration: TransportConfiguration;
221 provisionConfiguration: ProvisionConfiguration; 108 provisionConfiguration: ProvisionConfiguration;
222 - alarms?: any; 109 + alarms: any;
223 } 110 }
224 111
225 export interface ProfileRecord { 112 export interface ProfileRecord {
@@ -297,8 +184,3 @@ export interface Configuration { @@ -297,8 +184,3 @@ export interface Configuration {
297 export interface TransportConfiguration { 184 export interface TransportConfiguration {
298 type: string; 185 type: string;
299 } 186 }
300 -  
301 -export interface ProvisionConfiguration {  
302 - type: string;  
303 - provisionDeviceSecret: any;  
304 -}  
1 <script setup lang="ts"> 1 <script setup lang="ts">
2 import { BasicForm, FormActionType, useForm } from '/@/components/Form'; 2 import { BasicForm, FormActionType, useForm } from '/@/components/Form';
3 - import { List, ListProps, Button, Tooltip } from 'ant-design-vue'; 3 + import { List, ListProps, Button, Tooltip, DropdownButton, Menu } from 'ant-design-vue';
4 import { computed, Ref, ref, toRaw, unref, useSlots, watch } from 'vue'; 4 import { computed, Ref, ref, toRaw, unref, useSlots, watch } from 'vue';
5 import { useCardListScroll } from './hooks/useCardListScroll'; 5 import { useCardListScroll } from './hooks/useCardListScroll';
6 import { BasicCardListPropsType, CardListActionType } from './types'; 6 import { BasicCardListPropsType, CardListActionType } from './types';
@@ -96,6 +96,7 @@ @@ -96,6 +96,7 @@
96 clearSelectedKeys, 96 clearSelectedKeys,
97 getSelectedKeys, 97 getSelectedKeys,
98 getSelectedRecords, 98 getSelectedRecords,
  99 + getSelections,
99 } = useCardListSelected(getDataSourceRef, getProps, { 100 } = useCardListSelected(getDataSourceRef, getProps, {
100 updateTableDataRecord, 101 updateTableDataRecord,
101 findCardDataRecord, 102 findCardDataRecord,
@@ -142,6 +143,7 @@ @@ -142,6 +143,7 @@
142 clearSelectedKeys, 143 clearSelectedKeys,
143 getSelectedKeys, 144 getSelectedKeys,
144 getSelectedRecords, 145 getSelectedRecords,
  146 + getSelections,
145 }; 147 };
146 148
147 function setProps(props: Partial<BasicCardListPropsType> = {}) { 149 function setProps(props: Partial<BasicCardListPropsType> = {}) {
@@ -177,13 +179,21 @@ @@ -177,13 +179,21 @@
177 </span> 179 </span>
178 <slot v-else name="title"></slot> 180 <slot v-else name="title"></slot>
179 </div> 181 </div>
180 - <div class="flex flex-auto justify-end mr-4"> 182 + <div class="flex flex-auto justify-end mr-4 gap-4">
181 <slot name="toolbar"></slot> 183 <slot name="toolbar"></slot>
182 </div> 184 </div>
183 <div v-if="showCardListSetting" class="flex gap-4"> 185 <div v-if="showCardListSetting" class="flex gap-4">
184 - <Button v-if="getProps.selections" @click="selectAllToggle" type="primary">  
185 - {{ selectedKeys.length === getDataSourceRef.length ? '反选' : '全选' }}  
186 - </Button> 186 + <DropdownButton v-if="getProps.selections" @click="selectAllToggle" type="primary">
  187 + <template #overlay>
  188 + <Menu>
  189 + <Menu.Item @click="selectedAll">全选</Menu.Item>
  190 + <Menu.Item @click="clearSelectedKeys">反选</Menu.Item>
  191 + </Menu>
  192 + </template>
  193 + <span>
  194 + {{ selectedKeys.length === getDataSourceRef.length ? '反选' : '全选' }}
  195 + </span>
  196 + </DropdownButton>
187 <CardListLayout v-model:row="cardListLayout.row" v-model:col="cardListLayout.col" /> 197 <CardListLayout v-model:row="cardListLayout.row" v-model:col="cardListLayout.col" />
188 <Tooltip title="刷新"> 198 <Tooltip title="刷新">
189 <Button type="primary" @click="reload()" :loading="loading"> 199 <Button type="primary" @click="reload()" :loading="loading">
@@ -193,7 +203,7 @@ @@ -193,7 +203,7 @@
193 </div> 203 </div>
194 </section> 204 </section>
195 </template> 205 </template>
196 - <template #renderItem="{ item }: CardListRenderItem"> 206 + <template #renderItem="{ item }: BasicCardListRenderItem<any>">
197 <List.Item 207 <List.Item
198 :class="selectedKeys.includes(item[getRowKey]) ? selectedClass : ''" 208 :class="selectedKeys.includes(item[getRowKey]) ? selectedClass : ''"
199 @click="handlerSelected($event, item)" 209 @click="handlerSelected($event, item)"
@@ -8,7 +8,7 @@ import { PaginationProps } from 'ant-design-vue'; @@ -8,7 +8,7 @@ import { PaginationProps } from 'ant-design-vue';
8 import { FetchParams } from './useCardListData'; 8 import { FetchParams } from './useCardListData';
9 import { tryOnUnmounted } from '@vueuse/core'; 9 import { tryOnUnmounted } from '@vueuse/core';
10 10
11 -type UseTableMethod = CardListActionType & { 11 +type UseCardListMethod = CardListActionType & {
12 getForm: () => FormActionType; 12 getForm: () => FormActionType;
13 }; 13 };
14 14
@@ -49,46 +49,49 @@ export function useCardList( @@ -49,46 +49,49 @@ export function useCardList(
49 ); 49 );
50 } 50 }
51 51
52 - function getTableInstance(): CardListActionType {  
53 - const table = unref(cardListRef);  
54 - if (!table) { 52 + function getCardListInstance(): CardListActionType {
  53 + const cardList = unref(cardListRef);
  54 + if (!cardList) {
55 error( 55 error(
56 - 'The CardList instance has not been obtained yet, please make sure the table is presented when performing the table operation!' 56 + 'The CardList instance has not been obtained yet, please make sure the card list is presented when performing the card list operation!'
57 ); 57 );
58 } 58 }
59 - return table as CardListActionType; 59 + return cardList as CardListActionType;
60 } 60 }
61 61
62 - const cardListActionType: UseTableMethod = { 62 + const cardListActionType: UseCardListMethod = {
63 getForm: () => { 63 getForm: () => {
64 return unref(formRef) as unknown as FormActionType; 64 return unref(formRef) as unknown as FormActionType;
65 }, 65 },
66 setLoading: (loading: boolean) => { 66 setLoading: (loading: boolean) => {
67 - return getTableInstance().setLoading(loading); 67 + return getCardListInstance().setLoading(loading);
68 }, 68 },
69 setProps: (props: Partial<BasicCardListPropsType>) => { 69 setProps: (props: Partial<BasicCardListPropsType>) => {
70 - getTableInstance().setProps(props); 70 + getCardListInstance().setProps(props);
71 }, 71 },
72 getPagination: () => { 72 getPagination: () => {
73 - return getTableInstance().getPagination(); 73 + return getCardListInstance().getPagination();
74 }, 74 },
75 setPagination: (pagination: Partial<PaginationProps>) => { 75 setPagination: (pagination: Partial<PaginationProps>) => {
76 - return getTableInstance().setPagination(pagination); 76 + return getCardListInstance().setPagination(pagination);
77 }, 77 },
78 reload: (opt?: FetchParams) => { 78 reload: (opt?: FetchParams) => {
79 - return getTableInstance().reload(opt); 79 + return getCardListInstance().reload(opt);
80 }, 80 },
81 selectedAll: () => { 81 selectedAll: () => {
82 - return getTableInstance().selectedAll(); 82 + return getCardListInstance().selectedAll();
83 }, 83 },
84 clearSelectedKeys: () => { 84 clearSelectedKeys: () => {
85 - return getTableInstance().clearSelectedKeys(); 85 + return getCardListInstance().clearSelectedKeys();
86 }, 86 },
87 getSelectedKeys: () => { 87 getSelectedKeys: () => {
88 - return getTableInstance().getSelectedKeys(); 88 + return getCardListInstance().getSelectedKeys();
89 }, 89 },
90 getSelectedRecords: () => { 90 getSelectedRecords: () => {
91 - return getTableInstance().getSelectedRecords(); 91 + return getCardListInstance().getSelectedRecords();
  92 + },
  93 + getSelections: () => {
  94 + return getCardListInstance().getSelections();
92 }, 95 },
93 }; 96 };
94 97
1 import { ComputedRef, computed, ref, toRaw, unref, watch } from 'vue'; 1 import { ComputedRef, computed, ref, toRaw, unref, watch } from 'vue';
2 import { BasicCardListPropsType, CardListSelectionsType, UseCardListDataType } from '../types'; 2 import { BasicCardListPropsType, CardListSelectionsType, UseCardListDataType } from '../types';
3 -import { isBoolean } from '/@/utils/is'; 3 +import { isBoolean, isFunction } from '/@/utils/is';
4 import { cloneDeep } from 'lodash-es'; 4 import { cloneDeep } from 'lodash-es';
5 5
6 export const CHECKED_FIELD = 'CARD_LIST_CHECKED_STATUS'; 6 export const CHECKED_FIELD = 'CARD_LIST_CHECKED_STATUS';
@@ -23,18 +23,27 @@ export function useCardListSelected( @@ -23,18 +23,27 @@ export function useCardListSelected(
23 23
24 const selectedClass = ref(''); 24 const selectedClass = ref('');
25 25
  26 + const selectionRef = ref<CardListSelectionsType>({});
  27 +
  28 + const getSelectionsRef = computed<CardListSelectionsType & { enabled: boolean }>(() => {
  29 + const { selections } = unref(propsRef);
  30 + return {
  31 + enabled: !!selections,
  32 + ...unref(selectionRef),
  33 + ...(isBoolean(selections) ? {} : selections),
  34 + };
  35 + });
  36 +
26 const getHasSelectedRecordStatus = computed(() => 37 const getHasSelectedRecordStatus = computed(() =>
27 unref(getDataSourceRef).find((item) => item.checked) 38 unref(getDataSourceRef).find((item) => item.checked)
28 ); 39 );
29 40
30 const getShouldUseDefaultStyle = computed( 41 const getShouldUseDefaultStyle = computed(
31 - () =>  
32 - isBoolean(unref(propsRef).selections) ||  
33 - !(unref(propsRef).selections as CardListSelectionsType).customCheckedStyle 42 + () => unref(getSelectionsRef).enabled && !unref(getSelectionsRef).customCheckedStyle
34 ); 43 );
35 44
36 watch( 45 watch(
37 - () => unref(propsRef).selections, 46 + getSelectionsRef,
38 () => { 47 () => {
39 selectedClass.value = 48 selectedClass.value =
40 isBoolean(unref(propsRef).selections) || 49 isBoolean(unref(propsRef).selections) ||
@@ -48,24 +57,33 @@ export function useCardListSelected( @@ -48,24 +57,33 @@ export function useCardListSelected(
48 ); 57 );
49 58
50 function handlerSelected(_event: MouseEvent, record: Recordable) { 59 function handlerSelected(_event: MouseEvent, record: Recordable) {
51 - if (!unref(propsRef).selections) return; 60 + if (!unref(getSelectionsRef).enabled) return;
  61 +
  62 + if (unref(getSelectionsRef).beforeSelectValidate) {
  63 + if (!unref(getSelectionsRef).beforeSelectValidate?.(record)) return;
  64 + }
  65 +
52 const rowKey = record[unref(getRowKey)]; 66 const rowKey = record[unref(getRowKey)];
53 const index = unref(selectedKeys).findIndex((key) => key === rowKey); 67 const index = unref(selectedKeys).findIndex((key) => key === rowKey);
54 ~index ? selectedKeys.value.splice(index, 1) : unref(selectedKeys).push(rowKey); 68 ~index ? selectedKeys.value.splice(index, 1) : unref(selectedKeys).push(rowKey);
55 69
56 - if (isBoolean(unref(propsRef).selections)) return; 70 + if (!unref(getSelectionsRef).onSelect) return;
57 71
58 - (unref(propsRef).selections as CardListSelectionsType)?.onSelect?.(record, !!~index); 72 + unref(getSelectionsRef)?.onSelect?.(record, !!~index);
59 } 73 }
60 74
61 function selectedAll() { 75 function selectedAll() {
62 - selectedKeys.value = unref(getDataSourceRef).map((item) => item[unref(getRowKey)]); 76 + selectedKeys.value = unref(getDataSourceRef)
  77 + .filter(
  78 + (item) =>
  79 + isFunction(unref(getSelectionsRef).beforeSelectValidate) &&
  80 + unref(getSelectionsRef).beforeSelectValidate?.(item)
  81 + )
  82 + .map((item) => item[unref(getRowKey)]);
63 83
64 - if (isBoolean(unref(propsRef).selections)) return; 84 + if (!unref(getSelectionsRef).onSelect) return;
65 85
66 - (unref(propsRef).selections as CardListSelectionsType)?.onSelectAll?.(  
67 - toRaw(unref(getDataSourceRef))  
68 - ); 86 + unref(getSelectionsRef)?.onSelectAll?.(toRaw(unref(getDataSourceRef)));
69 } 87 }
70 88
71 function clearSelectedKeys() { 89 function clearSelectedKeys() {
@@ -87,11 +105,16 @@ export function useCardListSelected( @@ -87,11 +105,16 @@ export function useCardListSelected(
87 : selectedAll(); 105 : selectedAll();
88 } 106 }
89 107
  108 + function getSelections() {
  109 + return unref(getSelectionsRef);
  110 + }
  111 +
90 return { 112 return {
91 selectedKeys, 113 selectedKeys,
92 selectedClass, 114 selectedClass,
93 getShouldUseDefaultStyle, 115 getShouldUseDefaultStyle,
94 getHasSelectedRecordStatus, 116 getHasSelectedRecordStatus,
  117 + getSelections,
95 handlerSelected, 118 handlerSelected,
96 selectedAll, 119 selectedAll,
97 selectAllToggle, 120 selectAllToggle,
@@ -52,6 +52,7 @@ export interface CardListActionType { @@ -52,6 +52,7 @@ export interface CardListActionType {
52 clearSelectedKeys: UseCardListSelected['clearSelectedKeys']; 52 clearSelectedKeys: UseCardListSelected['clearSelectedKeys'];
53 getSelectedKeys: UseCardListSelected['getSelectedKeys']; 53 getSelectedKeys: UseCardListSelected['getSelectedKeys'];
54 getSelectedRecords: UseCardListSelected['getSelectedRecords']; 54 getSelectedRecords: UseCardListSelected['getSelectedRecords'];
  55 + getSelections: UseCardListSelected['getSelections'];
55 } 56 }
56 57
57 export interface CardListEmitType { 58 export interface CardListEmitType {
@@ -61,6 +62,7 @@ export interface CardListEmitType { @@ -61,6 +62,7 @@ export interface CardListEmitType {
61 62
62 export interface CardListSelectionsType<T = Recordable> { 63 export interface CardListSelectionsType<T = Recordable> {
63 customCheckedStyle?: boolean; 64 customCheckedStyle?: boolean;
  65 + beforeSelectValidate?: (record: Recordable) => boolean;
64 onSelect?: (record: T, selected: boolean) => any; 66 onSelect?: (record: T, selected: boolean) => any;
65 - onSelectAll: (selectedRecords: T[]) => any; 67 + onSelectAll?: (selectedRecords: T[]) => any;
66 } 68 }
@@ -134,7 +134,7 @@ @@ -134,7 +134,7 @@
134 </Authority> 134 </Authority>
135 </div> 135 </div>
136 </template> 136 </template>
137 - <template #renderItem="{ item }: CardListRenderItem<ConfigurationCenterItemsModal>"> 137 + <template #renderItem="{ item }: BasicCardListRenderItem<ConfigurationCenterItemsModal>">
138 <Card 138 <Card
139 :style="{ 139 :style="{
140 '--viewType': item.viewType === ViewTypeEnum.PUBLIC_VIEW ? '#faad14' : '#1890ff', 140 '--viewType': item.viewType === ViewTypeEnum.PUBLIC_VIEW ? '#faad14' : '#1890ff',
@@ -105,7 +105,7 @@ @@ -105,7 +105,7 @@
105 </Authority> 105 </Authority>
106 </div> 106 </div>
107 </template> 107 </template>
108 - <template #renderItem="{ item }: CardListRenderItem<ConfigurationCenterItemsModal>"> 108 + <template #renderItem="{ item }: BasicCardListRenderItem<ConfigurationCenterItemsModal>">
109 <Card 109 <Card
110 :style="{ 110 :style="{
111 '--viewType': '#1890ff', 111 '--viewType': '#1890ff',
@@ -150,7 +150,7 @@ @@ -150,7 +150,7 @@
150 </Authority> 150 </Authority>
151 </section> 151 </section>
152 </template> 152 </template>
153 - <template #renderItem="{ item }: CardListRenderItem<BigScreenCenterItemsModel>"> 153 + <template #renderItem="{ item }: BasicCardListRenderItem<BigScreenCenterItemsModel>">
154 <Card 154 <Card
155 :style="{ 155 :style="{
156 '--viewType': item.viewType === ViewType.PUBLIC_VIEW ? '#1890ff' : '#faad14', 156 '--viewType': item.viewType === ViewType.PUBLIC_VIEW ? '#1890ff' : '#faad14',
1 <script lang="ts" setup> 1 <script lang="ts" setup>
2 - import { PageWrapper } from '/@/components/Page';  
3 - import { BasicForm, useForm } from '/@/components/Form';  
4 - import { List, Button, Tooltip, Card, PaginationProps, Image, Popconfirm } from 'ant-design-vue';  
5 - import { ReloadOutlined } from '@ant-design/icons-vue';  
6 - import { computed, onMounted, reactive, ref, unref } from 'vue';  
7 - import {  
8 - AuthIcon,  
9 - CardLayoutButton,  
10 - EnumTableCardMode,  
11 - ModeSwitchButton,  
12 - } from '/@/components/Widget'; 2 + import { Button, Tooltip, Card, Image, Popconfirm } from 'ant-design-vue';
  3 + import { AuthIcon, EnumTableCardMode, ModeSwitchButton } from '/@/components/Widget';
13 import { Authority } from '/@/components/Authority'; 4 import { Authority } from '/@/components/Authority';
14 import { 5 import {
15 deviceConfigDelete, 6 deviceConfigDelete,
@@ -29,8 +20,9 @@ @@ -29,8 +20,9 @@
29 import { useModal } from '/@/components/Modal'; 20 import { useModal } from '/@/components/Modal';
30 import { useDrawer } from '/@/components/Drawer'; 21 import { useDrawer } from '/@/components/Drawer';
31 import productDefault from '/@/assets/icons/product-default.svg'; 22 import productDefault from '/@/assets/icons/product-default.svg';
32 - import { useRoute } from 'vue-router';  
33 import AuthDropDown from '/@/components/Widget/AuthDropDown.vue'; 23 import AuthDropDown from '/@/components/Widget/AuthDropDown.vue';
  24 + import { BasicCardList, useCardList } from '/@/components/CardList';
  25 + import { useRoute } from 'vue-router';
34 26
35 defineProps<{ 27 defineProps<{
36 mode: EnumTableCardMode; 28 mode: EnumTableCardMode;
@@ -42,94 +34,39 @@ @@ -42,94 +34,39 @@
42 SET_DEFAULT = 'setDefault', 34 SET_DEFAULT = 'setDefault',
43 DELETE = 'delete', 35 DELETE = 'delete',
44 } 36 }
  37 +
45 const IMAGE_FALLBACK = productDefault; 38 const IMAGE_FALLBACK = productDefault;
46 39
47 const { createMessage } = useMessage(); 40 const { createMessage } = useMessage();
48 41
49 - const [register, { getFieldsValue, setFieldsValue }] = useForm({  
50 - showAdvancedButton: true,  
51 - labelWidth: 100,  
52 - compact: true,  
53 - baseColProps: { span: 8 },  
54 - schemas: searchFormSchema,  
55 - resetFunc: async () => {  
56 - getDataSource({ name: '' }); 42 + const { query } = useRoute();
  43 +
  44 + const [registerCardList, { reload, getSelectedKeys, clearSelectedKeys }] = useCardList({
  45 + api: deviceConfigGetQuery,
  46 + useSearchForm: true,
  47 + gutter: 4,
  48 + rowKey: 'id',
  49 + formConfig: {
  50 + schemas: searchFormSchema,
  51 + labelWidth: 100,
  52 + model: {
  53 + name: (query as Recordable)?.name ? decodeURIComponent((query as Recordable)?.name) : null,
  54 + },
57 }, 55 },
58 - submitFunc: async () => {  
59 - getDataSource({ pageSize: pagination.pageSize, page: 1 }); 56 + selections: {
  57 + beforeSelectValidate: (record: ProfileRecord) => {
  58 + return !record.default;
  59 + },
60 }, 60 },
61 }); 61 });
62 62
63 const [registerModal, { openModal }] = useModal(); 63 const [registerModal, { openModal }] = useModal();
64 const [registerDrawer, { openDrawer }] = useDrawer(); 64 const [registerDrawer, { openDrawer }] = useDrawer();
65 65
66 - const loading = ref(false);  
67 -  
68 - const colNumber = ref(5);  
69 -  
70 - const pagination = reactive<PaginationProps>({  
71 - size: 'small',  
72 - showTotal: (total: number) => `共 ${total} 条数据`,  
73 - current: 1,  
74 - pageSize: unref(colNumber) * 2,  
75 - onChange: (page: number) => {  
76 - pagination.current = page;  
77 - getDataSource();  
78 - },  
79 - });  
80 -  
81 - const dataSource = ref<ProfileRecord[]>([]);  
82 -  
83 - const getSelectAllFlag = computed(() => {  
84 - return unref(dataSource).every((item) => item.checked || item.default);  
85 - });  
86 -  
87 - const getCheckedRecord = computed(() => {  
88 - return unref(dataSource)  
89 - .filter((item) => item.checked && !item.default)  
90 - .map((item) => item.id);  
91 - });  
92 -  
93 - const getDataSource = async (otherParams: Recordable = {}) => {  
94 - try {  
95 - loading.value = true;  
96 - if (otherParams) {  
97 - setFieldsValue(otherParams);  
98 - }  
99 - const params = getFieldsValue();  
100 - const pageSize = unref(colNumber) * 2;  
101 - const { items, total } = await deviceConfigGetQuery({  
102 - page: pagination.current,  
103 - pageSize: unref(colNumber) * 2,  
104 - ...params,  
105 - ...otherParams,  
106 - });  
107 - Object.assign(pagination, { total, pageSize });  
108 - dataSource.value = items.map((item) => ({ ...item, checked: false }));  
109 - } catch (error) {  
110 - } finally {  
111 - loading.value = false;  
112 - }  
113 - };  
114 -  
115 const handleModeChange = (mode: EnumTableCardMode) => { 66 const handleModeChange = (mode: EnumTableCardMode) => {
116 emit('changeMode', mode); 67 emit('changeMode', mode);
117 }; 68 };
118 69
119 - const handleCheckCard = (item: ProfileRecord) => {  
120 - if (item.default || item.name == 'default') return;  
121 - item.checked = !item.checked;  
122 - };  
123 -  
124 - const handleSelectAll = () => {  
125 - dataSource.value = unref(dataSource).map((item) => {  
126 - return {  
127 - ...item,  
128 - checked: !item.default ? !unref(getSelectAllFlag) : false,  
129 - };  
130 - });  
131 - };  
132 -  
133 const handleCreate = () => { 70 const handleCreate = () => {
134 openModal(true, { 71 openModal(true, {
135 isUpdate: false, 72 isUpdate: false,
@@ -147,11 +84,13 @@ @@ -147,11 +84,13 @@
147 }); 84 });
148 }; 85 };
149 86
150 - const handleDelete = async (id: string[]) => { 87 + const handleDelete = async () => {
151 try { 88 try {
152 - await deviceConfigDelete(id); 89 + const ids = getSelectedKeys();
  90 + await deviceConfigDelete(ids);
153 createMessage.success('删除成功'); 91 createMessage.success('删除成功');
154 - await getDataSource(); 92 + clearSelectedKeys();
  93 + await reload();
155 } catch (error) { 94 } catch (error) {
156 throw error; 95 throw error;
157 } 96 }
@@ -163,155 +102,108 @@ @@ -163,155 +102,108 @@
163 const data = await setDeviceProfileIsDefaultApi(tbProfileId, 'default', defaultObj); 102 const data = await setDeviceProfileIsDefaultApi(tbProfileId, 'default', defaultObj);
164 if (!data) return createMessage.error('设置该产品为默认失败'); 103 if (!data) return createMessage.error('设置该产品为默认失败');
165 createMessage.success('设置该产品为默认成功'); 104 createMessage.success('设置该产品为默认成功');
166 - await getDataSource(); 105 + await reload();
167 } catch (error) { 106 } catch (error) {
168 throw error; 107 throw error;
169 } 108 }
170 }; 109 };
171 -  
172 - const handleCardLayoutChange = () => {  
173 - pagination.current = 1;  
174 - getDataSource();  
175 - };  
176 -  
177 - const { query: routeParams } = useRoute();  
178 - onMounted(() => {  
179 - routeParams.name = decodeURIComponent(  
180 - ((routeParams as unknown as Recordable) || {})?.name || ''  
181 - );  
182 - getDataSource(routeParams);  
183 - });  
184 </script> 110 </script>
185 111
186 <template> 112 <template>
187 - <PageWrapper dense contentFullHeight contentClass="flex">  
188 - <section class="flex-auto p-4 w-full profile-list">  
189 - <div class="flex-auto w-full bg-light-50 dark:bg-dark-900 p-4">  
190 - <BasicForm @register="register" />  
191 - </div>  
192 - <List  
193 - ref="listEl"  
194 - :loading="loading"  
195 - class="flex-auto bg-light-50 dark:bg-dark-900 !p-2 !mt-4"  
196 - position="bottom"  
197 - :pagination="pagination"  
198 - :data-source="dataSource"  
199 - :grid="{ gutter: 4, column: colNumber }"  
200 - >  
201 - <template #header>  
202 - <div class="flex gap-3 justify-end">  
203 - <Authority :value="ProductPermission.CREATE">  
204 - <Button type="primary" @click="handleCreate">新增产品</Button>  
205 - </Authority>  
206 -  
207 - <Button type="primary" @click="handleSelectAll">  
208 - {{ getSelectAllFlag ? '反选' : '全选' }}  
209 - </Button>  
210 - <Authority :value="ProductPermission.DELETE">  
211 - <Popconfirm  
212 - title="您确定要批量删除数据"  
213 - ok-text="确定"  
214 - cancel-text="取消"  
215 - @confirm="handleDelete(getCheckedRecord)"  
216 - :disabled="!getCheckedRecord.length"  
217 - >  
218 - <Button type="primary" danger :disabled="!getCheckedRecord.length">  
219 - 批量删除  
220 - </Button>  
221 - </Popconfirm>  
222 - </Authority>  
223 -  
224 - <ModeSwitchButton :value="$props.mode" @change="handleModeChange" />  
225 - <CardLayoutButton v-model:value="colNumber" @change="handleCardLayoutChange" />  
226 -  
227 - <Tooltip title="刷新">  
228 - <Button type="primary" @click="getDataSource">  
229 - <ReloadOutlined :spin="loading" />  
230 - </Button> 113 + <section>
  114 + <BasicCardList @register="registerCardList">
  115 + <template #toolbar>
  116 + <Authority :value="ProductPermission.CREATE">
  117 + <Button type="primary" @click="handleCreate">新增产品</Button>
  118 + </Authority>
  119 +
  120 + <ModeSwitchButton :value="$props.mode" @change="handleModeChange" />
  121 +
  122 + <Authority :value="ProductPermission.DELETE">
  123 + <Popconfirm
  124 + title="您确定要批量删除数据"
  125 + ok-text="确定"
  126 + cancel-text="取消"
  127 + @confirm="handleDelete"
  128 + >
  129 + <Button type="primary" danger> 批量删除 </Button>
  130 + </Popconfirm>
  131 + </Authority>
  132 + </template>
  133 + <template #renderItem="{ item }: BasicCardListRenderItem<ProfileRecord>">
  134 + <Card hoverable>
  135 + <template #cover>
  136 + <div class="h-full w-full !flex justify-center items-center text-center p-1">
  137 + <Image
  138 + @click.stop
  139 + class="!w-32"
  140 + :src="item.image || IMAGE_FALLBACK"
  141 + placeholder
  142 + :fallback="IMAGE_FALLBACK"
  143 + />
  144 + </div>
  145 + </template>
  146 + <template class="ant-card-actions" #actions>
  147 + <Tooltip title="详情">
  148 + <AuthIcon
  149 + :auth="ProductPermission.DETAIL"
  150 + class="!text-lg"
  151 + icon="ant-design:eye-outlined"
  152 + @click.stop="handleShowDetail(item)"
  153 + />
  154 + </Tooltip>
  155 + <Tooltip title="编辑">
  156 + <AuthIcon
  157 + :auth="ProductPermission.UPDATE"
  158 + class="!text-lg"
  159 + icon="ant-design:form-outlined"
  160 + @click.stop="handleUpdate(item)"
  161 + :disabled="item.name == 'default'"
  162 + />
231 </Tooltip> 163 </Tooltip>
232 - </div>  
233 - </template>  
234 - <template #renderItem="{ item }">  
235 - <List.Item>  
236 - <Card  
237 - hoverable  
238 - @click="handleCheckCard(item)"  
239 - :class="item.checked ? '!border-blue-500 !border-2' : ''"  
240 - >  
241 - <template #cover>  
242 - <div class="h-full w-full !flex justify-center items-center text-center p-1">  
243 - <Image  
244 - @click.stop  
245 - :height="144"  
246 - :src="item.image || IMAGE_FALLBACK"  
247 - placeholder  
248 - :fallback="IMAGE_FALLBACK"  
249 - />  
250 - </div>  
251 - </template>  
252 - <template class="ant-card-actions" #actions>  
253 - <Tooltip title="详情">  
254 - <AuthIcon  
255 - :auth="ProductPermission.DETAIL"  
256 - class="!text-lg"  
257 - icon="ant-design:eye-outlined"  
258 - @click.stop="handleShowDetail(item)"  
259 - />  
260 - </Tooltip>  
261 - <Tooltip title="编辑">  
262 - <AuthIcon  
263 - :auth="ProductPermission.UPDATE"  
264 - class="!text-lg"  
265 - icon="ant-design:form-outlined"  
266 - @click.stop="handleUpdate(item)"  
267 - :disabled="item.name == 'default'"  
268 - />  
269 - </Tooltip>  
270 - <AuthDropDown  
271 - @click.stop  
272 - :trigger="['hover']"  
273 - :drop-menu-list="[  
274 - {  
275 - text: '默认',  
276 - event: DropMenuEvent.SET_DEFAULT,  
277 - icon: 'ant-design:unordered-list-outlined',  
278 - onClick: handleSetDefault.bind(null, item),  
279 - disabled: item.default,  
280 - },  
281 - {  
282 - text: '删除',  
283 - event: DropMenuEvent.DELETE,  
284 - auth: ProductPermission.DELETE,  
285 - icon: 'ant-design:delete-outlined',  
286 - popconfirm: {  
287 - title: '是否确认删除操作?',  
288 - onConfirm: handleDelete.bind(null, [item.id]),  
289 - disabled: item.default,  
290 - },  
291 - disabled: item.default || item.name == 'default',  
292 - },  
293 - ]"  
294 - />  
295 - </template>  
296 - <Card.Meta>  
297 - <template #title>  
298 - <span class="truncate"> {{ item.name }} </span>  
299 - </template>  
300 - <template #description>  
301 - <div class="truncate h-11">  
302 - <div class="truncate">{{ DeviceTypeName[item.deviceType] }} </div>  
303 - <div class="truncate">{{ item.transportType }} </div>  
304 - </div>  
305 - </template>  
306 - </Card.Meta>  
307 - </Card>  
308 - </List.Item>  
309 - </template>  
310 - </List>  
311 - </section>  
312 - <DeviceProfileModal @register="registerModal" @success="getDataSource" /> 164 + <AuthDropDown
  165 + @click.stop
  166 + :trigger="['hover']"
  167 + :drop-menu-list="[
  168 + {
  169 + text: '默认',
  170 + event: DropMenuEvent.SET_DEFAULT,
  171 + icon: 'ant-design:unordered-list-outlined',
  172 + onClick: handleSetDefault.bind(null, item),
  173 + disabled: item.default,
  174 + },
  175 + {
  176 + text: '删除',
  177 + event: DropMenuEvent.DELETE,
  178 + auth: ProductPermission.DELETE,
  179 + icon: 'ant-design:delete-outlined',
  180 + popconfirm: {
  181 + title: '是否确认删除操作?',
  182 + onConfirm: handleDelete.bind(null, [item.id]),
  183 + disabled: item.default,
  184 + },
  185 + disabled: item.default || item.name == 'default',
  186 + },
  187 + ]"
  188 + />
  189 + </template>
  190 + <Card.Meta>
  191 + <template #title>
  192 + <span class="truncate"> {{ item.name }} </span>
  193 + </template>
  194 + <template #description>
  195 + <div class="truncate h-11">
  196 + <div class="truncate">{{ DeviceTypeName[item.deviceType] }} </div>
  197 + <div class="truncate">{{ item.transportType }} </div>
  198 + </div>
  199 + </template>
  200 + </Card.Meta>
  201 + </Card>
  202 + </template>
  203 + </BasicCardList>
  204 + <DeviceProfileModal @register="registerModal" @success="reload" />
313 <DeviceProfileDrawer @register="registerDrawer" /> 205 <DeviceProfileDrawer @register="registerDrawer" />
314 - </PageWrapper> 206 + </section>
315 </template> 207 </template>
316 208
317 <style lang="less" scoped> 209 <style lang="less" scoped>
@@ -322,8 +214,4 @@ @@ -322,8 +214,4 @@
322 .profile-list:deep(.ant-card-body) { 214 .profile-list:deep(.ant-card-body) {
323 @apply !p-4; 215 @apply !p-4;
324 } 216 }
325 -  
326 - :deep(.ant-spin-nested-loading) {  
327 - height: 40rem;  
328 - }  
329 </style> 217 </style>
@@ -154,7 +154,7 @@ @@ -154,7 +154,7 @@
154 <Button type="primary" @click="handleOpenDetailModal">新增看板</Button> 154 <Button type="primary" @click="handleOpenDetailModal">新增看板</Button>
155 </Authority> 155 </Authority>
156 </template> 156 </template>
157 - <template #renderItem="{ item }: CardListRenderItem<DataBoardRecord>"> 157 + <template #renderItem="{ item }: BasicCardListRenderItem<DataBoardRecord>">
158 <Card class="data-card cursor-pointer"> 158 <Card class="data-card cursor-pointer">
159 <template #title> 159 <template #title>
160 <div class="font-bold">{{ item.name }}</div> 160 <div class="font-bold">{{ item.name }}</div>
@@ -20,7 +20,7 @@ export interface DefineComponentsBasicExpose<T = Recordable> { @@ -20,7 +20,7 @@ export interface DefineComponentsBasicExpose<T = Recordable> {
20 } 20 }
21 21
22 declare global { 22 declare global {
23 - interface CardListRenderItem<T = Recordable & { checked?: boolean }> { 23 + interface BasicCardListRenderItem<T = Recordable> {
24 item: T; 24 item: T;
25 totalHeight: number; 25 totalHeight: number;
26 } 26 }