|
@@ -0,0 +1,214 @@
|
|
|
+<template>
|
|
|
+ <el-table :data="list" border stripe @selection-change="toSelect">
|
|
|
+ <el-table-column type="selection" width="55" v-if="select"> </el-table-column>
|
|
|
+ <template v-for="(item, index) in fields">
|
|
|
+ <template v-if="item.custom">
|
|
|
+ <el-table-column :key="index" :label="item.label" v-bind="item.options" align="center" :show-overflow-tooltip="item.showTip || true">
|
|
|
+ <template v-slot="{ row }">
|
|
|
+ <slot :name="item.model" v-bind="{ item, row }"></slot>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <el-table-column
|
|
|
+ :key="index"
|
|
|
+ :label="item.label"
|
|
|
+ :prop="item.model"
|
|
|
+ :formatter="toFormatter"
|
|
|
+ v-bind="item.options"
|
|
|
+ :sortable="true"
|
|
|
+ align="center"
|
|
|
+ :show-overflow-tooltip="item.showTip === false ? item.showTip : true"
|
|
|
+ ></el-table-column>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ <template v-if="opera.length > 0">
|
|
|
+ <el-table-column label="操作" fixed="right" width="110" align="center">
|
|
|
+ <template v-slot="{ row, $index }">
|
|
|
+ <template v-for="(item, index) in opera">
|
|
|
+ <template v-if="display(item, row)">
|
|
|
+ <template v-if="vOpera">
|
|
|
+ <el-link
|
|
|
+ :key="`${item.model}-column-${index}`"
|
|
|
+ :type="item.type || 'primary'"
|
|
|
+ size="small"
|
|
|
+ :underline="false"
|
|
|
+ class="link"
|
|
|
+ v-opera="item.method"
|
|
|
+ @click="handleOpera(row, item.method, item.confirm, item.methodZh, item.label, $index, item.confirmWord)"
|
|
|
+ >
|
|
|
+ {{ item.label }}
|
|
|
+ </el-link>
|
|
|
+ </template>
|
|
|
+ <template v-else>
|
|
|
+ <el-link
|
|
|
+ :key="`${item.model}-column-${index}`"
|
|
|
+ :type="item.type || 'primary'"
|
|
|
+ size="small"
|
|
|
+ :underline="false"
|
|
|
+ class="link"
|
|
|
+ @click="handleOpera(row, item.method, item.confirm, item.methodZh, item.label, $index, item.confirmWord)"
|
|
|
+ >
|
|
|
+ {{ item.label }}
|
|
|
+ </el-link>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </template>
|
|
|
+ </el-table>
|
|
|
+ <el-row justify="end" class="page" v-if="usePage">
|
|
|
+ <el-pagination
|
|
|
+ background
|
|
|
+ layout="sizes,total, prev, pager, next"
|
|
|
+ :page-sizes="[10, 20, 50, 100, 200]"
|
|
|
+ :total="total"
|
|
|
+ :page-size="limit"
|
|
|
+ v-model:current-page="currentPage"
|
|
|
+ @current-change="changePage"
|
|
|
+ @size-change="sizeChange"
|
|
|
+ >
|
|
|
+ </el-pagination>
|
|
|
+ </el-row>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup lang="ts">
|
|
|
+// 基础
|
|
|
+import _ from 'lodash'
|
|
|
+import type { Ref } from 'vue'
|
|
|
+import { onMounted, toRefs, getCurrentInstance, ref } from 'vue'
|
|
|
+import { ElMessageBox } from 'element-plus'
|
|
|
+const { proxy } = getCurrentInstance() as any
|
|
|
+const emit = defineEmits(['toSelect', 'query'])
|
|
|
+
|
|
|
+// 参数
|
|
|
+interface fieldsItem {
|
|
|
+ // 是否自定义
|
|
|
+ custom: string
|
|
|
+ // 名称
|
|
|
+ label: string
|
|
|
+ // 绑定键值
|
|
|
+ model: string
|
|
|
+ // 其他
|
|
|
+ options: string
|
|
|
+ // 是否超出隐藏
|
|
|
+ showTip: boolean
|
|
|
+}
|
|
|
+interface operaItem {
|
|
|
+ // 名称
|
|
|
+ label: string
|
|
|
+ model: string
|
|
|
+ // 绑定键值
|
|
|
+ method: string
|
|
|
+ // 颜色
|
|
|
+ type: string
|
|
|
+ // 是否开启弹框
|
|
|
+ confirm: boolean
|
|
|
+ // 是否自定义文字说明
|
|
|
+ confirmWord: string
|
|
|
+ // 简短文字
|
|
|
+ methodZh: string
|
|
|
+}
|
|
|
+interface dataItem {
|
|
|
+ _id?: string
|
|
|
+}
|
|
|
+
|
|
|
+const props = defineProps({
|
|
|
+ // 列表配置
|
|
|
+ fields: { type: Array<fieldsItem>, required: true },
|
|
|
+ // 操作配置
|
|
|
+ opera: { type: Array<operaItem>, required: true },
|
|
|
+ // 列表数据
|
|
|
+ list: { type: Array<dataItem>, required: true },
|
|
|
+ // 是否开启多选
|
|
|
+ select: { type: Boolean, default: true },
|
|
|
+ // selected: { type: Array, default: () => [] },
|
|
|
+ vOpera: { type: Boolean, default: false },
|
|
|
+ // 分页
|
|
|
+ usePage: { type: Boolean, default: true },
|
|
|
+ total: { type: Number, default: 0 }
|
|
|
+})
|
|
|
+const { fields } = toRefs(props)
|
|
|
+const { opera } = toRefs(props)
|
|
|
+const { list } = toRefs(props)
|
|
|
+const { select } = toRefs(props)
|
|
|
+// const { selected } = toRefs(props);
|
|
|
+const { vOpera } = toRefs(props)
|
|
|
+const { usePage } = toRefs(props)
|
|
|
+const { total } = toRefs(props)
|
|
|
+
|
|
|
+let limit: number = proxy.$limit
|
|
|
+let currentPage: Ref<number> = ref(1)
|
|
|
+// 请求
|
|
|
+onMounted(async () => {})
|
|
|
+// 多选
|
|
|
+const toSelect = (val: Array<[]>) => {
|
|
|
+ emit(`toSelect`, val)
|
|
|
+}
|
|
|
+// 格式化内容
|
|
|
+const toFormatter = (row: any, column: { property: string }, cellValue: string) => {
|
|
|
+ let this_fields = fields.value.filter((fil) => fil.model === column.property)
|
|
|
+ if (this_fields.length > 0) {
|
|
|
+ let format: any = _.get(this_fields[0], `format`, false)
|
|
|
+ if (format) {
|
|
|
+ let res
|
|
|
+ if (_.isFunction(format)) {
|
|
|
+ res = format(cellValue)
|
|
|
+ } else {
|
|
|
+ res = toFormat({ model: this_fields[0].model, value: cellValue })
|
|
|
+ }
|
|
|
+ return res
|
|
|
+ } else {
|
|
|
+ return cellValue
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+const toFormat = (e: { model: string; value: string }) => {
|
|
|
+ console.log(e)
|
|
|
+}
|
|
|
+// 过滤
|
|
|
+const display = (item: operaItem, row: any) => {
|
|
|
+ let display: any = _.get(item, `display`, true)
|
|
|
+ if (display === true) return true
|
|
|
+ else {
|
|
|
+ let res = display(row)
|
|
|
+ return res
|
|
|
+ }
|
|
|
+}
|
|
|
+// 操作
|
|
|
+const handleOpera = (data: string, method: any, confirm = false, methodZh: string, label: string, index: string, confirmWord: string) => {
|
|
|
+ let self = true
|
|
|
+ if (_.isFunction(methodZh)) methodZh = methodZh(data)
|
|
|
+ else if (!_.isString(methodZh)) {
|
|
|
+ methodZh = label
|
|
|
+ self = false
|
|
|
+ }
|
|
|
+ if (confirm) {
|
|
|
+ let word = self ? methodZh : `您确认${methodZh}该数据?`
|
|
|
+ if (confirmWord) word = confirmWord
|
|
|
+ ElMessageBox.confirm(word, '提示', { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning' })
|
|
|
+ .then(() => {
|
|
|
+ emit(method, data, index)
|
|
|
+ })
|
|
|
+ .catch(() => {})
|
|
|
+ } else emit(method, data, index)
|
|
|
+}
|
|
|
+// 分页
|
|
|
+const changePage = (page: number = currentPage.value) => {
|
|
|
+ emit('query', { skip: (page - 1) * limit, limit: limit })
|
|
|
+}
|
|
|
+const sizeChange = (limits: number) => {
|
|
|
+ limit = limits
|
|
|
+ currentPage.value = 1
|
|
|
+ emit('query', { skip: 0, limit: limit })
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style scoped lang="less">
|
|
|
+.link {
|
|
|
+ padding: 0 5px 0 0;
|
|
|
+}
|
|
|
+.page {
|
|
|
+ margin: 10px 0 0 0;
|
|
|
+}
|
|
|
+</style>
|