VueTable
This commit is contained in:
		
							
								
								
									
										108
									
								
								vue-table/components/HeaderQuery.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								vue-table/components/HeaderQuery.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,108 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * @Author: your name
 | 
			
		||||
 * @Date: 2020-10-21 14:22:25
 | 
			
		||||
 * @LastEditTime: 2021-02-04 15:46:01
 | 
			
		||||
 * @LastEditors: Please set LastEditors
 | 
			
		||||
 * @Description: In User Settings Edit
 | 
			
		||||
 * @FilePath: \dbadmin\src\components\HeaderQueryForm.vue
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="header-query__component">
 | 
			
		||||
    <el-form
 | 
			
		||||
      :model="form"
 | 
			
		||||
      :rules="rules"
 | 
			
		||||
      label-position="left"
 | 
			
		||||
      :label-width="labelWidth"
 | 
			
		||||
      :size="size"
 | 
			
		||||
      @keydown.enter.native.prevent="request"
 | 
			
		||||
      inline
 | 
			
		||||
      v-bind="$attrs"
 | 
			
		||||
    >
 | 
			
		||||
      <slot></slot>
 | 
			
		||||
      <el-button v-if="btn" type="primary" :size="size" @click="request">
 | 
			
		||||
        {{ queryLabel }}
 | 
			
		||||
      </el-button>
 | 
			
		||||
    </el-form>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { Component, Prop, Emit } from 'vue-property-decorator'
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import { getModule } from 'vuex-module-decorators'
 | 
			
		||||
import QueryStore, { DEFAULT_TAG as DEFAULT_QUERY_TAG } from '@/store/modules/query'
 | 
			
		||||
 | 
			
		||||
import store from '@/store'
 | 
			
		||||
const queryStore = getModule(QueryStore, store)
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  name: 'HeaderQuery'
 | 
			
		||||
})
 | 
			
		||||
export default class HeaderQuery extends Vue {
 | 
			
		||||
  @Prop({ type: String, default: DEFAULT_QUERY_TAG })
 | 
			
		||||
  tag
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Object, required: true })
 | 
			
		||||
  form
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Object, default: () => ({}) })
 | 
			
		||||
  rules
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: String, default: 'mini' })
 | 
			
		||||
  size
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: String, default: '查询' })
 | 
			
		||||
  queryLabel
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Boolean, default: true })
 | 
			
		||||
  btn
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Boolean, default: true })
 | 
			
		||||
  cache
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: String, default: undefined })
 | 
			
		||||
  labelWidth
 | 
			
		||||
 | 
			
		||||
  pageData = null
 | 
			
		||||
 | 
			
		||||
  get storeData() {
 | 
			
		||||
    return queryStore.data[this.path][this.tag] || {}
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set storeData(data) {
 | 
			
		||||
    queryStore.setData({ path: this.path, data, tag: this.tag })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get path() {
 | 
			
		||||
    return this.$route.path
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get fetch() {
 | 
			
		||||
    return queryStore.fetchs[this.path][this.tag]
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  created() {
 | 
			
		||||
    queryStore.init({ tag: this.tag, path: this.path, initData: Object.assign({}, this.form) })
 | 
			
		||||
    this.pageData = queryStore.pageData[this.path][this.tag]
 | 
			
		||||
    this.emitUpdateQuery()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 触发外部更新值
 | 
			
		||||
   */
 | 
			
		||||
  @Emit('update:form')
 | 
			
		||||
  emitUpdateQuery() {
 | 
			
		||||
    return Object.assign({}, this.storeData)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Emit('submit')
 | 
			
		||||
  async request() {
 | 
			
		||||
    this.pageData.page = 1
 | 
			
		||||
    this.storeData = this.form
 | 
			
		||||
    this.fetch()
 | 
			
		||||
    return this.storeData
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped></style>
 | 
			
		||||
							
								
								
									
										556
									
								
								vue-table/components/Table.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										556
									
								
								vue-table/components/Table.vue
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,556 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * @Author: your name
 | 
			
		||||
 * @Date: 2020-09-08 16:22:26
 | 
			
		||||
 * @LastEditTime: 2021-02-04 16:52:15
 | 
			
		||||
 * @LastEditors: Please set LastEditors
 | 
			
		||||
 * @Description: In User Settings Edit
 | 
			
		||||
 * @FilePath: \dbadmin\src\components\TableForm\Table.vue
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="table__component" ref="root" :style="rootStyle">
 | 
			
		||||
    <el-button-group>
 | 
			
		||||
      <!-- 普通功能按钮插槽 -->
 | 
			
		||||
      <slot
 | 
			
		||||
        name="btns"
 | 
			
		||||
        :selectable="multiselect && selectedRows.length > 0"
 | 
			
		||||
        :disabled="!multiselect || selectedRows.length === 0"
 | 
			
		||||
        :selectrows="selectedRows"
 | 
			
		||||
        :multiStepAction="multiStepReq"
 | 
			
		||||
      ></slot>
 | 
			
		||||
 | 
			
		||||
      <!-- 数据导出按钮插槽 -->
 | 
			
		||||
      <slot v-if="allowExport" name="export-btn" :disabled="selectedRows.length === 0" :action="exportData" :loading="exporting"></slot>
 | 
			
		||||
    </el-button-group>
 | 
			
		||||
 | 
			
		||||
    <el-table
 | 
			
		||||
      :data="list"
 | 
			
		||||
      @selection-change="onSelectionChange"
 | 
			
		||||
      @current-change="$emit('current-change', $event)"
 | 
			
		||||
      ref="table"
 | 
			
		||||
      :height="tableHeight"
 | 
			
		||||
      v-loading="loading"
 | 
			
		||||
      :span-method="SpanMethod"
 | 
			
		||||
      :default-expand-all="expandAll"
 | 
			
		||||
      :class="tableClass"
 | 
			
		||||
      v-bind="tableOptions"
 | 
			
		||||
    >
 | 
			
		||||
      <el-table-column v-if="enableDrag" v-bind="dragColumnOptions">
 | 
			
		||||
        <i slot-scope="{ row }" class="el-icon-s-fold handle" style="font-size: 16px; cursor: move"></i>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <el-table-column type="selection" v-if="multiselect || allowExport" />
 | 
			
		||||
      <slot></slot>
 | 
			
		||||
    </el-table>
 | 
			
		||||
 | 
			
		||||
    <!-- 分页 -->
 | 
			
		||||
    <div v-if="visiblePage" class="page">
 | 
			
		||||
      <el-pagination
 | 
			
		||||
        :total="total"
 | 
			
		||||
        :page-size="size"
 | 
			
		||||
        background
 | 
			
		||||
        layout="sizes, prev, pager, next"
 | 
			
		||||
        :current-page.sync="currentPage"
 | 
			
		||||
        :page-sizes="[...(isDev ? [1, 2, 5] : []), 10, 20, 50, 100, 200]"
 | 
			
		||||
        @size-change="onSizeChange"
 | 
			
		||||
      ></el-pagination>
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { get, del as RequestDelete } from '@/utils/request'
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import { Component, Prop, Watch, Ref, ProvideReactive, Provide } from 'vue-property-decorator'
 | 
			
		||||
import { toTime, toDateTime, toDate } from '@/utils/util'
 | 
			
		||||
import { downloadXlsx } from '@/utils/excel'
 | 
			
		||||
import { debounce } from 'underscore'
 | 
			
		||||
import { getModule } from 'vuex-module-decorators'
 | 
			
		||||
import QueryStore, { DEFAULT_TAG as DEFAULT_QUERY_TAG } from '@/store/modules/query'
 | 
			
		||||
import Sortable from 'sortablejs'
 | 
			
		||||
 | 
			
		||||
// Table组件只读取不写vuex里面的查询参数,但会修改分页参数(入currentPage,pageSize)
 | 
			
		||||
import store from '@/store'
 | 
			
		||||
const queryStore = getModule(QueryStore, store)
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  name: 'Table'
 | 
			
		||||
})
 | 
			
		||||
export default class Table extends Vue {
 | 
			
		||||
  @Prop({ type: Boolean, default: false })
 | 
			
		||||
  enableDrag
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Object, default: () => ({}) })
 | 
			
		||||
  dragColumnOptions
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Object, default: () => ({}) })
 | 
			
		||||
  tableOptions
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Boolean, default: false })
 | 
			
		||||
  expandAll
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: String })
 | 
			
		||||
  tableClass
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Boolean, default: false })
 | 
			
		||||
  multiselect
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Boolean, default: true })
 | 
			
		||||
  visiblePage
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Function })
 | 
			
		||||
  responseHandler
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 是否允许导出数据
 | 
			
		||||
   */
 | 
			
		||||
  @Prop({ type: Boolean, default: false })
 | 
			
		||||
  allowExport
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 导出数据时需要特殊处理的字段
 | 
			
		||||
   * {
 | 
			
		||||
   *  [字段名]:处理方式
 | 
			
		||||
   * }
 | 
			
		||||
   */
 | 
			
		||||
  @Prop({ type: Object, default: () => ({}) })
 | 
			
		||||
  exportSpecialField
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: String, required: true })
 | 
			
		||||
  api
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: Function })
 | 
			
		||||
  SpanMethod
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: [String, Number] })
 | 
			
		||||
  height
 | 
			
		||||
 | 
			
		||||
  @Prop({ type: String, default: DEFAULT_QUERY_TAG })
 | 
			
		||||
  tag
 | 
			
		||||
 | 
			
		||||
  @Ref('table')
 | 
			
		||||
  tableRef
 | 
			
		||||
 | 
			
		||||
  @Ref('root')
 | 
			
		||||
  rootRef
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 当前页码
 | 
			
		||||
   */
 | 
			
		||||
  // currentPage = 1
 | 
			
		||||
 | 
			
		||||
  get currentPage() {
 | 
			
		||||
    if (!this.pageData) return 1
 | 
			
		||||
    if (!this.pageData.page) this.pageData.page = 1
 | 
			
		||||
    return this.pageData.page
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set currentPage(page) {
 | 
			
		||||
    if (!this.pageData) return
 | 
			
		||||
    this.pageData.page = page
 | 
			
		||||
    return page
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // size = 20
 | 
			
		||||
 | 
			
		||||
  get size() {
 | 
			
		||||
    if (!this.pageData) return 20
 | 
			
		||||
    if (!this.pageData.size) this.pageData.size = 20
 | 
			
		||||
    return this.pageData.size
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set size(size) {
 | 
			
		||||
    if (!this.pageData) return
 | 
			
		||||
    this.pageData.size = size
 | 
			
		||||
    return size
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 列表数据
 | 
			
		||||
   */
 | 
			
		||||
  @ProvideReactive('table_data')
 | 
			
		||||
  list = []
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 列表数据是否加载中
 | 
			
		||||
   */
 | 
			
		||||
  loading = false
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 列表数据总长度
 | 
			
		||||
   */
 | 
			
		||||
  total = 1
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 选中的行
 | 
			
		||||
   */
 | 
			
		||||
  selectedRows = []
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 数据导出处理中
 | 
			
		||||
   */
 | 
			
		||||
  exporting = false
 | 
			
		||||
 | 
			
		||||
  rootHeight = null
 | 
			
		||||
 | 
			
		||||
  tableHeightData = 50
 | 
			
		||||
 | 
			
		||||
  get tableHeight() {
 | 
			
		||||
    if (this.propHeightOk) {
 | 
			
		||||
      return this.height
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this.tableHeightData
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get propHeightOk() {
 | 
			
		||||
    return ['string', 'number'].includes(typeof this.height)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get rootStyle() {
 | 
			
		||||
    const style = {}
 | 
			
		||||
    if (this.rootHeight) {
 | 
			
		||||
      style.height = `${this.rootHeight}px`
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return style
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pageData = {}
 | 
			
		||||
 | 
			
		||||
  get path() {
 | 
			
		||||
    return this.$route.path
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async created() {
 | 
			
		||||
    queryStore.init({ path: this.path, tag: this.tag })
 | 
			
		||||
    queryStore.registerFetch({ path: this.path, func: this.fetch, tag: this.tag })
 | 
			
		||||
 | 
			
		||||
    this.$set(this, 'pageData', queryStore.pageData[this.$route.path][this.tag])
 | 
			
		||||
    await this.fetch()
 | 
			
		||||
    this.resizeHeight()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async mounted() {
 | 
			
		||||
    this.initSortable()
 | 
			
		||||
    window.addEventListener('resize', this.resizeHeight)
 | 
			
		||||
    await this.$nextTick()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  initSortable() {
 | 
			
		||||
    if (!this.enableDrag) return
 | 
			
		||||
    const tbody = this.tableRef.$el.querySelector('.el-table__body-wrapper table tbody')
 | 
			
		||||
    if (!tbody) return
 | 
			
		||||
 | 
			
		||||
    const onEnd = async event => {
 | 
			
		||||
      const list = this.list.splice(0)
 | 
			
		||||
      await this.$nextTick()
 | 
			
		||||
      const { oldIndex, newIndex } = event
 | 
			
		||||
      const oldObj = list[oldIndex]
 | 
			
		||||
      const newObj = list[newIndex]
 | 
			
		||||
      oldObj.sort = newIndex
 | 
			
		||||
      newObj.sort = oldIndex
 | 
			
		||||
      list[oldIndex] = newObj
 | 
			
		||||
      list[newIndex] = oldObj
 | 
			
		||||
      this.list.push(...list)
 | 
			
		||||
      this.$emit('sort', this.list)
 | 
			
		||||
      this.$emit('sort-change', { newObj, oldObj })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    new Sortable(tbody, {
 | 
			
		||||
      group: `TableComponent:${this._uid}`,
 | 
			
		||||
      handle: '.el-icon-s-fold.handle',
 | 
			
		||||
      draggable: 'tr.el-table__row',
 | 
			
		||||
      onEnd
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Watch('api')
 | 
			
		||||
  onWatchApiChange(api) {
 | 
			
		||||
    this.currentPage = 1
 | 
			
		||||
    this.fetch()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  beforeDestroy() {
 | 
			
		||||
    window.removeEventListener('resize', this.resizeHeight)
 | 
			
		||||
    queryStore.unregisterFetch(this.path, this.tag)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async setHeight() {
 | 
			
		||||
    if (this.propHeightOk) return
 | 
			
		||||
    if (!this.tableRef) await this.$nextTick()
 | 
			
		||||
    if (!this.tableRef || !this.tableRef.$el) return
 | 
			
		||||
    this.rootHeight = document.body.clientHeight - this.tableRef.$el.offsetTop - 60
 | 
			
		||||
    this.tableHeightData = this.rootHeight - 85
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resizeHeight = debounce(this.setHeight.bind(this), 300)
 | 
			
		||||
 | 
			
		||||
  @Watch('currentPage')
 | 
			
		||||
  /**
 | 
			
		||||
   * 页码有变化时获取数据
 | 
			
		||||
   */
 | 
			
		||||
  onWatchCurrentPageChange(page) {
 | 
			
		||||
    this.fetch()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onSizeChange(size) {
 | 
			
		||||
    this.size = size
 | 
			
		||||
    this.currentPage = 1
 | 
			
		||||
    this.fetch()
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  onSelectionChange(rows) {
 | 
			
		||||
    this.$emit('selection-change', rows)
 | 
			
		||||
    this.$set(this, 'selectedRows', rows)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 导出数据
 | 
			
		||||
   * @param {string} name 工作薄名
 | 
			
		||||
   * @param {string} filename 文件名
 | 
			
		||||
   * @param {Array} 英文字段-中文转换表
 | 
			
		||||
   */
 | 
			
		||||
  exportData(name, filename, fields) {
 | 
			
		||||
    if (this.exporting) return
 | 
			
		||||
    this.exporting = true
 | 
			
		||||
    const data = this.selectedRows.map(item => {
 | 
			
		||||
      const result = {}
 | 
			
		||||
 | 
			
		||||
      fields.forEach(([en, cn]) => {
 | 
			
		||||
        result[cn] = item[en]
 | 
			
		||||
 | 
			
		||||
        // 特殊处理的字段
 | 
			
		||||
        if (en in this.exportSpecialField) {
 | 
			
		||||
          const type = this.exportSpecialField[en]
 | 
			
		||||
          switch (type) {
 | 
			
		||||
            case 'time':
 | 
			
		||||
              result[cn] = toTime(result[cn])
 | 
			
		||||
              return
 | 
			
		||||
            case 'date-time':
 | 
			
		||||
              result[cn] = toDateTime(result[cn])
 | 
			
		||||
              return
 | 
			
		||||
            case 'date':
 | 
			
		||||
              result[cn] = toDate(result[cn])
 | 
			
		||||
              return
 | 
			
		||||
            default:
 | 
			
		||||
              break
 | 
			
		||||
          }
 | 
			
		||||
        } else if (typeof result[cn] === 'boolean') {
 | 
			
		||||
          result[cn] = result[cn] ? '是' : '否'
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
 | 
			
		||||
      return result
 | 
			
		||||
    })
 | 
			
		||||
    downloadXlsx(
 | 
			
		||||
      {
 | 
			
		||||
        [name]: data
 | 
			
		||||
      },
 | 
			
		||||
      filename
 | 
			
		||||
    )
 | 
			
		||||
    this.exporting = false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 获取列表数据
 | 
			
		||||
   */
 | 
			
		||||
  @Provide('fetch')
 | 
			
		||||
  async fetch(query) {
 | 
			
		||||
    if (this.loading) return
 | 
			
		||||
    this.loading = true
 | 
			
		||||
    let data, params
 | 
			
		||||
 | 
			
		||||
    if (query) {
 | 
			
		||||
      this.currentPage = 1
 | 
			
		||||
      params = query
 | 
			
		||||
    } else {
 | 
			
		||||
      params = queryStore.data[this.path][this.tag]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Object.entries(params).forEach(([key, value]) => {
 | 
			
		||||
      if ([undefined, NaN, null, ''].includes(value) || key === '__ob__') {
 | 
			
		||||
        delete params[key]
 | 
			
		||||
      }
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    const page_params = {}
 | 
			
		||||
 | 
			
		||||
    if (this.visiblePage) {
 | 
			
		||||
      page_params.limit = this.size
 | 
			
		||||
      page_params.page = this.currentPage
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      data = await get(this.api, {
 | 
			
		||||
        params: {
 | 
			
		||||
          ...params,
 | 
			
		||||
          ...page_params
 | 
			
		||||
        }
 | 
			
		||||
      })
 | 
			
		||||
      this.$emit('response', data)
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      this.loading = false
 | 
			
		||||
      return
 | 
			
		||||
    }
 | 
			
		||||
    this.total = data.count
 | 
			
		||||
    this.currentPage = data.page || data.currentPage
 | 
			
		||||
    const list = data.results.map(detail => {
 | 
			
		||||
      if (detail.created_time) {
 | 
			
		||||
        detail.created_time = toDateTime(detail.created_time)
 | 
			
		||||
      }
 | 
			
		||||
      if (detail.date_joined) {
 | 
			
		||||
        detail.date_joined = toDateTime(detail.date_joined)
 | 
			
		||||
      }
 | 
			
		||||
      if (detail.release_time) {
 | 
			
		||||
        detail.release_time = toDateTime(detail.release_time)
 | 
			
		||||
      }
 | 
			
		||||
      if (this.responseHandler) return this.responseHandler(detail)
 | 
			
		||||
      return detail
 | 
			
		||||
    })
 | 
			
		||||
    this.$emit('fetch-success', list)
 | 
			
		||||
    this.list.splice(0)
 | 
			
		||||
    this.$set(this, 'list', list)
 | 
			
		||||
    await this.$nextTick()
 | 
			
		||||
    this.$emit('get-table-ref', this.$refs.table)
 | 
			
		||||
    this.loading = false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 下一页
 | 
			
		||||
   */
 | 
			
		||||
  nextPage() {
 | 
			
		||||
    this.currentPage++
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 上一页
 | 
			
		||||
   */
 | 
			
		||||
  prevPage() {
 | 
			
		||||
    this.currentPage--
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 重置当前页码
 | 
			
		||||
   */
 | 
			
		||||
  resetPage() {
 | 
			
		||||
    this.currentPage = 1
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 切换某行某列的布尔值
 | 
			
		||||
   * @param {number} rowIndex 行
 | 
			
		||||
   * @param {string} name 字段
 | 
			
		||||
   * @param {boolean} status 修改的布尔值
 | 
			
		||||
   */
 | 
			
		||||
  toggleColumnBoolean(rowIndex, name, status) {
 | 
			
		||||
    const detail = this.list[rowIndex]
 | 
			
		||||
    if (!detail) throw new Error(`列${rowIndex}不存在`)
 | 
			
		||||
    if (typeof detail[name] !== 'boolean') throw new Error(`列${rowIndex}-键${name}不是布尔值`)
 | 
			
		||||
    const oldValue = detail[name]
 | 
			
		||||
    detail[name] = status
 | 
			
		||||
    this.$emit('column-bool-change', {
 | 
			
		||||
      row: rowIndex,
 | 
			
		||||
      name,
 | 
			
		||||
      value: status,
 | 
			
		||||
      oldValue
 | 
			
		||||
    })
 | 
			
		||||
    return status
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 设置某行某列的值
 | 
			
		||||
   * @param {number} rowIndex 行
 | 
			
		||||
   * @param {string} name 字段
 | 
			
		||||
   * @param {any} value 修改的值
 | 
			
		||||
   */
 | 
			
		||||
  setColumnValue(rowIndex, name, value) {
 | 
			
		||||
    const detail = this.list[rowIndex]
 | 
			
		||||
    if (!detail) throw new Error(`列${rowIndex}不存在`)
 | 
			
		||||
    const oldValue = detail[name]
 | 
			
		||||
    detail[name] = value
 | 
			
		||||
    this.$emit('column-value-change', {
 | 
			
		||||
      row: rowIndex,
 | 
			
		||||
      name,
 | 
			
		||||
      value,
 | 
			
		||||
      oldValue
 | 
			
		||||
    })
 | 
			
		||||
    return value
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 格式化日期对象
 | 
			
		||||
   * @param {string|Date} date 日期对象/字符串
 | 
			
		||||
   * @returns {string}
 | 
			
		||||
   */
 | 
			
		||||
  formatDate(date, time = true) {
 | 
			
		||||
    return time ? toDateTime(date) : toDate(date)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 格式化日期对象
 | 
			
		||||
   * @param {string|Date} date 日期对象/字符串
 | 
			
		||||
   * @returns {string}
 | 
			
		||||
   */
 | 
			
		||||
  formatTime(date) {
 | 
			
		||||
    return toTime(date)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 调用删除接口
 | 
			
		||||
   * @param {string} api 接口地址
 | 
			
		||||
   * @param {string} message 提示消息
 | 
			
		||||
   * @returns {Promise<boolean>} 是否删除成功
 | 
			
		||||
   */
 | 
			
		||||
  async del(api, message = '是否确认删除') {
 | 
			
		||||
    await this.$confirm(message)
 | 
			
		||||
    try {
 | 
			
		||||
      await RequestDelete(api)
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.error(`
 | 
			
		||||
Table组件调用删除接口失败
 | 
			
		||||
接口地址   ${api}
 | 
			
		||||
原因:
 | 
			
		||||
${err.message || err}
 | 
			
		||||
`)
 | 
			
		||||
      return false
 | 
			
		||||
    }
 | 
			
		||||
    this.fetch()
 | 
			
		||||
    return true
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async multiStepReq(ids, req, options = {}) {
 | 
			
		||||
    const baseOptions = {
 | 
			
		||||
      confirmMessage: '是否确认此操作?',
 | 
			
		||||
      successMessage: '批量操作成功'
 | 
			
		||||
    }
 | 
			
		||||
    options = Object.assign({}, baseOptions, options)
 | 
			
		||||
    await this.$confirm(options.confirmMessage)
 | 
			
		||||
    for (const id of ids) {
 | 
			
		||||
      await req(id, this.selectedRows)
 | 
			
		||||
    }
 | 
			
		||||
    this.$message.success(options.successMessage)
 | 
			
		||||
    this.fetch()
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style lang="scss" scoped>
 | 
			
		||||
.page {
 | 
			
		||||
  display: flex;
 | 
			
		||||
  justify-content: center;
 | 
			
		||||
  margin-top: 1em;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
.mo3 {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  -webkit-line-clamp: 3;
 | 
			
		||||
  -webkit-box-orient: vertical;
 | 
			
		||||
  display: -webkit-box;
 | 
			
		||||
  text-overflow: ellipsis;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.el-tooltip__popper {
 | 
			
		||||
  max-width: 500px;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										27
									
								
								vue-table/store/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vue-table/store/index.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
/*
 | 
			
		||||
 * @Author: your name
 | 
			
		||||
 * @Date: 2020-09-07 10:17:01
 | 
			
		||||
 * @LastEditTime: 2021-02-18 14:51:58
 | 
			
		||||
 * @LastEditors: Please set LastEditors
 | 
			
		||||
 * @Description: In User Settings Edit,
 | 
			
		||||
 * @FilePath: \dbadmin\src\store\index.js
 | 
			
		||||
 */
 | 
			
		||||
import Vue from 'vue'
 | 
			
		||||
import Vuex from 'vuex'
 | 
			
		||||
import query from './modules/query'
 | 
			
		||||
 | 
			
		||||
Vue.use(Vuex)
 | 
			
		||||
 | 
			
		||||
const store = new Vuex.Store({
 | 
			
		||||
  modules: {
 | 
			
		||||
    app,
 | 
			
		||||
    api,
 | 
			
		||||
    user,
 | 
			
		||||
    tagsView,
 | 
			
		||||
    permission,
 | 
			
		||||
    query
 | 
			
		||||
  },
 | 
			
		||||
  getters
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export default store
 | 
			
		||||
							
								
								
									
										88
									
								
								vue-table/store/modules/query.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								vue-table/store/modules/query.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
/*
 | 
			
		||||
 * @Author: your name
 | 
			
		||||
 * @Date: 2020-10-28 14:40:52
 | 
			
		||||
 * @LastEditTime: 2020-12-29 14:33:05
 | 
			
		||||
 * @LastEditors: Please set LastEditors
 | 
			
		||||
 * @Description: In User Settings Edit
 | 
			
		||||
 * @FilePath: \dbadmin\src\store\modules\query.js
 | 
			
		||||
 */
 | 
			
		||||
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
 | 
			
		||||
 | 
			
		||||
export const DEFAULT_TAG = 'default'
 | 
			
		||||
 | 
			
		||||
function nullObj() {
 | 
			
		||||
  return Object.create(null)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Module({ name: 'query', namespaced: true })
 | 
			
		||||
class Query extends VuexModule {
 | 
			
		||||
  data = nullObj()
 | 
			
		||||
 | 
			
		||||
  pageData = nullObj()
 | 
			
		||||
 | 
			
		||||
  fetchs = nullObj()
 | 
			
		||||
 | 
			
		||||
  @Mutation
 | 
			
		||||
  init(data) {
 | 
			
		||||
    let path = ''
 | 
			
		||||
    let initData = nullObj()
 | 
			
		||||
    let tag = DEFAULT_TAG
 | 
			
		||||
    if (typeof data === 'string') {
 | 
			
		||||
      path = data
 | 
			
		||||
    } else if (typeof data === 'object') {
 | 
			
		||||
      if (data.path) path = data.path
 | 
			
		||||
      if (data.initData) initData = data.initData
 | 
			
		||||
      if (data.tag) tag = data.tag
 | 
			
		||||
    }
 | 
			
		||||
    if (!path) throw new Error('path不能为空')
 | 
			
		||||
    initPath.call(this, path)
 | 
			
		||||
    if (!this.data[path][tag]) {
 | 
			
		||||
      this.data[path][tag] = initData
 | 
			
		||||
    }
 | 
			
		||||
    if (!this.pageData[path][tag]) {
 | 
			
		||||
      this.pageData[path][tag] = {
 | 
			
		||||
        page: 1,
 | 
			
		||||
        size: 20
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Mutation
 | 
			
		||||
  setData({ path, data, tag = DEFAULT_TAG }) {
 | 
			
		||||
    initPath.call(this, path)
 | 
			
		||||
    this.data[path][tag] = data
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Mutation
 | 
			
		||||
  registerFetch({ path, func, tag = DEFAULT_TAG }) {
 | 
			
		||||
    initPath.call(this, path)
 | 
			
		||||
    this.fetchs[path][tag] = func
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  @Mutation
 | 
			
		||||
  unregisterFetch(path, tag = DEFAULT_TAG) {
 | 
			
		||||
    initPath.call(this, path)
 | 
			
		||||
    delete this.fetchs[path][tag]
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function initPath(path) {
 | 
			
		||||
  if (this instanceof Window) {
 | 
			
		||||
    throw new Error('initPath this对象没有绑定')
 | 
			
		||||
  }
 | 
			
		||||
  if (!this.data[path]) this.data[path] = nullObj()
 | 
			
		||||
  if (!this.pageData[path]) this.pageData[path] = nullObj()
 | 
			
		||||
  if (!this.fetchs[path]) this.fetchs[path] = nullObj()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// function initTag(path, tag) {
 | 
			
		||||
//   if (this instanceof Window) {
 | 
			
		||||
//     throw new Error('initPath this对象没有绑定')
 | 
			
		||||
//   }
 | 
			
		||||
//   initTag.call(path)
 | 
			
		||||
//   if (!this.data[path][tag]) this.data[path][tag] = nullObj()
 | 
			
		||||
//   if (!this.pageData[path][tag]) this.pageData[path][tag] = nullObj()
 | 
			
		||||
//   if (!this.fetchs[path][tag]) this.fetchs[path][tag] = nullObj()
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
export default Query
 | 
			
		||||
		Reference in New Issue
	
	Block a user