|
|
@@ -0,0 +1,285 @@
|
|
|
+<template>
|
|
|
+ <div class="containerTable">
|
|
|
+ <div class="table_box">
|
|
|
+ <div class="table-title-btn">
|
|
|
+ <slot name="table-title-btn"></slot>
|
|
|
+ </div>
|
|
|
+ <el-table ref="multipleTableRef"
|
|
|
+ :header-cell-style="{ 'background-color': '#F7F7F9', 'border-bottom': '1px solid #EEF1F6', 'font-size': '15px', 'color': '#333', 'padding': '10px 0' }"
|
|
|
+ :data="props.tableData" :height="tableHeight" :max-height="maxHeight" table-layout="fixed" style="width: 100%;"
|
|
|
+ @selection-change="selectionChange" @select-all="selectAllChange">
|
|
|
+ <!-- 空内容自定义 -->
|
|
|
+ <template #empty>
|
|
|
+ <div class="flex f-c a-c ">
|
|
|
+ <img src="../../assets/images/empty.png" alt="">
|
|
|
+ <span style="font-size: 14px;color: #909399;">暂无数据</span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ <el-table-column type="selection" v-if="showSelect" :selectable="selectable" width="55" fixed="left" />
|
|
|
+ <el-table-column type="expand" v-if="secondaryTable">
|
|
|
+ <template #default="props">
|
|
|
+ <div>
|
|
|
+ <el-table :data="props.row.children">
|
|
|
+ <el-table-column v-for="column in secondaryColumns" :key="column.prop" :prop="column.prop"
|
|
|
+ :label="column.label" :sortable="column.sortable ? 'custom' : false" :width="column.width">
|
|
|
+ <template #header>
|
|
|
+ <slot name="search" :slotData="column"></slot>
|
|
|
+ </template>
|
|
|
+ <template #default="scope">
|
|
|
+ <RouterLink v-if="column.component === 'RouterLink'" :to="getRouterLinkTo(scope.row, column)"
|
|
|
+ class="custom-link">
|
|
|
+ {{ scope.row[column.prop] }}
|
|
|
+ </RouterLink>
|
|
|
+ <el-tag v-else-if="column.component === 'Tag'" :type="getTagTypeAndText(scope.row, column).type">
|
|
|
+ {{ getTagTypeAndText(scope.row, column).text }}
|
|
|
+ </el-tag>
|
|
|
+ <ImagePreview v-else-if="column.component === 'Image'" :src="getImgTo(scope.row, column)"
|
|
|
+ width="50px" height="50px"></ImagePreview>
|
|
|
+ <span v-else>
|
|
|
+ {{ getDisplayText(scope.row, column) }}
|
|
|
+ </span>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" fixed="right" :width="props.columnwidth">
|
|
|
+ <template #default="scope">
|
|
|
+ <slot name="secondary" :secondaryData="scope.row"></slot>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column v-if="showIndex" type="index" label="序号" width="55" />
|
|
|
+ <el-table-column v-for="column in columns" :key="column.prop" :prop="column.prop" :label="column.label"
|
|
|
+ :sortable="column.sortable ? 'custom' : false" :width="column.width"
|
|
|
+ :align="column.align ? column.align : 'center'">
|
|
|
+ <template #header>
|
|
|
+ <slot name="search" :slotData="column"></slot>
|
|
|
+ </template>
|
|
|
+ <template #default="scope">
|
|
|
+ <RouterLink v-if="column.component === 'RouterLink'" :to="getRouterLinkTo(scope.row, column)"
|
|
|
+ class="custom-link">
|
|
|
+ {{ scope.row[column.prop] }}
|
|
|
+ </RouterLink>
|
|
|
+ <el-tag v-else-if="column.component === 'Tag'" :type="getTagTypeAndText(scope.row, column).type">
|
|
|
+ {{ getTagTypeAndText(scope.row, column).text }}
|
|
|
+ </el-tag>
|
|
|
+ <ImagePreview v-else-if="column.component === 'Image'" :src="getImgTo(scope.row, column)" width="50px"
|
|
|
+ height="50px"></ImagePreview>
|
|
|
+ <div v-else>
|
|
|
+ <div
|
|
|
+ v-if="typeof getDisplayText(scope.row, column) === 'string' && getDisplayText(scope.row, column).includes('\n')"
|
|
|
+ class="flex f-c ">
|
|
|
+ <span v-for="(line, index) in getDisplayText(scope.row, column).split('\n')" :key="index">{{ line
|
|
|
+ }}</span>
|
|
|
+ </div>
|
|
|
+ <span v-else>
|
|
|
+ {{ getDisplayText(scope.row, column) }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="操作" fixed="right" :width="props.columnwidth" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <div class="flex a-c j-c">
|
|
|
+ <slot name="operation" :operationData="scope.row"></slot>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+ <div class="page_box" v-if="props.pageInfo">
|
|
|
+ <el-pagination v-model:current-page="props.pageInfo.pageNum" v-model:page-size="props.pageInfo.pageSize"
|
|
|
+ :page-sizes="props.pageInfo.sizes" layout="total, sizes, prev, pager, next, jumper"
|
|
|
+ :total="props.pageInfo.total" @size-change="handleSizeChange" @current-change="handleCurrentChange" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { defineProps, ref, onMounted, defineEmits } from "vue";
|
|
|
+import type { TableInstance } from "element-plus";
|
|
|
+
|
|
|
+interface TableRow {
|
|
|
+ [key: string]: any;
|
|
|
+}
|
|
|
+const emit = defineEmits(['getList', 'selectAllChange', 'selectionChange']);
|
|
|
+const props = defineProps<{
|
|
|
+ tableData: Array<TableRow>;
|
|
|
+ columnwidth: number,//操作栏宽度
|
|
|
+ secondaryTable?: boolean,//是否展示二级表格
|
|
|
+ columns: {
|
|
|
+ prop: string;
|
|
|
+ label: string;
|
|
|
+ sortable?: boolean;
|
|
|
+ width?: string;
|
|
|
+ style?: string;
|
|
|
+ align?: string,
|
|
|
+ component?: string,
|
|
|
+ formatter?: (row: any, column: any, cellValue: any, index: number) => any;
|
|
|
+
|
|
|
+ }[];
|
|
|
+ secondaryColumns?: {
|
|
|
+ prop: string;
|
|
|
+ label: string;
|
|
|
+ sortable?: boolean;
|
|
|
+ width?: string;
|
|
|
+ style?: string;
|
|
|
+ component?: string,
|
|
|
+ formatter?: (row: any, column: any, cellValue: any, index: number) => any;
|
|
|
+ }[];
|
|
|
+ pageInfo?: {
|
|
|
+ pageNum: number;
|
|
|
+ pageSize: number;
|
|
|
+ sizes: number[];
|
|
|
+ total: number;
|
|
|
+ };
|
|
|
+ showSelect: boolean;
|
|
|
+ showIndex: boolean;
|
|
|
+ tableheight?: (number | string),
|
|
|
+ maxHeight?: (number | string),
|
|
|
+ uniqueIdName?: string,
|
|
|
+}>();
|
|
|
+interface Row {
|
|
|
+ [key: string]: any; // 假设Row是一个具有任意属性的对象
|
|
|
+}
|
|
|
+interface RouterLink {
|
|
|
+ name: string;
|
|
|
+}
|
|
|
+const tableHeight = ref(props.tableheight); // 初始化表格高度
|
|
|
+const newSelectionList = ref<string[]>([]);
|
|
|
+const multipleTableRef = ref<TableInstance>();
|
|
|
+const TableData = ref<TableRow[]>();
|
|
|
+onMounted(() => {
|
|
|
+ let counter = 1;
|
|
|
+ TableData.value = props.tableData.map((row) => ({
|
|
|
+ ...row,
|
|
|
+ _edit: false, // 设置默认非编辑状态
|
|
|
+ counter: counter++
|
|
|
+
|
|
|
+ }));
|
|
|
+ setTimeout(() => {
|
|
|
+ const tableElement = multipleTableRef.value?.$el as HTMLElement;
|
|
|
+ if (tableElement && !props.maxHeight) {
|
|
|
+ const offsetTop = tableElement.offsetTop; // 获取 offsetTop
|
|
|
+ let height = window.innerHeight;
|
|
|
+ tableHeight.value = height - offsetTop - 270 + "px";
|
|
|
+ }
|
|
|
+ }, 10);
|
|
|
+
|
|
|
+
|
|
|
+});
|
|
|
+const selectable = () => true;
|
|
|
+const handleSizeChange = (val: number) => {
|
|
|
+ if (props.pageInfo) {
|
|
|
+ props.pageInfo.pageSize = val
|
|
|
+ emit('getList', props.pageInfo);
|
|
|
+ }
|
|
|
+}
|
|
|
+//多选
|
|
|
+
|
|
|
+const selectAllChange = (value: any[]) => {
|
|
|
+
|
|
|
+ newSelectionList.value = [];
|
|
|
+ if (value.length > 0) {
|
|
|
+ value.map(val => {
|
|
|
+ newSelectionList.value.push(val.id)
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ newSelectionList.value = [];
|
|
|
+ }
|
|
|
+ emit('selectAllChange', newSelectionList.value)
|
|
|
+
|
|
|
+}
|
|
|
+const selectionChange = (value: any[]) => {
|
|
|
+ newSelectionList.value = [];
|
|
|
+ if (value.length > 0) {
|
|
|
+ value.map(val => {
|
|
|
+ if (props.uniqueIdName) {
|
|
|
+ newSelectionList.value.push(val[props.uniqueIdName])
|
|
|
+ } else {
|
|
|
+ newSelectionList.value.push(val.id)
|
|
|
+ }
|
|
|
+ })
|
|
|
+ } else {
|
|
|
+ newSelectionList.value = [];
|
|
|
+ }
|
|
|
+ emit('selectionChange', newSelectionList.value)
|
|
|
+}
|
|
|
+const handleCurrentChange = (val: number) => {
|
|
|
+ if (props.pageInfo) {
|
|
|
+ props.pageInfo.pageNum = val
|
|
|
+ emit('getList', props.pageInfo);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|
|
|
+//空值处理
|
|
|
+const displayValue = (value: any) => {
|
|
|
+ return value === null || value === undefined || value === '' ? '-' : value;
|
|
|
+}
|
|
|
+// 格式化内容配置
|
|
|
+function getRouterLinkTo(row: Row, column: any): RouterLink {
|
|
|
+ return column.formatter ? column.formatter(row, column, row[column.prop]) : { name: 'OrganizationAdd' };
|
|
|
+}
|
|
|
+function getImgTo(row: Row, column: any) {
|
|
|
+ return row[column.prop];
|
|
|
+}
|
|
|
+function getTagTypeAndText(row: Row, column: any) {
|
|
|
+ // 使用 formatter 返回一个对象,包含 type 和 text
|
|
|
+ return column.formatter ? column.formatter(row, column, row[column.prop]) : { type: 'primary', text: row[column.prop] };
|
|
|
+}
|
|
|
+function getDisplayText(row: Row, column: any): string {
|
|
|
+ return column.formatter ? column.formatter(row, column, row[column.prop]) : displayValue(row[column.prop]);
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style lang="scss" scoped>
|
|
|
+.el-table .el-table__cell .routerlick > a {
|
|
|
+ color: red;
|
|
|
+}
|
|
|
+
|
|
|
+.containerTable {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+}
|
|
|
+
|
|
|
+.custom-link {
|
|
|
+ color: #0083ff;
|
|
|
+
|
|
|
+ /* 设置文字颜色 */
|
|
|
+ text-decoration: none;
|
|
|
+
|
|
|
+ /* 去掉下划线 */
|
|
|
+}
|
|
|
+
|
|
|
+.table_box {
|
|
|
+ flex: 1;
|
|
|
+ margin-bottom: 10px;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ .table_item_container {
|
|
|
+ padding: 0;
|
|
|
+ margin-left: 20px;
|
|
|
+
|
|
|
+ .table_item {
|
|
|
+ margin: 5px 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .table-title-btn {
|
|
|
+ margin-bottom: 20px;
|
|
|
+
|
|
|
+ :deep(.el-button) {
|
|
|
+ margin-right: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.page_box {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: flex-end;
|
|
|
+}
|
|
|
+</style>
|