Files
profitManage1.2/src/components/table/index.vue
T
2025-11-11 18:58:05 +08:00

355 lines
16 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="w100 h100">
<!-- 表格头部按钮 -->
<el-row :gutter="10" style="margin: 0 0 8px 0;">
<template v-if="config && config.tableButton && config.tableButton.top">
<el-col :span="1.5" v-for="item of config.tableButton.top">
<el-button :type="item.type" plain size="mini" :icon="item.icon" @click="handleClick(item,{})" :hasPermi="[item.hasPermi]">{{item.content}}</el-button>
</el-col>
</template>
<right-toolbar v-if="!(config && config.colTopHiddenIcon)" :modelIdent="this.modelIdent" :showSearch.sync="showSearch" @queryTable="renderList" @columnsChange="columnsChange" :columns="columns"></right-toolbar>
</el-row>
<!-- 表格数据 -->
<el-table v-loading="loading" :data="tableList" :ref="config && config.tableKey ? `tableRef_${config.tableKey}` : `selChangeList`" :key="tableKey" :highlight-current-row="config && config.currentSel || false" @current-change="(val) => handleClick({fnCode: 'currentData'},val)" highlight-selection-row @select-all="handleSelectAll" @select="handleSelectionChange">
<!-- :selectable="() => config && config.selectable ? false : true" -->
<el-table-column v-if="!(config && config.colHiddenCheck)" fixed="left" type="selection" width="55" :selectable="() => config && config.selectable ? false : true" align="center" />
<!-- 展开列内容 -->
<el-table-column v-if="config && config.expand" type="expand">
<template #default="props">
<slot
name="tableExpand"
:row="props.row"
:rowIndex="props.$index"
:props="props"
></slot>
</template>
</el-table-column>
<template v-for="(column, key, index) of columns">
<el-table-column v-if="column && column.visible" :label="column.label" :key="key" :prop="key" :width="column.width" :min-width="column.minWidth || '100px'" align="left">
<!-- 插槽 自定义列表表头数据格式 -->
<template #header v-if="column && column.slotHeaderName">
<span>{{column.label}}</span>
<el-tooltip trigger="click" effect="dark" placement="top">
<template #content>{{column.slotHeaderName}}</template>
<i class="el-icon-question"></i>
</el-tooltip>
</template>
<!-- 单元格内容自定义tooltip支持换行 -->
<template #default="scope">
<!-- 1. 有自定义插槽时插槽内容仍用原逻辑但包裹tooltip -->
<template v-if="column && column.slotName">
<el-tooltip
:disabled="!isCellOverflow(scope.row[key], `cell-${key}-${scope.row.id}`)"
placement="top"
effect="dark">
<div slot="content" v-html="formatCellContent(scope.row[key])"></div>
<div :ref="`cell-${key}-${scope.row.id}`" class="cell-content">
<slot
:name="column.slotName"
:valueKey="key"
:row="scope.row"
:rowIndex="scope.$index"
:column="column"
:scope="scope"
></slot>
</div>
</el-tooltip>
</template>
<!-- 2. 无自定义插槽时直接渲染内容+tooltip -->
<template v-else>
<el-tooltip
:disabled="!isCellOverflow(scope.row[key], `cell-${key}-${scope.row.id}`)"
placement="top"
effect="dark">
<div slot="content" v-html="formatCellContent(scope.row[key])"></div>
<div :ref="`cell-${key}-${scope.row.id}`" class="cell-content">
{{ scope.row[key] }}
</div>
</el-tooltip>
</template>
</template>
</el-table-column>
</template>
<!-- 表格行内按钮 -->
<el-table-column v-if="config && config.tableButton && config.tableButton.line" :width="config.tableButton.line.length * 70 + `px`" label="操作" fixed="right" align="center" class-name="small-padding fixed-width">
<template #default="scope">
<template v-for="item of config.tableButton.line">
<template v-if="item && item.more && item.more.length > 0">
<el-dropdown size="mini" trigger="click" @command="(command) => handleClick({fnCode: command}, scope.row)">
<el-button size="mini" type="text" icon="el-icon-d-arrow-right"><span style="margin-left: -5px;">{{item && item.title ? item.title : '更多'}}</span></el-button>
<el-dropdown-menu slot="dropdown">
<el-dropdown-item v-for="dropBut of item.more" :command="dropBut.fnCode" :icon="dropBut.icon" :hasPermi="[dropBut.hasPermi]">{{dropBut.content}}</el-dropdown-item>
</el-dropdown-menu>
</el-dropdown>
</template>
<template v-else>
<!-- <el-tooltip v-if="item && item.content" :content="item.content" placement="top">-->
<el-button v-if="item && item.content" size="mini" link :type="item.type" :icon="item.icon" v-show="item && item.showName ? item.showVal.includes(scope.row[item.showName]) : true" @click="handleClick(item, scope.row)" :hasPermi="[item.hasPermi]">{{item.content}}</el-button>
<!-- </el-tooltip>-->
</template>
</template>
</template>
</el-table-column>
</el-table>
<pagination v-show="queryParams.total > 0" :layout="queryParams && queryParams.layout" :total="queryParams.total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="renderList" />
<el-dialog title="导出项" :visible.sync="dialogOpen" width="900px" append-to-body>
<el-checkbox-group v-model="checkColumns">
<template v-for="(item, key, index) of columns">
<el-checkbox v-if="key !== 'id'" :label="key" :key="key" style="width: 25%;margin-right: 0px;">{{item.label}}</el-checkbox>
</template>
</el-checkbox-group>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="diaColSubmit"> </el-button>
<el-button @click="diaColCancel"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script setup>
export default {
name: 'table-list',
props: {
modelIdent: {
type: String,
default: ''
},
tableList: {
type: Array,
default: () => []
},
columns: {
type: Object,
default: () => {}
},
queryParams: {
type: Object,
default: {
total: 0,
pageNum: 1,
pageSize: 10,
layout: 'total, sizes, prev, pager, next, jumper'
}
},
config: {
type: Object,
default: () => ({
colHiddenCheck: false,
colTopHiddenIcon: false,
currentSel: false,
})
}
},
data() {
return {
tableKey: 0,
loading: false,
showSearch: true,
dialogOpen: false,
ids: [],
selectList: [],
isProcessing: false, // 防止事件循环的标志位
checkColumns: []
}
},
// 监听showSearch的变化,并且把变化后的值传给父组件
watch: {
showSearch: {
handler(val) {
this.$emit('value-change', val)
}
}
},
created() {
if (!(this.config && this.config.colTopHiddenIcon)) {
this.$modal.loading();
}
},
methods: {
// 1. 格式化单元格内容:将\n替换为<br>,支持HTML渲染
formatCellContent(content) {
if (!content) return '';
// 若内容是对象/数组,先转为字符串(避免[object Object]
const strContent = typeof content === 'object' ? JSON.stringify(content) : String(content);
return strContent.replace(/\n/g, '<br/>');
},
// 2. 判断单元格内容是否溢出(决定是否显示tooltip)
isCellOverflow(content, refName) {
// 获取单元格DOM(注意:ref在v-for中是数组,需取[0]
const cellDom = this.$refs[refName]?.[0];
if (!cellDom || !content) return false;
// 内容实际宽度 > 单元格可见宽度 → 溢出
return cellDom.scrollWidth > cellDom.offsetWidth;
},
setCurrent(row) {
this.$nextTick(() => {
const targetRow = this.tableList.find(item => item.id === row.id); // 用id匹配原对象
this.$refs.selChangeList.setCurrentRow(targetRow); // 使用传入的row参数
});
},
// 所有方法都抛出到父组件里去
handleClick(result, row) {
if (result && result.fnCode) {
switch (result.fnCode) {
case 'export':
this.dialogOpen = true;
this.diaColumnCheck();
break;
default:
this.$emit("fnClick", result, row, this.ids, this.selectList);
}
}
},
// 导出弹窗 默认选中项
diaColumnCheck() {
this.checkColumns = [];
Object.keys(this.columns).forEach(item => {
if (item !== 'id' && this.columns[item] && this.columns[item].visible) {
this.checkColumns.push(item);
}
});
},
// 弹窗确认
diaColSubmit(){
this.$emit("fnClick", {fnCode: 'export'}, {properties: this.checkColumns});
this.dialogOpen = false;
},
// 弹窗取消
diaColCancel() {
this.dialogOpen = false;
},
/** 多选框选中数据 */
handleSelectionChange(selection) {
if (this.config && this.config['tableKey']) {
this.selectList = [];
this.ids = [];
if (this.isProcessing) return;
this.isProcessing = true;
// 当选中行有关联值时,默认把所关联的的行选中
selection.forEach(res => {
if (res && res.relevance) {
let selArr = [res];
Object.keys(res.relevance).forEach(item => {
res.relevance[item].forEach(val => {
this.tableList.some(tabVal => {
if (tabVal[item] === val) {
selArr.push(tabVal);
return true;
}
});
});
});
this.selectList = this.selectList.concat(selArr);
this.ids = this.ids.concat(selArr.map(item => item.id));
} else {
if (!this.ids.includes(res.id)) {
this.selectList = this.selectList.concat(res);
this.ids = this.ids.concat(res.id);
}
}
});
this.selectList.forEach(val => {
this.$refs[`tableRef_${this.config.tableKey}`].toggleRowSelection(val,true);
});
this.isProcessing = false;
} else {
this.selectList = selection;
this.ids = selection.map(item => item.id);
}
},
// 全选按钮操作
handleSelectAll(tabAll){
// 资源监控策略和资源监控模块使用 selectable: 控制列是否可选,值为false则不可选--this.config.selectable为判断
if (this.config && this.config.tableKey && this.config.selectable === true) {
if (tabAll && tabAll.length > 0) {
this.defaultSelectRows([]); // 取消全选
} else {
this.selectAllRows(); // 全选
}
} else {
if (tabAll && tabAll.length > 0) {
this.selectList = tabAll;
this.ids = tabAll.map(tabId => tabId.id);
} else {
// 清空
this.selectList = [];
this.ids = [];
}
}
},
// 提供给父组件调用的方法:返回当前表格的选中数据 资源监控策略和资源监控模块使用
getSelectedData() {
return {
tableKey: this.config.tableKey, // 表格唯一标识
data: [...this.selectList] // 选中的数据
};
},
// 提供给父组件调用的方法:全选所有行 资源监控策略和资源监控模块使用
selectAllRows() {
const table = this.config && this.config.tableKey ? this.$refs[`tableRef_${this.config.tableKey}`] : this.$refs.selChangeList;
if (!table) return;
// 清空现有选中状态
this.selectList = [];
this.ids = [];
// 遍历所有行,执行选中
this.tableList.forEach(row => {
// 跳过不可选的行(根据selectable配置)
// const isSelectable = !(this.config && this.config.selectable);
// if (isSelectable) {
table.toggleRowSelection(row, true); // 选中行
this.selectList.push(row); // 同步到选中列表
this.ids.push(row.id); // 同步到选中ID列表
// }
});
},
// 提供给父组件调用的方法:默认选中值
defaultSelectRows(rows){
const tableInstance = this.config && this.config.tableKey ? this.$refs[`tableRef_${this.config.tableKey}`] : this.$refs.selChangeList;
this.selectList = [];
this.ids = [];
if (tableInstance) {
if (rows && rows.length > 0) {
rows.forEach(row => {
tableInstance.toggleRowSelection(row, true);
this.selectList.push(row);
this.ids.push(row.id);
});
} else {
tableInstance.clearSelection();
}
}
},
renderList() {
this.$emit("fnRenderList");
},
// columns改变时触发,重新计算样式并渲染列表(解决:新增列,多选框和操作按钮错位)
columnsChange(val, col) {
if (col) {
this.$modal.closeLoading();
}
this.tableKey++;
},
}
}
</script>
<style scoped>
/* 单元格内容样式:强制单行显示,溢出截断 */
.cell-content {
width: 100%;
white-space: nowrap; /* 关键:确保内容单行显示 */
overflow: hidden;
text-overflow: ellipsis; /* 溢出显示... */
word-break: keep-all; /* 避免英文单词截断 */
}
/* 自定义tooltip样式:支持换行+限制宽度 */
::v-deep .el-tooltip__popper {
max-width: 400px; /* 限制tooltip宽度,避免过宽 */
white-space: normal; /* 允许自动换行 */
line-height: 1.6; /* 调整行高,提升可读性 */
}
</style>