@neatui/vue 2.7.1 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,636 @@
1
+ <template>
2
+ <div class="pr">
3
+ <div class="full tableloader" style="overflow: auto; position: relative">
4
+ <table class="full-x" ui-table="@b line sz:l" ref="tableRef">
5
+ <thead class="table-head-fixed">
6
+ <tr>
7
+ <th v-if="selected" col-fixed="1" min-width>
8
+ <el-checkbox v-model="all" :indeterminate="!all && isHasSelect ? true : false" v-bind="selected"></el-checkbox>
9
+ </th>
10
+ <template v-for="(col, idx) in state.table" :key="idx">
11
+ <th
12
+ v-if="!col._close"
13
+ class="pr fs-xs nowrap"
14
+ :min-width="col.fixed"
15
+ :col-fixed="col.fixed"
16
+ :col-fixed-side="col.fixed || 'l'"
17
+ :data-field="col.field"
18
+ >
19
+ <div
20
+ :ui-flex="col.label[1] && col.label[1]['ui-flex'] ? col.label[1]['ui-flex'] : !slots.operate && idx === state._last ? 'row rm' : null"
21
+ v-bind="col.label[1]"
22
+ v-on="event(col.label[2], col)"
23
+ >
24
+ <span class="nl-xs" v-if="col.sort" ui-flex="row lm">
25
+ <span v-html="col.label[0]"></span>
26
+ <span class="co-main dib w-xs h-xs nl-ss" ui-flex="row lm" @click.stop="onsort(col)">
27
+ <span :ui-sort="col._sort || 0"></span>
28
+ </span>
29
+ </span>
30
+ <span class="nl-xs" v-else v-html="col.label[0]"></span>
31
+ <IFollowView v-if="operate && tools && !slots.operate && idx === state._last" tipBoxClass="n-no">
32
+ <svg t="1712827525722" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2969" style="width: 1em; height: 1em">
33
+ <path
34
+ d="M512 998.4c-22.4 0-44.8-3.2-67.2-6.4-35.2-6.4-67.2-32-76.8-64-16-54.4-64-89.6-121.6-89.6-9.6 0-19.2 0-28.8 3.2-6.4 0-12.8 3.2-19.2 3.2-28.8 0-54.4-12.8-73.6-35.2-25.6-35.2-51.2-73.6-67.2-115.2-12.8-35.2-6.4-73.6 19.2-99.2 44.8-48 44.8-121.6 0-172.8-25.6-25.6-32-64-19.2-99.2 19.2-38.4 41.6-76.8 70.4-112 19.2-22.4 44.8-35.2 73.6-35.2 6.4 0 12.8 0 19.2 3.2 9.6 3.2 19.2 3.2 28.8 3.2 54.4 0 102.4-35.2 118.4-89.6 9.6-35.2 41.6-60.8 76.8-64 22.4-3.2 44.8-3.2 67.2-3.2 22.4 0 44.8 0 67.2 3.2 35.2 6.4 67.2 32 76.8 64 9.6 32 28.8 57.6 57.6 70.4 19.2 9.6 41.6 16 64 16 9.6 0 19.2 0 28.8-3.2 6.4 0 12.8-3.2 19.2-3.2 28.8 0 54.4 12.8 73.6 35.2 25.6 35.2 48 76.8 67.2 118.4 12.8 32 6.4 73.6-19.2 99.2-44.8 48-44.8 121.6 0 172.8 25.6 25.6 32 64 19.2 99.2-16 41.6-38.4 80-67.2 115.2-19.2 22.4-44.8 35.2-73.6 35.2-6.4 0-12.8 0-19.2-3.2-9.6-3.2-19.2-3.2-28.8-3.2-54.4 0-102.4 35.2-118.4 89.6-9.6 35.2-41.6 60.8-76.8 64-25.6 3.2-48 3.2-70.4 3.2z m-265.6-236.8c89.6 0 169.6 57.6 198.4 144 3.2 6.4 6.4 9.6 12.8 9.6 19.2 3.2 35.2 3.2 54.4 3.2 12.8 0 25.6 0 38.4-3.2h22.4c6.4-3.2 9.6-6.4 9.6-9.6 16-51.2 48-92.8 92.8-115.2 32-19.2 67.2-25.6 102.4-25.6 16 0 32 3.2 44.8 6.4h3.2c3.2 0 9.6-3.2 12.8-3.2 22.4-28.8 41.6-60.8 57.6-96 3.2-6.4 0-12.8-3.2-16-70.4-80-70.4-198.4 0-275.2 3.2-6.4 3.2-12.8 3.2-19.2-12.8-35.2-32-67.2-57.6-96-6.4-6.4-9.6-9.6-12.8-9.6h-3.2c-16 3.2-28.8 6.4-44.8 6.4-35.2 0-70.4-9.6-102.4-25.6-44.8-25.6-76.8-67.2-92.8-115.2 0-6.4-6.4-9.6-9.6-9.6-19.2-3.2-38.4-3.2-57.6-3.2s-38.4 0-57.6 3.2c-6.4 3.2-9.6 6.4-9.6 9.6-16 51.2-48 92.8-92.8 115.2-32 19.2-67.2 25.6-102.4 25.6-16 0-32-3.2-44.8-6.4h-3.2c-9.6 3.2-12.8 3.2-16 6.4-22.4 28.8-41.6 60.8-57.6 96-3.2 6.4 0 12.8 3.2 16 70.4 80 70.4 198.4 0 275.2-3.2 3.2-3.2 9.6-3.2 16 12.8 35.2 32 67.2 54.4 96 3.2 3.2 9.6 6.4 16 6.4 12.8-3.2 28.8-6.4 44.8-6.4z m256-67.2c-48 0-92.8-19.2-128-54.4S320 560 320 512c0-99.2 83.2-182.4 182.4-182.4 102.4 0 182.4 83.2 182.4 182.4 0 102.4-80 182.4-182.4 182.4z m0-284.8c-57.6 0-102.4 48-102.4 105.6 0 57.6 48 105.6 105.6 105.6 57.6 0 105.6-48 102.4-105.6 0-60.8-48-105.6-105.6-105.6v-3.2 3.2z"
35
+ p-id="2970"
36
+ ></path>
37
+ </svg>
38
+ <template v-slot:tips>
39
+ <div class="w-mm h-ml n-sl ar fw4" ui-scroll="x:hidden :y">
40
+ <draggable
41
+ class="al"
42
+ v-model="state.table"
43
+ :force-fallback="true"
44
+ item-key="name"
45
+ chosen-class="chosen"
46
+ animation="200"
47
+ filter=".forbid"
48
+ :move="(e) => !e.relatedContext.element.fixed"
49
+ >
50
+ <div v-for="(element, idx) in state.table" :key="idx" ui-flex="row lm" class="ux-hover n-ss r-ss">
51
+ <label ui-form="@a type:checkbox" :class="`flex-block nowrap ${element.fixed ? 'forbid' : 'element'}`">
52
+ <input type="checkbox" :checked="!element._close" @change="fCloseItem(element)" />
53
+ <span>
54
+ {{ element.label[0] }}
55
+ </span>
56
+ </label>
57
+ <svg
58
+ v-if="element.fixed"
59
+ t="1712839748050"
60
+ class="icon"
61
+ viewBox="0 0 1024 1024"
62
+ version="1.1"
63
+ xmlns="http://www.w3.org/2000/svg"
64
+ p-id="56355"
65
+ style="width: 1em; height: 1em"
66
+ >
67
+ <path
68
+ d="M348.16 192c135.296 0 265.536 75.84 334.08 191.552h278.144a64 64 0 0 1 63.552 56.576l0.448 7.872-1.088 190.08a64 64 0 0 1-64 63.68L704 703.36v0.192h-24.448c-69.12 115.456-196.608 191.808-331.392 191.808a27.52 27.52 0 0 1-27.52-27.52l0.96-292.288H32a32 32 0 0 1 0-64h289.792l0.128-54.208c0-80.32-0.256-160.512-1.28-237.568A27.392 27.392 0 0 1 348.16 192z m36.928 66.304l0.768 128.768-1.088 442.048c97.088-12.16 187.84-71.424 239.808-158.336l15.424-25.856V437.888l-12.864-21.76a332.608 332.608 0 0 0-242.048-157.824zM704 639.36l255.296-1.664 1.088-190.208L704 447.488v191.936z"
69
+ fill="#7D8292"
70
+ p-id="56356"
71
+ ></path>
72
+ </svg>
73
+ </div>
74
+ </draggable>
75
+ </div>
76
+ </template>
77
+ </IFollowView>
78
+ </div>
79
+ </th>
80
+ <th v-if="operate && slots.operate" col-fixed="r" class="fs-xs nowrap ar">
81
+ <div ui-flex="row rm">
82
+ <span class="mr-sm">{{ words['operate'] || '操作' }}</span>
83
+ <IFollowView v-if="tools" tipBoxClass="n-no">
84
+ <svg t="1712827525722" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2969" style="width: 1em; height: 1em">
85
+ <path
86
+ d="M512 998.4c-22.4 0-44.8-3.2-67.2-6.4-35.2-6.4-67.2-32-76.8-64-16-54.4-64-89.6-121.6-89.6-9.6 0-19.2 0-28.8 3.2-6.4 0-12.8 3.2-19.2 3.2-28.8 0-54.4-12.8-73.6-35.2-25.6-35.2-51.2-73.6-67.2-115.2-12.8-35.2-6.4-73.6 19.2-99.2 44.8-48 44.8-121.6 0-172.8-25.6-25.6-32-64-19.2-99.2 19.2-38.4 41.6-76.8 70.4-112 19.2-22.4 44.8-35.2 73.6-35.2 6.4 0 12.8 0 19.2 3.2 9.6 3.2 19.2 3.2 28.8 3.2 54.4 0 102.4-35.2 118.4-89.6 9.6-35.2 41.6-60.8 76.8-64 22.4-3.2 44.8-3.2 67.2-3.2 22.4 0 44.8 0 67.2 3.2 35.2 6.4 67.2 32 76.8 64 9.6 32 28.8 57.6 57.6 70.4 19.2 9.6 41.6 16 64 16 9.6 0 19.2 0 28.8-3.2 6.4 0 12.8-3.2 19.2-3.2 28.8 0 54.4 12.8 73.6 35.2 25.6 35.2 48 76.8 67.2 118.4 12.8 32 6.4 73.6-19.2 99.2-44.8 48-44.8 121.6 0 172.8 25.6 25.6 32 64 19.2 99.2-16 41.6-38.4 80-67.2 115.2-19.2 22.4-44.8 35.2-73.6 35.2-6.4 0-12.8 0-19.2-3.2-9.6-3.2-19.2-3.2-28.8-3.2-54.4 0-102.4 35.2-118.4 89.6-9.6 35.2-41.6 60.8-76.8 64-25.6 3.2-48 3.2-70.4 3.2z m-265.6-236.8c89.6 0 169.6 57.6 198.4 144 3.2 6.4 6.4 9.6 12.8 9.6 19.2 3.2 35.2 3.2 54.4 3.2 12.8 0 25.6 0 38.4-3.2h22.4c6.4-3.2 9.6-6.4 9.6-9.6 16-51.2 48-92.8 92.8-115.2 32-19.2 67.2-25.6 102.4-25.6 16 0 32 3.2 44.8 6.4h3.2c3.2 0 9.6-3.2 12.8-3.2 22.4-28.8 41.6-60.8 57.6-96 3.2-6.4 0-12.8-3.2-16-70.4-80-70.4-198.4 0-275.2 3.2-6.4 3.2-12.8 3.2-19.2-12.8-35.2-32-67.2-57.6-96-6.4-6.4-9.6-9.6-12.8-9.6h-3.2c-16 3.2-28.8 6.4-44.8 6.4-35.2 0-70.4-9.6-102.4-25.6-44.8-25.6-76.8-67.2-92.8-115.2 0-6.4-6.4-9.6-9.6-9.6-19.2-3.2-38.4-3.2-57.6-3.2s-38.4 0-57.6 3.2c-6.4 3.2-9.6 6.4-9.6 9.6-16 51.2-48 92.8-92.8 115.2-32 19.2-67.2 25.6-102.4 25.6-16 0-32-3.2-44.8-6.4h-3.2c-9.6 3.2-12.8 3.2-16 6.4-22.4 28.8-41.6 60.8-57.6 96-3.2 6.4 0 12.8 3.2 16 70.4 80 70.4 198.4 0 275.2-3.2 3.2-3.2 9.6-3.2 16 12.8 35.2 32 67.2 54.4 96 3.2 3.2 9.6 6.4 16 6.4 12.8-3.2 28.8-6.4 44.8-6.4z m256-67.2c-48 0-92.8-19.2-128-54.4S320 560 320 512c0-99.2 83.2-182.4 182.4-182.4 102.4 0 182.4 83.2 182.4 182.4 0 102.4-80 182.4-182.4 182.4z m0-284.8c-57.6 0-102.4 48-102.4 105.6 0 57.6 48 105.6 105.6 105.6 57.6 0 105.6-48 102.4-105.6 0-60.8-48-105.6-105.6-105.6v-3.2 3.2z"
87
+ p-id="2970"
88
+ ></path>
89
+ </svg>
90
+ <template v-slot:tips>
91
+ <div class="w-mm h-ml n-sl ar fw4" ui-scroll="x:hidden :y">
92
+ <draggable
93
+ class="al"
94
+ v-model="state.table"
95
+ :force-fallback="true"
96
+ item-key="name"
97
+ chosen-class="chosen"
98
+ animation="200"
99
+ filter=".forbid"
100
+ :move="(e) => !e.relatedContext.element.fixed"
101
+ >
102
+ <div v-for="(element, idx) in state.table" :key="idx" ui-flex="row lm" class="ux-hover n-ss r-ss">
103
+ <label ui-form="@a type:checkbox" :class="`flex-block nowrap ${element.fixed ? 'forbid' : 'element'}`">
104
+ <input type="checkbox" :checked="!element._close" @change="fCloseItem(element)" />
105
+ <span>
106
+ {{ element.label[0] }}
107
+ </span>
108
+ </label>
109
+ <svg
110
+ v-if="element.fixed"
111
+ t="1712839748050"
112
+ class="icon"
113
+ viewBox="0 0 1024 1024"
114
+ version="1.1"
115
+ xmlns="http://www.w3.org/2000/svg"
116
+ p-id="56355"
117
+ style="width: 1em; height: 1em"
118
+ >
119
+ <path
120
+ d="M348.16 192c135.296 0 265.536 75.84 334.08 191.552h278.144a64 64 0 0 1 63.552 56.576l0.448 7.872-1.088 190.08a64 64 0 0 1-64 63.68L704 703.36v0.192h-24.448c-69.12 115.456-196.608 191.808-331.392 191.808a27.52 27.52 0 0 1-27.52-27.52l0.96-292.288H32a32 32 0 0 1 0-64h289.792l0.128-54.208c0-80.32-0.256-160.512-1.28-237.568A27.392 27.392 0 0 1 348.16 192z m36.928 66.304l0.768 128.768-1.088 442.048c97.088-12.16 187.84-71.424 239.808-158.336l15.424-25.856V437.888l-12.864-21.76a332.608 332.608 0 0 0-242.048-157.824zM704 639.36l255.296-1.664 1.088-190.208L704 447.488v191.936z"
121
+ fill="#7D8292"
122
+ p-id="56356"
123
+ ></path>
124
+ </svg>
125
+ </div>
126
+ </draggable>
127
+ </div>
128
+ </template>
129
+ </IFollowView>
130
+ </div>
131
+ </th>
132
+ </tr>
133
+ </thead>
134
+ <tbody :ui-tbody-load="state.load" v-if="$lists.length">
135
+ <tr
136
+ v-for="(item, idx) in $lists"
137
+ :key="idx + '_' + item._id"
138
+ v-bind="isFunction(props.rows.attrs) ? props.rows.attrs(item, idx, $lists) : props.rows.attrs"
139
+ v-on="event(props.rows.event, item, 'td')"
140
+ >
141
+ <td v-if="selected" col-fixed="1" min-width>
142
+ <el-checkbox v-model="$lists[idx].__selected" v-bind="selected"></el-checkbox>
143
+ </td>
144
+ <td
145
+ v-for="(col, idx) in state.table"
146
+ :key="idx"
147
+ v-if="!col._close"
148
+ :class="`${!slots.operate && idx === state._last && !slots.operate ? 'ar' : ''}`"
149
+ :min-width="col.fixed"
150
+ :col-fixed="col.fixed"
151
+ :col-fixed-side="col.fixed || 'l'"
152
+ :data-field="col.field"
153
+ >
154
+ <slot v-if="operate && slots[col.field]" :name="col.field" :data="item" :note="col"></slot>
155
+ <TableColView v-else :col="col" :data="item" />
156
+ </td>
157
+ <td v-if="operate && slots.operate" col-fixed="r" class="ar">
158
+ <slot name="operate" :item="item" :idx="idx"></slot>
159
+ </td>
160
+ </tr>
161
+ </tbody>
162
+ <tbody v-else-if="!load">
163
+ <tr>
164
+ <td :colspan="cols" class="ac ny-ls">
165
+ <p class="lh-xs o-sm">
166
+ <svg t="1721803279190" class="icon w-ss h-ss" viewBox="0 0 1203 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10075" width="128" height="128">
167
+ <path
168
+ d="M109.985185 984.809877c-39.190123 0-72.059259-31.604938-72.059259-70.795062V620.720988L211.120988 366.617284c15.17037-22.755556 41.718519-36.661728 68.266666-36.661728h632.098766c27.812346 0 53.096296 13.906173 68.266666 36.661728l171.930865 254.103704 1.264197 293.293827c0 39.190123-31.604938 70.795062-72.059259 70.795062H109.985185z m-48.039506-107.456791c0 59.417284 10.11358 83.437037 72.059259 83.437037h911.48642c60.681481 0 82.17284-20.22716 84.701235-77.116049V648.533333h-3.792593l-1.264198 1.264198h-50.567901l-297.08642 1.264197c-11.377778 0-20.22716 8.849383-20.22716 18.962963v11.377778c-6.320988 73.323457-73.323457 126.419753-161.817284 126.419753-72.059259 0-154.232099-49.303704-161.817284-127.68395v-11.377778c0-11.377778-8.849383-20.22716-20.22716-20.227161H61.945679v228.819753z m217.441975-520.849382c-18.962963 0-36.661728 8.849383-46.775308 25.28395L67.002469 624.51358h379.259259c3.792593 0 7.585185 3.792593 7.585186 7.585185v11.377778c0 78.380247 64.474074 141.590123 142.854321 141.590124 78.380247 0 142.854321-63.209877 142.854321-141.590124v-12.641975c0-2.528395 2.528395-6.320988 5.05679-6.320988H1125.135802L959.525926 381.787654c-10.11358-15.17037-27.812346-25.283951-46.775309-25.28395H279.387654z m541.076544-126.419753c-3.792593 0-7.585185-1.264198-10.113581-3.792593-2.528395-2.528395-5.05679-6.320988-5.05679-10.11358 0-3.792593 1.264198-7.585185 3.792593-10.11358l88.493827-88.493828c2.528395-2.528395 6.320988-3.792593 10.11358-3.792592 3.792593 0 8.849383 1.264198 11.377778 5.05679 5.05679 6.320988 5.05679 15.17037 0 20.22716l-87.22963 85.965432c-2.528395 3.792593-6.320988 5.05679-11.377777 5.056791z m-450.054321 0c-3.792593 0-7.585185-1.264198-10.113581-3.792593L273.066667 139.061728c-3.792593-2.528395-5.05679-6.320988-5.05679-11.377777s1.264198-7.585185 3.792592-11.377778c2.528395-3.792593 7.585185-5.05679 11.377778-5.05679 3.792593 0 7.585185 1.264198 10.11358 3.792592l88.493827 88.493827c6.320988 6.320988 6.320988 15.17037 0 21.491358-2.528395 2.528395-6.320988 5.05679-11.377777 5.056791z m225.02716-30.340741c-8.849383 0-15.17037-6.320988-15.17037-15.17037V54.360494c0-8.849383 6.320988-15.17037 15.17037-15.170371s15.17037 6.320988 15.17037 15.170371v131.476543c0 7.585185-6.320988 13.906173-15.17037 13.906173z"
169
+ p-id="10076"
170
+ ></path>
171
+ </svg>
172
+ </p>
173
+ <p class="o-mm">
174
+ {{ words['nodata'] || '暂无记录' }}
175
+ </p>
176
+ </td>
177
+ </tr>
178
+ </tbody>
179
+ </table>
180
+ </div>
181
+ <div v-show="load" class="pa full ot-no ol-no z10 ux-none fs-ms nb-ll co-main" style="background-color: rgba(255, 255, 255, 0.5)" ui-flex="col cm">
182
+ <i ui-load="@d"></i>
183
+ </div>
184
+ </div>
185
+ </template>
186
+
187
+ <script setup lang="ts">
188
+ import { ref, reactive, computed, watch, nextTick, onMounted, onBeforeUnmount, useSlots, useRoute } from 'vue';
189
+ import draggable from 'vuedraggable';
190
+ import { isFunction, isObject, deepcopy, isBoolean, isString, isArray } from '@fekit/utils';
191
+ import { itable } from '@fekit/itable';
192
+ import IFollowView from '../IFollowView/IFollowView.vue';
193
+ import TableColView from './TableColView@v3.vue';
194
+ import { hasSelected } from './index';
195
+
196
+ // 定义接口
197
+ interface TableColumn {
198
+ field: string;
199
+ label: any[];
200
+ sort?: boolean;
201
+ fixed?: string | number | boolean;
202
+ close?: boolean | number | string;
203
+ _close?: number;
204
+ _sort?: number;
205
+ _order?: number;
206
+ model?: any;
207
+ attrs?: any;
208
+ event?: any;
209
+ popup?: any;
210
+ child?: any;
211
+ enums?: any;
212
+ value?: any;
213
+ }
214
+
215
+ interface ListItem {
216
+ _id: string | number;
217
+ __selected?: boolean;
218
+ id?: string | number;
219
+ [key: string]: any;
220
+ }
221
+
222
+ interface StateType {
223
+ name: string;
224
+ load: number;
225
+ tool: number;
226
+ mode: number;
227
+ id: number;
228
+ table: TableColumn[];
229
+ param: Record<string, any>;
230
+ last: number;
231
+ _last: number;
232
+ cacheSelecteds: ListItem[];
233
+ cacheUnselecteds: ListItem[];
234
+ }
235
+
236
+ interface RowsType {
237
+ attrs?: any;
238
+ event?: any;
239
+ }
240
+
241
+ // Props定义
242
+ interface Props {
243
+ load?: boolean | number;
244
+ words?: Record<string, string>;
245
+ table?: TableColumn[];
246
+ lists?: ListItem[];
247
+ select?: boolean | object | Function;
248
+ crossPageSelection?: boolean;
249
+ operate?: boolean | object | Function;
250
+ tools?: boolean | object | Function;
251
+ rows?: RowsType;
252
+ }
253
+
254
+ const props = withDefaults(defineProps<Props>(), {
255
+ load: false,
256
+ words: () => ({}),
257
+ table: () => [],
258
+ lists: () => [],
259
+ select: true,
260
+ crossPageSelection: false,
261
+ operate: true,
262
+ tools: false,
263
+ rows: () => ({ attrs: {}, event: {} })
264
+ });
265
+
266
+ // Emits定义
267
+ const emit = defineEmits<{
268
+ selecteds: [value: any];
269
+ onsort: [sorts: TableColumn[], callback: () => void];
270
+ }>();
271
+
272
+ // 获取slots和route
273
+ const slots = useSlots();
274
+ const route = useRoute();
275
+
276
+ // 模板引用
277
+ const tableRef = ref<HTMLTableElement>();
278
+
279
+ // 响应式状态
280
+ const state = reactive<StateType>({
281
+ name: 'confs' + route.path.replace(/\//g, '_'),
282
+ load: 0,
283
+ tool: 1,
284
+ mode: 0,
285
+ id: 0,
286
+ table: [],
287
+ param: {},
288
+ last: 0,
289
+ _last: 0,
290
+ // 跨页缓存选中项
291
+ cacheSelecteds: [],
292
+ cacheUnselecteds: []
293
+ });
294
+
295
+ // 计算属性
296
+ const $lists = computed(() => {
297
+ // 新增跨页选中/取消功能
298
+ return props.lists?.map((item, idx) => {
299
+ item._id = item.id || item._id || idx;
300
+ // 跨页选择场景
301
+ if (props.crossPageSelection) {
302
+ // 如果 cacheSelecteds 中存在一条数据的 id 等于 item.id,且 cacheUnselecteds 中不存在,则认为选中
303
+ const isSelected = state.cacheSelecteds.some((cItem) => cItem._id === item._id) && !state.cacheUnselecteds.some((cItem) => cItem._id === item._id);
304
+ item.__selected = isSelected;
305
+ } else {
306
+ // 原逻辑
307
+ item.__selected = item.__selected || false;
308
+ }
309
+ return item;
310
+ });
311
+ });
312
+
313
+ const all = computed({
314
+ get() {
315
+ return $lists.value.length && $lists.value.every((item) => item.__selected);
316
+ },
317
+ set(value: boolean) {
318
+ $lists.value.map((item: ListItem = {}) => {
319
+ item.__selected = value;
320
+ });
321
+ }
322
+ });
323
+
324
+ const isHasSelect = computed(() => {
325
+ return hasSelected($lists.value);
326
+ });
327
+
328
+ const selected = computed(() => {
329
+ let _select = props.select;
330
+ if (isFunction(_select)) {
331
+ _select = (_select as Function)();
332
+ }
333
+ if (isBoolean(_select) && _select) {
334
+ _select = {};
335
+ } else if (isObject(_select)) {
336
+ _select = _select;
337
+ } else {
338
+ _select = false;
339
+ }
340
+ return _select;
341
+ });
342
+
343
+ const cols = computed(() => {
344
+ return (state?.table?.filter((item) => !item._close)?.length || 0) + (selected.value ? 1 : 0) + (props.operate ? 1 : 0);
345
+ });
346
+
347
+ // 方法
348
+ const pretable = () => {
349
+ const _cache = JSON.parse(localStorage.getItem(`${state.name}_table`) || '{}');
350
+ state._last = 0;
351
+ state.table = deepcopy(props.table || [])
352
+ .map((item, idx) => {
353
+ if (!isArray(item.label)) {
354
+ item.label = [item.label, item.attrs, {}];
355
+ } else {
356
+ if (item.label.length < 2) {
357
+ item.label.push(item.attrs);
358
+ }
359
+ if (item.label.length < 3) {
360
+ item.label.push({});
361
+ }
362
+ }
363
+ if (isFunction(item.label[0])) {
364
+ item.label[0] = (item.label[0] as Function)($lists.value, item);
365
+ }
366
+ if (isFunction(item.label[1])) {
367
+ item.label[1] = (item.label[1] as Function)($lists.value, item);
368
+ }
369
+ if (isFunction(item.label[2])) {
370
+ item.label[2] = (item.label[2] as Function)($lists.value, item);
371
+ }
372
+ if (!isObject(item.label[1])) {
373
+ item.label[1] = {};
374
+ }
375
+ if (!isObject(item.label[2])) {
376
+ item.label[2] = {};
377
+ }
378
+
379
+ // 缓存关闭字段
380
+ if (_cache[item.field] && Object.prototype.hasOwnProperty.call(_cache[item.field], '_close')) {
381
+ item._close = _cache[item.field]._close;
382
+ } else {
383
+ if (item.close === true || item.close === 1 || item.close === 'always') {
384
+ item._close = 1;
385
+ }
386
+ }
387
+ // 缓存列的排序
388
+ if (_cache[item.field] && Object.prototype.hasOwnProperty.call(_cache[item.field], '_order')) {
389
+ item._order = _cache[item.field]._order;
390
+ }
391
+ if (!item._close) {
392
+ state._last = idx;
393
+ }
394
+
395
+ // 缓存字段排序
396
+ if (_cache[item.field] && Object.prototype.hasOwnProperty.call(_cache[item.field], '_sort')) {
397
+ item._sort = _cache[item.field]._sort || 0;
398
+ }
399
+
400
+ // 模型处理
401
+ if (item.model) {
402
+ if (isString(item.model)) {
403
+ item.model = [item.model, {}];
404
+ }
405
+ } else {
406
+ item.model = ['Text', {}];
407
+ }
408
+
409
+ return item;
410
+ })
411
+ .sort((a, b) => (a._order || 0) - (b._order || 0))
412
+ .sort((a, b) => {
413
+ const fixedOrder: Record<string, number> = { 1: -1, l: -1, r: 1 };
414
+ const aFixed = (a.fixed || '').toString();
415
+ const bFixed = (b.fixed || '').toString();
416
+ return (fixedOrder[aFixed] || 0) - (fixedOrder[bFixed] || 0);
417
+ });
418
+ };
419
+
420
+ const fSelectAll = (value: boolean) => {
421
+ $lists.value.map((item: ListItem = {}) => {
422
+ item.__selected = value;
423
+ });
424
+ };
425
+
426
+ const event = (eventObj: any, data?: any, type?: string) => {
427
+ const _event: Record<string, Function> = {};
428
+ if (isObject(eventObj)) {
429
+ for (const key in eventObj) {
430
+ const fun = eventObj[key];
431
+ if (isFunction(fun)) {
432
+ _event[key] = (...args: any[]) => {
433
+ return (fun as Function)({ data }, ...args);
434
+ };
435
+ }
436
+ }
437
+ }
438
+ return { ..._event };
439
+ };
440
+
441
+ const fCloseItem = (item: TableColumn = {}) => {
442
+ item._close = item._close ? 0 : 1;
443
+ };
444
+
445
+ const onsort = (col: TableColumn) => {
446
+ const _sorts = state?.table?.filter((item) => item._sort !== 0);
447
+ col._sort = col._sort === 0 || !col._sort ? 1 : col._sort === 1 ? 2 : 0;
448
+ _sorts.unshift(col);
449
+ emit('onsort', _sorts, () => {
450
+ state.table.forEach((item) => {
451
+ if (item.field !== col.field && item._sort !== 0) {
452
+ item._sort = 0;
453
+ }
454
+ });
455
+ });
456
+ };
457
+
458
+ // 清空跨页选中项
459
+ const clearCrossPageSelecteds = () => {
460
+ state.cacheSelecteds = [];
461
+ state.cacheUnselecteds = [];
462
+ };
463
+
464
+ // 监听器
465
+ watch(
466
+ () => props.table,
467
+ () => {
468
+ pretable();
469
+ },
470
+ { deep: true, immediate: true }
471
+ );
472
+
473
+ watch(
474
+ $lists,
475
+ () => {
476
+ pretable();
477
+
478
+ // 新增跨页选中/取消功能
479
+ if (props.crossPageSelection) {
480
+ $lists.value?.forEach((item) => {
481
+ if (item.__selected) {
482
+ // 如果选中,则在 cacheSelecteds 中存整条数据(避免重复存储)
483
+ if (!state.cacheSelecteds.some((cItem) => cItem._id === item._id)) {
484
+ state.cacheSelecteds.push(deepcopy(item)); // 使用 deepcopy 防止引用问题
485
+ }
486
+ const unselectIdx = state.cacheUnselecteds.findIndex((cItem) => cItem._id === item._id);
487
+ if (unselectIdx > -1) {
488
+ state.cacheUnselecteds.splice(unselectIdx, 1);
489
+ }
490
+ } else {
491
+ // 如果未选中,则从 cacheSelecteds 中移除,并在 cacheUnselecteds 中存整条数据
492
+ const selectedIdx = state.cacheSelecteds.findIndex((cItem) => cItem._id === item._id);
493
+ if (selectedIdx > -1) {
494
+ state.cacheSelecteds.splice(selectedIdx, 1);
495
+ }
496
+ if (!state.cacheUnselecteds.some((cItem) => cItem._id === item._id)) {
497
+ state.cacheUnselecteds.push(deepcopy(item));
498
+ }
499
+ }
500
+ });
501
+ }
502
+ if (props.crossPageSelection) {
503
+ emit('selecteds', deepcopy(state.cacheSelecteds));
504
+ } else {
505
+ emit('selecteds', deepcopy(selected.value));
506
+ }
507
+ },
508
+ { deep: true, immediate: true }
509
+ );
510
+
511
+ watch(
512
+ () => state.table,
513
+ () => {
514
+ const _table: Record<string, any> = {};
515
+ state._last = 0;
516
+ state.table.forEach((item, idx) => {
517
+ _table[item.field] = { _order: idx };
518
+ if (Object.prototype.hasOwnProperty.call(item, '_close')) {
519
+ _table[item.field]._close = item._close ? 1 : 0;
520
+ }
521
+ if (!item._close) {
522
+ state._last = idx;
523
+ }
524
+ if (Object.prototype.hasOwnProperty.call(item, '_sort')) {
525
+ _table[item.field]._sort = item._sort || 0;
526
+ }
527
+ });
528
+ localStorage.setItem(`${state.name}_table`, JSON.stringify(_table));
529
+ },
530
+ { deep: true }
531
+ );
532
+
533
+ // 生命周期
534
+ onMounted(() => {
535
+ nextTick(() => {
536
+ if (tableRef.value) {
537
+ itable.listen(tableRef.value);
538
+ }
539
+ });
540
+
541
+ watch(
542
+ () => state.table,
543
+ () => {
544
+ nextTick(() => {
545
+ if (tableRef.value) {
546
+ itable.listen(tableRef.value);
547
+ }
548
+ });
549
+ },
550
+ { deep: true }
551
+ );
552
+
553
+ // 初始化获取缓存的数据排序
554
+ const _cache = JSON.parse(localStorage.getItem(`${state.name}_table`) || '{}');
555
+ const _sorts: TableColumn[] = [];
556
+ Object.keys(_cache)?.forEach((key) => {
557
+ const item = _cache[key];
558
+ if (item._sort !== 0) {
559
+ const col = state.table.find((i) => i.field === key);
560
+ if (col) {
561
+ _sorts.unshift(col);
562
+ }
563
+ }
564
+ });
565
+ emit('onsort', _sorts, () => {
566
+ const col = _sorts[0];
567
+ if (col) {
568
+ state.table.forEach((item) => {
569
+ if (item.field !== col.field && item._sort !== 0) {
570
+ item._sort = 0;
571
+ }
572
+ });
573
+ }
574
+ });
575
+ });
576
+
577
+ onBeforeUnmount(() => {
578
+ itable.remove();
579
+ });
580
+
581
+ // 暴露方法给父组件
582
+ defineExpose({
583
+ clearCrossPageSelecteds,
584
+ fSelectAll
585
+ });
586
+ </script>
587
+
588
+ <style>
589
+ .tableloader tr:hover td {
590
+ background-color: #f8f9fa !important;
591
+ }
592
+ .tableloader th {
593
+ font-size: 11px;
594
+ line-height: 1.5;
595
+ color: #909399;
596
+ box-shadow: inset 1px 1px 0 0 #f0f0f0;
597
+ }
598
+ .tableloader td {
599
+ font-size: 12px;
600
+ line-height: 1.5;
601
+ color: #606266;
602
+ box-shadow: inset 1px 1px 0 0 #f0f0f0;
603
+ }
604
+ .tableloader th:last-child,
605
+ .tableloader td:last-child {
606
+ box-shadow:
607
+ inset 1px 1px 0 0 #f0f0f0,
608
+ inset -1px 1px 0 0 #f0f0f0;
609
+ }
610
+ .tableloader tr:last-child td {
611
+ box-shadow:
612
+ inset 1px 1px 0 0 #f0f0f0,
613
+ inset 1px -1px 0 0 #f0f0f0;
614
+ }
615
+ .tableloader tr:last-child td:last-child {
616
+ box-shadow:
617
+ inset 1px 1px 0 0 #f0f0f0,
618
+ inset -1px -1px 0 0 #f0f0f0;
619
+ }
620
+ .tableloader tbody tr:nth-child(2n + 1),
621
+ .tableloader tbody tr:nth-child(2n + 1) td,
622
+ .tableloader tbody tr:nth-child(2n + 1) th {
623
+ background-color: #fff;
624
+ }
625
+
626
+ .tableloader-setwidth {
627
+ position: absolute;
628
+ width: 18px;
629
+ height: 100%;
630
+ right: -9px;
631
+ top: 0;
632
+ z-index: 1;
633
+ color: red;
634
+ cursor: col-resize;
635
+ }
636
+ </style>
@@ -0,0 +1,41 @@
1
+ import { isFunction } from '@fekit/utils';
2
+
3
+ // 定义类型接口
4
+ interface ListItem {
5
+ _id?: string | number;
6
+ __selected?: boolean;
7
+ id?: string | number;
8
+ [key: string]: any;
9
+ }
10
+
11
+ // 是否有选中记录
12
+ export const hasSelected = (lists: ListItem[] = []): number => {
13
+ return (lists?.length && lists?.filter((item) => item.__selected)?.length) || 0;
14
+ };
15
+
16
+ // 获取选中的记录
17
+ export const getSelectedLists = <T = any>(lists: ListItem[] = [], key: string | ((item: ListItem) => T) = ''): T[] => {
18
+ return (
19
+ lists
20
+ ?.filter((item) => {
21
+ return item.__selected;
22
+ })
23
+ ?.map((item) => {
24
+ return isFunction(key) ? (key as (item: ListItem) => T)(item) : key ? item[key as string] : item;
25
+ }) || []
26
+ );
27
+ };
28
+
29
+ // 全选计算属性 - 用于Vue2兼容性,Vue3中建议直接使用computed
30
+ export function allSelected(lists: ListItem[]) {
31
+ return {
32
+ get(): boolean {
33
+ return lists.length > 0 && lists.every((item) => item.__selected);
34
+ },
35
+ set(value: boolean): void {
36
+ lists.forEach((item = {}) => {
37
+ item.__selected = value;
38
+ });
39
+ }
40
+ };
41
+ }
@@ -1,5 +1,6 @@
1
1
  import FormLoader from './FormLoader';
2
2
  import LimitLoader from './LimitLoader';
3
- import TableLoader from './TableLoader';
3
+ export * from './TableLoader/index';
4
+ import TableLoader from './TableLoader/TableLoader.vue';
4
5
  import ViewLoader from './ViewLoader';
5
6
  export { FormLoader, LimitLoader, TableLoader, ViewLoader };