浏览代码

add proCardList

tongshangming 3 年之前
父节点
当前提交
e8f4a913cd
共有 4 个文件被更改,包括 337 次插入0 次删除
  1. 1 0
      src/components.d.ts
  2. 221 0
      src/components/ProCardList.vue
  3. 18 0
      src/router/asyncRouter.ts
  4. 97 0
      src/views/list/CardList.vue

+ 1 - 0
src/components.d.ts

@@ -20,6 +20,7 @@ declare module '@vue/runtime-core' {
     GlobalTabs: typeof import('./components/GlobalTabs.vue')['default']
     OrgLayout: typeof import('./components/org/OrgLayout.vue')['default']
     OrgList: typeof import('./components/org/OrgList.vue')['default']
+    ProCardList: typeof import('./components/ProCardList.vue')['default']
     ProForm: typeof import('./components/form/ProForm.vue')['default']
     ProTable: typeof import('./components/ProTable.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']

+ 221 - 0
src/components/ProCardList.vue

@@ -0,0 +1,221 @@
+<script lang="ts">
+export default {
+  inheritAttrs: false
+}
+</script>
+
+<script setup lang="ts">
+import router from '@/router'
+import { ElMessage, ElMessageBox, type DialogProps } from 'element-plus'
+import type { AdvancedForm, BasicForm, ICRUD } from '@/types/form'
+
+interface Props {
+  crud: ICRUD
+  pageSize?: number
+  formConfig: BasicForm | AdvancedForm
+  dialogConfig?: DialogProps
+  height?: string
+  cardHeight?: string
+  showAdd?: boolean
+}
+
+const props = withDefaults(defineProps<Props>(), {
+  pageSize: 12,
+  showAdd: true,
+  cardHeight: '246px'
+})
+
+const emits = defineEmits(['click-create', 'click-edit'])
+
+// ============== 查询部分开始 ===============
+const query = ref<any>({})
+const searchList = ref<any>([])
+watch(
+  () => props.formConfig.formItems,
+  val => {
+    val.forEach((item: any) => {
+      if (item.group) {
+        searchList.value = searchList.value.concat(item.group.filter((item: any) => item.search))
+      } else {
+        item.search && searchList.value.push(item)
+      }
+    })
+  },
+  { immediate: true }
+)
+
+const handleQuery = () => {
+  curPage.value = 1
+  getTableData()
+}
+const handleReset = () => {
+  query.value = {}
+  handleQuery()
+}
+// ============== 查询部分结束 ===============
+
+// ============== 表格部分开始 ===============
+const tableData = ref<any>([])
+const total = ref(0)
+const curPage = ref(1)
+const loading = ref(false)
+
+const getTableData = () => {
+  loading.value = true
+  props.crud
+    ?.getList({
+      ...query.value,
+      pageSize: props.pageSize,
+      pageNo: curPage.value
+    })
+    .then((res: any) => {
+      console.log('res', res)
+      tableData.value = res.list || res.rows
+      total.value = res.total
+    })
+    .finally(() => {
+      loading.value = false
+    })
+}
+
+watch(
+  curPage,
+  () => {
+    getTableData()
+  },
+  {
+    immediate: true
+  }
+)
+
+const refresh = () => {
+  curPage.value = 1
+  getTableData()
+}
+
+// ============== 表格部分结束 ===============
+
+// ============== crud部分开始 ===============
+const formRoute = ref<any>(props.formConfig.route)
+const handleCreate = () => {
+  emits('click-create')
+  if (formRoute.value) {
+    router.push(formRoute.value)
+  } else {
+    formData.value = {}
+    dialogVisible.value = true
+  }
+}
+const handleUpdate = (row: any) => {
+  emits('click-edit', row)
+  if (formRoute.value) {
+    router.push(formRoute.value)
+  } else {
+    if (props.crud?.getRecord) {
+      props.crud.getRecord({ id: row.id }).then((res: any) => {
+        formData.value = res.data
+      })
+    } else {
+      formData.value = { ...row }
+    }
+    dialogVisible.value = true
+  }
+}
+const handleDelete = (id: string | number) => {
+  ElMessageBox.confirm('您确定要删除该项吗', '提示', {
+    type: 'warning'
+  }).then(async () => {
+    await props.crud?.delete({ id })
+    getTableData()
+    ElMessage({
+      type: 'success',
+      message: '删除成功'
+    })
+  })
+}
+// ============== crud部分结束 ===============
+
+// ============== 表单部分开始 ===============
+const formData = ref<any>({})
+const dialogVisible = ref(false)
+const handleFormSuccess = () => {
+  getTableData()
+}
+// ============== 表单部分结束 ===============
+
+defineExpose({
+  handleCreate,
+  handleDelete,
+  handleUpdate,
+  refresh
+})
+</script>
+
+<template>
+  <div class="flex flex-col" :style="{ height: height || 'calc(100vh - 101px - var(--main-padding) * 2)' }">
+    <el-card class="mb-4" shadow="never" v-if="searchList.length">
+      <el-form :inline="true">
+        <el-form-item :label="item.label" v-for="(item, index) in searchList" :key="index">
+          <form-comp :item="item" v-model="query[item.name]"></form-comp>
+        </el-form-item>
+        <slot name="query" :query="query"></slot>
+        <el-form-item>
+          <el-button type="primary" icon="Search" @click="handleQuery">查询</el-button>
+          <el-button icon="Refresh" @click="handleReset">重置</el-button>
+        </el-form-item>
+      </el-form>
+    </el-card>
+
+    <el-card class="h-full flex-grow-1" :body-style="{ height: '100%' }" shadow="never">
+      <div class="flex flex-col h-full">
+        <slot name="header"></slot>
+
+        <div class="h-full flex-grow">
+          <el-row :gutter="10">
+            <el-col :span="6" v-if="showAdd" class="mb-10">
+              <div
+                class="flex items-center justify-center border border-dashed w-full h-full card-list-item"
+                :style="{ height: cardHeight }"
+              >
+                <el-button link icon="plus" @click="handleCreate">新增</el-button>
+              </div>
+            </el-col>
+            <el-col :span="6" v-for="(item, index) in tableData" :key="item.id" class="mb-10">
+              <el-card :body-style="{ padding: '0px' }" shadow="hover">
+                <slot :item="item" :index="index"></slot>
+              </el-card>
+            </el-col>
+          </el-row>
+        </div>
+        <div class="flex justify-end shrink-0">
+          <el-pagination
+            background
+            layout="prev, pager, next, jumper, total"
+            v-model:current-page="curPage"
+            :page-size="pageSize"
+            :total="total"
+            class="mt-16px"
+          />
+        </div>
+      </div>
+    </el-card>
+
+    <dialog-form
+      v-model="dialogVisible"
+      :dialogConfig="dialogConfig"
+      :formConfig="formConfig"
+      :formData="formData"
+      :create="crud.create"
+      :update="crud.update"
+      @success="handleFormSuccess"
+      v-if="dialogVisible"
+    />
+  </div>
+</template>
+
+<style scoped>
+.card-list-item {
+  border-color: var(--el-border-color-light);
+  border-radius: var(--el-card-border-radius);
+}
+</style>

+ 18 - 0
src/router/asyncRouter.ts

@@ -130,6 +130,24 @@ const asyncRouter: RouteRecordRaw[] = [
       }
     ]
   },
+  {
+    path: '/list',
+    name: 'list',
+    meta: {
+      title: '列表页',
+      icon: 'CircleCheck'
+    },
+    children: [
+      {
+        path: 'cardList',
+        name: 'cardList',
+        component: () => import('@/views/list/CardList.vue'),
+        meta: {
+          title: '卡片列表'
+        }
+      }
+    ]
+  },
   {
     path: '/result',
     name: 'result',

+ 97 - 0
src/views/list/CardList.vue

@@ -0,0 +1,97 @@
+<script setup lang="ts">
+import type { BasicForm, ICRUD } from '@/types/form'
+
+const CRUD: ICRUD = {
+  create(data: any) {
+    console.log(data)
+  },
+  update(data: any) {
+    console.log(data)
+  },
+  getList() {
+    return new Promise(resolve => {
+      resolve({
+        list: [
+          {
+            id: 1,
+            image: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
+            name: '轮播1'
+          },
+          {
+            id: 2,
+            image: 'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png',
+            name: '轮播2'
+          }
+        ],
+        total: 2
+      })
+    })
+  },
+  delete(data: any) {
+    console.log(data)
+  },
+  deleteBatch(data: any) {
+    console.log(data)
+  }
+}
+
+const formConfig = reactive<BasicForm>({
+  span: 24,
+  formItems: [
+    {
+      label: '图片',
+      value: '',
+      name: 'image',
+      type: 'upload',
+      rules: [{ required: true, message: '请上传图片', trigger: 'blur' }],
+      props: {
+        class: 'avatar-uploader',
+        'show-file-list': false
+      }
+    },
+    {
+      label: '标题',
+      value: '',
+      name: 'name',
+      type: 'input',
+      search: true
+    }
+    // {
+    //   label: '跳转地址',
+    //   value: '',
+    //   name: 'src',
+    //   type: 'input'
+    // }
+  ]
+})
+
+const cardList = ref<any>()
+const handleEdit = (item: any) => {
+  cardList.value.handleUpdate(item)
+}
+const handleDelete = (item: any) => {
+  cardList.value.handleDelete(item.id)
+}
+</script>
+
+<template>
+  <pro-card-list :crud="CRUD" :formConfig="formConfig" ref="cardList">
+    <template #default="{ item }">
+      <img :src="item.image" class="block w-full h-200px" />
+      <el-row class="text-center p-10px card-operate">
+        <el-col :span="12">
+          <el-button link icon="edit" @click="handleEdit(item)">编辑</el-button>
+        </el-col>
+        <el-col :span="12">
+          <el-button link icon="delete" @click="handleDelete(item)">删除</el-button>
+        </el-col>
+      </el-row>
+    </template>
+  </pro-card-list>
+</template>
+
+<style lang="scss" scoped>
+.card-operate {
+  border: 1px solid var(--el-border-color-light);
+}
+</style>