CommonStaticTable
							parent
							
								
									b4f0e07df4
								
							
						
					
					
						commit
						987c147fd8
					
				|  | @ -0,0 +1,465 @@ | |||
| <!-- | ||||
| @description: 封装组件 | ||||
| --> | ||||
| <template> | ||||
|   <div style="padding-left: 10px;"> | ||||
|     <el-row v-if="topLayout" style="margin-bottom: 20px"> | ||||
|       <el-col v-if="topLayoutLeft" :span="18"> | ||||
|         <div class="grid-content bg-purple"> | ||||
|           <el-input | ||||
|             v-model="searchForm.search" | ||||
|             :disabled="tableLoading" | ||||
|             :size="$ELEMENT.size" | ||||
|             :placeholder="filterPlaceholder" | ||||
|             clearable | ||||
|             style="width: 200px;" | ||||
|             @keyup.enter.native="handleSearchFormSubmit"/> | ||||
|           <el-button | ||||
|             :size="$ELEMENT.size" | ||||
|             type="primary" | ||||
|             title="过滤" | ||||
|             @click="handleSearchFormSubmit"> | ||||
|             <common-icon value="svg:icon-filter"/> | ||||
|           </el-button> | ||||
|           <el-button | ||||
|             v-show="isFilter" | ||||
|             :size="$ELEMENT.size" | ||||
|             type="info" | ||||
|             title="取消过滤" | ||||
|             style="margin-left: 0;" | ||||
|             @click="handleCancelFilter"> | ||||
|             <common-icon value="svg:icon-unfilter"/> | ||||
|           </el-button> | ||||
|           <slot name="button"/> | ||||
|         </div> | ||||
|       </el-col> | ||||
|       <el-col v-if="topLayoutRight" :span="6"> | ||||
|         <div class="grid-content bg-purple-light" style="text-align: right"> | ||||
|           <slot name="tools"/> | ||||
|           <el-button | ||||
|             :size="$ELEMENT.size" | ||||
|             name="refresh" | ||||
|             type="info" | ||||
|             title="导出数据" | ||||
|             @click="handleExportTableData"> | ||||
|             <svg-icon icon-class="icon-excel" style="font-size: 1em"/> | ||||
|           </el-button> | ||||
|           <el-popover | ||||
|             placement="bottom" | ||||
|             width="200" | ||||
|             trigger="click"> | ||||
|             <div style="width: 50px;"> | ||||
|               <el-checkbox-group v-model="showFields"> | ||||
|                 <el-checkbox | ||||
|                   v-for="(field, index) in fields" | ||||
|                   :key="index" | ||||
|                   :label="field" | ||||
|                   :checked="field.show" | ||||
|                   style="width: 100%" | ||||
|                   @change="handleSelectField($event, field)">{{ field.label }}</el-checkbox> | ||||
|               </el-checkbox-group> | ||||
|             </div> | ||||
|             <el-button | ||||
|               slot="reference" | ||||
|               :size="$ELEMENT.size" | ||||
|               name="refresh" | ||||
|               type="info" | ||||
|               icon="el-icon-s-fold" | ||||
|               title="设置显示的字段"/> | ||||
|           </el-popover> | ||||
|         </div> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|     <el-table | ||||
|       v-loading="tableLoading" | ||||
|       ref="table" | ||||
|       :data="filterData" | ||||
|       :span-method="spanMethod" | ||||
|       :max-height="maxHeight" | ||||
|       :row-key="getRowKeys" | ||||
|       :stripe="stripe" | ||||
|       :fit="fit" | ||||
|       :border="border" | ||||
|       :empty-text="emptyText" | ||||
|       :highlight-current-row="highlightCurrentRow" | ||||
|       :show-overflow-tooltip="showOverflowTooltip" | ||||
|       @cell-click="handleCellClick" | ||||
|       @cell-dblclick="handleCellDbClick" | ||||
|       @header-click="handleHeaderClick" | ||||
|       @row-click="handleRowClick" | ||||
|       @row-dblclick="handleRowDblClick" | ||||
|       @selection-change="handleSelectionChange"> | ||||
|       <el-table-column | ||||
|         v-if="selection" | ||||
|         :reserve-selection="true" | ||||
|         type="selection" | ||||
|         width="50"/> | ||||
|       <template v-for="field in fields"> | ||||
|         <el-table-column | ||||
|           v-if="field.show" | ||||
|           :key="field.prop" | ||||
|           :prop="field.prop" | ||||
|           :label="field.label" | ||||
|           :sortable="field.sortable" | ||||
|           :width="field.width || ''" | ||||
|           show-overflow-tooltip> | ||||
|           <template slot-scope="scope"> | ||||
|             <slot :name="field.prop" :values="scope.row" :prop="field.prop" :field="field"> | ||||
|               <span v-html="formatColumnData(scope.row, field)"/> | ||||
|             </slot> | ||||
|           </template> | ||||
|         </el-table-column> | ||||
|       </template> | ||||
|       <slot name="column"/> | ||||
|     </el-table> | ||||
|     <el-row> | ||||
|       <el-col :span="6" style="margin-top: 20px"> | ||||
|         <span>已选择:<span style="color: #ff00ff;font-weight: bold;">{{ multipleSelection.length }}</span>条</span> | ||||
|         <el-button | ||||
|           v-show="multipleSelection.length" | ||||
|           type="info" | ||||
|           size="mini" | ||||
|           title="清空多选" | ||||
|           @click="clearMultipleSelection">清空</el-button> | ||||
|       </el-col> | ||||
|       <el-col :span="18" style="margin-top: 20px; text-align: right"> | ||||
|         <span>总计:<span style="color: #ff00ff;font-weight: bold;">{{ filterData.length }}</span>条</span> | ||||
|       </el-col> | ||||
|     </el-row> | ||||
|   </div> | ||||
| </template> | ||||
| <script> | ||||
|   import moment from 'moment'; | ||||
|   import * as Utils from '@/utils'; | ||||
|   export default { | ||||
|     name: 'CommonStaticTable', | ||||
|     props: { | ||||
|       value: { | ||||
|         type: Array, | ||||
|         default: () => [] | ||||
|       }, | ||||
|       spanMethod: { | ||||
|         type: Function, | ||||
|         default: null | ||||
|       }, | ||||
|       data: { | ||||
|         type: Array, | ||||
|         default: () => [] | ||||
|       }, | ||||
|       initSelected: { | ||||
|         type: Array, | ||||
|         default: () => [] | ||||
|       }, | ||||
|       // eslint-disable-next-line vue/require-prop-types | ||||
|       maxHeight: { | ||||
|         default: 700 | ||||
|       }, | ||||
|       stripe: { | ||||
|         type: Boolean, | ||||
|         default: true | ||||
|       }, | ||||
|       fit: { | ||||
|         type: Boolean, | ||||
|         default: true | ||||
|       }, | ||||
|       highlightCurrentRow: { | ||||
|         type: Boolean, | ||||
|         default: true | ||||
|       }, | ||||
|       showOverflowTooltip: { | ||||
|         type: Boolean, | ||||
|         default: true | ||||
|       }, | ||||
|       border: { | ||||
|         type: Boolean, | ||||
|         default: false | ||||
|       }, | ||||
|       emptyText: { | ||||
|         type: String, | ||||
|         default: '暂无数据' | ||||
|       }, | ||||
|       topLayout: { | ||||
|         type: Array, | ||||
|         default: () => { | ||||
|           return ['left', 'right']; | ||||
|         } | ||||
|       }, | ||||
|       bottomLayout: { | ||||
|         type: Array, | ||||
|         default: () => { | ||||
|           return ['left', 'right']; | ||||
|         } | ||||
|       }, | ||||
|       fields: { | ||||
|         // 后端返回的字段 | ||||
|         type: Array, | ||||
|         default: () => { | ||||
|           return []; | ||||
|         } | ||||
|       }, | ||||
|       selection: { | ||||
|         // 开始开启多选(默认不开启, false) | ||||
|         type: Boolean, | ||||
|         default: false | ||||
|       }, | ||||
|       // api 对象 | ||||
|       api: { | ||||
|         type: Function, | ||||
|         default: null | ||||
|       }, | ||||
|       params: { | ||||
|         type: Object, | ||||
|         default: () => { | ||||
|           return {}; | ||||
|         } | ||||
|       } | ||||
|     }, | ||||
|     data() { | ||||
|       return { | ||||
|         tableEditable: true, | ||||
|         showFields: [], // 显示的字段 | ||||
|         filterFields: [], // 过滤的字段 | ||||
|         filterPlaceholder: '过滤', // 过滤提示文字 | ||||
|         buttonTagList: [], // 所有按钮标签 | ||||
|         excelDialogVisible: false, | ||||
|         tableLoading: false, | ||||
|         advancedSearchForm: {}, | ||||
|         advancedSearchFields: [], | ||||
|         rowKey: null, | ||||
|         multipleSelection: [], | ||||
|         excelHeader: [], | ||||
|         excelData: [], | ||||
|         searchForm: { | ||||
|           search: '' | ||||
|         }, | ||||
|         getRowKeys: row => { | ||||
|           if (this.rowKey) { | ||||
|             return row[this.rowKey]; | ||||
|           } | ||||
|           return row.id || row.uuid; | ||||
|         }, | ||||
|         exportFields: [], | ||||
|         tableData: [], | ||||
|         filterData: [], | ||||
|         isFilter: false | ||||
|       }; | ||||
|     }, | ||||
|     computed: { | ||||
|       topLayoutLeft() { | ||||
|         return this.topLayout.indexOf('left') >= 0; | ||||
|       }, | ||||
|       topLayoutRight() { | ||||
|         return this.topLayout.indexOf('right') >= 0; | ||||
|       } | ||||
|     }, | ||||
|     watch: { | ||||
|       data: { | ||||
|         handler: function(newData, oldData) { | ||||
|           this.handleChangeTableData(newData); | ||||
|         }, | ||||
|         immediate: true | ||||
|       } | ||||
|     }, | ||||
|     mounted() { | ||||
|     }, | ||||
|     created() { | ||||
|       this.initComponentData(); | ||||
|       this.initData(); | ||||
|       this.initSelect(); | ||||
|     }, | ||||
|     methods: { | ||||
|       initData() { | ||||
|         if (Utils.isFunction(this.api)) { | ||||
|           this.listInterfaceData(); | ||||
|         } | ||||
|       }, | ||||
|       initSelect() { | ||||
|         for (const row of this.initSelected) { | ||||
|           this.$refs['table'].toggleRowSelection(row, true); | ||||
|         } | ||||
|       }, | ||||
|       initComponentData() { | ||||
|         this.fields.forEach(field => { | ||||
|           field.show = (!!field.show); | ||||
|           field.type = (field.type || 'string').toLocaleLowerCase(); | ||||
|           field.label = field.label || field.prop; | ||||
|           field.search = (!!field.search); | ||||
|           field.sortable = (!!field.sortable); | ||||
|           field.unique = (!!field.unique); | ||||
|           field.width = field.width || ''; | ||||
|           if (field.type === 'choices') { | ||||
|             if (Utils.isArray(field.choices) && field.choices.length > 0) { | ||||
|               if (!Utils.isObj(field.choices[0])) { | ||||
|                 field.choices = field.choices.map(value => { | ||||
|                   return { | ||||
|                     label: value, | ||||
|                     value: value | ||||
|                   }; | ||||
|                 }); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           field.unique = (!!field.unique); | ||||
|           if (field.unique) { | ||||
|             this.rowKey = field.prop; | ||||
|           } | ||||
|         }); | ||||
|         this.filterFields = this.fields.filter(field => field.search).map(field => field.prop); | ||||
|         if (this.filterFields.length) { | ||||
|           const text = this.fields.filter(field => field.search).map(field => field.label).join('、'); | ||||
|           this.filterPlaceholder = `${text} 过滤`; | ||||
|         } | ||||
|       }, | ||||
|       listInterfaceData() { | ||||
|         this.tableLoading = true; | ||||
|         this.api(this.params).then(response => { | ||||
|           this.tableLoading = false; | ||||
|           this.handleChangeTableData(response.data); | ||||
|         }).catch(() => { | ||||
|           this.tableLoading = false; | ||||
|         }); | ||||
|       }, | ||||
|       formatColumnData(row, field) { | ||||
|         const type = field.type || 'string'; | ||||
|         const prop = field.prop; | ||||
|         if (field.formatter && typeof field.formatter === 'function') { | ||||
|           return field.formatter(row, prop, type); | ||||
|         } | ||||
|         if (type === 'string') { | ||||
|           return row[prop]; | ||||
|         } else if (type === 'datetime') { | ||||
|           return this.formatDatetime(row[prop]); | ||||
|         } else if (type === 'date') { | ||||
|           return this.formatDate(row[prop]); | ||||
|         } else if (type === 'time') { | ||||
|           return this.formatTime(row[prop]); | ||||
|         } else if (type.startsWith('bool')) { | ||||
|           return row[prop] ? '是' : '否'; | ||||
|         } else if (type === 'choices') { | ||||
|           const choices = field.choices; | ||||
|           return this.formatChoices(choices, row[prop]); | ||||
|         } else { | ||||
|           return row[prop]; | ||||
|         } | ||||
|       }, | ||||
|       formatChoices(choices, value) { | ||||
|         for (const choice of choices) { | ||||
|           if (choice.value === value) { | ||||
|             return choice.label; | ||||
|           } | ||||
|         } | ||||
|         return value; | ||||
|       }, | ||||
|       formatDatetime(datetime) { | ||||
|         return moment(datetime).format('YYYY-MM-DD HH:mm:ss'); | ||||
|       }, | ||||
|       formatDate(date) { | ||||
|         return moment(date).format('YYYY-MM-DD'); | ||||
|       }, | ||||
|       formatTime(time) { | ||||
|         return moment(time).format('HH:mm:ss'); | ||||
|       }, | ||||
|       getMultipleSelection() { | ||||
|         return this.multipleSelection || []; | ||||
|       }, | ||||
|       clearMultipleSelection() { | ||||
|         this.$refs.table.clearSelection(); | ||||
|       }, | ||||
|       clearSelection() { | ||||
|         this.$refs.table.clearSelection(); | ||||
|       }, | ||||
|       clearFilter() { | ||||
|         // 重置过滤 | ||||
|         this.searchForm.search = ''; | ||||
|         this.filterData = Array.from(this.tableData); | ||||
|       }, | ||||
|       handleSelectField(e, field) { | ||||
|         field.show = e; | ||||
|       }, | ||||
|       handleChangeTableData(data) { | ||||
|         this.tableData = Array.from(data); | ||||
|         this.filterData = Array.from(this.filterHandler(this.tableData)); | ||||
|       }, | ||||
|       // 导出表格的数据, 当前数据、当前列 | ||||
|       handleExportTableData() { | ||||
|         this.excelDialogVisible = true; | ||||
|         this.exportFields = this.fields.map(field => { | ||||
|           return { prop: field.prop, label: field.label, show: field.show }; | ||||
|         }); | ||||
|         this.excelHeader = this.showFields.map(field => field['prop']); | ||||
|       }, | ||||
|       // 处理修改多选的值 | ||||
|       handleSelectionChange(val) { | ||||
|         this.$emit('selection-change', val); | ||||
|         this.multipleSelection = val; | ||||
|       }, | ||||
|       handleSortChange(val) { | ||||
|         this.sort.prop = val.prop; | ||||
|         this.sort.order = val.order; | ||||
|         this.getTableData(); | ||||
|       }, | ||||
|       filterHandler(data) { | ||||
|         if (!data) { | ||||
|           data = this.tableData || []; | ||||
|         } | ||||
|         const search = this.searchForm.search.trim(); | ||||
|         if (!search.length || !this.filterFields.length) { | ||||
|           this.isFilter = false; | ||||
|           return data; | ||||
|         } | ||||
|         const filterData = data.filter(row => { | ||||
|           for (const field of this.filterFields) { | ||||
|             if (row[field] && row[field].indexOf(search) >= 0) { | ||||
|               return true; | ||||
|             } | ||||
|           } | ||||
|           return false; | ||||
|         }); | ||||
|         this.isFilter = true; | ||||
|         return filterData; | ||||
|       }, | ||||
|       handleCellClick(row, column, cell, event) { | ||||
|         this.$emit('cell-click', row, column, cell, event); | ||||
|       }, | ||||
|       handleCellDbClick(row, column, cell, event) { | ||||
|         this.$emit('cell-dblclick', row, column, cell, event); | ||||
|       }, | ||||
|       handleRowClick(row, column, event) { | ||||
|         this.$emit('row-click', row, column, event); | ||||
|       }, | ||||
|       handleRowDblClick(row, column, event) { | ||||
|         this.$emit('row-dblclick', row, column, event); | ||||
|       }, | ||||
|       handleHeaderClick(column, event) { | ||||
|         this.$emit('header-click', column, event); | ||||
|       }, | ||||
|       toggleRowSelection(row, selected = true) { | ||||
|         this.$refs.table.toggleRowSelection(row, selected); | ||||
|       }, | ||||
|       toggleFilter() { | ||||
|         // 触发过滤 | ||||
|         this.filterData = Array.from(this.filterHandler()); | ||||
|       }, | ||||
|       handleSearchFormSubmit() { | ||||
|         this.toggleFilter(); | ||||
|       }, | ||||
|       handleCancelFilter() { | ||||
|         this.isFilter = false; | ||||
|         this.clearFilter(); | ||||
|       } | ||||
|     } | ||||
|   }; | ||||
| </script> | ||||
| 
 | ||||
| <style scoped> | ||||
|   .picker { | ||||
|     width: 240px; | ||||
|   } | ||||
|   .el-pagination { | ||||
|     padding: 5px; | ||||
|   } | ||||
|   .right_pagination { | ||||
|     text-align: right; | ||||
|     padding-top: 20px; | ||||
|   } | ||||
| </style> | ||||
		Loading…
	
		Reference in New Issue
	
	 李强
						李强