Commit 0f5ddbf1ec777fc238a94bd037d37ea787316757
1 parent
1ddfc31c
feat: add CardList component
Showing
7 changed files
with
256 additions
and
0 deletions
src/components/CardList/index.ts
0 → 100644
src/components/CardList/src/CardList.vue
0 → 100644
1 | +<template> | ||
2 | + <div class="p-2"> | ||
3 | + <div class="bg-white mb-2 p-4"> | ||
4 | + <BasicForm @register="registerForm" /> | ||
5 | + </div> | ||
6 | + {{ sliderProp.width }} | ||
7 | + <div class="bg-white p-2" | ||
8 | + ><List | ||
9 | + :grid="{ gutter: 5, xs: 1, sm: 2, md: 4, lg: 4, xl: 6, xxl: grid }" | ||
10 | + :data-source="data" | ||
11 | + :pagination="paginationProp" | ||
12 | + > | ||
13 | + <template #header> | ||
14 | + <div class="flex justify-end space-x-2" | ||
15 | + ><slot name="header"></slot> | ||
16 | + <Tooltip> | ||
17 | + <template #title> | ||
18 | + <div class="w-50">每行显示数量</div | ||
19 | + ><Slider | ||
20 | + id="slider" | ||
21 | + v-bind="sliderProp" | ||
22 | + v-model:value="grid" | ||
23 | + @change="sliderChange" | ||
24 | + /></template> | ||
25 | + <Button><TableOutlined /></Button> | ||
26 | + </Tooltip> | ||
27 | + <Tooltip @click="fetch"> | ||
28 | + <template #title>刷新</template> | ||
29 | + <Button><RedoOutlined /></Button> | ||
30 | + </Tooltip> | ||
31 | + </div> | ||
32 | + </template> | ||
33 | + <template #renderItem="{ item }"> | ||
34 | + <ListItem> | ||
35 | + <Card> | ||
36 | + <template #title></template> | ||
37 | + <template #cover> | ||
38 | + <div :class="height"> | ||
39 | + <Image :src="item.imgs[0]" /> | ||
40 | + </div> | ||
41 | + </template> | ||
42 | + <template class="ant-card-actions" #actions> | ||
43 | + <!-- <SettingOutlined key="setting" />--> | ||
44 | + <EditOutlined key="edit" /> | ||
45 | + <Dropdown | ||
46 | + :trigger="['hover']" | ||
47 | + :dropMenuList="[ | ||
48 | + { | ||
49 | + text: '删除', | ||
50 | + event: '1', | ||
51 | + popConfirm: { | ||
52 | + title: '是否确认删除', | ||
53 | + confirm: handleDelete.bind(null, item.id), | ||
54 | + }, | ||
55 | + }, | ||
56 | + ]" | ||
57 | + popconfirm | ||
58 | + > | ||
59 | + <EllipsisOutlined key="ellipsis" /> | ||
60 | + </Dropdown> | ||
61 | + </template> | ||
62 | + | ||
63 | + <CardMeta> | ||
64 | + <template #title> | ||
65 | + <TypographyText :content="item.name" :ellipsis="{ tooltip: item.address }" /> | ||
66 | + </template> | ||
67 | + <template #avatar> | ||
68 | + <Avatar :src="item.avatar" /> | ||
69 | + </template> | ||
70 | + <template #description>{{ item.time }}</template> | ||
71 | + </CardMeta> | ||
72 | + </Card> | ||
73 | + </ListItem> | ||
74 | + </template> | ||
75 | + </List></div | ||
76 | + > | ||
77 | + </div> | ||
78 | +</template> | ||
79 | +<script lang="ts" setup> | ||
80 | + import { computed, onMounted, ref } from 'vue'; | ||
81 | + import { | ||
82 | + EditOutlined, | ||
83 | + EllipsisOutlined, | ||
84 | + RedoOutlined, | ||
85 | + TableOutlined, | ||
86 | + } from '@ant-design/icons-vue'; | ||
87 | + import { | ||
88 | + List, | ||
89 | + ListItem, | ||
90 | + Card, | ||
91 | + CardMeta, | ||
92 | + Image, | ||
93 | + TypographyText, | ||
94 | + Tooltip, | ||
95 | + Slider, | ||
96 | + Avatar, | ||
97 | + } from 'ant-design-vue'; | ||
98 | + import { Dropdown } from '/@/components/Dropdown'; | ||
99 | + import { BasicForm, useForm } from '/@/components/Form'; | ||
100 | + import { propTypes } from '/@/utils/propTypes'; | ||
101 | + import { Button } from '/@/components/Button'; | ||
102 | + import { isFunction } from '/@/utils/is'; | ||
103 | + import { useSlider, grid } from './data'; | ||
104 | + // 获取slider属性 | ||
105 | + const sliderProp = computed(() => useSlider(4)); | ||
106 | + // 组件接收参数 | ||
107 | + const props = defineProps({ | ||
108 | + // 请求API的参数 | ||
109 | + params: propTypes.object.def({}), | ||
110 | + //api | ||
111 | + api: propTypes.func, | ||
112 | + }); | ||
113 | + //暴露内部方法 | ||
114 | + const emit = defineEmits(['getMethod', 'delete']); | ||
115 | + //数据 | ||
116 | + const data = ref([]); | ||
117 | + // 切换每行个数 | ||
118 | + // cover图片自适应高度 | ||
119 | + //修改pageSize并重新请求数据 | ||
120 | + | ||
121 | + const height = computed(() => { | ||
122 | + return `h-${120 - grid.value * 6}`; | ||
123 | + }); | ||
124 | + //表单 | ||
125 | + const [registerForm, { validate }] = useForm({ | ||
126 | + schemas: [{ field: 'type', component: 'Input', label: '类型' }], | ||
127 | + labelWidth: 80, | ||
128 | + baseColProps: { span: 6 }, | ||
129 | + actionColOptions: { span: 24 }, | ||
130 | + autoSubmitOnEnter: true, | ||
131 | + submitFunc: handleSubmit, | ||
132 | + }); | ||
133 | + //表单提交 | ||
134 | + async function handleSubmit() { | ||
135 | + const data = await validate(); | ||
136 | + await fetch(data); | ||
137 | + } | ||
138 | + function sliderChange(n) { | ||
139 | + pageSize.value = n * 4; | ||
140 | + fetch(); | ||
141 | + } | ||
142 | + | ||
143 | + // 自动请求并暴露内部方法 | ||
144 | + onMounted(() => { | ||
145 | + fetch(); | ||
146 | + emit('getMethod', fetch); | ||
147 | + }); | ||
148 | + | ||
149 | + async function fetch(p = {}) { | ||
150 | + const { api, params } = props; | ||
151 | + if (api && isFunction(api)) { | ||
152 | + const res = await api({ ...params, page: page.value, pageSize: pageSize.value, ...p }); | ||
153 | + data.value = res.items; | ||
154 | + total.value = res.total; | ||
155 | + } | ||
156 | + } | ||
157 | + //分页相关 | ||
158 | + const page = ref(1); | ||
159 | + const pageSize = ref(36); | ||
160 | + const total = ref(0); | ||
161 | + const paginationProp = ref({ | ||
162 | + showSizeChanger: false, | ||
163 | + showQuickJumper: true, | ||
164 | + pageSize, | ||
165 | + current: page, | ||
166 | + total, | ||
167 | + showTotal: (total) => `总 ${total} 条`, | ||
168 | + onChange: pageChange, | ||
169 | + onShowSizeChange: pageSizeChange, | ||
170 | + }); | ||
171 | + | ||
172 | + function pageChange(p, pz) { | ||
173 | + page.value = p; | ||
174 | + pageSize.value = pz; | ||
175 | + fetch(); | ||
176 | + } | ||
177 | + function pageSizeChange(current, size) { | ||
178 | + pageSize.value = size; | ||
179 | + fetch(); | ||
180 | + } | ||
181 | + | ||
182 | + async function handleDelete(id) { | ||
183 | + emit('delete', id); | ||
184 | + } | ||
185 | +</script> |
src/components/CardList/src/data.ts
0 → 100644
1 | +import { ref } from 'vue'; | ||
2 | +//每行个数 | ||
3 | +export const grid = ref(12); | ||
4 | +// slider属性 | ||
5 | +export const useSlider = (min = 6, max = 12) => { | ||
6 | + // 每行显示个数滑动条 | ||
7 | + const getMarks = () => { | ||
8 | + const l = {}; | ||
9 | + for (let i = min; i < max + 1; i++) { | ||
10 | + l[i] = { | ||
11 | + style: { | ||
12 | + color: '#fff', | ||
13 | + }, | ||
14 | + label: i, | ||
15 | + }; | ||
16 | + } | ||
17 | + return l; | ||
18 | + }; | ||
19 | + return { | ||
20 | + min, | ||
21 | + max, | ||
22 | + marks: getMarks(), | ||
23 | + step: 1, | ||
24 | + }; | ||
25 | +}; |
src/locales/lang/en/routes/demo.ts
@@ -45,6 +45,7 @@ export default { | @@ -45,6 +45,7 @@ export default { | ||
45 | 45 | ||
46 | time: 'Relative Time', | 46 | time: 'Relative Time', |
47 | cropperImage: 'Cropper Image', | 47 | cropperImage: 'Cropper Image', |
48 | + cardList: 'Card List', | ||
48 | }, | 49 | }, |
49 | editor: { | 50 | editor: { |
50 | editor: 'Editor', | 51 | editor: 'Editor', |
src/locales/lang/zh-CN/routes/demo.ts
src/router/routes/modules/demo/comp.ts
@@ -534,6 +534,14 @@ const comp: AppRouteModule = { | @@ -534,6 +534,14 @@ const comp: AppRouteModule = { | ||
534 | title: t('routes.demo.comp.loading'), | 534 | title: t('routes.demo.comp.loading'), |
535 | }, | 535 | }, |
536 | }, | 536 | }, |
537 | + { | ||
538 | + path: 'cardList', | ||
539 | + name: 'CardListDemo', | ||
540 | + component: () => import('/@/views/demo/comp/card-list/index.vue'), | ||
541 | + meta: { | ||
542 | + title: t('routes.demo.comp.cardList'), | ||
543 | + }, | ||
544 | + }, | ||
537 | ], | 545 | ], |
538 | }; | 546 | }; |
539 | 547 |
src/views/demo/comp/card-list/index.vue
0 → 100644
1 | +<template> | ||
2 | + <PageWrapper title="卡片列表示例" content="基础封装"> | ||
3 | + <CardList :params="params" :api="demoListApi" @getMethod="getMethod" @delete="handleDel"> | ||
4 | + <template #header> | ||
5 | + <Button type="primary" color="error"> 按钮1 </Button> | ||
6 | + <Button type="primary" color="success"> 按钮2 </Button> | ||
7 | + </template> | ||
8 | + </CardList> | ||
9 | + </PageWrapper> | ||
10 | +</template> | ||
11 | +<script lang="ts" setup> | ||
12 | + import { CardList } from '/@/components/CardList'; | ||
13 | + import { Button } from '/@/components/Button'; | ||
14 | + import { PageWrapper } from '/@/components/Page'; | ||
15 | + import { demoListApi } from '/@/api/demo/table'; | ||
16 | + import { useMessage } from '/@/hooks/web/useMessage'; | ||
17 | + const { notification } = useMessage(); | ||
18 | + // 请求api时附带参数 | ||
19 | + const params = {}; | ||
20 | + | ||
21 | + let reload = () => {}; | ||
22 | + // 获取内部fetch方法; | ||
23 | + function getMethod(m: any) { | ||
24 | + reload = m; | ||
25 | + } | ||
26 | + //删除按钮事件 | ||
27 | + function handleDel(id) { | ||
28 | + console.log(id); | ||
29 | + notification.success({ message: `成功删除${id}` }); | ||
30 | + reload(); | ||
31 | + } | ||
32 | +</script> |