Commit 0f5ddbf1ec777fc238a94bd037d37ea787316757

Authored by JinMao
1 parent 1ddfc31c

feat: add CardList component

src/components/CardList/index.ts 0 → 100644
  1 +import { withInstall } from '/@/utils';
  2 +import cardList from './src/CardList.vue';
  3 +
  4 +export const CardList = withInstall(cardList);
... ...
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 45  
46 46 time: 'Relative Time',
47 47 cropperImage: 'Cropper Image',
  48 + cardList: 'Card List',
48 49 },
49 50 editor: {
50 51 editor: 'Editor',
... ...
src/locales/lang/zh-CN/routes/demo.ts
... ... @@ -44,6 +44,7 @@ export default {
44 44  
45 45 time: '相对时间',
46 46 cropperImage: '图片裁剪',
  47 + cardList: '卡片列表',
47 48 },
48 49 editor: {
49 50 editor: '编辑器',
... ...
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>
... ...