447 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			447 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <template>
 | |
|   <div class="ai-table" :class="[isShowBorder ? 'ai-table__border' : 'ai-table__noborder']">
 | |
|     <el-table
 | |
|         :data="tableData"
 | |
|         header-cell-class-name="ai-table__header"
 | |
|         cell-class-name="ai-table__cell"
 | |
|         row-class-name="ai-table__row"
 | |
|         :class="{'ai-header__border': isShowBorder}"
 | |
|         :ref="refName"
 | |
|         :size="tableSize"
 | |
|         :stripe="stripe"
 | |
|         :tooltip-effect="tooltipEffect"
 | |
|         @selection-change="handleSelectionChange"
 | |
|         v-on="$listeners"
 | |
|         v-bind="$attrs"
 | |
|         v-loading="loading">
 | |
|       <template v-for="colConfig in colConfigs.filter(e=>!e.hide)">
 | |
|         <slot v-if="colConfig.slot && colConfig.slot !== 'options'" :name="colConfig.slot"/>
 | |
|         <component
 | |
|             :key="colConfig.id"
 | |
|             v-else-if="colConfig.component"
 | |
|             :is="colConfig.component"
 | |
|             :col-config="colConfig">
 | |
|         </component>
 | |
|         <el-table-column
 | |
|             v-else-if="colConfig.dict"
 | |
|             :key="colConfig.id"
 | |
|             v-bind="colConfig">
 | |
|           <span slot-scope="{row}" :style="{color:colConfig.color||dict.getColor(colConfig.dict, row[colConfig.prop])}">
 | |
|             {{ dict.getLabel(colConfig.dict, row[colConfig.prop]) }}
 | |
|           </span>
 | |
|         </el-table-column>
 | |
|         <el-table-column
 | |
|             v-else-if="colConfig.openType"
 | |
|             :key="colConfig.id"
 | |
|             v-bind="colConfig">
 | |
|           <template v-slot="{row}">
 | |
|             <ai-open-data :type="colConfig.openType" :openid="row[colConfig.prop]"/>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
|         <el-table-column
 | |
|             v-else-if="colConfig.type"
 | |
|             :key="colConfig.id"
 | |
|             v-bind="colConfig"
 | |
|             :width="colConfig.width || 100"/>
 | |
|         <el-table-column v-else v-bind="colConfig" :key="colConfig.id"
 | |
|                          :show-overflow-tooltip="colConfig['show-overflow-tooltip'] != false">
 | |
|           <template slot-scope="scope">
 | |
|             <render-slot v-if="colConfig.render" :render="colConfig.render" :row="scope.row" :index="scope.$index"
 | |
|                          :column="colConfig"/>
 | |
|             <span v-else>{{ getValue(colConfig, scope.row) }}</span>
 | |
|           </template>
 | |
|         </el-table-column>
 | |
|       </template>
 | |
|       <slot class="table-options" name="options"></slot>
 | |
|       <template #empty>
 | |
|         <slot v-if="$scopedSlots.empty" name="empty"/>
 | |
|         <div v-else class="no-data" style="height:160px;"/>
 | |
|       </template>
 | |
|     </el-table>
 | |
|     <div class="pagination newPagination" v-if="isShowPagination">
 | |
|       <el-pagination
 | |
|           background
 | |
|           :current-page.sync="page.current"
 | |
|           :total="page.total"
 | |
|           :page-size="page.size"
 | |
|           v-bind="$attrs"
 | |
|           :page-sizes="pageSizes"
 | |
|           :layout="layout"
 | |
|           :pager-count="page.pagerCount"
 | |
|           @size-change="handleSizeChange"
 | |
|           @current-change="handleChange">
 | |
|         <div class="paginationPre">
 | |
|           <el-checkbox v-if="isHasPaginationBtnsSlot" :disabled="!tableData.length" :indeterminate="isIndeterminate"
 | |
|                        :value="checkAll"
 | |
|                        @click.native="toggleAllSelection">全选
 | |
|           </el-checkbox>
 | |
|           <slot name="pagination"/>
 | |
|           <div class="pagination-btns">
 | |
|             <slot name="paginationBtns"></slot>
 | |
|           </div>
 | |
|           <div class="paginationPre-total" :style="{marginLeft: isHasPaginationBtnsSlot ? '24px' : 0}">共<label class="color-primary">{{ page.total }}</label>条记录
 | |
|           </div>
 | |
|         </div>
 | |
|       </el-pagination>
 | |
|     </div>
 | |
|   </div>
 | |
| </template>
 | |
| 
 | |
| <script>
 | |
| import moment from 'dayjs'
 | |
| import dict from "../../lib/js/dict"
 | |
| 
 | |
| let renderSlot = {
 | |
|   functional: true,
 | |
|   props: {
 | |
|     row: Object,
 | |
|     render: Function,
 | |
|     index: Number,
 | |
|     column: {type: Object, default: null},
 | |
|   },
 | |
|   render: (h, data) => {
 | |
|     const params = {
 | |
|       row: data.props.row,
 | |
|       index: data.props.index
 | |
|     }
 | |
| 
 | |
|     if (data.props.column) {
 | |
|       params.column = data.props.column
 | |
|     }
 | |
| 
 | |
|     return data.props.render(h, params)
 | |
|   }
 | |
| }
 | |
| 
 | |
| export default {
 | |
|   name: 'AiTable',
 | |
|   props: {
 | |
|     colConfigs: Array,
 | |
|     tableData: Array,
 | |
|     current: {
 | |
|       type: Number,
 | |
|       default: 1
 | |
|     },
 | |
|     size: {
 | |
|       type: Number,
 | |
|       default: 10
 | |
|     },
 | |
|     isShowPagination: {
 | |
|       type: Boolean,
 | |
|       default: true
 | |
|     },
 | |
|     total: {
 | |
|       type: Number
 | |
|     },
 | |
|     layout: {
 | |
|       type: String,
 | |
|       default: 'slot,->, prev, pager, next, sizes, jumper'
 | |
|     },
 | |
|     stripe: {
 | |
|       type: Boolean,
 | |
|       default: true
 | |
|     },
 | |
|     loading: {
 | |
|       type: Boolean,
 | |
|       default: false
 | |
|     },
 | |
|     tooltipEffect: {
 | |
|       type: String
 | |
|     },
 | |
|     tableSize: {
 | |
|       type: String
 | |
|     },
 | |
|     tableRef: String,
 | |
|     dict: {default: () => dict},
 | |
|     pagerCount: {default: 5},
 | |
|     pageSizes: {default: () => [10, 20, 50, 100]}
 | |
|   },
 | |
|   data() {
 | |
|     return {
 | |
|       name: '',
 | |
|       chooseList: []
 | |
|     }
 | |
|   },
 | |
|   components: {renderSlot},
 | |
|   computed: {
 | |
|     refName() {
 | |
|       return this.tableRef || `aiTable${new Date().getTime()}`
 | |
|     },
 | |
|     isShowBorder() {
 | |
|       return !!this.$attrs.border || this.$attrs.border === ''
 | |
|     },
 | |
| 
 | |
|     isHasPaginationBtnsSlot() {
 | |
|       return this.$slots.paginationBtns
 | |
|     },
 | |
| 
 | |
|     page() {
 | |
|       return {
 | |
|         current: this.current,
 | |
|         size: this.size,
 | |
|         total: this.total,
 | |
|         pagerCount: this.pagerCount
 | |
|       }
 | |
|     },
 | |
|     isIndeterminate() {
 | |
|       return this.chooseList.length > 0 && this.chooseList.length < this.tableData.length
 | |
|     },
 | |
|     checkAll() {
 | |
|       return this.chooseList.length == this.tableData.length && this.tableData !== 0
 | |
|     }
 | |
|   },
 | |
|   methods: {
 | |
|     handleChange(e) {
 | |
|       this.$emit('update:current', e)
 | |
| 
 | |
|       this.$nextTick(() => {
 | |
|         this.$emit('getList')
 | |
|       })
 | |
|     },
 | |
|     handleSizeChange(e) {
 | |
|       this.$emit('update:size', e)
 | |
|       this.$nextTick(() => {
 | |
|         this.$emit('getList')
 | |
|       })
 | |
|     },
 | |
|     handleSelectionChange(e) {
 | |
|       this.chooseList = e
 | |
|       this.$emit('handleSelectionChange', e)
 | |
|     },
 | |
|     getValue(colConfig, row) {
 | |
|       if (this.isFunction(colConfig.formart)) {
 | |
|         return colConfig.formart.call(this, row[colConfig.prop])
 | |
|       }
 | |
| 
 | |
|       if (colConfig.dateFormat) {
 | |
|         return moment(row[colConfig.prop]).format(colConfig.dateFormat)
 | |
|       }
 | |
| 
 | |
|       return this.isInvalidValue(row[colConfig.prop])
 | |
|     },
 | |
|     isInvalidValue(value) {
 | |
|       if (value === null || value === undefined || value === '') {
 | |
|         return '-'
 | |
|       }
 | |
| 
 | |
|       return value
 | |
|     },
 | |
|     isFunction(fun) {
 | |
|       return typeof fun === 'function'
 | |
|     },
 | |
|     /**
 | |
|      * 表格方法代理
 | |
|      */
 | |
|     clearSelection() {
 | |
|       this.$refs[this.refName].clearSelection()
 | |
|     },
 | |
|     toggleRowSelection() {
 | |
|       this.$refs[this.refName].toggleRowSelection(...arguments)
 | |
|     },
 | |
|     toggleAllSelection() {
 | |
|       this.$refs[this.refName].toggleAllSelection()
 | |
|     },
 | |
|     toggleRowExpansion() {
 | |
|       this.$refs[this.refName].toggleRowExpansion(...arguments)
 | |
|     },
 | |
|     setCurrentRow() {
 | |
|       this.$refs[this.refName].setCurrentRow(...arguments)
 | |
|     },
 | |
|     clearSort() {
 | |
|       this.$refs[this.refName].clearSort()
 | |
|     },
 | |
|     clearFilter() {
 | |
|       this.$refs[this.refName].clearFilter(...arguments)
 | |
|     },
 | |
|     doLayout() {
 | |
|       this.$refs[this.refName].doLayout()
 | |
|     },
 | |
|     sort() {
 | |
|       this.$refs[this.refName].sort(...arguments)
 | |
|     },
 | |
|   }
 | |
| }
 | |
| </script>
 | |
| 
 | |
| <style lang="scss" scoped>
 | |
| .ai-table {
 | |
|   .color-primary {
 | |
|     color: $primaryColor;
 | |
|   }
 | |
| 
 | |
|   :deep( .ai-header__border .ai-table__header ){
 | |
|     border-bottom: 1px solid $borderColor !important;
 | |
|     border-right: 1px solid $borderColor !important;
 | |
|   }
 | |
| 
 | |
|   :deep( .el-table--border ){
 | |
|     border: 1px solid $borderColor;
 | |
|     border-right: none;
 | |
|     border-bottom: none;
 | |
|   }
 | |
| 
 | |
|   :deep( .el-table ){
 | |
|     color: #222;
 | |
| 
 | |
|     .caret-wrapper {
 | |
|       height: 24px;
 | |
| 
 | |
|       .ascending {
 | |
|         top: 1px;
 | |
|       }
 | |
| 
 | |
|       .descending {
 | |
|         bottom: 1px;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     thead {
 | |
|       color: #555
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   :deep( .cell ){
 | |
|     line-height: 24px;
 | |
|   }
 | |
| 
 | |
|   :deep( .el-table__header ){
 | |
|     th {
 | |
|       padding: 8px 0;
 | |
|     }
 | |
| 
 | |
|     tr {
 | |
|       .cell {
 | |
|         font-weight: 700;
 | |
|       }
 | |
| 
 | |
|       th:first-child {
 | |
|         .cell {
 | |
|           padding-left: 40px !important;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   :deep( .el-table__body ){
 | |
|     tr td:first-child .cell {
 | |
|       padding-left: 40px !important;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   :deep( .el-table__fixed-right ){
 | |
|     .el-table__body {
 | |
|       tr td:first-child .cell {
 | |
|         padding-left: 0 !important;
 | |
|         padding-right: 0;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   :deep( .ai-table__header ){
 | |
|     border-bottom: none;
 | |
|     background: #F3F4F5;
 | |
|   }
 | |
| 
 | |
|   :deep(.el-pager ){
 | |
|     li.active + li {
 | |
|       border-left: 1px solid $borderColor;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   .newPagination {
 | |
|     width: 100%;
 | |
|     display: flex;
 | |
|     align-items: center;
 | |
|     height: 64px;
 | |
|     padding: 0 40px !important;
 | |
| 
 | |
|     .el-pagination {
 | |
|       width: 100%;
 | |
|       padding: 0;
 | |
|     }
 | |
| 
 | |
|     .paginationPre {
 | |
|       display: flex;
 | |
|       height: 28px;
 | |
|       line-height: 1;
 | |
|       font-size: 14px;
 | |
|       font-weight: normal;
 | |
|       align-items: center;
 | |
| 
 | |
|       .pagination-btns {
 | |
|         display: flex;
 | |
|         align-items: center;
 | |
|         gap: 8px;
 | |
|         color: $primaryColor !important;
 | |
| 
 | |
|         :deep( span), :deep( div ){
 | |
|           font-size: 12px;
 | |
|           cursor: pointer;
 | |
|           color: $primaryColor !important;
 | |
| 
 | |
|           &:hover {
 | |
|             opacity: 0.8;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       .paginationPre-total {
 | |
|         font-size: 12px;
 | |
|         color: #555;
 | |
| 
 | |
|         label {
 | |
|           padding: 0 2px;
 | |
|           font-weight: 700;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       & > * + * {
 | |
|         margin-left: 24px;
 | |
|       }
 | |
| 
 | |
|       :deep( .el-pagination button), .el-pagination span:not([class*=suffix]) {
 | |
|         line-height: 1 !important;
 | |
|       }
 | |
| 
 | |
|       :deep(.el-checkbox ){
 | |
|         display: flex;
 | |
|         align-items: center;
 | |
| 
 | |
|         .el-checkbox__input, .el-checkbox__inner {
 | |
|           width: 14px;
 | |
|           height: 14px;
 | |
|           min-width: 0 !important;
 | |
|           line-height: 1 !important;
 | |
|         }
 | |
| 
 | |
|         .el-checkbox__label {
 | |
|           font-size: 12px;
 | |
|           color: #222222;
 | |
|           height: auto !important;
 | |
|           line-height: 1 !important;
 | |
|           padding-left: 3px !important;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| .ai-table__noborder {
 | |
|   :deep( .el-table td), :deep( .el-table th.is-center ){
 | |
|     border: none;
 | |
|   }
 | |
| 
 | |
|   .el-table::before {
 | |
|     display: none;
 | |
|   }
 | |
| 
 | |
|   :deep( .el-table--striped .el-table__body tr.el-table__row--striped td ){
 | |
|     background: #F5F6F9;
 | |
|   }
 | |
| 
 | |
|   :deep( .el-table__fixed-right::before), :deep( .el-table__fixed::before ){
 | |
|     display: none;
 | |
|   }
 | |
| }
 | |
| </style>
 |