523 lines
13 KiB
Vue
523 lines
13 KiB
Vue
<template>
|
||
<div class="ele-table-tool">
|
||
<div class="ele-table-tool-title">
|
||
<div class="ele-table-tool-title-label">
|
||
<slot v-if="$slots.label" name="label"></slot>
|
||
<span v-else>{{ label }}</span>
|
||
</div>
|
||
<div class="ele-table-tool-title-content">
|
||
<slot v-if="$slots.content" name="content"></slot>
|
||
<span v-else>{{ content }}</span>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="ele-tool">
|
||
<div class="ele-space">
|
||
<slot></slot>
|
||
</div>
|
||
<div class="ele-tool-item ele-action" v-if="columns && columns.length > 0">
|
||
<!--控制列-->
|
||
<i class="el-icon-menu" @click="openColumns" ></i>
|
||
</div>
|
||
</div>
|
||
|
||
<el-dialog title="列设置" :visible.sync="columnDialog" width="40%">
|
||
<div class="column-setting-container">
|
||
<div class="column-setting-header">
|
||
<el-checkbox
|
||
:indeterminate="isIndeterminate"
|
||
v-model="checkAll"
|
||
@change="handleCheckAllChange">
|
||
全选
|
||
</el-checkbox>
|
||
<span class="column-count">已选择 {{ checkedColumns.length }} / {{ tempColumns.length }} 列</span>
|
||
</div>
|
||
|
||
<el-table
|
||
:data="tempColumns"
|
||
ref="columnTableRef"
|
||
@selection-change="handleSelectionChange"
|
||
row-key="prop"
|
||
class="column-setting-table"
|
||
max-height="500px">
|
||
<el-table-column type="selection" width="55" :selectable="isColumnSelectable"></el-table-column>
|
||
<el-table-column label="标题" prop="label" min-width="120"></el-table-column>
|
||
<!-- <el-table-column label="字段" prop="prop" min-width="100"></el-table-column>-->
|
||
<el-table-column label="宽度PX" prop="width" min-width="120">
|
||
<template slot-scope="{row}">
|
||
<el-input
|
||
v-model="row.width"
|
||
type="number"
|
||
size="mini"
|
||
placeholder="自动">
|
||
</el-input>
|
||
</template>
|
||
</el-table-column>
|
||
<el-table-column label="固定" prop="fixed" min-width="120">
|
||
<template slot-scope="{row}">
|
||
<el-radio-group v-model="row.fixed" size="mini" boder>
|
||
<el-radio-button label="left">左侧</el-radio-button>
|
||
<el-radio-button label="">自动</el-radio-button>
|
||
<el-radio-button label="right">右侧</el-radio-button>
|
||
</el-radio-group>
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
</div>
|
||
|
||
<span slot="footer" class="dialog-footer">
|
||
<el-button @click="columnDialog = false">取 消</el-button>
|
||
<el-button type="primary" @click="doColumns">确 定</el-button>
|
||
</span>
|
||
</el-dialog>
|
||
|
||
</div>
|
||
</template>
|
||
|
||
<script>
|
||
module.exports = {
|
||
name: "index",
|
||
props: {
|
||
label: {
|
||
type: String,
|
||
default: "表格数据"
|
||
},
|
||
content: {
|
||
type: String,
|
||
default: ""
|
||
},
|
||
columns: {
|
||
type: Array,
|
||
default: function () {
|
||
return []
|
||
}
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
columnDialog: false,
|
||
checkedColumns: [],
|
||
checkAll: false,
|
||
isIndeterminate: false,
|
||
sortable: null, // Sortable实例
|
||
tempColumns: [] // 临时存储列配置,避免直接修改props
|
||
}
|
||
},
|
||
methods: {
|
||
// 打开列设置
|
||
openColumns() {
|
||
// 创建临时列配置的深拷贝,避免直接修改props
|
||
this.tempColumns = JSON.parse(JSON.stringify(this.columns))
|
||
this.columnDialog = true
|
||
this.initColumnSelection()
|
||
this.initSortable()
|
||
},
|
||
|
||
// 初始化拖拽排序
|
||
initSortable() {
|
||
this.$nextTick(() => {
|
||
if (this.$refs.columnTableRef && this.$refs.columnTableRef.$el) {
|
||
const tbody = this.$refs.columnTableRef.$el.querySelector('.el-table__body-wrapper tbody')
|
||
if (tbody && !this.sortable) {
|
||
this.sortable = new Sortable(tbody, {
|
||
animation: 150,
|
||
ghostClass: 'sortable-ghost',
|
||
chosenClass: 'sortable-chosen',
|
||
dragClass: 'sortable-drag',
|
||
onEnd: (evt) => {
|
||
const {oldIndex, newIndex} = evt
|
||
if (oldIndex !== newIndex) {
|
||
// 在tempColumns中重新排序
|
||
const movedItem = this.tempColumns.splice(oldIndex, 1)[0]
|
||
this.tempColumns.splice(newIndex, 0, movedItem)
|
||
|
||
// 重新初始化选择状态
|
||
this.$nextTick(() => {
|
||
this.initColumnSelection()
|
||
})
|
||
}
|
||
}
|
||
})
|
||
}
|
||
}
|
||
})
|
||
},
|
||
|
||
// 初始化列选择状态
|
||
initColumnSelection() {
|
||
// 设置默认选中状态(默认全部显示,除非明确指定visible为false)
|
||
this.checkedColumns = this.tempColumns.filter(col => col.visible !== false)
|
||
|
||
// 更新全选状态
|
||
this.updateCheckAllStatus()
|
||
|
||
// 设置表格选中状态
|
||
this.$nextTick(() => {
|
||
if (this.$refs.columnTableRef) {
|
||
this.tempColumns.forEach(row => {
|
||
if (row.visible !== false) {
|
||
this.$refs.columnTableRef.toggleRowSelection(row, true)
|
||
}
|
||
})
|
||
}
|
||
})
|
||
},
|
||
|
||
// 处理列选择变化
|
||
handleSelectionChange(selection) {
|
||
this.checkedColumns = selection
|
||
this.updateCheckAllStatus()
|
||
},
|
||
|
||
// 更新全选状态
|
||
updateCheckAllStatus() {
|
||
const selectableColumns = this.tempColumns.filter(col => this.isColumnSelectable(col))
|
||
this.checkAll = this.checkedColumns.length === selectableColumns.length
|
||
this.isIndeterminate = this.checkedColumns.length > 0 && this.checkedColumns.length < selectableColumns.length
|
||
},
|
||
|
||
// 处理全选变化
|
||
handleCheckAllChange(val) {
|
||
const selectableColumns = this.tempColumns.filter(col => this.isColumnSelectable(col))
|
||
|
||
if (val) {
|
||
this.checkedColumns = [...selectableColumns]
|
||
selectableColumns.forEach(row => {
|
||
this.$refs.columnTableRef.toggleRowSelection(row, true)
|
||
})
|
||
} else {
|
||
this.checkedColumns = []
|
||
this.$refs.columnTableRef.clearSelection()
|
||
}
|
||
this.isIndeterminate = false
|
||
},
|
||
|
||
// 判断列是否可选择
|
||
isColumnSelectable(row) {
|
||
return row.required !== true && row.type !== 'selection' && row.type !== 'index'
|
||
},
|
||
|
||
// 确定保存列设置
|
||
doColumns() {
|
||
// 基于tempColumns创建新的列配置数组,保留用户修改的宽度和固定值
|
||
const updatedColumns = this.tempColumns.map(col => {
|
||
return {
|
||
...col,
|
||
visible: this.checkedColumns.map(cc => cc.prop).includes(col.prop)
|
||
}
|
||
})
|
||
|
||
this.$emit('update:columns', updatedColumns)
|
||
this.columnDialog = false
|
||
}
|
||
},
|
||
watch: {
|
||
columns: {
|
||
handler() {
|
||
// 只有在对话框未打开时才初始化,避免覆盖用户正在编辑的tempColumns
|
||
if (!this.columnDialog) {
|
||
this.initColumnSelection()
|
||
}
|
||
},
|
||
immediate: true
|
||
},
|
||
|
||
columnDialog(val) {
|
||
if (!val && this.sortable) {
|
||
this.sortable.destroy()
|
||
this.sortable = null
|
||
}
|
||
}
|
||
},
|
||
created() {
|
||
},
|
||
beforeDestroy() {
|
||
if (this.sortable) {
|
||
this.sortable.destroy()
|
||
this.sortable = null
|
||
}
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style scoped>
|
||
.ele-table-tool:not(.ele-table-tool-default):not(.ele-table-tools-none) .ele-tool .ele-tool-item {
|
||
padding: 6px;
|
||
line-height: 1;
|
||
text-align: center;
|
||
border: unset;
|
||
border-radius: unset;
|
||
font-size: 14px;
|
||
margin-left: 10px;
|
||
}
|
||
|
||
.ele-table-tool .ele-table-tool-title {
|
||
margin: 0;
|
||
}
|
||
|
||
.ele-table-tool-title-label {
|
||
position: relative;
|
||
padding-left: 1em;
|
||
color: var(--color-primary);
|
||
font-weight: bold;
|
||
}
|
||
|
||
.ele-table-tool-title-label::before {
|
||
content: "";
|
||
position: absolute;
|
||
left: 0;
|
||
top: 50%;
|
||
transform: translateY(-50%);
|
||
width: 5px;
|
||
height: 1.3em;
|
||
background-color: var(--color-primary);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.ele-table-tool {
|
||
-ms-flex-wrap: wrap;
|
||
flex-wrap: wrap;
|
||
-ms-flex-align: center;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.ele-table-tool,
|
||
.ele-table-tool .ele-table-tool-title {
|
||
display: -webkit-box;
|
||
display: -ms-flexbox;
|
||
display: flex;
|
||
-webkit-box-align: center;
|
||
align-items: center;
|
||
}
|
||
|
||
.ele-table-tool .ele-table-tool-title {
|
||
-webkit-box-flex: 1;
|
||
-ms-flex: auto;
|
||
flex: auto;
|
||
margin-top: 5px;
|
||
margin-bottom: 5px;
|
||
-ms-flex-align: center;
|
||
}
|
||
|
||
.ele-table-tool .ele-table-tool-title > .ele-table-tool-title-label {
|
||
margin-right: 8px;
|
||
-webkit-box-sizing: border-box;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.ele-table-tool .ele-table-tool-title > .ele-table-tool-title-content {
|
||
-webkit-box-flex: 1;
|
||
-ms-flex: 1;
|
||
flex: 1;
|
||
-webkit-box-sizing: border-box;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
.ele-table-tool .ele-tool {
|
||
margin: 5px 0 5px auto;
|
||
display: -webkit-inline-box;
|
||
display: -ms-inline-flexbox;
|
||
display: inline-flex;
|
||
-webkit-box-align: center;
|
||
-ms-flex-align: center;
|
||
align-items: center;
|
||
-ms-flex-wrap: wrap;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.ele-table-tool .ele-tool .ele-tool-item {
|
||
font-size: 18px;
|
||
padding: 0 2px;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.ele-table-tool .ele-tool .ele-tool-item .el-dropdown > i {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.ele-table-tool .ele-tool .ele-tool-item + .ele-tool-item {
|
||
margin-left: 10px;
|
||
}
|
||
|
||
.ele-table-tool.ele-toolbar-form .ele-table-tool-title {
|
||
margin-top: 0;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.ele-table-tool.ele-toolbar-form .ele-table-tool-title .el-form-item,
|
||
.ele-table-tool.ele-toolbar-form .ele-table-tool-title .ele-form-actions {
|
||
margin-top: 5px;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.ele-table-tool.ele-toolbar-actions .ele-table-tool-title {
|
||
margin-top: 0;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
.ele-table-tool.ele-toolbar-actions .ele-table-tool-title > .el-button,
|
||
.ele-table-tool.ele-toolbar-actions .ele-table-tool-title > .el-dropdown,
|
||
.ele-table-tool.ele-toolbar-actions .ele-table-tool-title > .el-link,
|
||
.ele-table-tool.ele-toolbar-actions .ele-table-tool-title > .el-tag,
|
||
.ele-table-tool.ele-toolbar-actions .ele-table-tool-title > .ele-action {
|
||
margin-top: 5px;
|
||
margin-bottom: 5px;
|
||
}
|
||
|
||
.ele-table-tool:not(.ele-table-tool-default):not(.ele-table-tools-none) .ele-tool .ele-tool-item {
|
||
padding: 6px;
|
||
line-height: 1;
|
||
text-align: center;
|
||
border: 1px solid var(--border-color-base);
|
||
border-radius: 50%;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.ele-table-tool:not(.ele-table-tool-default):not(.ele-table-tools-none) .ele-tool .ele-tool-item .el-dropdown > i {
|
||
font-size: 14px;
|
||
}
|
||
|
||
.ele-table-tool:not(.ele-table-tool-default):not(.ele-table-tools-none) .ele-tool .ele-tool-item:hover {
|
||
color: var(--color-primary);
|
||
border-color: var(--color-primary-3);
|
||
background-color: var(--color-primary-1);
|
||
}
|
||
|
||
.ele-table-tool:not(.ele-table-tool-default):not(.ele-table-tools-none) .ele-tool .ele-tool-item:hover .el-dropdown > i {
|
||
color: var(--color-primary);
|
||
}
|
||
|
||
.ele-table-tool-default {
|
||
margin-bottom: 0;
|
||
padding: 5px 15px;
|
||
-webkit-box-sizing: border-box;
|
||
box-sizing: border-box;
|
||
background: var(--table-header-background-color);
|
||
border-top: 1px solid var(--border-color-lighter);
|
||
border-left: 1px solid var(--border-color-lighter);
|
||
border-right: 1px solid var(--border-color-lighter);
|
||
}
|
||
|
||
.ele-table-tool-default .ele-tool .ele-tool-item {
|
||
font-size: 16px;
|
||
padding: 5px 6px;
|
||
border-radius: 2px;
|
||
border: 1px solid var(--border-color-light);
|
||
-webkit-box-sizing: border-box;
|
||
box-sizing: border-box;
|
||
line-height: 1;
|
||
}
|
||
|
||
.ele-table-tool-default .ele-tool .ele-tool-item .el-dropdown > i {
|
||
font-size: 16px;
|
||
}
|
||
|
||
.ele-tab-tool {
|
||
padding: 0 15px;
|
||
-ms-flex-negative: 0;
|
||
flex-shrink: 0;
|
||
width: auto;
|
||
min-width: 40px;
|
||
height: 40px;
|
||
line-height: 40px;
|
||
-webkit-transition: background-color 0.3s,
|
||
color 0.3s;
|
||
transition: background-color 0.3s,
|
||
color 0.3s;
|
||
-webkit-box-sizing: border-box;
|
||
box-sizing: border-box;
|
||
text-align: center;
|
||
position: relative;
|
||
cursor: pointer;
|
||
}
|
||
|
||
.ele-tab-tool .el-icon-house {
|
||
font-size: 16px;
|
||
vertical-align: -1px;
|
||
}
|
||
|
||
.ele-tab-tool.is-tab:hover {
|
||
color: var(--color-primary);
|
||
background: var(--header-tool-hover-bg);
|
||
}
|
||
|
||
.ele-tab-tool.is-tab:after {
|
||
content: "";
|
||
width: 0;
|
||
height: 2px;
|
||
background: var(--color-primary);
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
}
|
||
|
||
.ele-tab-tool.is-tab.is-active {
|
||
color: var(--color-primary);
|
||
background: var(--color-primary-1);
|
||
}
|
||
|
||
.ele-tab-tool.is-tab.is-active:after {
|
||
width: 100%;
|
||
}
|
||
|
||
.column-setting-container {
|
||
/*max-height: calc(100vh - 182px);
|
||
overflow-y: auto;*/
|
||
}
|
||
|
||
.column-setting-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 15px;
|
||
padding: 10px;
|
||
background-color: #f5f7fa;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.column-count {
|
||
font-size: 12px;
|
||
color: #909399;
|
||
}
|
||
|
||
.column-setting-table {
|
||
margin-top: 10px;
|
||
}
|
||
|
||
/* 拖拽排序样式 */
|
||
.sortable-ghost {
|
||
opacity: 0.5;
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
.sortable-chosen {
|
||
background-color: #e6f7ff;
|
||
border: 1px dashed #1890ff;
|
||
}
|
||
|
||
.sortable-drag {
|
||
opacity: 0.8;
|
||
transform: rotate(5deg);
|
||
}
|
||
|
||
/* 表格行拖拽提示 */
|
||
.column-setting-table .el-table__row {
|
||
cursor: move;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.column-setting-table .el-table__row:hover {
|
||
background-color: #f5f7fa;
|
||
}
|
||
|
||
/* 拖拽提示文本 */
|
||
.column-setting-container::before {
|
||
content: "💡 提示:可以拖拽表格行来调整列的显示顺序";
|
||
display: block;
|
||
margin-bottom: 10px;
|
||
padding: 8px;
|
||
background-color: #fafafa;
|
||
border-left: 3px solid var(--color-primary);
|
||
}
|
||
</style>
|