Files
zhgh_whcp/target/classes/static/components/plugins/sysTableTool/index.vue
T
2026-01-08 14:58:16 +08:00

523 lines
13 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="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>