@netang/quasar 0.0.101 → 0.0.102

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.
Files changed (164) hide show
  1. package/.editorconfig +12 -0
  2. package/LICENSE +21 -21
  3. package/README.md +11 -11
  4. package/_docs/docs/.vuepress/client.js +8 -8
  5. package/_docs/docs/.vuepress/config.js +40 -40
  6. package/_docs/docs/.vuepress/configs/index.js +2 -2
  7. package/_docs/docs/.vuepress/configs/navbar/index.js +1 -1
  8. package/_docs/docs/.vuepress/configs/navbar/zh.js +16 -16
  9. package/_docs/docs/.vuepress/configs/sidebar/index.js +1 -1
  10. package/_docs/docs/.vuepress/configs/sidebar/zh.js +75 -75
  11. package/_docs/docs/.vuepress/public/css/index.css +3 -3
  12. package/_docs/docs/.vuepress/styles/index.scss +3 -3
  13. package/_docs/docs/components/column-title.md +25 -25
  14. package/_docs/docs/components/data.md +66 -66
  15. package/_docs/docs/components/dialog.md +59 -59
  16. package/_docs/docs/components/dragger.md +26 -26
  17. package/_docs/docs/components/editor-code.md +16 -16
  18. package/_docs/docs/components/empty.md +13 -13
  19. package/_docs/docs/components/field-date.md +16 -16
  20. package/_docs/docs/components/field-text.md +57 -57
  21. package/_docs/docs/components/field-tree.md +21 -21
  22. package/_docs/docs/components/img.md +25 -25
  23. package/_docs/docs/components/input-number.md +21 -21
  24. package/_docs/docs/components/list-menu-item.md +21 -21
  25. package/_docs/docs/components/list-menu.md +21 -21
  26. package/_docs/docs/components/power-page.md +21 -21
  27. package/_docs/docs/components/price.md +21 -21
  28. package/_docs/docs/components/render.md +12 -12
  29. package/_docs/docs/components/search-item.md +10 -10
  30. package/_docs/docs/components/search.md +12 -12
  31. package/_docs/docs/components/select.md +11 -11
  32. package/_docs/docs/components/splitter.md +15 -15
  33. package/_docs/docs/components/table-column-fixed.md +20 -20
  34. package/_docs/docs/components/table-pagination.md +20 -20
  35. package/_docs/docs/components/table-splitter.md +20 -20
  36. package/_docs/docs/components/table-summary.md +20 -20
  37. package/_docs/docs/components/table.md +25 -25
  38. package/_docs/docs/components/thumbnail.md +18 -18
  39. package/_docs/docs/components/toolbar.md +9 -9
  40. package/_docs/docs/components/uploader-query.md +19 -19
  41. package/_docs/docs/components/uploader.md +16 -16
  42. package/_docs/docs/components/value-format.md +26 -26
  43. package/_docs/docs/index.md +1 -1
  44. package/_docs/docs/utils/alert.md +26 -26
  45. package/_docs/docs/utils/area.md +112 -112
  46. package/_docs/docs/utils/arr.md +80 -80
  47. package/_docs/docs/utils/auth.md +101 -101
  48. package/_docs/docs/utils/bus.md +18 -18
  49. package/_docs/docs/utils/confirm.md +31 -31
  50. package/_docs/docs/utils/copy.md +22 -22
  51. package/_docs/docs/utils/dialog.md +98 -98
  52. package/_docs/docs/utils/dict.md +50 -50
  53. package/_docs/docs/utils/dictOptions.md +27 -27
  54. package/_docs/docs/utils/form.md +33 -33
  55. package/_docs/docs/utils/getData.md +60 -60
  56. package/_docs/docs/utils/getFile.md +21 -21
  57. package/_docs/docs/utils/getImage.md +33 -33
  58. package/_docs/docs/utils/getTime.md +51 -51
  59. package/_docs/docs/utils/index.md +1 -1
  60. package/_docs/docs/utils/loading.md +18 -18
  61. package/_docs/docs/utils/notify.md +29 -29
  62. package/_docs/docs/utils/power.md +353 -353
  63. package/_docs/docs/utils/previewImage.md +11 -11
  64. package/_docs/docs/utils/price.md +45 -45
  65. package/_docs/docs/utils/rule.md +30 -30
  66. package/_docs/docs/utils/ruleValid.md +31 -31
  67. package/_docs/docs/utils/symbols.md +30 -30
  68. package/_docs/docs/utils/table.md +194 -194
  69. package/_docs/docs/utils/timestamp.md +27 -27
  70. package/_docs/docs/utils/toast.md +27 -27
  71. package/_docs/docs/utils/tree.md +174 -174
  72. package/_docs/docs/utils/uploader.md +29 -29
  73. package/_docs/package.json +11 -11
  74. package/components/column-title/index.vue +37 -37
  75. package/components/data/index.vue +20 -20
  76. package/components/dialog/index.vue +372 -372
  77. package/components/dragger/index.vue +203 -203
  78. package/components/drawer/index.vue +303 -303
  79. package/components/editor-code/index.vue +289 -289
  80. package/components/empty/index.vue +71 -71
  81. package/components/field-date/index.vue +850 -850
  82. package/components/field-date/methods.js +100 -100
  83. package/components/field-table/index.vue +1222 -1222
  84. package/components/field-text/index.vue +165 -165
  85. package/components/field-tree/index.vue +739 -659
  86. package/components/img/index.vue +202 -202
  87. package/components/input-number/index.vue +546 -546
  88. package/components/list-menu/index.vue +149 -149
  89. package/components/list-menu-item/index.vue +79 -79
  90. package/components/power-page/index.vue +92 -92
  91. package/components/price/index.vue +188 -188
  92. package/components/private/components/index.js +11 -11
  93. package/components/private/components/move-to-tree/index.vue +154 -154
  94. package/components/private/edit-power-data/index.vue +816 -816
  95. package/components/private/table-visible-columns-button/index.vue +109 -109
  96. package/components/render/index.vue +150 -150
  97. package/components/search/index.vue +222 -222
  98. package/components/search-item/index.vue +210 -210
  99. package/components/select/index.vue +177 -177
  100. package/components/splitter/index.vue +415 -415
  101. package/components/table/index.vue +456 -456
  102. package/components/table-column-fixed/index.vue +112 -112
  103. package/components/table-pagination/index.vue +192 -192
  104. package/components/table-splitter/index.vue +360 -360
  105. package/components/table-summary/index.vue +110 -110
  106. package/components/thumbnail/index.vue +72 -72
  107. package/components/toolbar/container.vue +31 -31
  108. package/components/toolbar/index.vue +136 -136
  109. package/components/uploader/index.vue +158 -158
  110. package/components/uploader-query/index.vue +758 -758
  111. package/components/value-format/index.vue +274 -274
  112. package/configs/area3.js +1 -1
  113. package/docs/css/index.css +3 -3
  114. package/package.json +24 -24
  115. package/sass/common.scss +174 -174
  116. package/sass/index.scss +14 -14
  117. package/sass/line.scss +39 -39
  118. package/sass/quasar/btn.scss +46 -46
  119. package/sass/quasar/common.scss +3 -3
  120. package/sass/quasar/dialog.scss +7 -7
  121. package/sass/quasar/drawer.scss +6 -6
  122. package/sass/quasar/field.scss +243 -243
  123. package/sass/quasar/loading.scss +6 -6
  124. package/sass/quasar/menu.scss +8 -8
  125. package/sass/quasar/table.scss +150 -150
  126. package/sass/quasar/toolbar.scss +22 -22
  127. package/store/index.js +29 -29
  128. package/utils/$auth.js +127 -127
  129. package/utils/$form.js +56 -56
  130. package/utils/$power.js +1215 -1215
  131. package/utils/$rule.js +13 -13
  132. package/utils/$ruleValid.js +10 -10
  133. package/utils/$table.js +999 -999
  134. package/utils/$tree.js +713 -713
  135. package/utils/alert.js +12 -12
  136. package/utils/area.js +400 -400
  137. package/utils/arr.js +51 -51
  138. package/utils/bus.js +6 -6
  139. package/utils/config.js +52 -52
  140. package/utils/confirm.js +11 -11
  141. package/utils/copy.js +30 -30
  142. package/utils/dialog.js +36 -36
  143. package/utils/dict.js +21 -21
  144. package/utils/dictOptions.js +28 -28
  145. package/utils/getData.js +73 -73
  146. package/utils/getFile.js +40 -40
  147. package/utils/getImage.js +153 -153
  148. package/utils/getTime.js +106 -106
  149. package/utils/index.js +61 -61
  150. package/utils/loading.js +15 -15
  151. package/utils/notify.js +13 -13
  152. package/utils/previewImage.js +10 -10
  153. package/utils/price.js +18 -18
  154. package/utils/symbols.js +18 -18
  155. package/utils/timestamp.js +18 -18
  156. package/utils/toast.js +13 -13
  157. package/utils/uploader/aliyun.js +6 -6
  158. package/utils/uploader/local.js +8 -8
  159. package/utils/uploader/qiniu.js +321 -321
  160. package/utils/uploader.js +1059 -1059
  161. package/utils/useAuth.js +30 -30
  162. package/utils/useRouter.js +47 -47
  163. package/utils/useSearch.js +496 -496
  164. package/utils/useUploader.js +53 -53
@@ -1,456 +1,456 @@
1
- <template>
2
- <q-layout
3
- class="absolute-full"
4
- :class="{
5
- 'n-table--grid': tableGrid,
6
- }"
7
- view="lHr LpR lff"
8
- container
9
- >
10
- <!-- 头部 -->
11
- <n-toolbar
12
- :dense="dense"
13
- header
14
- >
15
- <!-- 插槽 -->
16
- <template
17
- v-for="slotName in slotNames.toolbar"
18
- v-slot:[slotName]
19
- >
20
- <slot :name="`toolbar-${slotName}`"/>
21
- </template>
22
- </n-toolbar>
23
-
24
- <!-- 左侧分类 -->
25
- <slot name="left-drawer" v-if="slotNames.leftDrawer" />
26
- <n-drawer
27
- :model-value="! hideLeftDrawer"
28
- :side="treeSide"
29
- :width="200"
30
- :min-width="150"
31
- bordered
32
- drag
33
- cache
34
- v-bind="leftDrawerProps"
35
- v-else-if="treeNodes.length"
36
- >
37
- <q-scroll-area class="absolute-full">
38
-
39
- <!-- 树筛选 -->
40
- <div class="q-pa-sm q-gutter-sm" v-if="treeFilter">
41
- <q-input
42
- v-model="treeFilterValue"
43
- placeholder="搜索"
44
- dense
45
- outlined
46
- clearable
47
-
48
- />
49
- </div>
50
-
51
- <!-- 分类树 -->
52
- <q-tree
53
- color="grey-5"
54
- ref="treeRef"
55
- :nodes="treeNodes"
56
- :filter="treeFilterValue"
57
- :node-key="treeNodeKey"
58
- :label-key="treeLabelKey"
59
- selected-color="primary"
60
- v-model:selected="treeSelected"
61
- no-selection-unset
62
- default-expand-all
63
- v-bind="treeProps"
64
- />
65
-
66
- </q-scroll-area>
67
- </n-drawer>
68
-
69
- <!-- 列表 -->
70
- <q-page-container>
71
- <q-page>
72
- <q-table
73
- class="n-table absolute-full"
74
- :class="{
75
- 'n-table--last-fixed': showTableFixed,
76
- }"
77
- v-model:pagination="tablePagination"
78
- v-model:selected="tableSelected"
79
- :row-key="tableRowKey"
80
- :rows="tableRows"
81
- :columns="tableColumns"
82
- :visible-columns="tableVisibleColumns"
83
- :selection="tableSelection"
84
- :separator="tableSeparator"
85
- :loading="tableLoading"
86
- :rows-per-page-options="tableRowsPerPageOptions"
87
- :grid="tableGrid"
88
- @row-click="tableRowClick"
89
- @row-dblclick="currentTableRowDblclick"
90
- @request="tableRequest"
91
- flat
92
- virtual-scroll
93
- :virtual-scroll-slice-ratio-before="20"
94
- :virtual-scroll-slice-size="50"
95
- :virtual-scroll-slice-ratio-after="20"
96
- :dense="dense"
97
- v-bind="$attrs"
98
- >
99
- <!-- 图片 -->
100
- <template
101
- v-for="imgName in tableImgNames"
102
- v-slot:[`body-cell-${imgName}`]="props"
103
- >
104
- <q-td :props="props">
105
- <!-- 缩略图 -->
106
- <n-thumbnail
107
- :src="props.row[imgName]"
108
- preview
109
- />
110
- </q-td>
111
- </template>
112
-
113
- <!-- 插槽 -->
114
- <template
115
- v-for="slotName in slotNames.table"
116
- v-slot:[slotName]="props"
117
- >
118
- <q-td :props="props">
119
- <slot
120
- :name="slotName"
121
- v-bind="props"
122
- />
123
- </q-td>
124
- </template>
125
-
126
- <!-- 操作 -->
127
- <template v-slot:body-cell-settings="props">
128
- <n-table-column-fixed
129
- :props="props"
130
- />
131
- </template>
132
-
133
- <!-- 合计 -->
134
- <template v-slot:bottom-row="props" v-if="tableSummary">
135
- <n-table-summary
136
- :props="props"
137
- />
138
- </template>
139
-
140
- <!-- 翻页 -->
141
- <template v-slot:pagination="props">
142
- <n-table-pagination
143
- :props="props"
144
- />
145
- </template>
146
- </q-table>
147
- </q-page>
148
- </q-page-container>
149
-
150
- <!-- 右侧搜索 -->
151
- <slot name="right-drawer" v-if="slotNames.rightDrawer" />
152
- <n-drawer
153
- :model-value="! hideRightDrawer"
154
- :side="searchSide"
155
- :min-width="320"
156
- bordered
157
- drag
158
- cache
159
- v-bind="rightDrawerProps"
160
- v-else-if="! noSearch && tableSearchValue.length"
161
- >
162
- <!-- 搜索 -->
163
- <n-search
164
- v-model="tableSearchValue"
165
- :options="tableSearchOptions"
166
- :on-search="tableReload"
167
- :on-reset="tableSearchReset"
168
- >
169
- <!-- 插槽 -->
170
- <template
171
- v-for="slotName in slotNames.search"
172
- v-slot:[slotName]
173
- >
174
- <slot :name="`search-${slotName}`"/>
175
- </template>
176
- </n-search>
177
- </n-drawer>
178
-
179
- </q-layout>
180
- </template>
181
-
182
- <script>
183
- import { ref, watch, computed, inject } from 'vue'
184
-
185
- import $n_isFunction from 'lodash/isFunction'
186
-
187
- import $n_isValidObject from '@netang/utils/isValidObject'
188
- import $n_isValidValue from '@netang/utils/isValidValue'
189
- import $n_collection from '@netang/utils/collection'
190
-
191
- import { NDialogKey, NTableKey } from '../../utils/symbols'
192
-
193
- import NToolbar from '../toolbar'
194
- import NDrawer from '../drawer'
195
- import NThumbnail from '../thumbnail'
196
- import NTableColumnFixed from '../table-column-fixed'
197
- import NTableSummary from '../table-summary'
198
- import NTablePagination from '../table-pagination'
199
- import NSearch from '../search'
200
-
201
- export default {
202
-
203
- /**
204
- * 标识
205
- */
206
- name: 'NTable',
207
-
208
- /**
209
- * 关闭组件 attribute 透传行为
210
- */
211
- inheritAttrs: false,
212
-
213
- /**
214
- * 组件
215
- */
216
- components: {
217
- NToolbar,
218
- NDrawer,
219
- NThumbnail,
220
- NTableColumnFixed,
221
- NTableSummary,
222
- NTablePagination,
223
- NSearch,
224
- },
225
-
226
- /**
227
- * 声明属性
228
- */
229
- props: {
230
- // 表格请求地址
231
- url: String,
232
- // 树声明属性
233
- treeProps: Object,
234
- // 树节点唯一键值
235
- treeNodeKey: {
236
- type: String,
237
- default: 'id',
238
- },
239
- // 树标签键值
240
- treeLabelKey: {
241
- type: String,
242
- default: 'title',
243
- },
244
- // 树节点列表
245
- treeNodes: {
246
- type: Array,
247
- default: ()=>[],
248
- },
249
- // 树节点点击
250
- treeNodeClick: Function,
251
- // 是否选中第一个树节点
252
- treeSelectFirstNode: {
253
- type: Boolean,
254
- default: true,
255
- },
256
- // 显示树筛选
257
- treeFilter: Boolean,
258
- // 树位置, 可选值: left / right
259
- treeSide: {
260
- type: String,
261
- default: 'left',
262
- },
263
- // 不显示搜索
264
- noSearch: Boolean,
265
- // 搜索位置
266
- searchSide: {
267
- type: String,
268
- default: 'right',
269
- },
270
- // 紧凑模式
271
- dense: {
272
- type: Boolean,
273
- default: true,
274
- },
275
- // 隐藏左边侧滑菜单
276
- hideLeftDrawer: Boolean,
277
- // 左边侧滑菜单声明属性
278
- leftDrawerProps: Object,
279
- // 隐藏右边侧滑菜单
280
- hideRightDrawer: Boolean,
281
- // 右边侧滑菜单声明属性
282
- rightDrawerProps: Object,
283
- },
284
-
285
- /**
286
- * 组合式
287
- */
288
- setup(props, { slots }) {
289
-
290
- // ==========【数据】============================================================================================
291
-
292
- // 获取表格注入
293
- const $table = inject(NTableKey)
294
-
295
- // 获取对话框注入
296
- const $dialog = inject(NDialogKey)
297
- const inDialog = !! $dialog
298
-
299
- // 当前双击表格行
300
- let currentTableRowDblclick
301
-
302
- // 如果在对话框内部
303
- if (inDialog) {
304
- // 提交表格已选数据给对话框
305
- $dialog.submit(() => $table.tableSelected.value)
306
-
307
- // 对话框中的表格双击表格行
308
- currentTableRowDblclick = function (e, row) {
309
- // 如果不是多选
310
- if ($table.tableSelection.value !== 'multiple') {
311
- $table.tableSelected.value = [ row ]
312
- $dialog.confirm()
313
- }
314
- }
315
-
316
- } else {
317
- // 表格实例中的双击表格行
318
- currentTableRowDblclick = $table.tableRowDblclick
319
- }
320
-
321
- // 树节点
322
- const treeRef = ref(null)
323
-
324
- // 树筛选值
325
- const treeFilterValue = ref('')
326
-
327
- // 树选择数据
328
- const treeSelected = ref(null)
329
-
330
- // ==========【计算属性】==========================================================================================
331
-
332
- /**
333
- * 插槽标识
334
- */
335
- const slotNames = computed(function() {
336
-
337
- const toolbar = []
338
- const search = []
339
- const table = []
340
- let leftDrawer = false
341
- let rightDrawer = false
342
-
343
- // 如果有插槽
344
- if ($n_isValidObject(slots)) {
345
- for (const key in slots) {
346
- if (key.startsWith('toolbar-')) {
347
- toolbar.push(key.replace('toolbar-', ''))
348
- } else if (key.startsWith('search-')) {
349
- search.push(key.replace('search-', ''))
350
- } else if (key === 'left-drawer') {
351
- leftDrawer = true
352
- } else if (key === 'right-drawer') {
353
- rightDrawer = true
354
- } else {
355
- table.push(key)
356
- }
357
- }
358
- }
359
-
360
- return {
361
- toolbar,
362
- search,
363
- table,
364
- leftDrawer,
365
- rightDrawer,
366
- }
367
- })
368
-
369
- // ==========【监听数据】=========================================================================================
370
-
371
- // 如果有树节点点击方法
372
- if ($n_isFunction(props.treeNodeClick)) {
373
-
374
- /**
375
- * 树节点 all
376
- */
377
- const treeNodesAll = computed(function () {
378
- return $n_collection(props.treeNodes)
379
- .keyBy(props.treeNodeKey)
380
- .toObject()
381
- })
382
-
383
- // 是否已选择过第一个节点
384
- let isSelectedFirstNode = false
385
-
386
- /**
387
- * 监听树选择数据
388
- */
389
- watch(treeSelected, function(nodeKey) {
390
-
391
- // 如果节点值不是有效值
392
- if (! $n_isValidValue(nodeKey)) {
393
-
394
- // 则无任何操作
395
- return
396
- }
397
-
398
- // 树节点点击
399
- const res = props.treeNodeClick(nodeKey, treeNodesAll.value[nodeKey])
400
-
401
- if ($n_isValidObject(res)) {
402
-
403
- // 设置表格传参
404
- $table.setQuery(res)
405
-
406
- // 表格重新加载
407
- $table.tableReload()
408
- }
409
- })
410
-
411
- /**
412
- * 监听树节点数据
413
- */
414
- watch(() => props.treeNodes, function (val) {
415
-
416
- // 如果已选择过第一个节点
417
- if (isSelectedFirstNode) {
418
-
419
- // 则无任何操作
420
- return
421
- }
422
-
423
- // 选中第一个节点的值
424
- treeSelected.value = val[0][props.treeNodeKey]
425
-
426
- // 已选择过第一个节点
427
- isSelectedFirstNode = true
428
-
429
- }, {
430
- // 立即执行
431
- immediate: true,
432
- })
433
- }
434
-
435
- // ==========【返回】=============================================================================================
436
-
437
- return {
438
- // 解构表格实例
439
- ...$table,
440
-
441
- // 树节点
442
- treeRef,
443
- // 树筛选值
444
- treeFilterValue,
445
- // 树选择数据
446
- treeSelected,
447
-
448
- // 插槽 body 单元格标识
449
- slotNames,
450
-
451
- // 当前双击表格行
452
- currentTableRowDblclick,
453
- }
454
- },
455
- }
456
- </script>
1
+ <template>
2
+ <q-layout
3
+ class="absolute-full"
4
+ :class="{
5
+ 'n-table--grid': tableGrid,
6
+ }"
7
+ view="lHr LpR lff"
8
+ container
9
+ >
10
+ <!-- 头部 -->
11
+ <n-toolbar
12
+ :dense="dense"
13
+ header
14
+ >
15
+ <!-- 插槽 -->
16
+ <template
17
+ v-for="slotName in slotNames.toolbar"
18
+ v-slot:[slotName]
19
+ >
20
+ <slot :name="`toolbar-${slotName}`"/>
21
+ </template>
22
+ </n-toolbar>
23
+
24
+ <!-- 左侧分类 -->
25
+ <slot name="left-drawer" v-if="slotNames.leftDrawer" />
26
+ <n-drawer
27
+ :model-value="! hideLeftDrawer"
28
+ :side="treeSide"
29
+ :width="200"
30
+ :min-width="150"
31
+ bordered
32
+ drag
33
+ cache
34
+ v-bind="leftDrawerProps"
35
+ v-else-if="treeNodes.length"
36
+ >
37
+ <q-scroll-area class="absolute-full">
38
+
39
+ <!-- 树筛选 -->
40
+ <div class="q-pa-sm q-gutter-sm" v-if="treeFilter">
41
+ <q-input
42
+ v-model="treeFilterValue"
43
+ placeholder="搜索"
44
+ dense
45
+ outlined
46
+ clearable
47
+
48
+ />
49
+ </div>
50
+
51
+ <!-- 分类树 -->
52
+ <q-tree
53
+ color="grey-5"
54
+ ref="treeRef"
55
+ :nodes="treeNodes"
56
+ :filter="treeFilterValue"
57
+ :node-key="treeNodeKey"
58
+ :label-key="treeLabelKey"
59
+ selected-color="primary"
60
+ v-model:selected="treeSelected"
61
+ no-selection-unset
62
+ default-expand-all
63
+ v-bind="treeProps"
64
+ />
65
+
66
+ </q-scroll-area>
67
+ </n-drawer>
68
+
69
+ <!-- 列表 -->
70
+ <q-page-container>
71
+ <q-page>
72
+ <q-table
73
+ class="n-table absolute-full"
74
+ :class="{
75
+ 'n-table--last-fixed': showTableFixed,
76
+ }"
77
+ v-model:pagination="tablePagination"
78
+ v-model:selected="tableSelected"
79
+ :row-key="tableRowKey"
80
+ :rows="tableRows"
81
+ :columns="tableColumns"
82
+ :visible-columns="tableVisibleColumns"
83
+ :selection="tableSelection"
84
+ :separator="tableSeparator"
85
+ :loading="tableLoading"
86
+ :rows-per-page-options="tableRowsPerPageOptions"
87
+ :grid="tableGrid"
88
+ @row-click="tableRowClick"
89
+ @row-dblclick="currentTableRowDblclick"
90
+ @request="tableRequest"
91
+ flat
92
+ virtual-scroll
93
+ :virtual-scroll-slice-ratio-before="20"
94
+ :virtual-scroll-slice-size="50"
95
+ :virtual-scroll-slice-ratio-after="20"
96
+ :dense="dense"
97
+ v-bind="$attrs"
98
+ >
99
+ <!-- 图片 -->
100
+ <template
101
+ v-for="imgName in tableImgNames"
102
+ v-slot:[`body-cell-${imgName}`]="props"
103
+ >
104
+ <q-td :props="props">
105
+ <!-- 缩略图 -->
106
+ <n-thumbnail
107
+ :src="props.row[imgName]"
108
+ preview
109
+ />
110
+ </q-td>
111
+ </template>
112
+
113
+ <!-- 插槽 -->
114
+ <template
115
+ v-for="slotName in slotNames.table"
116
+ v-slot:[slotName]="props"
117
+ >
118
+ <q-td :props="props">
119
+ <slot
120
+ :name="slotName"
121
+ v-bind="props"
122
+ />
123
+ </q-td>
124
+ </template>
125
+
126
+ <!-- 操作 -->
127
+ <template v-slot:body-cell-settings="props">
128
+ <n-table-column-fixed
129
+ :props="props"
130
+ />
131
+ </template>
132
+
133
+ <!-- 合计 -->
134
+ <template v-slot:bottom-row="props" v-if="tableSummary">
135
+ <n-table-summary
136
+ :props="props"
137
+ />
138
+ </template>
139
+
140
+ <!-- 翻页 -->
141
+ <template v-slot:pagination="props">
142
+ <n-table-pagination
143
+ :props="props"
144
+ />
145
+ </template>
146
+ </q-table>
147
+ </q-page>
148
+ </q-page-container>
149
+
150
+ <!-- 右侧搜索 -->
151
+ <slot name="right-drawer" v-if="slotNames.rightDrawer" />
152
+ <n-drawer
153
+ :model-value="! hideRightDrawer"
154
+ :side="searchSide"
155
+ :min-width="320"
156
+ bordered
157
+ drag
158
+ cache
159
+ v-bind="rightDrawerProps"
160
+ v-else-if="! noSearch && tableSearchValue.length"
161
+ >
162
+ <!-- 搜索 -->
163
+ <n-search
164
+ v-model="tableSearchValue"
165
+ :options="tableSearchOptions"
166
+ :on-search="tableReload"
167
+ :on-reset="tableSearchReset"
168
+ >
169
+ <!-- 插槽 -->
170
+ <template
171
+ v-for="slotName in slotNames.search"
172
+ v-slot:[slotName]
173
+ >
174
+ <slot :name="`search-${slotName}`"/>
175
+ </template>
176
+ </n-search>
177
+ </n-drawer>
178
+
179
+ </q-layout>
180
+ </template>
181
+
182
+ <script>
183
+ import { ref, watch, computed, inject } from 'vue'
184
+
185
+ import $n_isFunction from 'lodash/isFunction'
186
+
187
+ import $n_isValidObject from '@netang/utils/isValidObject'
188
+ import $n_isValidValue from '@netang/utils/isValidValue'
189
+ import $n_collection from '@netang/utils/collection'
190
+
191
+ import { NDialogKey, NTableKey } from '../../utils/symbols'
192
+
193
+ import NToolbar from '../toolbar'
194
+ import NDrawer from '../drawer'
195
+ import NThumbnail from '../thumbnail'
196
+ import NTableColumnFixed from '../table-column-fixed'
197
+ import NTableSummary from '../table-summary'
198
+ import NTablePagination from '../table-pagination'
199
+ import NSearch from '../search'
200
+
201
+ export default {
202
+
203
+ /**
204
+ * 标识
205
+ */
206
+ name: 'NTable',
207
+
208
+ /**
209
+ * 关闭组件 attribute 透传行为
210
+ */
211
+ inheritAttrs: false,
212
+
213
+ /**
214
+ * 组件
215
+ */
216
+ components: {
217
+ NToolbar,
218
+ NDrawer,
219
+ NThumbnail,
220
+ NTableColumnFixed,
221
+ NTableSummary,
222
+ NTablePagination,
223
+ NSearch,
224
+ },
225
+
226
+ /**
227
+ * 声明属性
228
+ */
229
+ props: {
230
+ // 表格请求地址
231
+ url: String,
232
+ // 树声明属性
233
+ treeProps: Object,
234
+ // 树节点唯一键值
235
+ treeNodeKey: {
236
+ type: String,
237
+ default: 'id',
238
+ },
239
+ // 树标签键值
240
+ treeLabelKey: {
241
+ type: String,
242
+ default: 'title',
243
+ },
244
+ // 树节点列表
245
+ treeNodes: {
246
+ type: Array,
247
+ default: ()=>[],
248
+ },
249
+ // 树节点点击
250
+ treeNodeClick: Function,
251
+ // 是否选中第一个树节点
252
+ treeSelectFirstNode: {
253
+ type: Boolean,
254
+ default: true,
255
+ },
256
+ // 显示树筛选
257
+ treeFilter: Boolean,
258
+ // 树位置, 可选值: left / right
259
+ treeSide: {
260
+ type: String,
261
+ default: 'left',
262
+ },
263
+ // 不显示搜索
264
+ noSearch: Boolean,
265
+ // 搜索位置
266
+ searchSide: {
267
+ type: String,
268
+ default: 'right',
269
+ },
270
+ // 紧凑模式
271
+ dense: {
272
+ type: Boolean,
273
+ default: true,
274
+ },
275
+ // 隐藏左边侧滑菜单
276
+ hideLeftDrawer: Boolean,
277
+ // 左边侧滑菜单声明属性
278
+ leftDrawerProps: Object,
279
+ // 隐藏右边侧滑菜单
280
+ hideRightDrawer: Boolean,
281
+ // 右边侧滑菜单声明属性
282
+ rightDrawerProps: Object,
283
+ },
284
+
285
+ /**
286
+ * 组合式
287
+ */
288
+ setup(props, { slots }) {
289
+
290
+ // ==========【数据】============================================================================================
291
+
292
+ // 获取表格注入
293
+ const $table = inject(NTableKey)
294
+
295
+ // 获取对话框注入
296
+ const $dialog = inject(NDialogKey)
297
+ const inDialog = !! $dialog
298
+
299
+ // 当前双击表格行
300
+ let currentTableRowDblclick
301
+
302
+ // 如果在对话框内部
303
+ if (inDialog) {
304
+ // 提交表格已选数据给对话框
305
+ $dialog.submit(() => $table.tableSelected.value)
306
+
307
+ // 对话框中的表格双击表格行
308
+ currentTableRowDblclick = function (e, row) {
309
+ // 如果不是多选
310
+ if ($table.tableSelection.value !== 'multiple') {
311
+ $table.tableSelected.value = [ row ]
312
+ $dialog.confirm()
313
+ }
314
+ }
315
+
316
+ } else {
317
+ // 表格实例中的双击表格行
318
+ currentTableRowDblclick = $table.tableRowDblclick
319
+ }
320
+
321
+ // 树节点
322
+ const treeRef = ref(null)
323
+
324
+ // 树筛选值
325
+ const treeFilterValue = ref('')
326
+
327
+ // 树选择数据
328
+ const treeSelected = ref(null)
329
+
330
+ // ==========【计算属性】==========================================================================================
331
+
332
+ /**
333
+ * 插槽标识
334
+ */
335
+ const slotNames = computed(function() {
336
+
337
+ const toolbar = []
338
+ const search = []
339
+ const table = []
340
+ let leftDrawer = false
341
+ let rightDrawer = false
342
+
343
+ // 如果有插槽
344
+ if ($n_isValidObject(slots)) {
345
+ for (const key in slots) {
346
+ if (key.startsWith('toolbar-')) {
347
+ toolbar.push(key.replace('toolbar-', ''))
348
+ } else if (key.startsWith('search-')) {
349
+ search.push(key.replace('search-', ''))
350
+ } else if (key === 'left-drawer') {
351
+ leftDrawer = true
352
+ } else if (key === 'right-drawer') {
353
+ rightDrawer = true
354
+ } else {
355
+ table.push(key)
356
+ }
357
+ }
358
+ }
359
+
360
+ return {
361
+ toolbar,
362
+ search,
363
+ table,
364
+ leftDrawer,
365
+ rightDrawer,
366
+ }
367
+ })
368
+
369
+ // ==========【监听数据】=========================================================================================
370
+
371
+ // 如果有树节点点击方法
372
+ if ($n_isFunction(props.treeNodeClick)) {
373
+
374
+ /**
375
+ * 树节点 all
376
+ */
377
+ const treeNodesAll = computed(function () {
378
+ return $n_collection(props.treeNodes)
379
+ .keyBy(props.treeNodeKey)
380
+ .toObject()
381
+ })
382
+
383
+ // 是否已选择过第一个节点
384
+ let isSelectedFirstNode = false
385
+
386
+ /**
387
+ * 监听树选择数据
388
+ */
389
+ watch(treeSelected, function(nodeKey) {
390
+
391
+ // 如果节点值不是有效值
392
+ if (! $n_isValidValue(nodeKey)) {
393
+
394
+ // 则无任何操作
395
+ return
396
+ }
397
+
398
+ // 树节点点击
399
+ const res = props.treeNodeClick(nodeKey, treeNodesAll.value[nodeKey])
400
+
401
+ if ($n_isValidObject(res)) {
402
+
403
+ // 设置表格传参
404
+ $table.setQuery(res)
405
+
406
+ // 表格重新加载
407
+ $table.tableReload()
408
+ }
409
+ })
410
+
411
+ /**
412
+ * 监听树节点数据
413
+ */
414
+ watch(() => props.treeNodes, function (val) {
415
+
416
+ // 如果已选择过第一个节点
417
+ if (isSelectedFirstNode) {
418
+
419
+ // 则无任何操作
420
+ return
421
+ }
422
+
423
+ // 选中第一个节点的值
424
+ treeSelected.value = val[0][props.treeNodeKey]
425
+
426
+ // 已选择过第一个节点
427
+ isSelectedFirstNode = true
428
+
429
+ }, {
430
+ // 立即执行
431
+ immediate: true,
432
+ })
433
+ }
434
+
435
+ // ==========【返回】=============================================================================================
436
+
437
+ return {
438
+ // 解构表格实例
439
+ ...$table,
440
+
441
+ // 树节点
442
+ treeRef,
443
+ // 树筛选值
444
+ treeFilterValue,
445
+ // 树选择数据
446
+ treeSelected,
447
+
448
+ // 插槽 body 单元格标识
449
+ slotNames,
450
+
451
+ // 当前双击表格行
452
+ currentTableRowDblclick,
453
+ }
454
+ },
455
+ }
456
+ </script>