|
@@ -0,0 +1,439 @@
|
|
|
+<template>
|
|
|
+ <ElTooltip placement="top" content="自定义列">
|
|
|
+ <el-icon :size="20" @click="dialogVisible = true"><Operation /></el-icon>
|
|
|
+ </ElTooltip>
|
|
|
+ <ElDialog v-model="dialogVisible" title="自定义列" width="840">
|
|
|
+ <div class="customized-column-content zt-column-content">
|
|
|
+ <div class="column-area">
|
|
|
+ <div class="column-select-panel">
|
|
|
+ <div class="panel-title-line !dark:bg-[var(--el-bg-color)]"> 可添加的列 </div>
|
|
|
+ <div class="panel-content">
|
|
|
+ <div class="column-select-area column-select-area0">
|
|
|
+ <div class="column-group clearfix">
|
|
|
+ <div class="column-items clearfix">
|
|
|
+ <div class="column-item check-group">
|
|
|
+ <el-checkbox
|
|
|
+ v-model="checkedadAll"
|
|
|
+ :indeterminate="isIndeterminate"
|
|
|
+ @change="onCheckAllChange"
|
|
|
+ >
|
|
|
+ 全选
|
|
|
+ </el-checkbox>
|
|
|
+ </div>
|
|
|
+ <el-checkbox-group v-model="checkedList" @change="onCheckChange">
|
|
|
+ <div
|
|
|
+ class="column-item"
|
|
|
+ v-for="(columnItem, index) in originColumns"
|
|
|
+ :key="columnItem.prop"
|
|
|
+ >
|
|
|
+ <el-checkbox
|
|
|
+ :key="columnItem.prop"
|
|
|
+ @change="
|
|
|
+ (e: any) => {
|
|
|
+ checkOne(e, columnItem, index)
|
|
|
+ }
|
|
|
+ "
|
|
|
+ :label="columnItem.label"
|
|
|
+ :value="columnItem.prop"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ </el-checkbox-group>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="column-selected">
|
|
|
+ <div class="panel-title-line !dark:bg-[var(--el-bg-color)]">
|
|
|
+ <span
|
|
|
+ >已选{{ dragColumns.length }}列
|
|
|
+ <el-tooltip class="item" effect="dark" content="拖动可以排序" placement="top">
|
|
|
+ <i class="el-icon-question"></i>
|
|
|
+ </el-tooltip>
|
|
|
+ </span>
|
|
|
+
|
|
|
+ <span class="delete-all" @click="clearAll">清空全部</span>
|
|
|
+ </div>
|
|
|
+ <div class="panel-selected" ref="draged">
|
|
|
+ <draggable
|
|
|
+ class="page-prop-area drag-area"
|
|
|
+ v-model="dragColumns"
|
|
|
+ item-key="prop"
|
|
|
+ :animation="200"
|
|
|
+ ghost-class="draggable-ghost"
|
|
|
+ :force-fallback="true"
|
|
|
+ @change="handleColumnChange"
|
|
|
+ >
|
|
|
+ <template #item="{ element, index }">
|
|
|
+ <div
|
|
|
+ class="selected-column-item select-none dark:border-solid !dark:bg-[var(--el-bg-color)] dark:border dark:border-zinc-400"
|
|
|
+ >
|
|
|
+ <div class="column-title">
|
|
|
+ <el-icon><Operation /></el-icon>
|
|
|
+ <p>{{ element.label }}</p>
|
|
|
+ </div>
|
|
|
+ <el-icon class="el-icon-close close" @click="removeColumn(element, index)"
|
|
|
+ ><CircleClose
|
|
|
+ /></el-icon>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </draggable>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <template #footer>
|
|
|
+ <XButton title="取消" @click="resetColumn" />
|
|
|
+ <XButton title="应用自定义列" type="primary" @click="applyColumn" />
|
|
|
+ </template>
|
|
|
+ </ElDialog>
|
|
|
+</template>
|
|
|
+<script lang="ts" setup>
|
|
|
+import { nextTick } from 'vue'
|
|
|
+import { ElDialog } from 'element-plus'
|
|
|
+import { useTableContext } from '../hooks/useTableContext'
|
|
|
+import draggable from 'vuedraggable'
|
|
|
+import { cloneDeep, differenceBy } from 'lodash-es'
|
|
|
+import { ColumnProps } from '@/types/table'
|
|
|
+import { Operation, CircleClose } from '@element-plus/icons-vue'
|
|
|
+import { onDragFalg } from '@/utils/drag'
|
|
|
+import { STORAGE_KEY, localStorage } from '@/utils/storage'
|
|
|
+
|
|
|
+// 定义一个通用的 Recordable 类型用于不确定的对象
|
|
|
+type Recordable<T = any> = Record<string, T>;
|
|
|
+
|
|
|
+defineOptions({ name: 'ColumnSetting' })
|
|
|
+
|
|
|
+const table = useTableContext()
|
|
|
+
|
|
|
+// 不再需要 useCache 钩子
|
|
|
+// const { wsCache } = useCache()
|
|
|
+
|
|
|
+//是否初始化
|
|
|
+let inited = false
|
|
|
+// 是否当前的setColums触发的
|
|
|
+let isSetColumnsFromThis = false
|
|
|
+// 是否当前组件触发的setProps
|
|
|
+let isSetPropsFromThis = false
|
|
|
+
|
|
|
+//不确定状态
|
|
|
+const isIndeterminate = ref(false)
|
|
|
+//是否全选
|
|
|
+const checkedadAll = ref(false)
|
|
|
+//原始列
|
|
|
+const originColumns = ref<ColumnProps[]>([])
|
|
|
+//拖拽后的值
|
|
|
+const dragColumns = ref<ColumnProps[]>([])
|
|
|
+//选中列的值列表
|
|
|
+const checkedList = ref<string[]>([])
|
|
|
+
|
|
|
+//其他列
|
|
|
+const otherColumns = ref<ColumnProps[]>([])
|
|
|
+
|
|
|
+const dialogVisible = ref(false)
|
|
|
+
|
|
|
+const getValues = computed(() => {
|
|
|
+ return unref(table?.getBindValues) || {}
|
|
|
+})
|
|
|
+
|
|
|
+watchEffect(() => {
|
|
|
+ //const columns = table.getColumns()
|
|
|
+
|
|
|
+ setTimeout(() => {
|
|
|
+ if (isSetColumnsFromThis) {
|
|
|
+ isSetColumnsFromThis = false
|
|
|
+ } else {
|
|
|
+ initTable()
|
|
|
+ }
|
|
|
+ }, 0)
|
|
|
+})
|
|
|
+
|
|
|
+watch(dialogVisible, (val) => {
|
|
|
+ if (val) {
|
|
|
+ initTable()
|
|
|
+ }
|
|
|
+})
|
|
|
+
|
|
|
+//全选事件
|
|
|
+const onCheckAllChange = (val: string) => {
|
|
|
+ isSetPropsFromThis = true
|
|
|
+ isSetColumnsFromThis = true
|
|
|
+ if (val) {
|
|
|
+ checkedList.value = unref(originColumns).map((item: any) => {
|
|
|
+ return item.prop as string
|
|
|
+ })
|
|
|
+ /* originColumns.value.forEach((item) => {
|
|
|
+ item.defaultHidden = false
|
|
|
+ }) */
|
|
|
+ dragColumns.value = cloneDeep(unref(originColumns))
|
|
|
+ } else {
|
|
|
+ checkedList.value = []
|
|
|
+ dragColumns.value = []
|
|
|
+ isIndeterminate.value = false
|
|
|
+ /* originColumns.value.forEach((item) => {
|
|
|
+ item.defaultHidden = true
|
|
|
+ }) */
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//组改变
|
|
|
+const onCheckChange = (val: string) => {
|
|
|
+ let checkedCount = val.length
|
|
|
+ checkedadAll.value = checkedCount === unref(originColumns).length
|
|
|
+ isIndeterminate.value = checkedCount > 0 && checkedCount < unref(originColumns).length
|
|
|
+}
|
|
|
+
|
|
|
+//单选某一项
|
|
|
+const checkOne = (val: boolean, column: ColumnProps, index: number) => {
|
|
|
+ isSetPropsFromThis = true
|
|
|
+ isSetColumnsFromThis = true
|
|
|
+ if (val) {
|
|
|
+ dragColumns.value.push(column)
|
|
|
+ //originColumns.value[index].defaultHidden = false
|
|
|
+ } else {
|
|
|
+
|
|
|
+ let idx = unref(dragColumns).findIndex((r: any) => r.prop === column.prop)
|
|
|
+ if (idx > -1) {
|
|
|
+ dragColumns.value.splice(idx, 1)
|
|
|
+ }
|
|
|
+ //originColumns.value[index].defaultHidden = true
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//重制列表
|
|
|
+const resetColumn = () => {
|
|
|
+ dialogVisible.value = false
|
|
|
+ isSetPropsFromThis = false
|
|
|
+ isSetColumnsFromThis = false
|
|
|
+ setTimeout(() => {
|
|
|
+ initTable()
|
|
|
+ }, 0)
|
|
|
+}
|
|
|
+
|
|
|
+//应用列表
|
|
|
+const applyColumn = () => {
|
|
|
+ isSetPropsFromThis = true
|
|
|
+ isSetColumnsFromThis = true
|
|
|
+ //吧otherColumn 填回去 因为固定列不参与自定义,最后要赋值回去,不然回显有bug
|
|
|
+ unref(otherColumns)
|
|
|
+ .filter((r: any) => r.type)
|
|
|
+ .reverse()
|
|
|
+ .forEach((item: any) => {
|
|
|
+ dragColumns.value.unshift(item)
|
|
|
+ })
|
|
|
+
|
|
|
+ /* unref(otherColumns)
|
|
|
+ .filter((r) => !r.type)
|
|
|
+ .forEach((item) => {
|
|
|
+ dragColumns.value.push(item)
|
|
|
+ }) */
|
|
|
+
|
|
|
+ //找到所有没有勾选的,加default
|
|
|
+
|
|
|
+ let allColumns: Record<string, any> = localStorage.get(STORAGE_KEY.COLUMNS) ?? {}
|
|
|
+ allColumns[getValues.value.tableKey] = dragColumns.value
|
|
|
+ localStorage.set(STORAGE_KEY.COLUMNS, allColumns)
|
|
|
+ //table.setColumns(dragColumns.value)
|
|
|
+ dialogVisible.value = false
|
|
|
+ table.setLocalColumns(dragColumns.value)
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+//移除某一项
|
|
|
+const removeColumn = (column: any, index: number) => {
|
|
|
+ dragColumns.value.splice(index, 1)
|
|
|
+ let idx = unref(checkedList).findIndex((r) => r === column.prop)
|
|
|
+ if (idx > -1) {
|
|
|
+ checkedList.value.splice(idx, 1)
|
|
|
+ }
|
|
|
+ /* let idx2 = originColumns.value.findIndex((r) => r.prop === column.prop)
|
|
|
+ originColumns.value[idx2].defaultHidden = true */
|
|
|
+
|
|
|
+ if (!unref(checkedList).length) {
|
|
|
+ isIndeterminate.value = false
|
|
|
+ checkedadAll.value = false
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+async function initTable() {
|
|
|
+ //初始化
|
|
|
+ otherColumns.value = []
|
|
|
+ originColumns.value = []
|
|
|
+ checkedList.value = []
|
|
|
+ let dragColumn: any[] = []
|
|
|
+
|
|
|
+ //获取左侧所有的cloumn,固定的
|
|
|
+ let column = table
|
|
|
+ .getCacheColumns()
|
|
|
+ .map((column: any) => {
|
|
|
+ if (column.type || column.prop == 'action') {
|
|
|
+ otherColumns.value.push(column)
|
|
|
+ } else {
|
|
|
+ return column
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .filter((column: any) => {
|
|
|
+ return column
|
|
|
+ })
|
|
|
+
|
|
|
+ originColumns.value = [...column]
|
|
|
+
|
|
|
+ //用来排序显示的列表要去掉fixed的 序号/多选/和操作还有没权限的
|
|
|
+ //获取当前显示的去掉序号等
|
|
|
+
|
|
|
+ await nextTick()
|
|
|
+
|
|
|
+ let curColumn = unref(table.getViewColumns).filter((column: any) => !column.type && column.prop != 'action')
|
|
|
+ curColumn.forEach((item: any) => {
|
|
|
+ checkedList.value.push(item.prop)
|
|
|
+ })
|
|
|
+
|
|
|
+ dragColumns.value = [...curColumn]
|
|
|
+ //渲染是否全部/部分选中
|
|
|
+ checkedadAll.value = checkedList.value.length === unref(originColumns).length
|
|
|
+ isIndeterminate.value =
|
|
|
+ checkedList.value.length > 0 && checkedList.value.length < unref(originColumns).length
|
|
|
+}
|
|
|
+
|
|
|
+//请空
|
|
|
+function clearAll() {
|
|
|
+ checkedList.value = []
|
|
|
+ dragColumns.value = []
|
|
|
+ checkedadAll.value = false
|
|
|
+ isIndeterminate.value = false
|
|
|
+}
|
|
|
+
|
|
|
+// 拖拽改变
|
|
|
+const handleColumnChange = (e: any) => {
|
|
|
+ let arr = onDragFalg(e, unref(dragColumns))
|
|
|
+ if (arr) dragColumns.value = arr
|
|
|
+}
|
|
|
+</script>
|
|
|
+<style scoped lang="scss">
|
|
|
+.column-area {
|
|
|
+ height: 445px;
|
|
|
+
|
|
|
+ .ad-d-flex {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .panel-title-line {
|
|
|
+ background-color: #f9fafd;
|
|
|
+ border: #e4e9ed 1px solid;
|
|
|
+ box-sizing: border-box;
|
|
|
+ line-height: 22px;
|
|
|
+ padding: 8px 12px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .column-selected {
|
|
|
+ width: 246px;
|
|
|
+ float: left;
|
|
|
+ height: 445px;
|
|
|
+ padding-bottom: 9px;
|
|
|
+
|
|
|
+ .panel-selected {
|
|
|
+ border: #e4e9ed 1px solid;
|
|
|
+ border-top: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ height: 395px;
|
|
|
+ padding: 0 7px 12px 7px;
|
|
|
+ overflow-y: auto;
|
|
|
+
|
|
|
+ .selected-column-item {
|
|
|
+ width: 100%;
|
|
|
+ height: auto;
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ justify-content: space-between;
|
|
|
+ background: #f8f8f8;
|
|
|
+ border-radius: 4px;
|
|
|
+ margin-top: 8px;
|
|
|
+ line-height: 18px;
|
|
|
+ padding: 5px 12px;
|
|
|
+
|
|
|
+ .column-title {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+
|
|
|
+ .close {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+
|
|
|
+ p {
|
|
|
+ padding: 3px 5px;
|
|
|
+ margin: 0;
|
|
|
+ cursor: move;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .delete-all {
|
|
|
+ cursor: pointer;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #338aff;
|
|
|
+ float: right;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ .column-select-panel {
|
|
|
+ width: 500px;
|
|
|
+ float: left;
|
|
|
+ margin-right: 16px;
|
|
|
+ height: 445px;
|
|
|
+
|
|
|
+ .panel-content {
|
|
|
+ border: #e4e9ed 1px solid;
|
|
|
+ border-top: 0;
|
|
|
+ box-sizing: border-box;
|
|
|
+ height: 395px;
|
|
|
+ padding: 0;
|
|
|
+ overflow: hidden;
|
|
|
+
|
|
|
+ .column-select-area {
|
|
|
+ height: 395px;
|
|
|
+ overflow-y: auto;
|
|
|
+ width: 100%;
|
|
|
+
|
|
|
+ .column-group {
|
|
|
+ padding: 0 16px;
|
|
|
+
|
|
|
+ .column-items {
|
|
|
+ margin-bottom: 4px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .check-group {
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+
|
|
|
+ .group-title {
|
|
|
+ cursor: pointer;
|
|
|
+ line-height: 46px;
|
|
|
+ font-size: 16px;
|
|
|
+ color: #333;
|
|
|
+ position: relative;
|
|
|
+ }
|
|
|
+
|
|
|
+ .column-item {
|
|
|
+ margin-top: 10px;
|
|
|
+ width: 208px;
|
|
|
+ float: left;
|
|
|
+ min-height: 25px;
|
|
|
+
|
|
|
+ &:nth-child(2n) {
|
|
|
+ margin-right: 10px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+.selected-column-item {
|
|
|
+ .anticon {
|
|
|
+ cursor: pointer;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|