|
1 | 1 | <template>
|
2 |
| - <a-popover :style="{ width: '200px' }" trigger="click"> |
| 2 | + <a-popover :style="{ width: '200px' }" trigger="click" @popup-visible-change="onPopVisibleChange"> |
3 | 3 | <template #content>
|
4 | 4 | <div style="border-bottom: 1px solid #f5f5f5" class="flex items-center justify-between">
|
5 | 5 | <a-checkbox v-model="allChecked" @change="onAllChange"> 全选 </a-checkbox>
|
6 | 6 | <a-button type="text" class="text-right" @click="onReset"> 重置 </a-button>
|
7 | 7 | </div>
|
8 |
| - <draggable |
9 |
| - :list="innerTableProps" |
10 |
| - animation="500" |
11 |
| - tag="transition-group" |
12 |
| - item-key="key" |
13 |
| - @end="onUpdateValue" |
14 |
| - > |
15 |
| - <template #item="{ element }"> |
16 |
| - <div class="flex pt-2 pb-2"> |
17 |
| - <a-checkbox v-model="element.checked" :label="element.prop" @change="onChange"> |
18 |
| - {{ element.title }} |
19 |
| - </a-checkbox> |
20 |
| - <div class="flex-1"></div> |
21 |
| - <icon-menu /> |
22 |
| - </div> |
23 |
| - </template> |
24 |
| - </draggable> |
| 8 | + <div class="pt-2 pb-2" id="sortColumnWrapper"> |
| 9 | + <div class="column-item" v-for="item of innerTableProps" :key="item.key"> |
| 10 | + <a-checkbox v-model="item.checked" :label="item.title" @change="onChange"> |
| 11 | + {{ item.title }} |
| 12 | + </a-checkbox> |
| 13 | + <div class="flex-1"></div> |
| 14 | + <icon-menu class="handle-icon" /> |
| 15 | + </div> |
| 16 | + </div> |
25 | 17 | </template>
|
26 | 18 | <a-button type="primary" size="small" shape="circle">
|
27 | 19 | <template #icon>
|
|
33 | 25 |
|
34 | 26 | <script lang="ts">
|
35 | 27 | import { TablePropsType } from '@/types/components'
|
36 |
| - import { defineComponent, PropType, reactive, ref, toRef } from 'vue' |
37 |
| - import draggable from 'vuedraggable' |
| 28 | + import { defineComponent, PropType, reactive, ref, toRef, nextTick } from 'vue' |
| 29 | + import Sortable from 'sortablejs' |
| 30 | + import { cloneDeep, isUndefined } from 'lodash-es' |
38 | 31 | export default defineComponent({
|
39 | 32 | name: 'SortableTable',
|
40 |
| - components: { draggable }, |
41 | 33 | props: {
|
42 | 34 | columns: {
|
43 | 35 | type: Array as PropType<TablePropsType[]>,
|
|
47 | 39 | emits: ['update'],
|
48 | 40 | setup(props, { emit }) {
|
49 | 41 | const tempTableProps = toRef(props, 'columns')
|
| 42 | + const originColumns = cloneDeep<TablePropsType[]>(tempTableProps.value!) |
50 | 43 | const tempArray =
|
51 | 44 | tempTableProps.value
|
52 | 45 | ?.filter((it) => !!it.key)
|
53 | 46 | .map((it) => {
|
54 | 47 | return {
|
55 | 48 | ...it,
|
56 |
| - checked: ref(true), |
| 49 | + checked: true, |
57 | 50 | } as TablePropsType
|
58 | 51 | }) || []
|
59 |
| - const innerTableProps = reactive(tempArray) |
| 52 | + const innerTableProps = reactive<TablePropsType[]>(tempArray) |
60 | 53 | const isIndeterminate = ref(
|
61 | 54 | innerTableProps.filter((it) => it.checked).length !== innerTableProps.length
|
62 | 55 | )
|
63 | 56 | const allChecked = ref(innerTableProps.every((it) => it.checked))
|
64 | 57 | function onAllChange(value: any) {
|
65 |
| - innerTableProps.forEach((it) => (it.checked = value?.target?.checked)) |
66 |
| - emit( |
67 |
| - 'update', |
68 |
| - innerTableProps.filter((it) => it.checked) |
69 |
| - ) |
| 58 | + innerTableProps.forEach((it) => (it.checked = value)) |
| 59 | + onUpdateValue(innerTableProps.filter((it) => it.checked)) |
70 | 60 | }
|
71 | 61 | const onChange = () => {
|
72 | 62 | const checkedItems = innerTableProps.filter((it) => it.checked)
|
73 | 63 | allChecked.value = checkedItems.length === innerTableProps.length
|
74 | 64 | isIndeterminate.value =
|
75 | 65 | checkedItems.length > 0 && checkedItems.length !== innerTableProps.length
|
76 |
| - emit('update', checkedItems) |
| 66 | + onUpdateValue(checkedItems) |
77 | 67 | }
|
78 | 68 | const onReset = () => {
|
| 69 | + innerTableProps.length = 0 |
| 70 | + innerTableProps.push(...originColumns) |
79 | 71 | innerTableProps.forEach((it) => (it.checked = true))
|
80 |
| - onChange() |
| 72 | + allChecked.value = true |
| 73 | + onUpdateValue(innerTableProps) |
| 74 | + } |
| 75 | + function onUpdateValue(columns: TablePropsType[]) { |
| 76 | + emit('update', columns) |
81 | 77 | }
|
82 |
| - function onUpdateValue() { |
83 |
| - emit('update', innerTableProps) |
| 78 | + function onPopVisibleChange(visible: boolean) { |
| 79 | + if (visible) { |
| 80 | + nextTick(() => { |
| 81 | + new Sortable(document.getElementById('sortColumnWrapper') as HTMLElement, { |
| 82 | + handle: '.handle-icon', |
| 83 | + animation: 150, |
| 84 | + dataIdAttr: '', |
| 85 | + onEnd({ newIndex, oldIndex }) { |
| 86 | + if (isUndefined(newIndex) || isUndefined(oldIndex)) { |
| 87 | + return |
| 88 | + } |
| 89 | + const originItem = innerTableProps[oldIndex] |
| 90 | + if (newIndex > oldIndex) { |
| 91 | + innerTableProps.splice(newIndex + 1, 0, originItem) |
| 92 | + innerTableProps.splice(oldIndex, 1) |
| 93 | + } else { |
| 94 | + innerTableProps.splice(newIndex, 0, originItem) |
| 95 | + innerTableProps.splice(oldIndex + 1, 1) |
| 96 | + } |
| 97 | + onUpdateValue(innerTableProps) |
| 98 | + }, |
| 99 | + }) |
| 100 | + }) |
| 101 | + } |
84 | 102 | }
|
85 | 103 | return {
|
86 | 104 | innerTableProps,
|
|
90 | 108 | onChange,
|
91 | 109 | onReset,
|
92 | 110 | onUpdateValue,
|
| 111 | + onPopVisibleChange, |
93 | 112 | }
|
94 | 113 | },
|
95 | 114 | })
|
96 | 115 | </script>
|
| 116 | + |
| 117 | +<style lang="less" scoped> |
| 118 | + .column-item { |
| 119 | + display: flex; |
| 120 | + align-items: center; |
| 121 | + padding: 8px 0; |
| 122 | + .handle-icon { |
| 123 | + &:hover { |
| 124 | + cursor: move; |
| 125 | + } |
| 126 | + } |
| 127 | + } |
| 128 | +</style> |
0 commit comments