kailong321200875 1 жил өмнө
parent
commit
7fa533b8ba

+ 9 - 0
mock/role/index.mock.ts

@@ -158,6 +158,14 @@ const adminList = [
             meta: {
               title: 'router.tableVideoPreview'
             }
+          },
+          {
+            path: 'card-table',
+            component: 'views/Components/Table/CardTable',
+            name: 'CardTable',
+            meta: {
+              title: 'router.cardTable'
+            }
           }
           // {
           //   path: 'ref-table',
@@ -659,6 +667,7 @@ const testList: string[] = [
   '/components/table/table-image-preview',
   '/components/table/table-video-preview',
   '/components/table/ref-table',
+  '/components/table/card-table',
   '/components/editor-demo',
   '/components/editor-demo/editor',
   '/components/editor-demo/json-editor',

+ 55 - 0
mock/table/index.mock.ts

@@ -176,6 +176,39 @@ for (let i = 0; i < count; i++) {
   })
 }
 
+const cardList = [
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/WdGqmHpayyMjiEhcKoVE.png',
+    name: 'Alipay',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/zOsKZmFRdUtvpqCImOVY.png',
+    name: 'Angular',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/siCrBXXhmvTQGWPNLBow.png',
+    name: 'Bootstrap',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/kZzEzemZyKLKFsojXItE.png',
+    name: 'React',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/ComBAopevLwENQdKWiIn.png',
+    name: 'Vue',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  },
+  {
+    logo: 'https://gw.alipayobjects.com/zos/rmsportal/nxkuOJlFJuAUhzlMTCEe.png',
+    name: 'Webpack',
+    desc: '在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,这些类似的组件会被抽离成一套标准规范。'
+  }
+]
+
 export default [
   // 树形列表接口
   {
@@ -294,5 +327,27 @@ export default [
         }
       }
     }
+  },
+  {
+    url: '/mock/card/list',
+    method: 'GET',
+    delay,
+    body: ({ query }) => {
+      const { name, pageIndex, pageSize } = query
+      const mockList = cardList.filter((item) => {
+        if (name && item.name.indexOf(name) < 0) return false
+        return true
+      })
+      const pageList = mockList.filter(
+        (_, index) => index < pageSize * pageIndex && index >= pageSize * (pageIndex - 1)
+      )
+      return {
+        code: SUCCESS_CODE,
+        data: {
+          total: mockList.length,
+          list: pageList
+        }
+      }
+    }
   }
 ]

+ 4 - 0
src/api/table/index.ts

@@ -5,6 +5,10 @@ export const getTableListApi = (params: any) => {
   return request.get({ url: '/mock/example/list', params })
 }
 
+export const getCardTableListApi = (params: any) => {
+  return request.get({ url: '/mock/card/list', params })
+}
+
 export const getTreeTableListApi = (params: any) => {
   return request.get({ url: '/mock/example/treeList', params })
 }

+ 76 - 15
src/components/Table/src/Table.vue

@@ -6,7 +6,9 @@ import {
   ComponentSize,
   ElTooltipProps,
   ElImage,
-  ElButton
+  ElButton,
+  ElEmpty,
+  ElCard
 } from 'element-plus'
 import { defineComponent, PropType, ref, computed, unref, watch, onMounted } from 'vue'
 import { propTypes } from '@/utils/propTypes'
@@ -185,7 +187,25 @@ export default defineComponent({
       default: 'fixed'
     },
     scrollbarAlwaysOn: propTypes.bool.def(false),
-    flexible: propTypes.bool.def(false)
+    flexible: propTypes.bool.def(false),
+    // 自定义内容
+    customContent: propTypes.bool.def(false),
+    cardBodyStyle: {
+      type: Object as PropType<CSSProperties>,
+      default: () => ({})
+    },
+    cardBodyClass: {
+      type: String as PropType<string>,
+      default: ''
+    },
+    cardWrapStyle: {
+      type: Object as PropType<CSSProperties>,
+      default: () => ({})
+    },
+    cardWrapClass: {
+      type: String as PropType<string>,
+      default: ''
+    }
   },
   emits: ['update:pageSize', 'update:currentPage', 'register', 'refresh'],
   setup(props, { attrs, emit, slots, expose }) {
@@ -484,19 +504,60 @@ export default defineComponent({
 
       return (
         <div v-loading={unref(getProps).loading}>
-          {unref(getProps).showAction ? (
-            <TableActions
-              columns={unref(getProps).columns}
-              onChangSize={changSize}
-              onRefresh={refresh}
-            />
-          ) : null}
-          <ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
-            {{
-              default: () => renderTableColumn(),
-              ...tableSlots
-            }}
-          </ElTable>
+          {unref(getProps).customContent ? (
+            <div class="flex flex-wrap">
+              {unref(getProps)?.data?.length ? (
+                unref(getProps)?.data.map((item) => {
+                  const cardSlots = {
+                    default: () => {
+                      return getSlot(slots, 'content', item)
+                    }
+                  }
+                  if (getSlot(slots, 'content-header')) {
+                    cardSlots['header'] = () => {
+                      return getSlot(slots, 'content-header', item)
+                    }
+                  }
+                  if (getSlot(slots, 'content-footer')) {
+                    cardSlots['footer'] = () => {
+                      return getSlot(slots, 'content-footer', item)
+                    }
+                  }
+                  return (
+                    <ElCard
+                      shadow="hover"
+                      class={unref(getProps).cardWrapClass}
+                      style={unref(getProps).cardWrapStyle}
+                      bodyClass={unref(getProps).cardBodyClass}
+                      bodyStyle={unref(getProps).cardBodyStyle}
+                    >
+                      {cardSlots}
+                    </ElCard>
+                  )
+                })
+              ) : (
+                <div class="flex flex-1 justify-center">
+                  <ElEmpty description="暂无数据" />
+                </div>
+              )}
+            </div>
+          ) : (
+            <>
+              {unref(getProps).showAction ? (
+                <TableActions
+                  columns={unref(getProps).columns}
+                  onChangSize={changSize}
+                  onRefresh={refresh}
+                />
+              ) : null}
+              <ElTable ref={elTableRef} data={unref(getProps).data} {...unref(getBindValue)}>
+                {{
+                  default: () => renderTableColumn(),
+                  ...tableSlots
+                }}
+              </ElTable>
+            </>
+          )}
           {unref(getProps).pagination ? (
             <ElPagination
               v-model:pageSize={pageSizeRef.value}

+ 4 - 2
src/locales/en.ts

@@ -181,7 +181,8 @@ export default {
     imageCropping: 'Image cropping',
     videoPlayer: 'Video player',
     // 表格视频预览
-    tableVideoPreview: 'Table video preview'
+    tableVideoPreview: 'Table video preview',
+    cardTable: 'Card table'
   },
   permission: {
     hasPermission: 'Please set the operation permission value'
@@ -457,7 +458,8 @@ export default {
     getSelections: 'Get selections',
     preview: 'Preview',
     showOrHiddenSortable: 'Show or hidden sortable',
-    videoPreview: 'Video preview'
+    videoPreview: 'Video preview',
+    cardTable: 'Card table'
   },
   richText: {
     richText: 'Rich text',

+ 4 - 2
src/locales/zh-CN.ts

@@ -178,7 +178,8 @@ export default {
     waterfall: '瀑布流',
     imageCropping: '图片裁剪',
     videoPlayer: '视频播放器',
-    tableVideoPreview: '表格视频预览'
+    tableVideoPreview: '表格视频预览',
+    cardTable: '卡片表格'
   },
   permission: {
     hasPermission: '请设置操作权限值'
@@ -449,7 +450,8 @@ export default {
     getSelections: '获取多选数据',
     preview: '封面',
     showOrHiddenSortable: '显示/隐藏排序',
-    videoPreview: '视频预览'
+    videoPreview: '视频预览',
+    cardTable: '卡片表格'
   },
   richText: {
     richText: '富文本',

+ 8 - 0
src/router/index.ts

@@ -209,6 +209,14 @@ export const asyncRouterMap: AppRouteRecordRaw[] = [
             meta: {
               title: t('router.tableVideoPreview')
             }
+          },
+          {
+            path: 'card-table',
+            component: () => import('@/views/Components/Table/CardTable.vue'),
+            name: 'CardTable',
+            meta: {
+              title: t('router.cardTable')
+            }
           }
         ]
       },

+ 80 - 0
src/views/Components/Table/CardTable.vue

@@ -0,0 +1,80 @@
+<script setup lang="tsx">
+import { ContentWrap } from '@/components/ContentWrap'
+import { useI18n } from '@/hooks/web/useI18n'
+import { Table } from '@/components/Table'
+import { getCardTableListApi } from '@/api/table'
+import { ref } from 'vue'
+import { ElLink, ElDivider } from 'element-plus'
+
+interface Params {
+  pageIndex?: number
+  pageSize?: number
+}
+
+const { t } = useI18n()
+
+const loading = ref(true)
+
+let tableDataList = ref<any[]>([])
+
+const getTableList = async (params?: Params) => {
+  const res = await getCardTableListApi(
+    params || {
+      pageIndex: 1,
+      pageSize: 10
+    }
+  )
+    .catch(() => {})
+    .finally(() => {
+      loading.value = false
+    })
+  if (res) {
+    tableDataList.value = res.data.list
+  }
+}
+
+getTableList()
+
+const actionClick = (row?: any) => {
+  console.log(row)
+}
+</script>
+
+<template>
+  <ContentWrap :title="t('tableDemo.cardTable')">
+    <Table
+      :columns="[]"
+      :data="tableDataList"
+      :loading="loading"
+      custom-content
+      :card-wrap-style="{
+        width: '200px',
+        marginBottom: '20px',
+        marginRight: '20px'
+      }"
+    >
+      <template #content="row">
+        <div class="flex cursor-pointer">
+          <div class="pr-16px">
+            <img :src="row.logo" class="w-48px h-48px rounded-[50%]" alt="" />
+          </div>
+          <div>
+            <div class="mb-12px font-700 font-size-16px">{{ row.name }}</div>
+            <div class="line-clamp-3 font-size-12px">{{ row.desc }}</div>
+          </div>
+        </div>
+      </template>
+      <template #content-footer="item">
+        <div class="flex justify-center items-center">
+          <div class="flex-1 text-center" @click="() => actionClick(item)">
+            <ElLink :underline="false">操作一</ElLink>
+          </div>
+          <ElDivider direction="vertical" />
+          <div class="flex-1 text-center" @click="() => actionClick(item)">
+            <ElLink :underline="false">操作二</ElLink>
+          </div>
+        </div>
+      </template>
+    </Table>
+  </ContentWrap>
+</template>