ZmTableColumnSettingTree.vue 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <script lang="ts" setup>
  2. import { computed, inject, ref } from 'vue'
  3. import { VueDraggable } from 'vue-draggable-plus'
  4. import { TableContextKey } from './token'
  5. import type { ColumnFixed, ColumnSettingItem } from './token'
  6. defineOptions({
  7. name: 'ZmTableColumnSettingTree'
  8. })
  9. interface Props {
  10. modelValue: ColumnSettingItem[]
  11. parentKey?: string
  12. level?: number
  13. }
  14. const props = withDefaults(defineProps<Props>(), {
  15. level: 0
  16. })
  17. const emits = defineEmits<{
  18. 'update:modelValue': [value: ColumnSettingItem[]]
  19. }>()
  20. const tableContext = inject(TableContextKey, {
  21. data: ref([]),
  22. loading: ref(false),
  23. columnAlign: ref('center' as const),
  24. columnMaxWidth: ref(360),
  25. columnSettings: ref([]),
  26. updateColumnVisible: () => {},
  27. updateColumnFixed: () => {},
  28. updateColumnOrder: () => {},
  29. resetColumnSettings: () => {}
  30. })
  31. const columnList = computed<ColumnSettingItem[]>({
  32. get: () => props.modelValue,
  33. set: (value) => {
  34. emits('update:modelValue', value)
  35. }
  36. })
  37. const dragHandleClass = computed(() => `column-setting-drag-handle-${props.level}`)
  38. const dragHandleSelector = computed(() => `.${dragHandleClass.value}`)
  39. const dragGroup = computed(() => ({
  40. name: `zm-table-column-setting-${props.parentKey || 'root'}`,
  41. pull: false,
  42. put: false
  43. }))
  44. const hasChildColumns = (item: ColumnSettingItem) => !!item.children?.length
  45. const getVisibleTooltip = (item: ColumnSettingItem) => (item.visible ? '隐藏列' : '显示列')
  46. const getFixedTooltip = (item: ColumnSettingItem, fixed: Exclude<ColumnFixed, false>) => {
  47. if (item.fixed === fixed) return fixed === 'left' ? '取消固定左侧' : '取消固定右侧'
  48. return fixed === 'left' ? '固定到左侧' : '固定到右侧'
  49. }
  50. const handleChildColumnOrder = (parentKey: string, children: ColumnSettingItem[]) => {
  51. tableContext.updateColumnOrder(
  52. children.map((item) => item.key),
  53. parentKey
  54. )
  55. }
  56. const toggleColumnFixed = (item: ColumnSettingItem, fixed: Exclude<ColumnFixed, false>) => {
  57. tableContext.updateColumnFixed(item.key, item.fixed === fixed ? false : fixed)
  58. }
  59. </script>
  60. <template>
  61. <VueDraggable
  62. v-model="columnList"
  63. :animation="150"
  64. :handle="dragHandleSelector"
  65. :group="dragGroup"
  66. ghost-class="column-setting-ghost"
  67. class="column-setting-list"
  68. :class="{ 'is-root': level === 0, 'is-child-list': level > 0 }"
  69. >
  70. <div v-for="item in columnList" :key="item.key" class="column-setting-group">
  71. <div
  72. class="column-setting-item"
  73. :class="{ 'is-group': hasChildColumns(item), 'is-child': level > 0 }"
  74. >
  75. <button
  76. type="button"
  77. class="column-setting-icon-btn column-setting-drag-handle"
  78. :class="dragHandleClass"
  79. title="拖拽排序"
  80. >
  81. <div class="i-lucide:grip-vertical"></div>
  82. </button>
  83. <span class="column-setting-label" :title="item.label">
  84. {{ item.label }}
  85. </span>
  86. <el-tooltip
  87. :content="getVisibleTooltip(item)"
  88. placement="top"
  89. :show-after="500"
  90. :hide-after="0"
  91. >
  92. <button
  93. type="button"
  94. class="column-setting-icon-btn"
  95. :class="{ 'is-active': item.visible }"
  96. @click="tableContext.updateColumnVisible(item.key, !item.visible)"
  97. >
  98. <div :class="item.visible ? 'i-lucide:eye' : 'i-lucide:eye-off'"></div>
  99. </button>
  100. </el-tooltip>
  101. <el-tooltip
  102. :content="getFixedTooltip(item, 'left')"
  103. placement="top"
  104. :show-after="500"
  105. :hide-after="0"
  106. >
  107. <button
  108. type="button"
  109. class="column-setting-icon-btn"
  110. :class="{ 'is-active': item.fixed === 'left' }"
  111. @click="toggleColumnFixed(item, 'left')"
  112. >
  113. <div class="i-lucide:panel-left"></div>
  114. </button>
  115. </el-tooltip>
  116. <el-tooltip
  117. :content="getFixedTooltip(item, 'right')"
  118. placement="top"
  119. :show-after="500"
  120. :hide-after="0"
  121. >
  122. <button
  123. type="button"
  124. class="column-setting-icon-btn"
  125. :class="{ 'is-active': item.fixed === 'right' }"
  126. @click="toggleColumnFixed(item, 'right')"
  127. >
  128. <div class="i-lucide:panel-right"></div>
  129. </button>
  130. </el-tooltip>
  131. </div>
  132. <ZmTableColumnSettingTree
  133. v-if="item.children?.length"
  134. :model-value="item.children"
  135. :parent-key="item.key"
  136. :level="level + 1"
  137. @update:model-value="(children) => handleChildColumnOrder(item.key, children)"
  138. />
  139. </div>
  140. </VueDraggable>
  141. </template>
  142. <style scoped lang="scss">
  143. .column-setting-list {
  144. display: flex;
  145. min-width: 0;
  146. flex-direction: column;
  147. gap: var(--zm-table-column-setting-gap, 4px);
  148. &.is-root {
  149. max-height: var(--zm-table-column-setting-max-height, 360px);
  150. overflow-y: auto;
  151. }
  152. &.is-child-list {
  153. padding-left: 18px;
  154. margin: 3px 0 6px;
  155. border-left: 1px dashed var(--zm-table-column-setting-border-color, var(--el-border-color));
  156. gap: 3px;
  157. }
  158. }
  159. .column-setting-group {
  160. min-width: 0;
  161. }
  162. .column-setting-item {
  163. display: grid;
  164. height: var(--zm-table-column-setting-row-height, 32px);
  165. min-width: 0;
  166. padding: 0 4px;
  167. font-size: var(--zm-table-column-setting-font-size, 12px);
  168. font-weight: var(--zm-table-column-setting-item-font-weight, 400);
  169. color: var(--zm-table-column-setting-text-color, var(--el-text-color-regular));
  170. border-radius: var(--zm-table-column-setting-radius, 6px);
  171. align-items: center;
  172. column-gap: 6px;
  173. grid-template-columns: 22px minmax(0, 1fr) repeat(3, 24px);
  174. &:hover {
  175. background: var(--zm-table-column-setting-hover-bg, var(--el-fill-color-lighter));
  176. }
  177. &.is-group {
  178. font-weight: var(--zm-table-column-setting-group-font-weight, 600);
  179. }
  180. &.is-child {
  181. height: var(--zm-table-column-setting-child-row-height, 30px);
  182. padding-left: 2px;
  183. }
  184. }
  185. .column-setting-label {
  186. overflow: hidden;
  187. color: currentcolor;
  188. text-overflow: ellipsis;
  189. white-space: nowrap;
  190. }
  191. .column-setting-icon-btn {
  192. display: flex;
  193. width: var(--zm-table-column-setting-icon-btn-size, 22px);
  194. height: var(--zm-table-column-setting-icon-btn-size, 22px);
  195. padding: 0;
  196. color: var(--zm-table-column-setting-icon-color, #8aa0b8);
  197. cursor: pointer;
  198. background: transparent;
  199. border: 0;
  200. border-radius: 4px;
  201. align-items: center;
  202. justify-content: center;
  203. &:hover,
  204. &.is-active {
  205. color: var(--zm-table-column-setting-icon-active-color, var(--el-color-primary));
  206. background-color: var(
  207. --zm-table-column-setting-icon-active-bg,
  208. var(--el-color-primary-light-9)
  209. );
  210. }
  211. > div {
  212. width: var(--zm-table-column-setting-icon-size, 15px);
  213. height: var(--zm-table-column-setting-icon-size, 15px);
  214. }
  215. }
  216. .column-setting-drag-handle {
  217. cursor: grab;
  218. &:active {
  219. cursor: grabbing;
  220. }
  221. }
  222. .column-setting-ghost {
  223. background: var(--zm-table-column-setting-ghost-bg, var(--el-color-primary-light-9));
  224. opacity: var(--zm-table-column-setting-ghost-opacity, 0.55);
  225. }
  226. </style>