Vue+Element 仿飞书表格||甘特图表格 ,搜索、筛选、字段管理、卡片管理功能

一、整体效果图

二、选中数据效果

Vue+Element 仿飞书表格||甘特图表格 ,搜索、筛选、字段管理、卡片管理功能_第1张图片

注明:此表格是表头自定义多类型筛选的升级版

  1. 涉及到的组件代码会以链接的形式贴出来
  2. 涉及到的Scss变量、样式、接口方法,请自行调试
  3. 列表的表头及每列数据均由后端返回
  4. 列表当中数据的状态颜色、tag标签均可配置
  5. 效果仅针对记录当前项目功能效果的实现
  6. Zn开头的组件为全局加载,请自行引入加载
  7. 列表无数据或无权限时prop传入图片路径及提示语即可,(此处可优化)
  8. 表格第一列序号与复选框hover切换
  9. 表格上方左侧为视图类别,类似tabs切换,类型不同,展示的数据形式也不同 , 比如下方数据展示有可能是列表, 有可能是card(创建视图功能暂未开发 , 目前只做了类型切换的展示 , 具体样子可去飞书观看一下)

三、页面示例代码

<template>
  <div class="workOrder-container">
    <zn-query-form>
      <zn-query-form-left-panel>
        <zn-views-tabs :options="viewsTabsOptions" @upTable="getHeader" />
      </zn-query-form-left-panel>
      <zn-query-form-right-panel>
        <!-- 搜索 -->
        <zn-search-btn @up-Search="upSearch" />
        <!-- 筛选 -->
        <zn-screen-btn
          ref="ZnScreenBtn"
          :mark="mark"
          :views_id="queryForm.views_id"
          :options="managementOptions"
          @upTable="fetchData"
        />
        <!-- 字段管理 -->
        <zn-field-management-btn
          ref="ZnFieldManagementBtn"
          v-if="viewsType == 'table'"
          :mark="mark"
          :views_id="queryForm.views_id"
          :options="managementOptions"
          @upTable="upTableData"
        />
        <!-- 卡片管理 -->
        <zn-card-management-btn
          ref="ZnCardManagementBtn"
          v-if="viewsType == 'gallery'"
          :mark="mark"
          :views_id="queryForm.views_id"
          :options="managementOptions"
          @upCard="upCardData"
        />
        <!-- 导出全部 -->
        <el-button
          type="primary"
          size="medium"
          plain
          @click="reportAll"
          v-permissions="{
            permission: ['workOrder:workOrder:allWorkOrder:export'],
          }"
        >
          <zn-icon :iconName="'emport'" />
          导出
        </el-button>
        <el-button
          class="el-add"
          type="primary"
          size="medium"
          @click="addWorkOrder"
          v-permissions="{ permission: ['workOrder:allWorkOrder:add'] }"
        >
          <zn-icon :iconName="'callcenter-add'" />
          新建工单
        </el-button>
      </zn-query-form-right-panel>
    </zn-query-form>
    <!-- 相册试图页面 -->
    <div
      v-if="viewsType === 'gallery'"
      class="content-view album-view"
      v-infinite-scroll="loadMore"
      :infinite-scroll-immediate="false"
    >
      <zn-filter-album
        ref="filterAlbum"
        :albumData="tableList"
        :finallyColumns="finallyColumns"
        :deatilsPath="deatilsPath"
        :indexColumn="indexColumn"
        @fetch-data="fetchData"
      />
    </div>
    <!-- 表格试图页面 -->
    <div class="content-view table-view" v-else>
      <zn-filter-table
        v-if="viewsType == 'table'"
        ref="filterTable"
        :class="total === 0 ? 'table-view-empty' : ''"
        :multiple="true"
        :tableData="tableList"
        :finallyColumns="finallyColumns"
        :deatilsPath="deatilsPath"
        @selectList="getSelect"
        @fetch-data="fetchData"
        :defaultPageImgUrl="
          require('@/assets/images/default_page/pic-currency.png')
        "
        :defaultPageTips="'暂无数据'"
      >
        <el-button type="text" size="medium" @click="reportPart">
          <zn-icon :iconName="'emport'" />
          <span>导出选中</span>
        </el-button>
      </zn-filter-table>
      <zn-pagination
        v-show="total > 0"
        :page.sync="queryForm.page"
        :limit.sync="queryForm.listRows"
        @pagination="fetchData"
        :total="total"
        :algin="'right'"
        class="table-pagination"
      />
    </div>
    <add-work-order
      :modalToBody="false"
      :configData="configData"
      ref="addWorkOrder"
    />
  </div>
</template>

<script>
import addWorkOrder from './components/addWorkOrder'
import {
  getList,
  getWorkOrderConfig,
  exportAllExcel,
  exportSelectExcel,
} from '@/api/workOrder'
import { getTableHeader, viewsTabs, filters } from '@/api/index'
export default {
  name: 'WorkOrder',
  props: {},
  components: {
    addWorkOrder,
  },
  data() {
    return {
      mark: 'WorkOrderList',
      configData: null,
      viewsType: '', //当前页面显示视图类型
      total: 0,
      tableList: [],
      viewsTabsOptions: [], // viewsTabs数据
      managementOptions: {}, // 字段、卡片管理数据
      listLoading: false,
      queryForm: {
        page: 1,
        listRows: 10,
        keywords: '',
        views_id: '', //当前页面显示视图ID
      },
      deatilsPath: '/workOrder/workOrderDetail', //表格当前行跳转路径
      columns: [], //筛选条件中的数据
      checkList: [], //筛选条件中选中的数据
      moreList: [], //表格复选多选中的数据
      indexColumn: '', // 相册视图标题字段
    }
  },
  computed: {
    finallyColumns() {
      if (this.checkList.length > 0) {
        return this.columns.filter((item) =>
          this.checkList.includes(item.label)
        )
      }
    },
  },
  watch: {},
  created() {
    this.getConfigData()
    this.getViewsTabs()
  },
  mounted() {},
  methods: {
    // 获取工单配置参数
    getConfigData() {
      getWorkOrderConfig().then((res) => {
        this.configData = res.data
      })
    },
    addWorkOrder() {
      this.$refs['addWorkOrder'].show()
    },
    // 顶栏左侧viewsTabs
    getViewsTabs() {
      viewsTabs({ mark: this.mark }).then((res) => {
        this.viewsTabsOptions = res.data
        if (res.code == 200 && res.data.length > 0) {
          this.queryForm.views_id = res.data[0].id // 更新当前页面显示视图ID
          this.viewsType = res.data[0].type // 更新当前页面显示视图类型
          this.getFilters() //回显筛选
          this.getHeader()
          if (res.data[0].type === 'table') {
            this.fetchData()
          } else {
            this.fetchAlbumData()
          }
        }
      })
    },
    // 获取已保存的筛选规则
    getFilters() {
      filters({ mark: this.mark, views_id: this.queryForm.views_id }).then(
        (res) => {
          if (this.$refs.ZnScreenBtn) {
            this.$refs.ZnScreenBtn.form.filters = res.data.filters
          }
        }
      )
    },
    // 顶栏右侧字段管理、卡片管理
    async getHeader(obj) {
      getTableHeader({
        mark: this.mark,
        views_id: obj ? obj.id : this.queryForm.views_id,
      }).then((res) => {
        this.managementOptions = res.data //字段管理、卡片管理
        this.columns = res.data.fields //table列(未经卡片管理、字段管理筛选的数据)
        this.indexColumn = res.data.options.indexColumn
        if (obj) {
          this.queryForm.views_id = obj.id // 更新当前页面显示视图ID
          this.viewsType = obj.type // 更新当前页面显示视图类型
          this.getFilters() //回显筛选
          // 更新数据
          if (obj.type === 'table') {
            this.fetchData()
          } else {
            this.tableList = []
            this.queryForm.page = 1
            this.loadMore()
          }
        }
        this.managementOptions.fields.map((item) => {
          if (item.isShow == true) {
            this.checkList.push(item.label)
          }
        })
      })
    },
    // 请求table数据
    async fetchData() {
      this.listLoading = true
      const {
        data: { data, total },
      } = await getList(this.queryForm)
      this.tableList = data
      this.total = total
      this.listLoading = false
    },
    // 请求album数据
    async fetchAlbumData() {
      this.listLoading = true
      const {
        data: { data, total, last_page },
      } = await getList(this.queryForm)
      this.tableList = this.tableList.concat(data)
      if (this.queryForm.page >= last_page + 1) {
        this.queryForm.page = last_page + 1
      } else {
        this.queryForm.page = this.queryForm.page + 1
      }
      this.total = total
      this.listLoading = false
    },
    // 更新搜索字段,更新table数据
    upSearch(val) {
      this.tableList = []
      this.queryForm.page = 1
      this.queryForm.keywords = val
      if (this.viewsType === 'table') {
        this.fetchData()
      } else {
        this.loadMore()
      }
    },
    // 获取多选选中的table数据(需求未出,功能暂留)
    getSelect(list) {
      this.moreList = list
    },
    // 卡片管理子组件条件返回,更新表格视图
    upTableData(columns, checkList) {
      this.columns = columns //所有表头
      this.checkList = checkList //对应表头
    },
    // 卡片管理子组件条件返回,更新表格视图
    upCardData(columns, checkList, showLabel) {
      this.columns = columns //所有表头
      this.checkList = checkList //对应表头
      this.showLabel = showLabel //卡片视图中是否显示label
    },
    // 无线加载
    loadMore() {
      this.queryForm.listRows = 6
      this.fetchAlbumData()
    },
    // 导出选中
    reportPart() {
      exportSelectExcel({
        views_id: this.queryForm.views_id,
        ids: this.moreList.map((item) => item.id).join(','),
      }).then((res) => {
        if (res.code === 200) {
          this.$download(res.data)
        }
      })
    },
    // 导出全部
    reportAll() {
      exportAllExcel({
        views_id: this.queryForm.views_id,
        keywords: this.queryForm.keywords,
      }).then((res) => {
        if (res.code === 200) {
          this.$download(res.data)
        }
      })
    },
  },
}
</script>

<style lang="scss" scoped>
.workOrder-container {
  height: calc(100vh - 60px - 50px - 16px * 2);
  ::v-deep .add-workorder-drawer {
    position: absolute;
  }
  .el-add {
    margin-right: 0 !important;
  }
  .content-view {
    height: calc(100% - 55px);
    &.album-view {
      overflow-x: hidden;
      overflow-y: auto;
      padding: 0 16px 16px;
    }
    &.table-view {
      position: relative;
    }
    // 分页样式
    .filter-table {
      height: calc(100% - 69px);
      padding-bottom: 0;
      &.table-view-empty {
        height: 100%;
      }
      ::v-deep .el-table {
        height: 100%;
        .el-table__body-wrapper {
          height: calc(100% - 48px);
          overflow: auto;
        }
      }
    }
  }
}
</style>

四、总结

  1. 功能很强,但是也有局限性,适用于瀑布流开发模式
  2. 页面调用的这个层级其实还可以再封装一层
  3. 有些地方是需要再优化的,由于需求一直在变,也无心高度优化(每个版本都要动这里面的东西,心累)

五、github源码链接

github源码链接,代码中有数据示例

你可能感兴趣的:(前端踩坑合集,vue.js,甘特图,javascript)