@netang/quasar 0.1.26 → 0.1.27
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.
- package/components/mixed-table/index.vue +15 -13
- package/components/table/index.vue +454 -6
- package/components/table-column-fixed/index.vue +110 -112
- package/components/tree/index.vue +4 -5
- package/package.json +1 -1
- package/sass/quasar/table.scss +161 -150
|
@@ -70,6 +70,7 @@
|
|
|
70
70
|
<q-page-container>
|
|
71
71
|
<q-page>
|
|
72
72
|
<n-table
|
|
73
|
+
ref="tableRef"
|
|
73
74
|
class="n-table absolute-full"
|
|
74
75
|
:class="{
|
|
75
76
|
'n-table--last-fixed': showTableFixed,
|
|
@@ -101,13 +102,11 @@
|
|
|
101
102
|
v-for="imgName in tableImgNames"
|
|
102
103
|
v-slot:[`body-cell-${imgName}`]="props"
|
|
103
104
|
>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
/>
|
|
110
|
-
</q-td>
|
|
105
|
+
<!-- 缩略图 -->
|
|
106
|
+
<n-thumbnail
|
|
107
|
+
:src="props.row[imgName]"
|
|
108
|
+
preview
|
|
109
|
+
/>
|
|
111
110
|
</template>
|
|
112
111
|
|
|
113
112
|
<!-- 插槽 -->
|
|
@@ -115,12 +114,10 @@
|
|
|
115
114
|
v-for="slotName in slotNames.table"
|
|
116
115
|
v-slot:[slotName]="props"
|
|
117
116
|
>
|
|
118
|
-
<
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
/>
|
|
123
|
-
</q-td>
|
|
117
|
+
<slot
|
|
118
|
+
:name="slotName"
|
|
119
|
+
v-bind="props"
|
|
120
|
+
/>
|
|
124
121
|
</template>
|
|
125
122
|
|
|
126
123
|
<!-- 操作 -->
|
|
@@ -320,6 +317,9 @@ export default {
|
|
|
320
317
|
currentTableRowDblclick = $table.tableRowDblclick
|
|
321
318
|
}
|
|
322
319
|
|
|
320
|
+
// 表格节点
|
|
321
|
+
const tableRef = ref(null)
|
|
322
|
+
|
|
323
323
|
// 树节点
|
|
324
324
|
const treeRef = ref(null)
|
|
325
325
|
|
|
@@ -451,6 +451,8 @@ export default {
|
|
|
451
451
|
// 解构表格实例
|
|
452
452
|
...$table,
|
|
453
453
|
|
|
454
|
+
// 表格节点
|
|
455
|
+
tableRef,
|
|
454
456
|
// 树节点
|
|
455
457
|
treeRef,
|
|
456
458
|
// 树筛选值
|
|
@@ -1,12 +1,68 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<q-table
|
|
3
3
|
class="n-table"
|
|
4
|
+
:columns="columns"
|
|
5
|
+
:rows="currentRows"
|
|
4
6
|
:virtual-scroll-slice-size="virtualScrollItemSize"
|
|
5
7
|
v-bind="$attrs"
|
|
6
8
|
>
|
|
7
|
-
<!--
|
|
9
|
+
<!-- 展开子数据插槽 -->
|
|
8
10
|
<template
|
|
9
|
-
v-
|
|
11
|
+
v-slot:[slotNames.expandName]="props"
|
|
12
|
+
v-if="hasChildren"
|
|
13
|
+
>
|
|
14
|
+
<q-td
|
|
15
|
+
class="row no-wrap items-center "
|
|
16
|
+
:style="{ paddingLeft: (meta[props.key].level * 16) + 'px' }"
|
|
17
|
+
:props="props"
|
|
18
|
+
>
|
|
19
|
+
<!-- 旋转器 -->
|
|
20
|
+
<q-spinner
|
|
21
|
+
class="q-tree__spinner q-ml-sm"
|
|
22
|
+
:color="iconColor"
|
|
23
|
+
v-if="meta[props.key].lazy === 'loading'"
|
|
24
|
+
/>
|
|
25
|
+
|
|
26
|
+
<!-- 箭头 -->
|
|
27
|
+
<template v-else>
|
|
28
|
+
<q-icon
|
|
29
|
+
class="q-tree__arrow q-ml-sm"
|
|
30
|
+
:name="computedIcon"
|
|
31
|
+
:color="iconColor"
|
|
32
|
+
:class="`${meta[props.key].expanded ? 'q-tree__arrow--rotate' : ''}`"
|
|
33
|
+
@click="onExpandClick(props, $event)"
|
|
34
|
+
v-if="meta[props.key].isParent || meta[props.key].lazy === true"
|
|
35
|
+
/>
|
|
36
|
+
<span class="q-icon n-table__arrow-noop q-ml-sm" v-else></span>
|
|
37
|
+
</template>
|
|
38
|
+
|
|
39
|
+
<!-- 如果有插槽 -->
|
|
40
|
+
<slot
|
|
41
|
+
:name="slotNames.expandName"
|
|
42
|
+
v-bind="props"
|
|
43
|
+
v-if="slotNames.hasExpandSlot"
|
|
44
|
+
/>
|
|
45
|
+
<!-- 否则显示值 -->
|
|
46
|
+
<span v-else>{{getCellValue(props.col, props.row)}}</span>
|
|
47
|
+
</q-td>
|
|
48
|
+
</template>
|
|
49
|
+
|
|
50
|
+
<!-- 单元格插槽 -->
|
|
51
|
+
<template
|
|
52
|
+
v-for="slotName in slotNames.bodyCell"
|
|
53
|
+
v-slot:[slotName]="props"
|
|
54
|
+
>
|
|
55
|
+
<q-td :props="props">
|
|
56
|
+
<slot
|
|
57
|
+
:name="slotName"
|
|
58
|
+
v-bind="props"
|
|
59
|
+
/>
|
|
60
|
+
</q-td>
|
|
61
|
+
</template>
|
|
62
|
+
|
|
63
|
+
<!-- 其他插槽 -->
|
|
64
|
+
<template
|
|
65
|
+
v-for="slotName in slotNames.other"
|
|
10
66
|
v-slot:[slotName]="props"
|
|
11
67
|
>
|
|
12
68
|
<slot
|
|
@@ -14,13 +70,19 @@
|
|
|
14
70
|
v-bind="props"
|
|
15
71
|
/>
|
|
16
72
|
</template>
|
|
73
|
+
|
|
17
74
|
</q-table>
|
|
18
75
|
</template>
|
|
19
76
|
|
|
20
77
|
<script>
|
|
21
|
-
import { computed } from 'vue'
|
|
78
|
+
import { ref, watch, computed, getCurrentInstance, nextTick } from 'vue'
|
|
79
|
+
import { stopAndPrevent } from 'quasar/src/utils/event'
|
|
80
|
+
|
|
81
|
+
import $n_has from 'lodash/has'
|
|
22
82
|
|
|
23
|
-
import $
|
|
83
|
+
import $n_isValidArray from '@netang/utils/isValidArray'
|
|
84
|
+
import $n_indexOf from '@netang/utils/indexOf'
|
|
85
|
+
import $n_forIn from '@netang/utils/forIn'
|
|
24
86
|
|
|
25
87
|
export default {
|
|
26
88
|
|
|
@@ -33,32 +95,418 @@ export default {
|
|
|
33
95
|
* 声明属性
|
|
34
96
|
*/
|
|
35
97
|
props: {
|
|
98
|
+
// 行数据
|
|
99
|
+
rows: {
|
|
100
|
+
type: Array,
|
|
101
|
+
default: () => []
|
|
102
|
+
},
|
|
103
|
+
// 定义每一行的唯一键的每一行属性
|
|
104
|
+
rowKey: {
|
|
105
|
+
type: [ String, Function ],
|
|
106
|
+
default: 'id'
|
|
107
|
+
},
|
|
108
|
+
// 头部列数据
|
|
109
|
+
columns: Array,
|
|
110
|
+
// 已展开数据数组
|
|
111
|
+
expanded: Array, // v-model:expanded
|
|
36
112
|
// 以像素为单位的默认行大小
|
|
37
113
|
virtualScrollItemSize: {
|
|
38
114
|
type: [ Number, String ],
|
|
39
115
|
default: 50,
|
|
40
116
|
},
|
|
117
|
+
|
|
118
|
+
// 【覆盖声明】-------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
// 是否默认展开所有行, 当 Table 包含展开行存在或者为树形表格时有效
|
|
121
|
+
defaultExpandAll: Boolean,
|
|
122
|
+
// 子数据属性名称
|
|
123
|
+
childrenKey: {
|
|
124
|
+
type: String,
|
|
125
|
+
default: 'children'
|
|
126
|
+
},
|
|
127
|
+
icon: String,
|
|
128
|
+
iconColor: {
|
|
129
|
+
type: String,
|
|
130
|
+
default: 'grey'
|
|
131
|
+
},
|
|
41
132
|
},
|
|
42
133
|
|
|
43
134
|
/**
|
|
44
135
|
* 组合式
|
|
45
136
|
*/
|
|
46
|
-
setup(props, { slots }) {
|
|
137
|
+
setup(props, { slots, emit }) {
|
|
138
|
+
|
|
139
|
+
const { proxy } = getCurrentInstance()
|
|
140
|
+
const { $q } = proxy
|
|
141
|
+
|
|
142
|
+
// 懒加载
|
|
143
|
+
const lazy = ref({})
|
|
144
|
+
// 已展开节点数组
|
|
145
|
+
const innerExpanded = ref(props.expanded || [])
|
|
47
146
|
|
|
48
147
|
// ==========【计算属性】==========================================================================================
|
|
49
148
|
|
|
149
|
+
/**
|
|
150
|
+
* 获取每一行的唯一键的每一行属性
|
|
151
|
+
*/
|
|
152
|
+
const getRowKey = computed(() => (
|
|
153
|
+
typeof props.rowKey === 'function'
|
|
154
|
+
? props.rowKey
|
|
155
|
+
: row => row[ props.rowKey ]
|
|
156
|
+
))
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* 图标
|
|
160
|
+
*/
|
|
161
|
+
const computedIcon = computed(() => props.icon || $q.iconSet.tree.icon)
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* 是否有子数据
|
|
165
|
+
*/
|
|
166
|
+
const hasChildren = computed(function() {
|
|
167
|
+
if (
|
|
168
|
+
$n_isValidArray(props.rows)
|
|
169
|
+
&& $n_isValidArray(props.columns)
|
|
170
|
+
&& props.columns[0].name
|
|
171
|
+
) {
|
|
172
|
+
for (const item of props.rows) {
|
|
173
|
+
// 如果有子数据
|
|
174
|
+
if (
|
|
175
|
+
$n_has(item, props.childrenKey)
|
|
176
|
+
&& $n_isValidArray(item[props.childrenKey])
|
|
177
|
+
) {
|
|
178
|
+
return true
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return false
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* meta
|
|
187
|
+
*/
|
|
188
|
+
const meta = computed(function () {
|
|
189
|
+
|
|
190
|
+
const meta = {}
|
|
191
|
+
|
|
192
|
+
function travel(row, level, parent) {
|
|
193
|
+
|
|
194
|
+
// 唯一键值
|
|
195
|
+
const key = getRowKey.value(row)
|
|
196
|
+
// 是否为父级
|
|
197
|
+
const isParent = $n_has(row, props.childrenKey) && $n_isValidArray(row[props.childrenKey])
|
|
198
|
+
// 是否可展开
|
|
199
|
+
// const expandable = row.expandable !== false
|
|
200
|
+
|
|
201
|
+
// 懒加载
|
|
202
|
+
let localLazy = row.lazy
|
|
203
|
+
if (
|
|
204
|
+
localLazy === true
|
|
205
|
+
&& lazy.value[ key ] !== void 0
|
|
206
|
+
&& Array.isArray(row[ props.childrenKey ]) === true
|
|
207
|
+
) {
|
|
208
|
+
localLazy = lazy.value[ key ]
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const m = {
|
|
212
|
+
key,
|
|
213
|
+
level,
|
|
214
|
+
parent,
|
|
215
|
+
isParent,
|
|
216
|
+
lazy: localLazy,
|
|
217
|
+
// link: row.disabled !== true && (selectable === true || (expandable === true && (isParent === true || localLazy === true))),
|
|
218
|
+
children: [],
|
|
219
|
+
// matchesFilter: props.filter ? computedFilterMethod.value(row, props.filter) : true,
|
|
220
|
+
|
|
221
|
+
// 是否已展开
|
|
222
|
+
expanded: isParent ? innerExpanded.value.includes(key) : false,
|
|
223
|
+
// expandable,
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
meta[ key ] = m
|
|
227
|
+
|
|
228
|
+
// 如果为父级
|
|
229
|
+
if (isParent) {
|
|
230
|
+
// m.childrens = row[ props.childrenKey ]
|
|
231
|
+
m.children = row[ props.childrenKey ].map(n => travel(n, level + 1, m))
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return m
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
props.rows.forEach(row => travel(row, 0, null))
|
|
238
|
+
return meta
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* 当前行数据
|
|
243
|
+
*/
|
|
244
|
+
const currentRows = computed(function() {
|
|
245
|
+
|
|
246
|
+
// 如果有子数据
|
|
247
|
+
if (hasChildren.value) {
|
|
248
|
+
return getRows(props.rows, 0, 0)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// 否则返回原始行数据
|
|
252
|
+
return props.rows
|
|
253
|
+
})
|
|
254
|
+
|
|
50
255
|
/**
|
|
51
256
|
* 插槽标识
|
|
52
257
|
*/
|
|
53
258
|
const slotNames = computed(function() {
|
|
54
|
-
|
|
259
|
+
|
|
260
|
+
// 展开插槽标识
|
|
261
|
+
let expandName = hasChildren.value ? `body-cell-${props.columns[0].name}` : ''
|
|
262
|
+
// 是否存在展开插槽
|
|
263
|
+
let hasExpandSlot = expandName && $n_has(slots, expandName)
|
|
264
|
+
// 单元格插槽标识
|
|
265
|
+
const bodyCell = []
|
|
266
|
+
// 其他插槽标识
|
|
267
|
+
const other = []
|
|
268
|
+
|
|
269
|
+
$n_forIn(slots, function (value, key) {
|
|
270
|
+
if (key.startsWith('body-cell-')) {
|
|
271
|
+
if (! hasExpandSlot || key !== expandName) {
|
|
272
|
+
bodyCell.push(key)
|
|
273
|
+
}
|
|
274
|
+
} else {
|
|
275
|
+
other.push(key)
|
|
276
|
+
}
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
return {
|
|
280
|
+
// 展开插槽标识
|
|
281
|
+
expandName,
|
|
282
|
+
// 是否存在展开插槽
|
|
283
|
+
hasExpandSlot,
|
|
284
|
+
// 单元格插槽标识
|
|
285
|
+
bodyCell,
|
|
286
|
+
// 其他插槽标识
|
|
287
|
+
other,
|
|
288
|
+
}
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
// ==========【监听数据】=========================================================================================
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* 监听已展开节点数据
|
|
295
|
+
*/
|
|
296
|
+
watch(() => props.expanded, val => {
|
|
297
|
+
innerExpanded.value = val
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* 监听行数据
|
|
302
|
+
*/
|
|
303
|
+
watch(()=>props.rows, () => {
|
|
304
|
+
if (props.defaultExpandAll) {
|
|
305
|
+
expandAll()
|
|
306
|
+
}
|
|
307
|
+
}, {
|
|
308
|
+
// 深度监听
|
|
309
|
+
deep: true,
|
|
310
|
+
// 立即执行
|
|
311
|
+
immediate: true,
|
|
55
312
|
})
|
|
56
313
|
|
|
314
|
+
// ==========【方法】=============================================================================================
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* 获取行数据
|
|
318
|
+
*/
|
|
319
|
+
function getRows(rows, __level, __parentKey) {
|
|
320
|
+
|
|
321
|
+
const lists = []
|
|
322
|
+
|
|
323
|
+
for (const row of rows) {
|
|
324
|
+
|
|
325
|
+
lists.push(row)
|
|
326
|
+
|
|
327
|
+
const key = getRowKey.value(row)
|
|
328
|
+
const m = meta.value[ key ]
|
|
329
|
+
|
|
330
|
+
// 如果有子数据
|
|
331
|
+
if (
|
|
332
|
+
m.isParent
|
|
333
|
+
&& $n_indexOf(innerExpanded.value, key) > -1
|
|
334
|
+
) {
|
|
335
|
+
const childRows = getRows(row[ props.childrenKey ])
|
|
336
|
+
if (childRows.length) {
|
|
337
|
+
lists.push(...childRows)
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return lists
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* 展开点击
|
|
347
|
+
*/
|
|
348
|
+
function onExpandClick (props, e) {
|
|
349
|
+
if (e !== void 0) {
|
|
350
|
+
stopAndPrevent(e)
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const m = meta.value[props.key]
|
|
354
|
+
|
|
355
|
+
// keyboard !== true && meta.selectable !== false && blur(meta.key)
|
|
356
|
+
setExpanded(props.key, ! m.expanded, props.row, m)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* 在给定键的节点处展开树
|
|
361
|
+
*/
|
|
362
|
+
function setExpanded (key, state, row, m) {
|
|
363
|
+
|
|
364
|
+
if (m.lazy && m.lazy !== 'loaded') {
|
|
365
|
+
if (m.lazy === 'loading') {
|
|
366
|
+
return
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
lazy.value[ key ] = 'loading'
|
|
370
|
+
if (Array.isArray(row[ props.childrenKey ]) !== true) {
|
|
371
|
+
row[ props.childrenKey ] = []
|
|
372
|
+
}
|
|
373
|
+
emit('lazyLoad', {
|
|
374
|
+
row,
|
|
375
|
+
key,
|
|
376
|
+
done: children => {
|
|
377
|
+
lazy.value[ key ] = 'loaded'
|
|
378
|
+
row[ props.childrenKey ] = Array.isArray(children) === true ? children : []
|
|
379
|
+
nextTick(() => {
|
|
380
|
+
const localMeta = meta.value[ key ]
|
|
381
|
+
if (localMeta && localMeta.isParent === true) {
|
|
382
|
+
localSetExpanded(key, true)
|
|
383
|
+
}
|
|
384
|
+
})
|
|
385
|
+
},
|
|
386
|
+
fail: () => {
|
|
387
|
+
delete lazy.value[ key ]
|
|
388
|
+
if (row[ props.childrenKey ].length === 0) {
|
|
389
|
+
delete row[ props.childrenKey ]
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
})
|
|
393
|
+
|
|
394
|
+
} else if (m.isParent === true) {
|
|
395
|
+
localSetExpanded(key, state)
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function localSetExpanded (key, state) {
|
|
400
|
+
let target = innerExpanded.value
|
|
401
|
+
const shouldEmit = props.expanded !== void 0
|
|
402
|
+
|
|
403
|
+
if (shouldEmit === true) {
|
|
404
|
+
target = target.slice()
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if (state) {
|
|
408
|
+
// if (props.accordion) {
|
|
409
|
+
// if (meta.value[ key ]) {
|
|
410
|
+
// const collapse = []
|
|
411
|
+
// if (meta.value[ key ].parent) {
|
|
412
|
+
// meta.value[ key ].parent.children.forEach(m => {
|
|
413
|
+
// if (m.key !== key && m.expandable === true) {
|
|
414
|
+
// collapse.push(m.key)
|
|
415
|
+
// }
|
|
416
|
+
// })
|
|
417
|
+
// }
|
|
418
|
+
// else {
|
|
419
|
+
// props.nodes.forEach(node => {
|
|
420
|
+
// const k = node[ props.nodeKey ]
|
|
421
|
+
// if (k !== key) {
|
|
422
|
+
// collapse.push(k)
|
|
423
|
+
// }
|
|
424
|
+
// })
|
|
425
|
+
// }
|
|
426
|
+
// if (collapse.length > 0) {
|
|
427
|
+
// target = target.filter(k => collapse.includes(k) === false)
|
|
428
|
+
// }
|
|
429
|
+
// }
|
|
430
|
+
// }
|
|
431
|
+
|
|
432
|
+
target = target.concat([ key ])
|
|
433
|
+
.filter((key, index, self) => self.indexOf(key) === index)
|
|
434
|
+
}
|
|
435
|
+
else {
|
|
436
|
+
target = target.filter(k => k !== key)
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
if (shouldEmit === true) {
|
|
440
|
+
emit('update:expanded', target)
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
innerExpanded.value = target
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function getCellValue (col, row) {
|
|
448
|
+
const val = typeof col.field === 'function' ? col.field(row) : row[ col.field ]
|
|
449
|
+
return col.format !== void 0 ? col.format(val, row) : val
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* 用于折叠所有分支
|
|
454
|
+
*/
|
|
455
|
+
function collapseAll () {
|
|
456
|
+
if (props.expanded !== void 0) {
|
|
457
|
+
emit('update:expanded', [])
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
innerExpanded.value = []
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* 用于展开所有分支
|
|
466
|
+
*/
|
|
467
|
+
function expandAll () {
|
|
468
|
+
|
|
469
|
+
if (! hasChildren.value) {
|
|
470
|
+
return
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
const expanded = innerExpanded.value
|
|
474
|
+
|
|
475
|
+
const travel = row => {
|
|
476
|
+
if (
|
|
477
|
+
$n_has(row, props.childrenKey)
|
|
478
|
+
&& $n_isValidArray(row[props.childrenKey])
|
|
479
|
+
) {
|
|
480
|
+
expanded.push(row[ props.rowKey ])
|
|
481
|
+
row[ props.childrenKey ].forEach(travel)
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
props.rows.forEach(travel)
|
|
486
|
+
|
|
487
|
+
if (props.expanded !== void 0) {
|
|
488
|
+
emit('update:expanded', expanded)
|
|
489
|
+
|
|
490
|
+
} else {
|
|
491
|
+
innerExpanded.value = expanded
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
|
|
57
495
|
// ==========【返回】=============================================================================================
|
|
58
496
|
|
|
59
497
|
return {
|
|
498
|
+
// 当前行数据
|
|
499
|
+
currentRows,
|
|
500
|
+
hasChildren,
|
|
60
501
|
// 插槽标识
|
|
61
502
|
slotNames,
|
|
503
|
+
computedIcon,
|
|
504
|
+
meta,
|
|
505
|
+
|
|
506
|
+
onExpandClick,
|
|
507
|
+
expandAll,
|
|
508
|
+
collapseAll,
|
|
509
|
+
getCellValue,
|
|
62
510
|
}
|
|
63
511
|
},
|
|
64
512
|
}
|
|
@@ -1,112 +1,110 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<q-
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
import
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import $
|
|
26
|
-
|
|
27
|
-
import
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
//
|
|
104
|
-
tableFixedPowerBtns,
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div class="q-gutter-sm" v-if="currentTableFixedPowerBtns.length">
|
|
3
|
+
<q-btn
|
|
4
|
+
v-for="item in currentTableFixedPowerBtns"
|
|
5
|
+
:key="`btn-item-${item.id}`"
|
|
6
|
+
class="n-button-icon"
|
|
7
|
+
:icon="item.icon"
|
|
8
|
+
dense
|
|
9
|
+
unelevated
|
|
10
|
+
round
|
|
11
|
+
@click.prevent.stop="onClick(item)"
|
|
12
|
+
>
|
|
13
|
+
<!-- 标题提示 -->
|
|
14
|
+
<q-tooltip>{{item.title}}</q-tooltip>
|
|
15
|
+
</q-btn>
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
18
|
+
|
|
19
|
+
<script>
|
|
20
|
+
import { inject, computed } from 'vue'
|
|
21
|
+
|
|
22
|
+
import $n_cloneDeep from 'lodash/cloneDeep'
|
|
23
|
+
import $n_isFunction from 'lodash/isFunction'
|
|
24
|
+
|
|
25
|
+
import $n_forEach from '@netang/utils/forEach'
|
|
26
|
+
|
|
27
|
+
import { NPowerKey, NTableKey } from '../../utils/symbols'
|
|
28
|
+
|
|
29
|
+
export default {
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* 标识
|
|
33
|
+
*/
|
|
34
|
+
name: 'NTableColumnFixed',
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* 声明属性
|
|
38
|
+
*/
|
|
39
|
+
props: {
|
|
40
|
+
// 传值
|
|
41
|
+
props: Object,
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 组合式
|
|
46
|
+
*/
|
|
47
|
+
setup(props) {
|
|
48
|
+
|
|
49
|
+
// ==========【数据】============================================================================================
|
|
50
|
+
|
|
51
|
+
// 获取权限注入
|
|
52
|
+
const {
|
|
53
|
+
// 权限按钮点击
|
|
54
|
+
powerBtnClick,
|
|
55
|
+
// 格式化权限按钮
|
|
56
|
+
formatPowerBtns,
|
|
57
|
+
} = inject(NPowerKey)
|
|
58
|
+
|
|
59
|
+
// 获取表格注入
|
|
60
|
+
const {
|
|
61
|
+
// 固定在右边的权限按钮列表
|
|
62
|
+
tableFixedPowerBtns,
|
|
63
|
+
} = inject(NTableKey)
|
|
64
|
+
|
|
65
|
+
// ==========【计算属性】=========================================================================================
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 当前表格固定权限按钮
|
|
69
|
+
*/
|
|
70
|
+
const currentTableFixedPowerBtns = computed(function () {
|
|
71
|
+
|
|
72
|
+
const lists = []
|
|
73
|
+
|
|
74
|
+
$n_forEach(tableFixedPowerBtns.value, function (item) {
|
|
75
|
+
|
|
76
|
+
item = $n_cloneDeep(item)
|
|
77
|
+
|
|
78
|
+
// 格式化权限按钮
|
|
79
|
+
if (formatPowerBtns(item, true, [ props.props.row ]) === false || item.hidden === true) {
|
|
80
|
+
return
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
lists.push(item)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
return lists
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
// ==========【方法】=============================================================================================
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 点击
|
|
93
|
+
*/
|
|
94
|
+
function onClick(item) {
|
|
95
|
+
powerBtnClick(item, [ props.props.row ])
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ==========【返回】=============================================================================================
|
|
99
|
+
|
|
100
|
+
return {
|
|
101
|
+
// 固定在右边的权限按钮列表
|
|
102
|
+
tableFixedPowerBtns,
|
|
103
|
+
// 当前表格固定权限按钮
|
|
104
|
+
currentTableFixedPowerBtns: $n_isFunction(formatPowerBtns) ? currentTableFixedPowerBtns : tableFixedPowerBtns,
|
|
105
|
+
// 权限按钮点击
|
|
106
|
+
onClick,
|
|
107
|
+
}
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
</script>
|
|
@@ -84,7 +84,7 @@ import {
|
|
|
84
84
|
nextTick, getCurrentInstance, onBeforeUpdate, onMounted, onUnmounted
|
|
85
85
|
} from 'vue'
|
|
86
86
|
|
|
87
|
-
import { stopAndPrevent } from 'quasar/src/utils/event
|
|
87
|
+
import { stopAndPrevent } from 'quasar/src/utils/event'
|
|
88
88
|
|
|
89
89
|
const tickStrategyOptions = [ 'none', 'strict', 'leaf', 'leaf-filtered' ]
|
|
90
90
|
|
|
@@ -1003,9 +1003,7 @@ export default {
|
|
|
1003
1003
|
}
|
|
1004
1004
|
}
|
|
1005
1005
|
|
|
1006
|
-
|
|
1007
|
-
* 默认展开全部
|
|
1008
|
-
*/
|
|
1006
|
+
// 默认展开全部
|
|
1009
1007
|
props.defaultExpandAll === true && expandAll()
|
|
1010
1008
|
|
|
1011
1009
|
// expose public methods
|
|
@@ -1076,7 +1074,7 @@ export default {
|
|
|
1076
1074
|
const dragCss = $n_get(dragClasses.value, key)
|
|
1077
1075
|
|
|
1078
1076
|
// 当前节点类名
|
|
1079
|
-
const classes = 'n-tree__node relative-position row no-wrap items-center
|
|
1077
|
+
const classes = 'n-tree__node relative-position row no-wrap items-center q-tree__node--link q-hoverable'
|
|
1080
1078
|
// + (m.link === true ? ' q-tree__node--link q-hoverable q-focusable' : '')
|
|
1081
1079
|
+ (m.selected === true || props.multiple && m.ticked === true ? ' n-tree__node--selected' : '')
|
|
1082
1080
|
+ (m.disabled === true ? ' q-tree__node--disabled' : '')
|
|
@@ -1491,6 +1489,7 @@ export default {
|
|
|
1491
1489
|
.n-tree {
|
|
1492
1490
|
color: $grey;
|
|
1493
1491
|
|
|
1492
|
+
// 空箭头
|
|
1494
1493
|
&__arrow--noop {
|
|
1495
1494
|
width: 16px;
|
|
1496
1495
|
height: 16px;
|
package/package.json
CHANGED
package/sass/quasar/table.scss
CHANGED
|
@@ -1,150 +1,161 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 表格
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
// 头部底部背景色
|
|
6
|
-
$header-footer-bg-color: $grey-2;
|
|
7
|
-
$dark-header-footer-bg-color: $color-gray-93;
|
|
8
|
-
// 单元格背景色
|
|
9
|
-
$td-bg-color: #ffffff;
|
|
10
|
-
$dark-td-bg-color: $dark;
|
|
11
|
-
|
|
12
|
-
.n-table {
|
|
13
|
-
|
|
14
|
-
// 单元格换行
|
|
15
|
-
&__col-wrap {
|
|
16
|
-
word-wrap: break-word !important;
|
|
17
|
-
white-space: pre-wrap !important;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
1
|
+
/**
|
|
2
|
+
* 表格
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
// 头部底部背景色
|
|
6
|
+
$header-footer-bg-color: $grey-2;
|
|
7
|
+
$dark-header-footer-bg-color: $color-gray-93;
|
|
8
|
+
// 单元格背景色
|
|
9
|
+
$td-bg-color: #ffffff;
|
|
10
|
+
$dark-td-bg-color: $dark;
|
|
11
|
+
|
|
12
|
+
.n-table {
|
|
13
|
+
|
|
14
|
+
// 单元格换行
|
|
15
|
+
&__col-wrap {
|
|
16
|
+
word-wrap: break-word !important;
|
|
17
|
+
white-space: pre-wrap !important;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// 箭头
|
|
21
|
+
//.q-tree__arrow {
|
|
22
|
+
// color: $grey;
|
|
23
|
+
//}
|
|
24
|
+
|
|
25
|
+
// 空箭头
|
|
26
|
+
&__arrow-noop {
|
|
27
|
+
width: 16px;
|
|
28
|
+
margin-right: 4px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&.q-table {
|
|
32
|
+
&--dense {
|
|
33
|
+
// 复选框
|
|
34
|
+
.q-table {
|
|
35
|
+
th,
|
|
36
|
+
td {
|
|
37
|
+
&.q-table--col-auto-width:first-child {
|
|
38
|
+
padding: 0 12px;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
thead tr,
|
|
44
|
+
tbody tr,
|
|
45
|
+
tbody td {
|
|
46
|
+
height: 40px;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
&--horizontal-separator,
|
|
51
|
+
&--cell-separator {
|
|
52
|
+
tbody {
|
|
53
|
+
// 表格内容最后一排数据底部加上横线
|
|
54
|
+
&.q-virtual-scroll__content {
|
|
55
|
+
tr:last-child > td {
|
|
56
|
+
border-bottom-width: 1px;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 宫格模式
|
|
64
|
+
&--grid {
|
|
65
|
+
background-color: rgba(var(--n-reverse-color-rgb), 0.1);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 撑满
|
|
69
|
+
&.absolute-full {
|
|
70
|
+
border-radius: unset;
|
|
71
|
+
|
|
72
|
+
// 顶部吸顶
|
|
73
|
+
thead tr th {
|
|
74
|
+
position: sticky;
|
|
75
|
+
z-index: 2;
|
|
76
|
+
}
|
|
77
|
+
thead tr:first-child th {
|
|
78
|
+
top: 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 最后一列固定
|
|
82
|
+
&.n-table--last-fixed {
|
|
83
|
+
// 最后一列吸顶
|
|
84
|
+
th:last-child,
|
|
85
|
+
td:last-child {
|
|
86
|
+
position: sticky;
|
|
87
|
+
right: 0;
|
|
88
|
+
z-index: 1;
|
|
89
|
+
}
|
|
90
|
+
th:last-child {
|
|
91
|
+
z-index: 2;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 亮色
|
|
98
|
+
.body--light {
|
|
99
|
+
.n-table {
|
|
100
|
+
|
|
101
|
+
// 头部和底部背景色
|
|
102
|
+
.q-table__top,
|
|
103
|
+
.q-table__bottom,
|
|
104
|
+
thead tr:first-child th {
|
|
105
|
+
background-color: $header-footer-bg-color;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// 撑满
|
|
109
|
+
&.absolute-full {
|
|
110
|
+
// 最后一列固定
|
|
111
|
+
&.n-table--last-fixed {
|
|
112
|
+
// 头部最后一个
|
|
113
|
+
thead tr:last-child th:last-child {
|
|
114
|
+
background-color: $header-footer-bg-color;
|
|
115
|
+
}
|
|
116
|
+
// 内容最后一个
|
|
117
|
+
td:last-child {
|
|
118
|
+
background-color: $td-bg-color;
|
|
119
|
+
}
|
|
120
|
+
th:last-child,
|
|
121
|
+
td:last-child {
|
|
122
|
+
background-color: $td-bg-color;
|
|
123
|
+
border-left: 1px solid $table-border-color;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// 暗色
|
|
131
|
+
.body--dark {
|
|
132
|
+
.n-table {
|
|
133
|
+
|
|
134
|
+
// 头部和底部背景色
|
|
135
|
+
.q-table__top,
|
|
136
|
+
.q-table__bottom,
|
|
137
|
+
thead tr:first-child th {
|
|
138
|
+
background-color: $dark-header-footer-bg-color;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 撑满
|
|
142
|
+
&.absolute-full {
|
|
143
|
+
// 最后一列固定
|
|
144
|
+
&.n-table--last-fixed {
|
|
145
|
+
// 头部最后一个
|
|
146
|
+
thead tr:last-child th:last-child {
|
|
147
|
+
background-color: $dark-header-footer-bg-color;
|
|
148
|
+
}
|
|
149
|
+
// 内容最后一个
|
|
150
|
+
td:last-child {
|
|
151
|
+
background-color: $dark-td-bg-color;
|
|
152
|
+
}
|
|
153
|
+
th:last-child,
|
|
154
|
+
td:last-child {
|
|
155
|
+
background-color: $dark-td-bg-color;
|
|
156
|
+
border-left: 1px solid $table-dark-border-color;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|