分享通过 vxe-table 实现电商系统商品列表页面,包含多行文本、展开子列表功能等

122 阅读2分钟

分享通过 vxe-table 实现电商系统商品列表页面,包含多行文本、展开子列表功能等

具体可以去看官网文档:vxetable.cn
Gitee:gitee.com/x-extends/v…
Github:github.com/x-extends/v…

安装

npm install vxe-pc-ui@4.3.90 vxe-table@4.11.3
// ...
import VxeUI from 'vxe-pc-ui'
import 'vxe-pc-ui/lib/style.css'
import VxeUITable from 'vxe-table'
import 'vxe-table/lib/style.css'
// ...

createApp(App).use(VxeUI).use(VxeUITable).mount('#app')
// ...

效果

table_demo_product.gif

代码

<template>
  <div class="demo-page-wrapper">
    <vxe-grid v-bind="gridOptions" v-on="gridEvents">
      <template #productNameDefault="{ row }">
        <vxe-text-ellipsis status="primary" line-clamp="3" :content="row.productName" href="https://vxeui.com" target="_blank"></vxe-text-ellipsis>
        <div>颜色:{{ row.productColor }} 尺寸:{{ row.productSize }}</div>
      </template>

      <template #productSKUDefault="{ row }">
        <div>SKU:<vxe-text :content="row.productSKU" click-to-copy></vxe-text></div>
        <div>编码:<vxe-text :content="row.productCode" click-to-copy></vxe-text></div>
      </template>

      <template #productAmountDefault="{ row }">
        <div>现价:¥{{ row.productAmount }}</div>
        <div>折扣价:¥{{ row.productDiscountAmount }}</div>
        <div>秒杀价:¥{{ row.productLkAmount }}</div>
      </template>

      <template #productNumDefault="{ row }">
        <div>库存:{{ row.productStoreNum }}</div>
        <div>已上架:{{ row.productAddNum }}</div>
        <div>已下架:{{ row.productRemoveNum }}</div>
      </template>

      <template #productStatusDefault="{ row }">
        <vxe-tag :status="row.productStatus" :content="row.productStatus === 'success' ? '已上架' : '已下架'"></vxe-tag>
      </template>

      <template #productOwnerDefault="{ row }">
        <div>负责人:{{ row.productOwner }}</div>
        <div>创建人:{{ row.createBy }}</div>
        <div>更新人:{{ row.updateBy }}</div>
      </template>

      <template #updateDateDefault="{ row }">
        <div>上架时间:{{ row.addDate }}</div>
        <div>下架时间:{{ row.removeDate }}</div>
        <div>更新时间:{{ row.updateDate }}</div>
        <div>更新时间:{{ row.updateDate }}</div>
      </template>

      <template #expandContent="{ row }">
        <vxe-grid v-bind="subGridOptions" :data="row.subList">
          <template #statusDefault="{ row }">
            <vxe-tag :status="row.status" :content="row.status === 'success' ? '成功' : '失败'"></vxe-tag>
          </template>
        </vxe-grid>
      </template>
    </vxe-grid>
  </div>
</template>

<script setup>
import { reactive } from 'vue'

const productUrlCellRender = reactive({
  name: 'VxeImage',
  props: {
    width: 100,
    height: 100
  }
})

const countRow = reactive({
  checkbox: '合计',
  productName: 0,
  productAmount: 0
})

const gridOptions = reactive({
  border: true,
  loading: false,
  stripe: true,
  showOverflow: true,
  showFooter: true,
  height: '100%',
  cellConfig: {
    height: 140
  },
  columnConfig: {
    resizable: true,
    drag: true
  },
  columnDragConfig: {
    trigger: 'cell',
    showIcon: false
  },
  rowConfig: {
    drag: true
  },
  resizableConfig: {
    isDblclickAutoWidth: true
  },
  expandConfig: {
    padding: true
  },
  formConfig: {
    titleWidth: 80,
    titleAlign: 'right',
    items: [
      { field: 'productName', title: '产品名字', span: 6, itemRender: { name: 'VxeInput' } },
      { field: 'productSKU', title: 'SKU', span: 6, itemRender: { name: 'VxeInput' } },
      { field: 'productCode', title: '产品编码', span: 6, itemRender: { name: 'VxeInput' } },
      { field: 'email', title: '邮箱', span: 6, folding: true, itemRender: { name: 'VxeInput' } },
      { field: 'nickname', title: '昵称', span: 6, folding: true, itemRender: { name: 'VxeInput' } },
      { field: 'startTime', title: '开始时间', span: 6, folding: true, itemRender: { name: 'VxeDatePicker' } },
      { field: 'endTime', title: '结束时间', span: 6, folding: true, itemRender: { name: 'VxeDatePicker' } },
      {
        span: 6,
        collapseNode: true,
        itemRender: {
          name: 'VxeButtonGroup',
          options: [
            { type: 'submit', content: '查询', status: 'primary', icon: 'vxe-icon-search' },
            { type: 'reset', content: '重置', icon: 'vxe-icon-repeat' }
          ]
        }
      }
    ]
  },
  toolbarConfig: {
    custom: true,
    refresh: true,
    zoom: true
  },
  checkboxConfig: {
    range: true
  },
  mouseConfig: {
    selected: true
  },
  keyboardConfig: {
    isEdit: true,
    isArrow: true,
    isEnter: true,
    isBack: true,
    isDel: true,
    isEsc: true
  },
  pagerConfig: {
    pageSize: 100,
    pageSizes: [3, 20, 100, 500, 1000, 5000, 10000, 50000, 100000]
  },
  scrollX: {
    gt: 0,
    enabled: true
  },
  scrollY: {
    gt: 0,
    mode: 'wheel',
    enabled: true
  },
  columns: [
    { field: 'checkbox', type: 'checkbox', width: 60, align: 'center' },
    { field: 'seq', type: 'seq', width: 100, align: 'center', dragSort: true },
    { field: 'expand', type: 'expand', width: 60, align: 'center', slots: { content: 'expandContent' } },
    { field: 'productUrl', title: '产品图片', width: 160, align: 'center', cellRender: productUrlCellRender },
    { field: 'productName', title: '产品名称', minWidth: 200, slots: { default: 'productNameDefault' } },
    { field: 'productSKU', title: 'SKU', minWidth: 200, slots: { default: 'productSKUDefault' } },
    { field: 'productAmount', title: '价格', width: 160, slots: { default: 'productAmountDefault' } },
    { field: 'productNum', title: '数量', width: 120, slots: { default: 'productNumDefault' } },
    { field: 'productStatus', title: '状态', width: 100, align: 'center', slots: { default: 'productStatusDefault' } },
    { field: 'productOwner', title: '负责人', width: 160, slots: { default: 'productOwnerDefault' } },
    { field: 'updateDate', title: '更新时间', width: 240, slots: { default: 'updateDateDefault' } }
  ],
  proxyConfig: {
    response: {
      result: 'data',
      total: 'total'
    },
    ajax: {
      query ({ page }) {
        // 调用后端接口,返回 { total: 1000, data: [] }
        return axios.get(`https://vxeui.com/test/list/${page.pageSize}/${page.currentPage}`).then(res => res.data)
      }
    }
  },
  footerData: [
    countRow
  ]
})

const gridEvents = {
  pageChange ({ pageSize }) {
    gridOptions.pagerConfig.pageSize = pageSize
  },
  proxyQuery () {
    updateFooterCount()
  }
}

const imgUrlCellRender = reactive({
  name: 'VxeImage',
  props: {
    width: 40,
    height: 40
  }
})

const subGridOptions = reactive({
  border: true,
  showOverflow: true,
  columns: [
    { field: 'imgUrl', title: '关联产品', width: 80, align: 'center', cellRender: imgUrlCellRender },
    { field: 'name', title: '名称' },
    { field: 'storeNum', title: '库存', width: 120, align: 'center' },
    { field: 'status', title: '状态', width: 120, align: 'center', slots: { default: 'statusDefault' } },
    { field: 'color', title: '颜色', width: 120, align: 'center' },
    { field: 'size', title: '尺寸', width: 120, align: 'center' }
  ]
})

const updateFooterCount = () => {
  countRow.productName = 999
  countRow.productAmount = 888
}
</script>