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
src/locales/lang/zh-CN/routes/demo.ts
src/router/routes/modules/demo/comp.ts
... | ... | @@ -534,6 +534,14 @@ const comp: AppRouteModule = { |
534 | 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> | ... | ... |