| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 |
- <script lang="ts" setup>
- import { computed, inject, ref } from 'vue'
- import { VueDraggable } from 'vue-draggable-plus'
- import { TableContextKey } from './token'
- import type { ColumnFixed, ColumnSettingItem } from './token'
- defineOptions({
- name: 'ZmTableColumnSettingTree'
- })
- interface Props {
- modelValue: ColumnSettingItem[]
- parentKey?: string
- level?: number
- }
- const props = withDefaults(defineProps<Props>(), {
- level: 0
- })
- const emits = defineEmits<{
- 'update:modelValue': [value: ColumnSettingItem[]]
- }>()
- const tableContext = inject(TableContextKey, {
- data: ref([]),
- loading: ref(false),
- columnAlign: ref('center' as const),
- columnMaxWidth: ref(360),
- columnSettings: ref([]),
- updateColumnVisible: () => {},
- updateColumnFixed: () => {},
- updateColumnOrder: () => {},
- resetColumnSettings: () => {}
- })
- const columnList = computed<ColumnSettingItem[]>({
- get: () => props.modelValue,
- set: (value) => {
- emits('update:modelValue', value)
- }
- })
- const dragHandleClass = computed(() => `column-setting-drag-handle-${props.level}`)
- const dragHandleSelector = computed(() => `.${dragHandleClass.value}`)
- const dragGroup = computed(() => ({
- name: `zm-table-column-setting-${props.parentKey || 'root'}`,
- pull: false,
- put: false
- }))
- const hasChildColumns = (item: ColumnSettingItem) => !!item.children?.length
- const getVisibleTooltip = (item: ColumnSettingItem) => (item.visible ? '隐藏列' : '显示列')
- const getFixedTooltip = (item: ColumnSettingItem, fixed: Exclude<ColumnFixed, false>) => {
- if (item.fixed === fixed) return fixed === 'left' ? '取消固定左侧' : '取消固定右侧'
- return fixed === 'left' ? '固定到左侧' : '固定到右侧'
- }
- const handleChildColumnOrder = (parentKey: string, children: ColumnSettingItem[]) => {
- tableContext.updateColumnOrder(
- children.map((item) => item.key),
- parentKey
- )
- }
- const toggleColumnFixed = (item: ColumnSettingItem, fixed: Exclude<ColumnFixed, false>) => {
- tableContext.updateColumnFixed(item.key, item.fixed === fixed ? false : fixed)
- }
- </script>
- <template>
- <VueDraggable
- v-model="columnList"
- :animation="150"
- :handle="dragHandleSelector"
- :group="dragGroup"
- ghost-class="column-setting-ghost"
- class="column-setting-list"
- :class="{ 'is-root': level === 0, 'is-child-list': level > 0 }"
- >
- <div v-for="item in columnList" :key="item.key" class="column-setting-group">
- <div
- class="column-setting-item"
- :class="{ 'is-group': hasChildColumns(item), 'is-child': level > 0 }"
- >
- <button
- type="button"
- class="column-setting-icon-btn column-setting-drag-handle"
- :class="dragHandleClass"
- title="拖拽排序"
- >
- <div class="i-lucide:grip-vertical"></div>
- </button>
- <span class="column-setting-label" :title="item.label">
- {{ item.label }}
- </span>
- <el-tooltip
- :content="getVisibleTooltip(item)"
- placement="top"
- :show-after="500"
- :hide-after="0"
- >
- <button
- type="button"
- class="column-setting-icon-btn"
- :class="{ 'is-active': item.visible }"
- @click="tableContext.updateColumnVisible(item.key, !item.visible)"
- >
- <div :class="item.visible ? 'i-lucide:eye' : 'i-lucide:eye-off'"></div>
- </button>
- </el-tooltip>
- <el-tooltip
- :content="getFixedTooltip(item, 'left')"
- placement="top"
- :show-after="500"
- :hide-after="0"
- >
- <button
- type="button"
- class="column-setting-icon-btn"
- :class="{ 'is-active': item.fixed === 'left' }"
- @click="toggleColumnFixed(item, 'left')"
- >
- <div class="i-lucide:panel-left"></div>
- </button>
- </el-tooltip>
- <el-tooltip
- :content="getFixedTooltip(item, 'right')"
- placement="top"
- :show-after="500"
- :hide-after="0"
- >
- <button
- type="button"
- class="column-setting-icon-btn"
- :class="{ 'is-active': item.fixed === 'right' }"
- @click="toggleColumnFixed(item, 'right')"
- >
- <div class="i-lucide:panel-right"></div>
- </button>
- </el-tooltip>
- </div>
- <ZmTableColumnSettingTree
- v-if="item.children?.length"
- :model-value="item.children"
- :parent-key="item.key"
- :level="level + 1"
- @update:model-value="(children) => handleChildColumnOrder(item.key, children)"
- />
- </div>
- </VueDraggable>
- </template>
- <style scoped lang="scss">
- .column-setting-list {
- display: flex;
- min-width: 0;
- flex-direction: column;
- gap: var(--zm-table-column-setting-gap, 4px);
- &.is-root {
- max-height: var(--zm-table-column-setting-max-height, 360px);
- overflow-y: auto;
- }
- &.is-child-list {
- padding-left: 18px;
- margin: 3px 0 6px;
- border-left: 1px dashed var(--zm-table-column-setting-border-color, var(--el-border-color));
- gap: 3px;
- }
- }
- .column-setting-group {
- min-width: 0;
- }
- .column-setting-item {
- display: grid;
- height: var(--zm-table-column-setting-row-height, 32px);
- min-width: 0;
- padding: 0 4px;
- font-size: var(--zm-table-column-setting-font-size, 12px);
- font-weight: var(--zm-table-column-setting-item-font-weight, 400);
- color: var(--zm-table-column-setting-text-color, var(--el-text-color-regular));
- border-radius: var(--zm-table-column-setting-radius, 6px);
- align-items: center;
- column-gap: 6px;
- grid-template-columns: 22px minmax(0, 1fr) repeat(3, 24px);
- &:hover {
- background: var(--zm-table-column-setting-hover-bg, var(--el-fill-color-lighter));
- }
- &.is-group {
- font-weight: var(--zm-table-column-setting-group-font-weight, 600);
- }
- &.is-child {
- height: var(--zm-table-column-setting-child-row-height, 30px);
- padding-left: 2px;
- }
- }
- .column-setting-label {
- overflow: hidden;
- color: currentcolor;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- .column-setting-icon-btn {
- display: flex;
- width: var(--zm-table-column-setting-icon-btn-size, 22px);
- height: var(--zm-table-column-setting-icon-btn-size, 22px);
- padding: 0;
- color: var(--zm-table-column-setting-icon-color, #8aa0b8);
- cursor: pointer;
- background: transparent;
- border: 0;
- border-radius: 4px;
- align-items: center;
- justify-content: center;
- &:hover,
- &.is-active {
- color: var(--zm-table-column-setting-icon-active-color, var(--el-color-primary));
- background-color: var(
- --zm-table-column-setting-icon-active-bg,
- var(--el-color-primary-light-9)
- );
- }
- > div {
- width: var(--zm-table-column-setting-icon-size, 15px);
- height: var(--zm-table-column-setting-icon-size, 15px);
- }
- }
- .column-setting-drag-handle {
- cursor: grab;
- &:active {
- cursor: grabbing;
- }
- }
- .column-setting-ghost {
- background: var(--zm-table-column-setting-ghost-bg, var(--el-color-primary-light-9));
- opacity: var(--zm-table-column-setting-ghost-opacity, 0.55);
- }
- </style>
|