@netang/quasar 0.2.30 → 0.2.32
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/.editorconfig +12 -12
- package/_docs/docs/components/field-table.md +58 -58
- package/_docs/docs/components/field-tree.md +21 -21
- package/_docs/docs/components/table.md +24 -24
- package/_docs/docs/utils/table.md +196 -196
- package/components/column-title/index.vue +38 -38
- package/components/data/index.vue +20 -20
- package/components/dialog/img-viewer/index.vue +697 -697
- package/components/dialog/index.vue +387 -387
- package/components/dragger/index.vue +203 -203
- package/components/drawer/index.vue +303 -303
- package/components/editor-code/index.vue +328 -328
- package/components/empty/index.vue +82 -82
- package/components/field-date/index.vue +860 -860
- package/components/field-date/methods.js +100 -100
- package/components/field-table/index.vue +1483 -1483
- package/components/field-text/index.vue +166 -166
- package/components/field-tree/index.vue +755 -755
- package/components/img/index.vue +279 -279
- package/components/input-number/index.vue +560 -560
- package/components/list-menu/index.vue +149 -149
- package/components/list-menu-item/index.vue +79 -79
- package/components/mixed-table/index.vue +532 -532
- package/components/mixed-table-splitter/index.vue +377 -377
- package/components/power-page/index.vue +96 -96
- package/components/price/index.vue +188 -188
- package/components/private/components/index.js +11 -11
- package/components/private/components/move-to-tree/index.vue +154 -154
- package/components/private/edit-power-data/index.vue +846 -846
- package/components/private/table-visible-columns-button/index.vue +114 -114
- package/components/render/index.vue +123 -123
- package/components/search/index.vue +231 -231
- package/components/search-item/index.vue +210 -210
- package/components/select/index.vue +177 -177
- package/components/splitter/index.vue +422 -422
- package/components/table/index.vue +513 -513
- package/components/table-column-fixed/index.vue +110 -110
- package/components/table-pagination/index.vue +192 -192
- package/components/table-summary/index.vue +107 -107
- package/components/thumbnail/index.vue +72 -72
- package/components/toolbar/index.vue +150 -150
- package/components/tree/index.vue +1728 -1728
- package/components/tree/virtual-scroll.vue +41 -41
- package/components/uploader/index.vue +196 -196
- package/components/uploader-query/index.vue +945 -945
- package/components/value-format/index.vue +274 -274
- package/components/virtual-scroll/index.vue +136 -136
- package/configs/area3.js +1 -1
- package/docs/404.html +33 -33
- package/docs/assets/404.html-60b35caa.js +1 -1
- package/docs/assets/404.html-d1e63d77.js +1 -1
- package/docs/assets/alert.html-b2a2a72f.js +5 -5
- package/docs/assets/alert.html-ba46d137.js +1 -1
- package/docs/assets/app-9f30aa4b.js +6 -6
- package/docs/assets/area.html-01b9b58d.js +42 -42
- package/docs/assets/area.html-9a4fce6a.js +1 -1
- package/docs/assets/arr.html-145d27e7.js +1 -1
- package/docs/assets/arr.html-674e65ab.js +11 -11
- package/docs/assets/auth.html-579fa830.js +1 -1
- package/docs/assets/auth.html-8544ed95.js +8 -8
- package/docs/assets/bus.html-c71254aa.js +1 -1
- package/docs/assets/bus.html-dc7d3d19.js +6 -6
- package/docs/assets/column-title.html-c735cb5a.js +3 -3
- package/docs/assets/column-title.html-e9316762.js +1 -1
- package/docs/assets/confirm.html-ddfdc27f.js +10 -10
- package/docs/assets/confirm.html-ef3e2bef.js +1 -1
- package/docs/assets/copy.html-d20345b6.js +1 -1
- package/docs/assets/copy.html-ef8c8571.js +13 -13
- package/docs/assets/data.html-6432175d.js +30 -30
- package/docs/assets/data.html-a3b05d5b.js +1 -1
- package/docs/assets/dialog.html-1f698e5a.js +1 -1
- package/docs/assets/dialog.html-62902b83.js +68 -68
- package/docs/assets/dialog.html-baea77c9.js +1 -1
- package/docs/assets/dialog.html-bb082fc4.js +1 -1
- package/docs/assets/dict.html-1311da3d.js +23 -23
- package/docs/assets/dict.html-b96fbf0c.js +1 -1
- package/docs/assets/dictOptions.html-7c4f40a5.js +1 -1
- package/docs/assets/dictOptions.html-fb99d175.js +5 -5
- package/docs/assets/dragger.html-668d3efa.js +1 -1
- package/docs/assets/dragger.html-749d585a.js +1 -1
- package/docs/assets/editor-code.html-6ab26ea9.js +1 -1
- package/docs/assets/editor-code.html-d196205d.js +1 -1
- package/docs/assets/empty.html-1c139131.js +1 -1
- package/docs/assets/empty.html-1e9c441d.js +1 -1
- package/docs/assets/field-date.html-069fdb13.js +1 -1
- package/docs/assets/field-date.html-ad204aa9.js +1 -1
- package/docs/assets/field-table.html-ce480f03.js +1 -1
- package/docs/assets/field-table.html-d9236160.js +1 -1
- package/docs/assets/field-text.html-7277c62f.js +1 -1
- package/docs/assets/field-text.html-ccb4cecf.js +1 -1
- package/docs/assets/field-tree.html-519bfb45.js +1 -1
- package/docs/assets/field-tree.html-fdc748d6.js +1 -1
- package/docs/assets/form.html-2b562c37.js +2 -2
- package/docs/assets/form.html-75104cd5.js +1 -1
- package/docs/assets/framework-204010b2.js +5 -5
- package/docs/assets/getData.html-990e3787.js +1 -1
- package/docs/assets/getData.html-bb72025f.js +34 -34
- package/docs/assets/getFile.html-42368004.js +1 -1
- package/docs/assets/getFile.html-99abd054.js +3 -3
- package/docs/assets/getImage.html-3429c5a1.js +1 -1
- package/docs/assets/getImage.html-4d886d83.js +3 -3
- package/docs/assets/getTime.html-7435f922.js +1 -1
- package/docs/assets/getTime.html-b37f49eb.js +20 -20
- package/docs/assets/img.html-7d1da657.js +1 -1
- package/docs/assets/img.html-fbea1105.js +1 -1
- package/docs/assets/index.html-1695dd7c.js +1 -1
- package/docs/assets/index.html-65a4aa67.js +1 -1
- package/docs/assets/index.html-7b98d5bd.js +1 -1
- package/docs/assets/index.html-c01f2648.js +1 -1
- package/docs/assets/input-number.html-0b250d2a.js +1 -1
- package/docs/assets/input-number.html-a8eb0378.js +1 -1
- package/docs/assets/list-menu-item.html-7f1b4611.js +1 -1
- package/docs/assets/list-menu-item.html-84ed5ab8.js +1 -1
- package/docs/assets/list-menu.html-28b4163f.js +1 -1
- package/docs/assets/list-menu.html-cb6ba95b.js +1 -1
- package/docs/assets/loading.html-dae9e39d.js +6 -6
- package/docs/assets/loading.html-dc74c9e6.js +1 -1
- package/docs/assets/notify.html-e6c4c514.js +1 -1
- package/docs/assets/notify.html-f2c4d914.js +8 -8
- package/docs/assets/power-page.html-32e02f82.js +1 -1
- package/docs/assets/power-page.html-485e77da.js +1 -1
- package/docs/assets/power.html-d258cc19.js +93 -93
- package/docs/assets/power.html-e490bd32.js +1 -1
- package/docs/assets/previewImage.html-6a6b4245.js +1 -1
- package/docs/assets/previewImage.html-c5b7e945.js +2 -2
- package/docs/assets/price.html-1882c548.js +19 -19
- package/docs/assets/price.html-94d3f5be.js +1 -1
- package/docs/assets/price.html-d213df0f.js +1 -1
- package/docs/assets/price.html-deaf880f.js +1 -1
- package/docs/assets/render.html-8efcbdd4.js +1 -1
- package/docs/assets/render.html-df228e38.js +1 -1
- package/docs/assets/rule.html-2cd57fc2.js +13 -13
- package/docs/assets/rule.html-61662001.js +1 -1
- package/docs/assets/ruleValid.html-04fe2552.js +1 -1
- package/docs/assets/ruleValid.html-e0a776af.js +14 -14
- package/docs/assets/search-0782d0d1.svg +1 -1
- package/docs/assets/search-item.html-3f75394c.js +1 -1
- package/docs/assets/search-item.html-4e942ecd.js +1 -1
- package/docs/assets/search.html-2807043e.js +1 -1
- package/docs/assets/search.html-c24f8806.js +1 -1
- package/docs/assets/select.html-00d0607c.js +1 -1
- package/docs/assets/select.html-de7731f5.js +1 -1
- package/docs/assets/splitter.html-56f51a70.js +1 -1
- package/docs/assets/splitter.html-f5c836d7.js +1 -1
- package/docs/assets/style-161e43ab.css +1 -1
- package/docs/assets/symbols.html-a6aea4bf.js +1 -1
- package/docs/assets/symbols.html-b1f65bad.js +21 -21
- package/docs/assets/table-column-fixed.html-3a69e7b2.js +1 -1
- package/docs/assets/table-column-fixed.html-e763c38b.js +1 -1
- package/docs/assets/table-pagination.html-236934d3.js +1 -1
- package/docs/assets/table-pagination.html-c37ee2ac.js +1 -1
- package/docs/assets/table-splitter.html-07eab15c.js +1 -1
- package/docs/assets/table-splitter.html-7670ee65.js +1 -1
- package/docs/assets/table-summary.html-04db434f.js +1 -1
- package/docs/assets/table-summary.html-943c65a0.js +1 -1
- package/docs/assets/table.html-36253ad7.js +1 -1
- package/docs/assets/table.html-7f9c5d1b.js +38 -38
- package/docs/assets/table.html-93d53dc8.js +1 -1
- package/docs/assets/table.html-ac99b9cb.js +1 -1
- package/docs/assets/thumbnail.html-bab1976b.js +1 -1
- package/docs/assets/thumbnail.html-eb64e5e8.js +1 -1
- package/docs/assets/timestamp.html-4e54f79b.js +13 -13
- package/docs/assets/timestamp.html-d0e1b88a.js +1 -1
- package/docs/assets/toast.html-58ecbe21.js +1 -1
- package/docs/assets/toast.html-c9b9d36b.js +6 -6
- package/docs/assets/toolbar.html-83d9f97c.js +1 -1
- package/docs/assets/toolbar.html-ff7b8c92.js +1 -1
- package/docs/assets/tree.html-d07cbe79.js +23 -23
- package/docs/assets/tree.html-ea04193e.js +1 -1
- package/docs/assets/uploader-query.html-05590718.js +1 -1
- package/docs/assets/uploader-query.html-3175bac5.js +1 -1
- package/docs/assets/uploader.html-36da4394.js +2 -2
- package/docs/assets/uploader.html-6b5f3079.js +1 -1
- package/docs/assets/uploader.html-b9340b57.js +1 -1
- package/docs/assets/uploader.html-bc1c22e3.js +1 -1
- package/docs/assets/value-format.html-8ae3d47d.js +1 -1
- package/docs/assets/value-format.html-afa99b3d.js +1 -1
- package/docs/components/column-title.html +35 -35
- package/docs/components/data.html +62 -62
- package/docs/components/dialog.html +33 -33
- package/docs/components/dragger.html +33 -33
- package/docs/components/editor-code.html +33 -33
- package/docs/components/empty.html +33 -33
- package/docs/components/field-date.html +33 -33
- package/docs/components/field-table.html +33 -33
- package/docs/components/field-text.html +33 -33
- package/docs/components/field-tree.html +33 -33
- package/docs/components/img.html +33 -33
- package/docs/components/input-number.html +33 -33
- package/docs/components/list-menu-item.html +33 -33
- package/docs/components/list-menu.html +33 -33
- package/docs/components/power-page.html +33 -33
- package/docs/components/price.html +33 -33
- package/docs/components/render.html +33 -33
- package/docs/components/search-item.html +33 -33
- package/docs/components/search.html +33 -33
- package/docs/components/select.html +33 -33
- package/docs/components/splitter.html +33 -33
- package/docs/components/table-column-fixed.html +33 -33
- package/docs/components/table-pagination.html +33 -33
- package/docs/components/table-splitter.html +33 -33
- package/docs/components/table-summary.html +33 -33
- package/docs/components/table.html +33 -33
- package/docs/components/thumbnail.html +33 -33
- package/docs/components/toolbar.html +33 -33
- package/docs/components/uploader-query.html +33 -33
- package/docs/components/uploader.html +33 -33
- package/docs/components/value-format.html +33 -33
- package/docs/css/index.css +3 -3
- package/docs/index.html +33 -33
- package/docs/utils/alert.html +37 -37
- package/docs/utils/area.html +74 -74
- package/docs/utils/arr.html +43 -43
- package/docs/utils/auth.html +40 -40
- package/docs/utils/bus.html +38 -38
- package/docs/utils/confirm.html +42 -42
- package/docs/utils/copy.html +45 -45
- package/docs/utils/dialog.html +100 -100
- package/docs/utils/dict.html +55 -55
- package/docs/utils/dictOptions.html +37 -37
- package/docs/utils/form.html +34 -34
- package/docs/utils/getData.html +66 -66
- package/docs/utils/getFile.html +35 -35
- package/docs/utils/getImage.html +35 -35
- package/docs/utils/getTime.html +52 -52
- package/docs/utils/index.html +33 -33
- package/docs/utils/loading.html +38 -38
- package/docs/utils/notify.html +40 -40
- package/docs/utils/power.html +125 -125
- package/docs/utils/previewImage.html +34 -34
- package/docs/utils/price.html +51 -51
- package/docs/utils/rule.html +45 -45
- package/docs/utils/ruleValid.html +46 -46
- package/docs/utils/symbols.html +53 -53
- package/docs/utils/table.html +70 -70
- package/docs/utils/timestamp.html +45 -45
- package/docs/utils/toast.html +38 -38
- package/docs/utils/tree.html +55 -55
- package/docs/utils/uploader.html +34 -34
- package/package.json +25 -25
- package/sass/common.scss +184 -184
- package/sass/index.scss +12 -12
- package/sass/line.scss +39 -39
- package/sass/quasar/btn.scss +46 -46
- package/sass/quasar/common.scss +3 -3
- package/sass/quasar/drawer.scss +6 -6
- package/sass/quasar/field.scss +259 -259
- package/sass/quasar/loading.scss +6 -6
- package/sass/quasar/table.scss +168 -168
- package/sass/quasar/toolbar.scss +22 -22
- package/sass/variables.scss +140 -140
- package/store/index.js +29 -29
- package/utils/$auth.js +128 -128
- package/utils/$form.js +72 -72
- package/utils/$power.js +1494 -1492
- package/utils/$render.js +75 -75
- package/utils/$rule.js +13 -13
- package/utils/$ruleValid.js +10 -10
- package/utils/$search.js +416 -416
- package/utils/$table.js +1348 -1276
- package/utils/$tree.js +682 -682
- package/utils/alert.js +12 -12
- package/utils/area.js +400 -400
- package/utils/arr.js +51 -51
- package/utils/bus.js +6 -6
- package/utils/config.js +66 -66
- package/utils/confirm.js +11 -11
- package/utils/copy.js +30 -30
- package/utils/dialog.js +36 -36
- package/utils/dict.js +21 -21
- package/utils/dictOptions.js +28 -28
- package/utils/getData.js +88 -88
- package/utils/getFile.js +67 -67
- package/utils/getImage.js +276 -276
- package/utils/getTime.js +113 -113
- package/utils/index.js +67 -67
- package/utils/loading.js +15 -15
- package/utils/notify.js +13 -13
- package/utils/play.js +40 -40
- package/utils/previewImage.js +14 -14
- package/utils/price.js +18 -18
- package/utils/symbols.js +18 -18
- package/utils/timestamp.js +18 -18
- package/utils/toast.js +13 -13
- package/utils/uploader.js +2114 -2114
- package/utils/useAuth.js +30 -30
- package/utils/useFileUrl.js +26 -26
- package/utils/useRouter.js +47 -47
- package/utils/useSearch.js +562 -562
|
@@ -1,1483 +1,1483 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
|
|
3
|
-
<!-- 如果有默认插槽 -->
|
|
4
|
-
<template v-if="$slots.default">
|
|
5
|
-
<slot
|
|
6
|
-
:showValue="showValue"
|
|
7
|
-
:selected="selected"
|
|
8
|
-
:onRemove="onRemoveSelected"
|
|
9
|
-
:onShowDialog="onShowDialog"
|
|
10
|
-
:onClear="onFieldClear"
|
|
11
|
-
/>
|
|
12
|
-
</template>
|
|
13
|
-
|
|
14
|
-
<!--:class="fieldFocused ? 'q-field--float q-field--focused q-field--highlighted' : ''"-->
|
|
15
|
-
<!--:clearable="clearable && (! multiple || collapseTags)"-->
|
|
16
|
-
<q-field
|
|
17
|
-
class="n-field-table"
|
|
18
|
-
:model-value="showValue"
|
|
19
|
-
:disable="disable"
|
|
20
|
-
:readonly="readonly"
|
|
21
|
-
:clearable="clearable"
|
|
22
|
-
for="field-table"
|
|
23
|
-
@focus="onFieldFocus"
|
|
24
|
-
@blur="onFieldBlur"
|
|
25
|
-
@clear="onFieldClear"
|
|
26
|
-
v-bind="$attrs"
|
|
27
|
-
v-else
|
|
28
|
-
>
|
|
29
|
-
<template v-slot:control>
|
|
30
|
-
|
|
31
|
-
<template v-if="multiple">
|
|
32
|
-
<template v-if="selected.length">
|
|
33
|
-
|
|
34
|
-
<!-- 多选插槽 -->
|
|
35
|
-
<slot
|
|
36
|
-
name="selected"
|
|
37
|
-
:selected="selected"
|
|
38
|
-
:remove="onRemoveSelected"
|
|
39
|
-
v-if="$slots.selected"
|
|
40
|
-
/>
|
|
41
|
-
|
|
42
|
-
<!-- 显示折叠的值数量 -->
|
|
43
|
-
<q-chip
|
|
44
|
-
dense
|
|
45
|
-
:label="`+${selected.length}`"
|
|
46
|
-
v-else-if="collapseTags"
|
|
47
|
-
/>
|
|
48
|
-
|
|
49
|
-
<!-- 多选标签 -->
|
|
50
|
-
<template v-else>
|
|
51
|
-
<q-chip
|
|
52
|
-
v-for="(item, index) in selected"
|
|
53
|
-
:key="`options-${index}`"
|
|
54
|
-
:label="currentFormatLabel(item)"
|
|
55
|
-
dense
|
|
56
|
-
:removable="! readonly && ! disable"
|
|
57
|
-
@remove="onRemoveSelected(index)"
|
|
58
|
-
>
|
|
59
|
-
<q-tooltip>{{currentFormatLabel(item)}}</q-tooltip>
|
|
60
|
-
</q-chip>
|
|
61
|
-
</template>
|
|
62
|
-
</template>
|
|
63
|
-
|
|
64
|
-
<!-- 占位符-->
|
|
65
|
-
<span class="n-placeholder" v-else-if="placeholder">{{placeholder}}</span>
|
|
66
|
-
</template>
|
|
67
|
-
|
|
68
|
-
<!-- 显示文字 -->
|
|
69
|
-
<span v-else-if="showValue">{{showValue}}</span>
|
|
70
|
-
|
|
71
|
-
<!-- 占位符-->
|
|
72
|
-
<span class="n-placeholder" v-else-if="placeholder">{{placeholder}}</span>
|
|
73
|
-
|
|
74
|
-
<!-- 筛选输入框 -->
|
|
75
|
-
<input
|
|
76
|
-
ref="inputRef"
|
|
77
|
-
class="q-field__input q-placeholder col q-field__input--padding"
|
|
78
|
-
v-model="inputValue"
|
|
79
|
-
v-if="filter && ! readonly && ! disable"
|
|
80
|
-
/>
|
|
81
|
-
|
|
82
|
-
</template>
|
|
83
|
-
|
|
84
|
-
<!-- 弹出对话框图标 -->
|
|
85
|
-
<template v-slot:append v-if="! noDialog && ! readonly && ! disable">
|
|
86
|
-
<q-icon
|
|
87
|
-
class="cursor-pointer"
|
|
88
|
-
name="search"
|
|
89
|
-
@click.prevent.stop="onShowDialog"
|
|
90
|
-
/>
|
|
91
|
-
</template>
|
|
92
|
-
|
|
93
|
-
<!-- 默认插槽 -->
|
|
94
|
-
<template
|
|
95
|
-
v-for="slotName in slotNames.normal"
|
|
96
|
-
v-slot:[slotName]
|
|
97
|
-
>
|
|
98
|
-
<slot :name="slotName" />
|
|
99
|
-
</template>
|
|
100
|
-
|
|
101
|
-
<!-- 弹出层代理 -->
|
|
102
|
-
<q-popup-proxy
|
|
103
|
-
ref="popupRef"
|
|
104
|
-
no-refocus
|
|
105
|
-
no-focus
|
|
106
|
-
fit
|
|
107
|
-
@focus="onFieldBlur"
|
|
108
|
-
@show="onPopupShow"
|
|
109
|
-
@before-hide="showPopup = false"
|
|
110
|
-
v-if="! readonly && ! disable"
|
|
111
|
-
>
|
|
112
|
-
<!-- 快捷表格 -->
|
|
113
|
-
<n-table
|
|
114
|
-
class="n-table n-field-table__popup-table"
|
|
115
|
-
v-model:pagination="tablePagination"
|
|
116
|
-
:selected="selected"
|
|
117
|
-
@update:selected="emitModelValue"
|
|
118
|
-
:row-key="tableRowKey"
|
|
119
|
-
:rows="tableRows"
|
|
120
|
-
:columns="columns"
|
|
121
|
-
:selection="multiple ? 'multiple' : 'none'"
|
|
122
|
-
:loading="tableLoading"
|
|
123
|
-
:rows-per-page-options="tableRowsPerPageOptions"
|
|
124
|
-
@row-click="quickTableRowClick"
|
|
125
|
-
@request="tableRequest"
|
|
126
|
-
flat
|
|
127
|
-
virtual-scroll
|
|
128
|
-
dense
|
|
129
|
-
v-bind="tableProps"
|
|
130
|
-
>
|
|
131
|
-
<!-- 图片 -->
|
|
132
|
-
<template
|
|
133
|
-
v-for="imgItem in tableImgs"
|
|
134
|
-
v-slot:[`body-cell-${imgItem.name}`]="props"
|
|
135
|
-
>
|
|
136
|
-
<n-data
|
|
137
|
-
:data="formatImg(props.row[imgItem.name], imgItem)"
|
|
138
|
-
v-slot="{ data }"
|
|
139
|
-
>
|
|
140
|
-
<!-- 缩略图 -->
|
|
141
|
-
<n-thumbnail
|
|
142
|
-
v-for="(item, index) in data"
|
|
143
|
-
:key="`thumbnail-item-${item}`"
|
|
144
|
-
class="n-table__thumbnail"
|
|
145
|
-
:src="item"
|
|
146
|
-
preview
|
|
147
|
-
:preview-props="{
|
|
148
|
-
startPosition: index,
|
|
149
|
-
images: data,
|
|
150
|
-
}"
|
|
151
|
-
/>
|
|
152
|
-
</n-data>
|
|
153
|
-
</template>
|
|
154
|
-
|
|
155
|
-
<!-- 表格插槽 -->
|
|
156
|
-
<template
|
|
157
|
-
v-for="slotName in slotNames.table"
|
|
158
|
-
v-slot:[slotName]="props"
|
|
159
|
-
>
|
|
160
|
-
<q-td :props="props">
|
|
161
|
-
<slot
|
|
162
|
-
:name="slotName"
|
|
163
|
-
v-bind="props"
|
|
164
|
-
/>
|
|
165
|
-
</q-td>
|
|
166
|
-
</template>
|
|
167
|
-
|
|
168
|
-
<!-- 翻页 -->
|
|
169
|
-
<template v-slot:pagination="props">
|
|
170
|
-
<n-table-pagination
|
|
171
|
-
:props="props"
|
|
172
|
-
no-power
|
|
173
|
-
dense
|
|
174
|
-
/>
|
|
175
|
-
</template>
|
|
176
|
-
</n-table>
|
|
177
|
-
</q-popup-proxy>
|
|
178
|
-
</q-field>
|
|
179
|
-
|
|
180
|
-
<!-- 弹出对话框 -->
|
|
181
|
-
<n-dialog
|
|
182
|
-
v-model="showDialog"
|
|
183
|
-
width="80%"
|
|
184
|
-
:on-confirm="onDialogConfirm"
|
|
185
|
-
@before-show="onDialogBeforeShow"
|
|
186
|
-
@show="onDialogShow"
|
|
187
|
-
@hide="onDialogHide"
|
|
188
|
-
cancel
|
|
189
|
-
v-bind="dialogProps"
|
|
190
|
-
>
|
|
191
|
-
<q-page>
|
|
192
|
-
<n-mixed-table />
|
|
193
|
-
</q-page>
|
|
194
|
-
</n-dialog>
|
|
195
|
-
</template>
|
|
196
|
-
|
|
197
|
-
<script>
|
|
198
|
-
import { ref, computed, watch, onUpdated } from 'vue'
|
|
199
|
-
|
|
200
|
-
import $n_has from 'lodash/has'
|
|
201
|
-
import $n_uniq from 'lodash/uniq'
|
|
202
|
-
import $n_cloneDeep from 'lodash/cloneDeep'
|
|
203
|
-
import $n_isFunction from 'lodash/isFunction'
|
|
204
|
-
import $n_findIndex from 'lodash/findIndex'
|
|
205
|
-
import $n_get from 'lodash/get'
|
|
206
|
-
import $n_find from 'lodash/find'
|
|
207
|
-
|
|
208
|
-
import $n_indexOf from '@netang/utils/indexOf'
|
|
209
|
-
import $n_forEach from '@netang/utils/forEach'
|
|
210
|
-
import $n_isValidArray from '@netang/utils/isValidArray'
|
|
211
|
-
import $n_join from '@netang/utils/join'
|
|
212
|
-
import $n_split from '@netang/utils/split'
|
|
213
|
-
import $n_isValidObject from '@netang/utils/isValidObject'
|
|
214
|
-
import $n_isValidValue from '@netang/utils/isValidValue'
|
|
215
|
-
import $n_isValidString from '@netang/utils/isValidString'
|
|
216
|
-
import $n_numberDeep from '@netang/utils/numberDeep'
|
|
217
|
-
import $n_sleep from '@netang/utils/sleep'
|
|
218
|
-
import $n_http from '@netang/utils/http'
|
|
219
|
-
import $n_runAsync from '@netang/utils/runAsync'
|
|
220
|
-
|
|
221
|
-
import $n_$power from '../../utils/$power'
|
|
222
|
-
import $n_$table from '../../utils/$table'
|
|
223
|
-
|
|
224
|
-
import { configs } from '../../utils/config'
|
|
225
|
-
|
|
226
|
-
import $n_getImage from '../../utils/getImage'
|
|
227
|
-
|
|
228
|
-
const {
|
|
229
|
-
// 字典常量
|
|
230
|
-
dicts,
|
|
231
|
-
} = configs
|
|
232
|
-
|
|
233
|
-
export default {
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* 标识
|
|
237
|
-
*/
|
|
238
|
-
name: 'NFieldTable',
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* 关闭组件 attribute 透传行为
|
|
242
|
-
*/
|
|
243
|
-
inheritAttrs: false,
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* 声明属性
|
|
247
|
-
*/
|
|
248
|
-
props: {
|
|
249
|
-
// 值 v-model
|
|
250
|
-
modelValue: {
|
|
251
|
-
required: true,
|
|
252
|
-
},
|
|
253
|
-
// 值字段(必填)
|
|
254
|
-
valueKey: {
|
|
255
|
-
type: String,
|
|
256
|
-
required: true,
|
|
257
|
-
},
|
|
258
|
-
// 标签字段
|
|
259
|
-
labelKey: String,
|
|
260
|
-
// 值类型
|
|
261
|
-
// string: 字符串或数字
|
|
262
|
-
// stringArray: 普通数组(包含字符串或数字的一维数组)
|
|
263
|
-
// objectArray: 对象数组(包含对象的一维数组)
|
|
264
|
-
valueType: {
|
|
265
|
-
type: String,
|
|
266
|
-
default: 'objectArray'
|
|
267
|
-
},
|
|
268
|
-
// 值分隔符(值类型为 string 有效)
|
|
269
|
-
valueSeparator: {
|
|
270
|
-
type: String,
|
|
271
|
-
default: ',',
|
|
272
|
-
},
|
|
273
|
-
|
|
274
|
-
// 请求路由路径
|
|
275
|
-
path: String,
|
|
276
|
-
// 请求地址(默认为 path)
|
|
277
|
-
url: String,
|
|
278
|
-
// 请求参数
|
|
279
|
-
query: Object,
|
|
280
|
-
// 附加请求数据
|
|
281
|
-
data: Object,
|
|
282
|
-
// 加载已选数据数组
|
|
283
|
-
// 如果有数组数据, 则初始化时从数组中选取已有的数据
|
|
284
|
-
loadSelected: [Array, Function],
|
|
285
|
-
// 初始是否不加载已选数据
|
|
286
|
-
// true, 则初始时不加载数据(同时 loadSelected 无效)
|
|
287
|
-
noDefaultLoadSelected: Boolean,
|
|
288
|
-
// 更新值时不加载已选数据
|
|
289
|
-
noUpdateLoadSelected: Boolean,
|
|
290
|
-
// 格式化显示标签
|
|
291
|
-
formatLabel: Function,
|
|
292
|
-
// 下拉表格显示的字段数组(空为:[值字段, 标签字段])
|
|
293
|
-
showKeys: Array,
|
|
294
|
-
// 隐藏搜索字段数组
|
|
295
|
-
hideSearchKeys: Array,
|
|
296
|
-
// 默认筛选字段(空为:标签字段)
|
|
297
|
-
filterKey: String,
|
|
298
|
-
// 是否开启筛选
|
|
299
|
-
filter: Boolean,
|
|
300
|
-
// 表格声明属性
|
|
301
|
-
tableProps: Object,
|
|
302
|
-
// 对话框声明属性
|
|
303
|
-
dialogProps: Object,
|
|
304
|
-
|
|
305
|
-
// 关闭对话框
|
|
306
|
-
noDialog: Boolean,
|
|
307
|
-
|
|
308
|
-
// 表格列数据
|
|
309
|
-
columns: Array,
|
|
310
|
-
// 行数据
|
|
311
|
-
rows: Array,
|
|
312
|
-
// 是否多选
|
|
313
|
-
multiple: Boolean,
|
|
314
|
-
// 多选模式下是否折叠标签
|
|
315
|
-
collapseTags: Boolean,
|
|
316
|
-
// 占位符
|
|
317
|
-
placeholder: String,
|
|
318
|
-
// 是否可清除
|
|
319
|
-
clearable: Boolean,
|
|
320
|
-
// 是否禁用
|
|
321
|
-
disable: Boolean,
|
|
322
|
-
// 是否只读
|
|
323
|
-
readonly: Boolean,
|
|
324
|
-
// 输入防抖(毫秒)
|
|
325
|
-
inputDebounce: {
|
|
326
|
-
type: [ Number, String ],
|
|
327
|
-
default: 500
|
|
328
|
-
},
|
|
329
|
-
// 自定义请求方法
|
|
330
|
-
request: Function,
|
|
331
|
-
// 每次对话框显示都请求
|
|
332
|
-
requestEveryDialogShow: Boolean,
|
|
333
|
-
},
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* 声明事件
|
|
337
|
-
*/
|
|
338
|
-
emits: [
|
|
339
|
-
'loaded',
|
|
340
|
-
'update:modelValue',
|
|
341
|
-
'update:selected',
|
|
342
|
-
],
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* 组合式
|
|
346
|
-
*/
|
|
347
|
-
setup(props, { emit, slots }) {
|
|
348
|
-
|
|
349
|
-
// ==========【计算属性】=========================================================================================
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* 插槽标识
|
|
353
|
-
*/
|
|
354
|
-
const slotNames = computed(function() {
|
|
355
|
-
|
|
356
|
-
const table = []
|
|
357
|
-
const normal = []
|
|
358
|
-
|
|
359
|
-
// 如果有插槽
|
|
360
|
-
if ($n_isValidObject(slots)) {
|
|
361
|
-
for (const key in slots) {
|
|
362
|
-
if (key !== 'append' && key !== 'control') {
|
|
363
|
-
if (key.startsWith('table-')) {
|
|
364
|
-
table.push(key.replace('table-', ''))
|
|
365
|
-
} else {
|
|
366
|
-
normal.push(key)
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
return {
|
|
373
|
-
table,
|
|
374
|
-
normal,
|
|
375
|
-
}
|
|
376
|
-
})
|
|
377
|
-
|
|
378
|
-
/**
|
|
379
|
-
* 当前标签字段
|
|
380
|
-
*/
|
|
381
|
-
const currentlabelKey = computed(function() {
|
|
382
|
-
return props.labelKey || props.valueKey
|
|
383
|
-
})
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* 当前显示字段
|
|
387
|
-
*/
|
|
388
|
-
const currentShowKeys = computed(function() {
|
|
389
|
-
return $n_uniq($n_isValidArray(props.showKeys)
|
|
390
|
-
? props.showKeys
|
|
391
|
-
: [ props.valueKey, currentlabelKey.value ])
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
/**
|
|
395
|
-
* 当前搜索字段
|
|
396
|
-
*/
|
|
397
|
-
const currentFilterKey = computed(function() {
|
|
398
|
-
return props.filterKey || currentlabelKey.value
|
|
399
|
-
})
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
* 显示值
|
|
403
|
-
*/
|
|
404
|
-
const showValue = computed(function () {
|
|
405
|
-
|
|
406
|
-
// 如果有已选数据
|
|
407
|
-
return $n_isValidArray(selected.value)
|
|
408
|
-
// 取已选数据第一条
|
|
409
|
-
? currentFormatLabel(selected.value[0])
|
|
410
|
-
: ''
|
|
411
|
-
})
|
|
412
|
-
|
|
413
|
-
// ==========【数据】============================================================================================
|
|
414
|
-
|
|
415
|
-
// 创建权限实例
|
|
416
|
-
const $power = $n_$power.create({
|
|
417
|
-
// 路由路径
|
|
418
|
-
path: $n_isValidString(props.path) ? props.path : false,
|
|
419
|
-
// 路由参数
|
|
420
|
-
query: props.query,
|
|
421
|
-
// 关闭权限页面
|
|
422
|
-
power: false,
|
|
423
|
-
// 禁止对话框注入
|
|
424
|
-
$dialog: null,
|
|
425
|
-
})
|
|
426
|
-
|
|
427
|
-
const {
|
|
428
|
-
// 当前路由路径
|
|
429
|
-
routePath,
|
|
430
|
-
} = $power
|
|
431
|
-
|
|
432
|
-
// 创建表格实例
|
|
433
|
-
const $table = $n_$table.create({
|
|
434
|
-
// 权限实例
|
|
435
|
-
$power,
|
|
436
|
-
// 请求地址
|
|
437
|
-
url: props.url,
|
|
438
|
-
// 附加请求数据
|
|
439
|
-
data: props.data,
|
|
440
|
-
// 获取表格列数据
|
|
441
|
-
columns: getTableColumns(),
|
|
442
|
-
// 表格行唯一键值
|
|
443
|
-
rowKey: props.valueKey,
|
|
444
|
-
// 行数据
|
|
445
|
-
rows: props.rows,
|
|
446
|
-
// 选择类型, 可选值 single multiple none
|
|
447
|
-
selection: props.multiple ? 'multiple' : 'single',
|
|
448
|
-
// 已选数据
|
|
449
|
-
selected: [],
|
|
450
|
-
// http 设置
|
|
451
|
-
httpSettings: {
|
|
452
|
-
// 头部请求
|
|
453
|
-
headers: {
|
|
454
|
-
// 添加头部查看请求
|
|
455
|
-
Pview: 1,
|
|
456
|
-
},
|
|
457
|
-
},
|
|
458
|
-
// 刷新后清空已选数据
|
|
459
|
-
refreshResetSelected: false,
|
|
460
|
-
// 自定义请求方法
|
|
461
|
-
async request({ httpOptions, props: httpProps }) {
|
|
462
|
-
return $n_isFunction(props.request) ?
|
|
463
|
-
// 如果有自定义请求方法
|
|
464
|
-
await $n_runAsync(props.request)({
|
|
465
|
-
// http 请求参数
|
|
466
|
-
httpOptions,
|
|
467
|
-
// 对话框是否已显示
|
|
468
|
-
showDialog: $n_get(httpProps, 'showDialog') === 1 ? true : showDialog.value,
|
|
469
|
-
}) :
|
|
470
|
-
// 否则请求数据
|
|
471
|
-
await $n_http(httpOptions)
|
|
472
|
-
},
|
|
473
|
-
})
|
|
474
|
-
|
|
475
|
-
// 创建睡眠实例
|
|
476
|
-
const sleep = $n_sleep()
|
|
477
|
-
|
|
478
|
-
// 输入框节点
|
|
479
|
-
const inputRef = ref(null)
|
|
480
|
-
|
|
481
|
-
// 输入框值
|
|
482
|
-
const inputValue = ref('')
|
|
483
|
-
|
|
484
|
-
// 弹出层节点
|
|
485
|
-
const popupRef = ref(null)
|
|
486
|
-
|
|
487
|
-
// 是否显示对话框
|
|
488
|
-
const showDialog = ref(false)
|
|
489
|
-
|
|
490
|
-
// 是否显示弹出层
|
|
491
|
-
const showPopup = ref(false)
|
|
492
|
-
|
|
493
|
-
// 当前表格列数据
|
|
494
|
-
const columns = getQuickTableColumns()
|
|
495
|
-
|
|
496
|
-
// 停止观察值
|
|
497
|
-
let stopValueWatcher = false
|
|
498
|
-
|
|
499
|
-
// 临时已选数据
|
|
500
|
-
let tempSelected = []
|
|
501
|
-
|
|
502
|
-
// 初始化已选数据
|
|
503
|
-
const selected = ref(valueToSelected(props.modelValue, true, true))
|
|
504
|
-
|
|
505
|
-
// 加载已选数据
|
|
506
|
-
if (
|
|
507
|
-
! props.noDefaultLoadSelected
|
|
508
|
-
&& props.loadSelected === void 0
|
|
509
|
-
) {
|
|
510
|
-
loadSelected()
|
|
511
|
-
.finally()
|
|
512
|
-
} else {
|
|
513
|
-
// 初始化加载成功
|
|
514
|
-
emit('loaded', selected.value)
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// ==========【监听数据】=========================================================================================
|
|
518
|
-
|
|
519
|
-
/**
|
|
520
|
-
* 监听声明值
|
|
521
|
-
*/
|
|
522
|
-
watch(() => props.modelValue, async function(val) {
|
|
523
|
-
|
|
524
|
-
// 如果停止观察值
|
|
525
|
-
if (stopValueWatcher === true) {
|
|
526
|
-
// 取消停止观察值
|
|
527
|
-
stopValueWatcher = false
|
|
528
|
-
return
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// 值转已选数据
|
|
532
|
-
let newSelected = valueToSelected(val, false, false)
|
|
533
|
-
|
|
534
|
-
// 如果值类型是数组对象
|
|
535
|
-
if (props.valueType === 'objectArray') {
|
|
536
|
-
|
|
537
|
-
// 设置已选数据
|
|
538
|
-
setSelected(newSelected)
|
|
539
|
-
|
|
540
|
-
// 否则值类型是字符串或数组
|
|
541
|
-
} else {
|
|
542
|
-
|
|
543
|
-
// 初始已选数据
|
|
544
|
-
const _selected = []
|
|
545
|
-
|
|
546
|
-
// 如果值转已选数据是有效数组
|
|
547
|
-
if (newSelected.length) {
|
|
548
|
-
|
|
549
|
-
const newSelectedOld = newSelected
|
|
550
|
-
const __selected = []
|
|
551
|
-
|
|
552
|
-
// 如果有已选数据
|
|
553
|
-
const currentSelected = tempSelected.length ? tempSelected : selected.value
|
|
554
|
-
if (currentSelected.length) {
|
|
555
|
-
|
|
556
|
-
const _newSelected = []
|
|
557
|
-
|
|
558
|
-
// 遍历新已选数据
|
|
559
|
-
for (const newItem of newSelected) {
|
|
560
|
-
// 已选中的数据
|
|
561
|
-
const hasItem = $n_find(currentSelected, e => e[props.valueKey] === newItem)
|
|
562
|
-
if (hasItem) {
|
|
563
|
-
__selected.push(hasItem)
|
|
564
|
-
// 需增加的值
|
|
565
|
-
} else {
|
|
566
|
-
_newSelected.push(newItem)
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// 设置新的需要增加的值
|
|
571
|
-
newSelected = _newSelected
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
// 需增加的值
|
|
575
|
-
if (newSelected.length) {
|
|
576
|
-
// 如果更新值时不加载已选数据
|
|
577
|
-
if (props.noUpdateLoadSelected) {
|
|
578
|
-
// 请求选择数据
|
|
579
|
-
__selected.push(...newSelected.map(e => setSelectedItem(e)))
|
|
580
|
-
} else {
|
|
581
|
-
// 请求选择数据
|
|
582
|
-
__selected.push(...await onRequestSelected(newSelected))
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// 重新筛选和排序已选数据
|
|
587
|
-
for (const item of newSelectedOld) {
|
|
588
|
-
// 已选中的数据
|
|
589
|
-
const hasItem = $n_find(__selected, e => e[props.valueKey] === item)
|
|
590
|
-
if (hasItem) {
|
|
591
|
-
_selected.push(hasItem)
|
|
592
|
-
}
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// 设置已选数据
|
|
597
|
-
setSelected(_selected)
|
|
598
|
-
|
|
599
|
-
// 清空临时已选数据
|
|
600
|
-
tempSelected = []
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// 将已选数据转为值
|
|
604
|
-
const _value = selectedToValue(selected.value)
|
|
605
|
-
|
|
606
|
-
// 如果声明值发生变化
|
|
607
|
-
if (_value !== props.modelValue) {
|
|
608
|
-
// 停止观察值
|
|
609
|
-
stopValueWatcher = true
|
|
610
|
-
// 触发更新已选数据
|
|
611
|
-
emit('update:modelValue', _value)
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// 设置输入框焦点
|
|
615
|
-
setInputFocus()
|
|
616
|
-
|
|
617
|
-
// 设置输入框文字选中
|
|
618
|
-
setInputSelection()
|
|
619
|
-
|
|
620
|
-
}, {
|
|
621
|
-
// 深度监听
|
|
622
|
-
deep: true,
|
|
623
|
-
})
|
|
624
|
-
|
|
625
|
-
/**
|
|
626
|
-
* 监听输入框值
|
|
627
|
-
*/
|
|
628
|
-
watch(inputValue, async function (val) {
|
|
629
|
-
|
|
630
|
-
// 延迟执行
|
|
631
|
-
await sleep(props.inputDebounce)
|
|
632
|
-
|
|
633
|
-
// 是否有值
|
|
634
|
-
const hasValue = $n_isValidValue(val)
|
|
635
|
-
|
|
636
|
-
const n_search = {}
|
|
637
|
-
n_search[currentFilterKey.value] = [
|
|
638
|
-
{
|
|
639
|
-
// 比较类型
|
|
640
|
-
compare: dicts.SEARCH_COMPARE_TYPE__LIKE,
|
|
641
|
-
// 值
|
|
642
|
-
value: hasValue ? val : '',
|
|
643
|
-
}
|
|
644
|
-
]
|
|
645
|
-
|
|
646
|
-
// 设置表格传参
|
|
647
|
-
$table.setQuery({
|
|
648
|
-
n_search,
|
|
649
|
-
})
|
|
650
|
-
|
|
651
|
-
if (
|
|
652
|
-
// 如果弹出层是隐藏的
|
|
653
|
-
! showPopup.value
|
|
654
|
-
// 如果输入框有值
|
|
655
|
-
&& hasValue
|
|
656
|
-
) {
|
|
657
|
-
// 显示弹出层节点
|
|
658
|
-
showPopupRef()
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
// 表格重新加载
|
|
662
|
-
await $table.tableReload()
|
|
663
|
-
})
|
|
664
|
-
|
|
665
|
-
/**
|
|
666
|
-
* 监听其他值
|
|
667
|
-
*/
|
|
668
|
-
// watch([
|
|
669
|
-
// ()=>props.path,
|
|
670
|
-
// ()=>props.url,
|
|
671
|
-
// ()=>props.query,
|
|
672
|
-
// ()=>props.data,
|
|
673
|
-
// ()=>props.showKeys,
|
|
674
|
-
// ()=>props.hideSearchKeys,
|
|
675
|
-
// ], function () {
|
|
676
|
-
// _dialogShowed = false
|
|
677
|
-
// _popupShowed = false
|
|
678
|
-
//
|
|
679
|
-
// }, {
|
|
680
|
-
// deep: true
|
|
681
|
-
// })
|
|
682
|
-
|
|
683
|
-
// ==========【方法】=============================================================================================
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* 加载已选数据
|
|
687
|
-
*/
|
|
688
|
-
async function loadSelected() {
|
|
689
|
-
if (
|
|
690
|
-
// 如果值类型不是数组对象
|
|
691
|
-
props.valueType !== 'objectArray'
|
|
692
|
-
// 如果初始加载已选数据
|
|
693
|
-
&& ! props.noDefaultLoadSelected
|
|
694
|
-
// 如果有请求路由路径
|
|
695
|
-
&& routePath
|
|
696
|
-
) {
|
|
697
|
-
// 获取值数组
|
|
698
|
-
const values = valueToSelected(props.modelValue, false, false)
|
|
699
|
-
if (values.length) {
|
|
700
|
-
// 初始的已选数据
|
|
701
|
-
const _selected = await onRequestSelected(values)
|
|
702
|
-
const _value = selectedToValue(_selected)
|
|
703
|
-
|
|
704
|
-
// 如果声明值未发生变化
|
|
705
|
-
if (_value === props.modelValue) {
|
|
706
|
-
|
|
707
|
-
// 设置已选数据
|
|
708
|
-
setSelected(_selected)
|
|
709
|
-
|
|
710
|
-
} else {
|
|
711
|
-
// 设置临时已选数据
|
|
712
|
-
tempSelected = _selected
|
|
713
|
-
// 触发更新值
|
|
714
|
-
emit('update:modelValue', _value)
|
|
715
|
-
}
|
|
716
|
-
// 初始化加载成功
|
|
717
|
-
emit('loaded', _selected)
|
|
718
|
-
return
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
// 触发更新已选数据
|
|
723
|
-
emit('update:selected', selected.value)
|
|
724
|
-
// 初始化加载成功
|
|
725
|
-
emit('loaded', selected.value)
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
/**
|
|
729
|
-
* 触发更新值
|
|
730
|
-
*/
|
|
731
|
-
function emitModelValue(val) {
|
|
732
|
-
|
|
733
|
-
// 设置临时已选数据
|
|
734
|
-
tempSelected = val
|
|
735
|
-
|
|
736
|
-
// 触发更新值
|
|
737
|
-
emit('update:modelValue', selectedToValue(val))
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
/**
|
|
741
|
-
* 设置已选数据
|
|
742
|
-
*/
|
|
743
|
-
function setSelected(val) {
|
|
744
|
-
|
|
745
|
-
// 设置已选数据
|
|
746
|
-
selected.value = val
|
|
747
|
-
|
|
748
|
-
// 触发更新已选数据
|
|
749
|
-
emit('update:selected', val)
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
/**
|
|
753
|
-
* 当前格式化显示标签
|
|
754
|
-
*/
|
|
755
|
-
function currentFormatLabel(item) {
|
|
756
|
-
|
|
757
|
-
// 如果有格式化显示标签方法
|
|
758
|
-
if ($n_isFunction(props.formatLabel)) {
|
|
759
|
-
// 执行格式化显示标签方法
|
|
760
|
-
return props.formatLabel(item)
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
// 否则显示该值的标签字段
|
|
764
|
-
const val = item[currentlabelKey.value]
|
|
765
|
-
return $n_isValidValue(val) ? val : item[props.valueKey]
|
|
766
|
-
}
|
|
767
|
-
|
|
768
|
-
/**
|
|
769
|
-
* 设置已选数据的单个元素
|
|
770
|
-
*/
|
|
771
|
-
function setSelectedItem(val) {
|
|
772
|
-
const obj = {}
|
|
773
|
-
obj[props.valueKey] = val
|
|
774
|
-
obj[currentlabelKey.value] = val
|
|
775
|
-
return obj
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
/**
|
|
779
|
-
* 值转已选数据
|
|
780
|
-
*/
|
|
781
|
-
function valueToSelected(val, isFirst, toSelected) {
|
|
782
|
-
|
|
783
|
-
// 如果值类型是数组对象
|
|
784
|
-
if (props.valueType === 'objectArray') {
|
|
785
|
-
|
|
786
|
-
// 如果是有效数组
|
|
787
|
-
if ($n_isValidArray(val)) {
|
|
788
|
-
for (const item of val) {
|
|
789
|
-
if (
|
|
790
|
-
// 如果元素不是有效对象
|
|
791
|
-
! $n_isValidObject(item)
|
|
792
|
-
// 如果元素没有值字段
|
|
793
|
-
|| ! $n_has(item, props.valueKey)
|
|
794
|
-
) {
|
|
795
|
-
return []
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
// 否则直接返回
|
|
801
|
-
return val
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
if (
|
|
805
|
-
// 如果初始化
|
|
806
|
-
isFirst
|
|
807
|
-
// 如果初始加载已选数据方法
|
|
808
|
-
&& ! props.noDefaultLoadSelected
|
|
809
|
-
// 如果有初始加载已选数据
|
|
810
|
-
&& props.loadSelected !== void 0
|
|
811
|
-
) {
|
|
812
|
-
// 将值转为数组
|
|
813
|
-
val = props.valueType === 'string' ? $n_split(val, props.valueSeparator) : val
|
|
814
|
-
|
|
815
|
-
// 如果是有效数组
|
|
816
|
-
if ($n_isValidArray(val)) {
|
|
817
|
-
val = val.filter(e => $n_isValidValue(e))
|
|
818
|
-
if (val.length) {
|
|
819
|
-
return onLoadSelected(val, isFirst)
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
return []
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
if (
|
|
826
|
-
// 非初始化
|
|
827
|
-
! isFirst
|
|
828
|
-
// 或初始不加载已选数据
|
|
829
|
-
|| props.noDefaultLoadSelected
|
|
830
|
-
// 或没有路由路径
|
|
831
|
-
|| ! routePath
|
|
832
|
-
) {
|
|
833
|
-
// 将值转为数组
|
|
834
|
-
val = props.valueType === 'string' ? $n_split(val, props.valueSeparator) : val
|
|
835
|
-
|
|
836
|
-
// 如果是有效数组
|
|
837
|
-
if ($n_isValidArray(val)) {
|
|
838
|
-
val = val.filter(e => $n_isValidValue(e))
|
|
839
|
-
return toSelected ? val.map(e => setSelectedItem(e)) : val
|
|
840
|
-
}
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
return []
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
/**
|
|
847
|
-
* 已选数据转值
|
|
848
|
-
*/
|
|
849
|
-
function selectedToValue(val) {
|
|
850
|
-
|
|
851
|
-
// 如果值类型是数组对象
|
|
852
|
-
if (props.valueType === 'objectArray') {
|
|
853
|
-
|
|
854
|
-
// 则直接返回
|
|
855
|
-
return val
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
// 值数组
|
|
859
|
-
const values = val.length
|
|
860
|
-
// 如果有已选数据
|
|
861
|
-
? (
|
|
862
|
-
props.multiple
|
|
863
|
-
// 如果是多选
|
|
864
|
-
? val.map(e => e[props.valueKey])
|
|
865
|
-
// 否则是单选
|
|
866
|
-
: [ val[0][props.valueKey] ]
|
|
867
|
-
)
|
|
868
|
-
// 否则为空
|
|
869
|
-
: []
|
|
870
|
-
|
|
871
|
-
// 如果值类型是数组
|
|
872
|
-
if (props.valueType === 'stringArray') {
|
|
873
|
-
|
|
874
|
-
// 直接返回数组
|
|
875
|
-
return values
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
// 返回转为分隔符隔开的字符串
|
|
879
|
-
return $n_numberDeep($n_join(values, props.valueSeparator))
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
/**
|
|
883
|
-
* 加载已选数据
|
|
884
|
-
*/
|
|
885
|
-
function onLoadSelected(values, isFirst) {
|
|
886
|
-
|
|
887
|
-
function next(lists) {
|
|
888
|
-
const _selected = []
|
|
889
|
-
$n_forEach(lists, function (item) {
|
|
890
|
-
if (
|
|
891
|
-
$n_has(item, props.valueKey)
|
|
892
|
-
&& $n_indexOf(values, item[props.valueKey]) > -1
|
|
893
|
-
&& $n_findIndex(_selected, e => e[props.valueKey] === item[props.valueKey]) === -1
|
|
894
|
-
) {
|
|
895
|
-
_selected.push($n_cloneDeep(item))
|
|
896
|
-
}
|
|
897
|
-
})
|
|
898
|
-
return _selected
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
// 如果是加载已选数据方法
|
|
902
|
-
if ($n_isFunction(props.loadSelected)) {
|
|
903
|
-
const res = props.loadSelected(values, next, isFirst)
|
|
904
|
-
if ($n_isValidArray(res)) {
|
|
905
|
-
return res
|
|
906
|
-
}
|
|
907
|
-
return []
|
|
908
|
-
}
|
|
909
|
-
|
|
910
|
-
return next(props.loadSelected)
|
|
911
|
-
}
|
|
912
|
-
|
|
913
|
-
/**
|
|
914
|
-
* 请求选择数据
|
|
915
|
-
*/
|
|
916
|
-
async function onRequestSelected(value) {
|
|
917
|
-
|
|
918
|
-
let requestValues = value
|
|
919
|
-
|
|
920
|
-
const all = {}
|
|
921
|
-
let hasAll = false
|
|
922
|
-
|
|
923
|
-
// 如果有初始加载已选数据数组
|
|
924
|
-
if (props.loadSelected !== void 0) {
|
|
925
|
-
const rows = onLoadSelected(value, false)
|
|
926
|
-
if ($n_isValidArray(rows)) {
|
|
927
|
-
|
|
928
|
-
requestValues = []
|
|
929
|
-
|
|
930
|
-
for (const item of rows) {
|
|
931
|
-
all[item[props.valueKey]] = item
|
|
932
|
-
}
|
|
933
|
-
for (const val of value) {
|
|
934
|
-
if (! $n_has(all, val)) {
|
|
935
|
-
requestValues.push(val)
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
if (! requestValues.length) {
|
|
939
|
-
return rows
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
hasAll = true
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
|
|
946
|
-
// 请求参数
|
|
947
|
-
const httpOptions = {
|
|
948
|
-
url: $table.routePath,
|
|
949
|
-
data: Object.assign(
|
|
950
|
-
// 获取表格请求数据
|
|
951
|
-
$table.getTableRequestData({
|
|
952
|
-
// filter,
|
|
953
|
-
pagination: {
|
|
954
|
-
// 页码
|
|
955
|
-
page: 1,
|
|
956
|
-
// 每页的数据条数
|
|
957
|
-
rowsPerPage: value.length,
|
|
958
|
-
// 排序字段
|
|
959
|
-
sortBy: null,
|
|
960
|
-
// 是否降序排列
|
|
961
|
-
descending: true,
|
|
962
|
-
}
|
|
963
|
-
}, false),
|
|
964
|
-
{
|
|
965
|
-
// 查看字段
|
|
966
|
-
n_view: {
|
|
967
|
-
// 查看字段
|
|
968
|
-
field: props.valueKey,
|
|
969
|
-
// 查看值
|
|
970
|
-
value: requestValues,
|
|
971
|
-
},
|
|
972
|
-
}
|
|
973
|
-
),
|
|
974
|
-
// 是否开启防抖(防止重复请求)
|
|
975
|
-
debounce: false,
|
|
976
|
-
}
|
|
977
|
-
|
|
978
|
-
// 请求数据
|
|
979
|
-
const { status, data } = $n_isFunction(props.request) ?
|
|
980
|
-
// 如果有自定义请求方法
|
|
981
|
-
await $n_runAsync(props.request)({
|
|
982
|
-
// http 请求参数
|
|
983
|
-
httpOptions,
|
|
984
|
-
// 对话框是否已显示
|
|
985
|
-
showDialog: showDialog.value,
|
|
986
|
-
}) :
|
|
987
|
-
// 否则请求数据
|
|
988
|
-
await $n_http(httpOptions)
|
|
989
|
-
|
|
990
|
-
if (status) {
|
|
991
|
-
if ($n_isValidArray($n_get(data, 'rows'))) {
|
|
992
|
-
if (! hasAll) {
|
|
993
|
-
return data.rows
|
|
994
|
-
}
|
|
995
|
-
for (const item of data.rows) {
|
|
996
|
-
all[item[props.valueKey]] = item
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
const newRows = []
|
|
1002
|
-
for (const val of value) {
|
|
1003
|
-
if ($n_has(all, val)) {
|
|
1004
|
-
newRows.push(all[val])
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
return newRows
|
|
1008
|
-
}
|
|
1009
|
-
|
|
1010
|
-
/**
|
|
1011
|
-
* 获取表格列数据
|
|
1012
|
-
*/
|
|
1013
|
-
function getTableColumns() {
|
|
1014
|
-
|
|
1015
|
-
let columns
|
|
1016
|
-
|
|
1017
|
-
// 如果有声明路由表格列数据
|
|
1018
|
-
if ($n_isValidArray(props.columns)) {
|
|
1019
|
-
columns = $n_cloneDeep(props.columns)
|
|
1020
|
-
|
|
1021
|
-
// 如果有路由路径
|
|
1022
|
-
} else if (routePath) {
|
|
1023
|
-
// 否则如果有路由表格列数据
|
|
1024
|
-
const rawTableColumns = $n_$table.config(routePath, 'columns')
|
|
1025
|
-
if ($n_isValidArray(rawTableColumns)) {
|
|
1026
|
-
columns = $n_cloneDeep(rawTableColumns)
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
if ($n_isValidArray(columns)) {
|
|
1031
|
-
if ($n_isValidArray(props.hideSearchKeys)) {
|
|
1032
|
-
for (const item of columns) {
|
|
1033
|
-
if (
|
|
1034
|
-
props.hideSearchKeys.indexOf(item.name) > -1
|
|
1035
|
-
&& $n_has(item, 'search')
|
|
1036
|
-
) {
|
|
1037
|
-
item.search.hide = true
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
return columns
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
return []
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
/**
|
|
1048
|
-
* 获取快捷表格列数据
|
|
1049
|
-
*/
|
|
1050
|
-
function getQuickTableColumns() {
|
|
1051
|
-
|
|
1052
|
-
const columns = []
|
|
1053
|
-
|
|
1054
|
-
// 如果有原始表格列数据
|
|
1055
|
-
if ($n_isValidArray($table.tableColumns.value)) {
|
|
1056
|
-
|
|
1057
|
-
// 克隆原始表格列数据
|
|
1058
|
-
const rawTableColumns = $n_cloneDeep($table.tableColumns.value)
|
|
1059
|
-
|
|
1060
|
-
// 快捷表格显示的属性名称数组
|
|
1061
|
-
$n_forEach(currentShowKeys.value, function (key) {
|
|
1062
|
-
for (const item of rawTableColumns) {
|
|
1063
|
-
if (item.name === key) {
|
|
1064
|
-
// 删除搜索字段
|
|
1065
|
-
if ($n_has(item, 'search')) {
|
|
1066
|
-
delete item.search
|
|
1067
|
-
}
|
|
1068
|
-
// 删除可见字段
|
|
1069
|
-
if ($n_has(item, 'visible')) {
|
|
1070
|
-
delete item.visible
|
|
1071
|
-
}
|
|
1072
|
-
columns.push(item)
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
})
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
return columns
|
|
1079
|
-
}
|
|
1080
|
-
|
|
1081
|
-
/**
|
|
1082
|
-
* 移除已选数据
|
|
1083
|
-
*/
|
|
1084
|
-
function onRemoveSelected(index) {
|
|
1085
|
-
|
|
1086
|
-
const _selected = [...selected.value]
|
|
1087
|
-
_selected.splice(index, 1)
|
|
1088
|
-
|
|
1089
|
-
// 触发更新值
|
|
1090
|
-
emitModelValue(_selected)
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
/**
|
|
1094
|
-
* 字段获取焦点触发
|
|
1095
|
-
*/
|
|
1096
|
-
function onFieldFocus(e) {
|
|
1097
|
-
|
|
1098
|
-
// 停止冒泡
|
|
1099
|
-
e.stopPropagation()
|
|
1100
|
-
|
|
1101
|
-
// 设置输入框焦点
|
|
1102
|
-
setInputFocus()
|
|
1103
|
-
|
|
1104
|
-
// window.scrollTo(window.pageXOffset || window.scrollX || document.body.scrollLeft || 0, 0)
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
/**
|
|
1108
|
-
* 字段失去焦点触发
|
|
1109
|
-
*/
|
|
1110
|
-
function onFieldBlur(e) {
|
|
1111
|
-
|
|
1112
|
-
// 停止冒泡
|
|
1113
|
-
e.stopPropagation()
|
|
1114
|
-
|
|
1115
|
-
if (
|
|
1116
|
-
// 如果开启筛选
|
|
1117
|
-
props.filter
|
|
1118
|
-
// 如果没有显示弹出层
|
|
1119
|
-
&& ! showPopup.value
|
|
1120
|
-
) {
|
|
1121
|
-
// 清空输入框值
|
|
1122
|
-
inputValue.value = ''
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
1125
|
-
|
|
1126
|
-
/**
|
|
1127
|
-
* 字段清空触发
|
|
1128
|
-
*/
|
|
1129
|
-
function onFieldClear() {
|
|
1130
|
-
|
|
1131
|
-
// 触发更新值
|
|
1132
|
-
// 清空快捷表格已选数据
|
|
1133
|
-
emitModelValue([])
|
|
1134
|
-
|
|
1135
|
-
// 隐藏弹出层节点
|
|
1136
|
-
hidePopupRef()
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
/**
|
|
1140
|
-
* 显示弹出层节点
|
|
1141
|
-
*/
|
|
1142
|
-
function showPopupRef() {
|
|
1143
|
-
|
|
1144
|
-
// 如果有弹出层节点
|
|
1145
|
-
if (popupRef.value) {
|
|
1146
|
-
// 显示弹出层
|
|
1147
|
-
popupRef.value.show()
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
/**
|
|
1152
|
-
* 隐藏弹出层节点
|
|
1153
|
-
*/
|
|
1154
|
-
function hidePopupRef() {
|
|
1155
|
-
|
|
1156
|
-
// 如果有弹出层节点
|
|
1157
|
-
if (popupRef.value) {
|
|
1158
|
-
// 隐藏弹出层
|
|
1159
|
-
popupRef.value.hide()
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
/**
|
|
1164
|
-
* 弹出层显示回调
|
|
1165
|
-
*/
|
|
1166
|
-
let _popupShowed = false
|
|
1167
|
-
function onPopupShow() {
|
|
1168
|
-
|
|
1169
|
-
// 显示弹出层
|
|
1170
|
-
showPopup.value = true
|
|
1171
|
-
|
|
1172
|
-
// 设置输入框焦点
|
|
1173
|
-
setInputFocus()
|
|
1174
|
-
|
|
1175
|
-
// 如果每次对话框显示都请求
|
|
1176
|
-
if (props.requestEveryDialogShow) {
|
|
1177
|
-
// 表格重新加载
|
|
1178
|
-
$table.tableReload()
|
|
1179
|
-
.finally()
|
|
1180
|
-
return
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
if (_popupShowed) {
|
|
1184
|
-
return
|
|
1185
|
-
}
|
|
1186
|
-
_popupShowed = true
|
|
1187
|
-
|
|
1188
|
-
// 表格重新加载
|
|
1189
|
-
$table.tableReload()
|
|
1190
|
-
.finally()
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
/**
|
|
1194
|
-
* 显示对话框
|
|
1195
|
-
*/
|
|
1196
|
-
function onShowDialog() {
|
|
1197
|
-
// 显示对话框
|
|
1198
|
-
showDialog.value = true
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
/**
|
|
1202
|
-
* 对话框显示前回调
|
|
1203
|
-
*/
|
|
1204
|
-
function onDialogBeforeShow() {
|
|
1205
|
-
|
|
1206
|
-
// 设置当前已选数据
|
|
1207
|
-
$table.tableSelected.value = [...selected.value]
|
|
1208
|
-
|
|
1209
|
-
// 隐藏弹出层节点
|
|
1210
|
-
hidePopupRef()
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
/**
|
|
1214
|
-
* 对话框显示回调
|
|
1215
|
-
*/
|
|
1216
|
-
let _dialogShowed = false
|
|
1217
|
-
function onDialogShow() {
|
|
1218
|
-
|
|
1219
|
-
// 如果每次对话框显示都请求
|
|
1220
|
-
if (props.requestEveryDialogShow) {
|
|
1221
|
-
// 表格重新加载
|
|
1222
|
-
$table.tableReload()
|
|
1223
|
-
.finally()
|
|
1224
|
-
return
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
if (_dialogShowed) {
|
|
1228
|
-
return
|
|
1229
|
-
}
|
|
1230
|
-
_dialogShowed = true
|
|
1231
|
-
|
|
1232
|
-
// 表格重新加载
|
|
1233
|
-
$table.tableReload()
|
|
1234
|
-
.finally()
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
/**
|
|
1238
|
-
* 对话框隐藏后回调
|
|
1239
|
-
*/
|
|
1240
|
-
function onDialogHide() {
|
|
1241
|
-
|
|
1242
|
-
let isReload = true
|
|
1243
|
-
|
|
1244
|
-
// 清空输入框值
|
|
1245
|
-
if (
|
|
1246
|
-
// 如果开启筛选
|
|
1247
|
-
props.filter
|
|
1248
|
-
// 如果有输入框值
|
|
1249
|
-
&& inputValue.value
|
|
1250
|
-
) {
|
|
1251
|
-
// 此时清空输入框后, 会自动刷新表格
|
|
1252
|
-
inputValue.value = ''
|
|
1253
|
-
|
|
1254
|
-
// 所以只需要重置搜索值即可, 不需要再重置后刷新表格
|
|
1255
|
-
isReload = false
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
// 获取表格搜索值
|
|
1259
|
-
let searchValue = $table.getTableSearchValue()
|
|
1260
|
-
if (searchValue.length) {
|
|
1261
|
-
|
|
1262
|
-
// 如果有隐藏搜索字段数组
|
|
1263
|
-
if ($n_isValidArray(props.hideSearchKeys)) {
|
|
1264
|
-
// 从搜索值数组中去除隐藏搜索字段的数组
|
|
1265
|
-
searchValue = searchValue.filter(e => $n_indexOf(e.field, props.hideSearchKeys) === -1)
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
// 表格搜索重置
|
|
1269
|
-
$table.tableSearchReset(isReload && searchValue.length, {
|
|
1270
|
-
showDialog: 1,
|
|
1271
|
-
})
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
|
|
1275
|
-
/**
|
|
1276
|
-
* 对话框点击确认回调
|
|
1277
|
-
*/
|
|
1278
|
-
function onDialogConfirm(data) {
|
|
1279
|
-
|
|
1280
|
-
// 触发更新值
|
|
1281
|
-
emitModelValue([...data])
|
|
1282
|
-
}
|
|
1283
|
-
|
|
1284
|
-
/**
|
|
1285
|
-
* 单击快捷表格行
|
|
1286
|
-
*/
|
|
1287
|
-
function quickTableRowClick(e, row) {
|
|
1288
|
-
|
|
1289
|
-
// 如果为多选
|
|
1290
|
-
if (props.multiple) {
|
|
1291
|
-
|
|
1292
|
-
// 克隆已选数据
|
|
1293
|
-
const _selected = [...selected.value]
|
|
1294
|
-
|
|
1295
|
-
const opt = {}
|
|
1296
|
-
opt[props.valueKey] = row[props.valueKey]
|
|
1297
|
-
|
|
1298
|
-
// 获取当前数据索引
|
|
1299
|
-
const itemIndex = $n_findIndex(_selected, opt)
|
|
1300
|
-
|
|
1301
|
-
// 如果不存在
|
|
1302
|
-
if (itemIndex === -1) {
|
|
1303
|
-
// 则添加
|
|
1304
|
-
_selected.push(row)
|
|
1305
|
-
|
|
1306
|
-
// 否则
|
|
1307
|
-
} else {
|
|
1308
|
-
// 删除
|
|
1309
|
-
_selected.splice(itemIndex, 1)
|
|
1310
|
-
}
|
|
1311
|
-
|
|
1312
|
-
// 触发更新值
|
|
1313
|
-
emitModelValue(_selected)
|
|
1314
|
-
|
|
1315
|
-
// 否则为单选
|
|
1316
|
-
} else {
|
|
1317
|
-
|
|
1318
|
-
// 触发更新值
|
|
1319
|
-
emitModelValue([ row ])
|
|
1320
|
-
|
|
1321
|
-
// 隐藏弹出层节点
|
|
1322
|
-
hidePopupRef()
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
/**
|
|
1327
|
-
* 设置输入框文字选中
|
|
1328
|
-
*/
|
|
1329
|
-
function setInputSelection() {
|
|
1330
|
-
if (
|
|
1331
|
-
// 如果开启筛选
|
|
1332
|
-
props.filter
|
|
1333
|
-
// 如果有输入框节点
|
|
1334
|
-
&& inputRef.value
|
|
1335
|
-
// 如果输入框有值
|
|
1336
|
-
&& inputValue.value.length
|
|
1337
|
-
) {
|
|
1338
|
-
// 全选文字
|
|
1339
|
-
inputRef.value.select()
|
|
1340
|
-
// inputRef.value.setSelectionRange(0, inputValue.value.length)
|
|
1341
|
-
}
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
/**
|
|
1345
|
-
* 设置输入框焦点
|
|
1346
|
-
*/
|
|
1347
|
-
function setInputFocus() {
|
|
1348
|
-
if (
|
|
1349
|
-
// 如果开启筛选
|
|
1350
|
-
props.filter
|
|
1351
|
-
// 如果有输入框节点
|
|
1352
|
-
&& inputRef.value
|
|
1353
|
-
) {
|
|
1354
|
-
inputRef.value.focus()
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
/**
|
|
1359
|
-
* 格式化图片
|
|
1360
|
-
*/
|
|
1361
|
-
function formatImg(img, { count }) {
|
|
1362
|
-
|
|
1363
|
-
// 图片数组
|
|
1364
|
-
const imgs = []
|
|
1365
|
-
|
|
1366
|
-
// 转为图片数组
|
|
1367
|
-
const arr = $n_split(img, ',')
|
|
1368
|
-
for (const item of arr) {
|
|
1369
|
-
const src = $n_getImage(item)
|
|
1370
|
-
if (src) {
|
|
1371
|
-
imgs.push(item)
|
|
1372
|
-
if (
|
|
1373
|
-
count > 0
|
|
1374
|
-
&& imgs.length === count
|
|
1375
|
-
) {
|
|
1376
|
-
break
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
return imgs
|
|
1382
|
-
}
|
|
1383
|
-
|
|
1384
|
-
// ==========【生命周期】=========================================================================================
|
|
1385
|
-
|
|
1386
|
-
/**
|
|
1387
|
-
* 在组件因为响应式状态变更而更新其 DOM 树之后调用
|
|
1388
|
-
*/
|
|
1389
|
-
onUpdated(function () {
|
|
1390
|
-
if (
|
|
1391
|
-
popupRef.value
|
|
1392
|
-
&& $n_has(popupRef.value, 'currentComponent.ref.updatePosition')
|
|
1393
|
-
) {
|
|
1394
|
-
popupRef.value.currentComponent.ref.updatePosition()
|
|
1395
|
-
}
|
|
1396
|
-
})
|
|
1397
|
-
|
|
1398
|
-
// ==========【返回】=============================================================================================
|
|
1399
|
-
|
|
1400
|
-
return {
|
|
1401
|
-
// 解构表格实例
|
|
1402
|
-
...$table,
|
|
1403
|
-
|
|
1404
|
-
// 插槽标识
|
|
1405
|
-
slotNames,
|
|
1406
|
-
// 当前标签字段
|
|
1407
|
-
currentlabelKey,
|
|
1408
|
-
// 显示值
|
|
1409
|
-
showValue,
|
|
1410
|
-
|
|
1411
|
-
// 输入框节点
|
|
1412
|
-
inputRef,
|
|
1413
|
-
// 输入框值
|
|
1414
|
-
inputValue,
|
|
1415
|
-
// 弹出层节点
|
|
1416
|
-
popupRef,
|
|
1417
|
-
// 是否显示对话框
|
|
1418
|
-
showDialog,
|
|
1419
|
-
// 是否显示弹出层
|
|
1420
|
-
showPopup,
|
|
1421
|
-
// 当前已选数据
|
|
1422
|
-
selected,
|
|
1423
|
-
// 当前表格列数据
|
|
1424
|
-
columns,
|
|
1425
|
-
|
|
1426
|
-
// 当前格式化显示标签
|
|
1427
|
-
currentFormatLabel,
|
|
1428
|
-
// 移除已选数据
|
|
1429
|
-
onRemoveSelected,
|
|
1430
|
-
|
|
1431
|
-
// 字段获取焦点触发
|
|
1432
|
-
onFieldFocus,
|
|
1433
|
-
// 字段失去焦点触发
|
|
1434
|
-
onFieldBlur,
|
|
1435
|
-
// 字段清空触发
|
|
1436
|
-
onFieldClear,
|
|
1437
|
-
|
|
1438
|
-
// 弹出层显示回调
|
|
1439
|
-
onPopupShow,
|
|
1440
|
-
|
|
1441
|
-
// 显示对话框
|
|
1442
|
-
onShowDialog,
|
|
1443
|
-
// 对话框显示前回调
|
|
1444
|
-
onDialogBeforeShow,
|
|
1445
|
-
// 对话框显示回调
|
|
1446
|
-
onDialogShow,
|
|
1447
|
-
// 对话框隐藏后回调
|
|
1448
|
-
onDialogHide,
|
|
1449
|
-
// 对话框点击确认回调
|
|
1450
|
-
onDialogConfirm,
|
|
1451
|
-
|
|
1452
|
-
// 单击快捷表格行
|
|
1453
|
-
quickTableRowClick,
|
|
1454
|
-
|
|
1455
|
-
// 触发更新值
|
|
1456
|
-
emitModelValue,
|
|
1457
|
-
// 格式化图片
|
|
1458
|
-
formatImg,
|
|
1459
|
-
}
|
|
1460
|
-
},
|
|
1461
|
-
}
|
|
1462
|
-
</script>
|
|
1463
|
-
|
|
1464
|
-
<style lang="scss">
|
|
1465
|
-
.n-field-table {
|
|
1466
|
-
.q-field__input--padding {
|
|
1467
|
-
padding-left: 4px;
|
|
1468
|
-
min-width: 50px !important;
|
|
1469
|
-
cursor: text;
|
|
1470
|
-
}
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
/**
|
|
1474
|
-
* 桌面
|
|
1475
|
-
*/
|
|
1476
|
-
body.desktop {
|
|
1477
|
-
.n-field-table {
|
|
1478
|
-
&__popup-table {
|
|
1479
|
-
height: 300px;
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
</style>
|
|
1
|
+
<template>
|
|
2
|
+
|
|
3
|
+
<!-- 如果有默认插槽 -->
|
|
4
|
+
<template v-if="$slots.default">
|
|
5
|
+
<slot
|
|
6
|
+
:showValue="showValue"
|
|
7
|
+
:selected="selected"
|
|
8
|
+
:onRemove="onRemoveSelected"
|
|
9
|
+
:onShowDialog="onShowDialog"
|
|
10
|
+
:onClear="onFieldClear"
|
|
11
|
+
/>
|
|
12
|
+
</template>
|
|
13
|
+
|
|
14
|
+
<!--:class="fieldFocused ? 'q-field--float q-field--focused q-field--highlighted' : ''"-->
|
|
15
|
+
<!--:clearable="clearable && (! multiple || collapseTags)"-->
|
|
16
|
+
<q-field
|
|
17
|
+
class="n-field-table"
|
|
18
|
+
:model-value="showValue"
|
|
19
|
+
:disable="disable"
|
|
20
|
+
:readonly="readonly"
|
|
21
|
+
:clearable="clearable"
|
|
22
|
+
for="field-table"
|
|
23
|
+
@focus="onFieldFocus"
|
|
24
|
+
@blur="onFieldBlur"
|
|
25
|
+
@clear="onFieldClear"
|
|
26
|
+
v-bind="$attrs"
|
|
27
|
+
v-else
|
|
28
|
+
>
|
|
29
|
+
<template v-slot:control>
|
|
30
|
+
|
|
31
|
+
<template v-if="multiple">
|
|
32
|
+
<template v-if="selected.length">
|
|
33
|
+
|
|
34
|
+
<!-- 多选插槽 -->
|
|
35
|
+
<slot
|
|
36
|
+
name="selected"
|
|
37
|
+
:selected="selected"
|
|
38
|
+
:remove="onRemoveSelected"
|
|
39
|
+
v-if="$slots.selected"
|
|
40
|
+
/>
|
|
41
|
+
|
|
42
|
+
<!-- 显示折叠的值数量 -->
|
|
43
|
+
<q-chip
|
|
44
|
+
dense
|
|
45
|
+
:label="`+${selected.length}`"
|
|
46
|
+
v-else-if="collapseTags"
|
|
47
|
+
/>
|
|
48
|
+
|
|
49
|
+
<!-- 多选标签 -->
|
|
50
|
+
<template v-else>
|
|
51
|
+
<q-chip
|
|
52
|
+
v-for="(item, index) in selected"
|
|
53
|
+
:key="`options-${index}`"
|
|
54
|
+
:label="currentFormatLabel(item)"
|
|
55
|
+
dense
|
|
56
|
+
:removable="! readonly && ! disable"
|
|
57
|
+
@remove="onRemoveSelected(index)"
|
|
58
|
+
>
|
|
59
|
+
<q-tooltip>{{currentFormatLabel(item)}}</q-tooltip>
|
|
60
|
+
</q-chip>
|
|
61
|
+
</template>
|
|
62
|
+
</template>
|
|
63
|
+
|
|
64
|
+
<!-- 占位符-->
|
|
65
|
+
<span class="n-placeholder" v-else-if="placeholder">{{placeholder}}</span>
|
|
66
|
+
</template>
|
|
67
|
+
|
|
68
|
+
<!-- 显示文字 -->
|
|
69
|
+
<span v-else-if="showValue">{{showValue}}</span>
|
|
70
|
+
|
|
71
|
+
<!-- 占位符-->
|
|
72
|
+
<span class="n-placeholder" v-else-if="placeholder">{{placeholder}}</span>
|
|
73
|
+
|
|
74
|
+
<!-- 筛选输入框 -->
|
|
75
|
+
<input
|
|
76
|
+
ref="inputRef"
|
|
77
|
+
class="q-field__input q-placeholder col q-field__input--padding"
|
|
78
|
+
v-model="inputValue"
|
|
79
|
+
v-if="filter && ! readonly && ! disable"
|
|
80
|
+
/>
|
|
81
|
+
|
|
82
|
+
</template>
|
|
83
|
+
|
|
84
|
+
<!-- 弹出对话框图标 -->
|
|
85
|
+
<template v-slot:append v-if="! noDialog && ! readonly && ! disable">
|
|
86
|
+
<q-icon
|
|
87
|
+
class="cursor-pointer"
|
|
88
|
+
name="search"
|
|
89
|
+
@click.prevent.stop="onShowDialog"
|
|
90
|
+
/>
|
|
91
|
+
</template>
|
|
92
|
+
|
|
93
|
+
<!-- 默认插槽 -->
|
|
94
|
+
<template
|
|
95
|
+
v-for="slotName in slotNames.normal"
|
|
96
|
+
v-slot:[slotName]
|
|
97
|
+
>
|
|
98
|
+
<slot :name="slotName" />
|
|
99
|
+
</template>
|
|
100
|
+
|
|
101
|
+
<!-- 弹出层代理 -->
|
|
102
|
+
<q-popup-proxy
|
|
103
|
+
ref="popupRef"
|
|
104
|
+
no-refocus
|
|
105
|
+
no-focus
|
|
106
|
+
fit
|
|
107
|
+
@focus="onFieldBlur"
|
|
108
|
+
@show="onPopupShow"
|
|
109
|
+
@before-hide="showPopup = false"
|
|
110
|
+
v-if="! readonly && ! disable"
|
|
111
|
+
>
|
|
112
|
+
<!-- 快捷表格 -->
|
|
113
|
+
<n-table
|
|
114
|
+
class="n-table n-field-table__popup-table"
|
|
115
|
+
v-model:pagination="tablePagination"
|
|
116
|
+
:selected="selected"
|
|
117
|
+
@update:selected="emitModelValue"
|
|
118
|
+
:row-key="tableRowKey"
|
|
119
|
+
:rows="tableRows"
|
|
120
|
+
:columns="columns"
|
|
121
|
+
:selection="multiple ? 'multiple' : 'none'"
|
|
122
|
+
:loading="tableLoading"
|
|
123
|
+
:rows-per-page-options="tableRowsPerPageOptions"
|
|
124
|
+
@row-click="quickTableRowClick"
|
|
125
|
+
@request="tableRequest"
|
|
126
|
+
flat
|
|
127
|
+
virtual-scroll
|
|
128
|
+
dense
|
|
129
|
+
v-bind="tableProps"
|
|
130
|
+
>
|
|
131
|
+
<!-- 图片 -->
|
|
132
|
+
<template
|
|
133
|
+
v-for="imgItem in tableImgs"
|
|
134
|
+
v-slot:[`body-cell-${imgItem.name}`]="props"
|
|
135
|
+
>
|
|
136
|
+
<n-data
|
|
137
|
+
:data="formatImg(props.row[imgItem.name], imgItem)"
|
|
138
|
+
v-slot="{ data }"
|
|
139
|
+
>
|
|
140
|
+
<!-- 缩略图 -->
|
|
141
|
+
<n-thumbnail
|
|
142
|
+
v-for="(item, index) in data"
|
|
143
|
+
:key="`thumbnail-item-${item}`"
|
|
144
|
+
class="n-table__thumbnail"
|
|
145
|
+
:src="item"
|
|
146
|
+
preview
|
|
147
|
+
:preview-props="{
|
|
148
|
+
startPosition: index,
|
|
149
|
+
images: data,
|
|
150
|
+
}"
|
|
151
|
+
/>
|
|
152
|
+
</n-data>
|
|
153
|
+
</template>
|
|
154
|
+
|
|
155
|
+
<!-- 表格插槽 -->
|
|
156
|
+
<template
|
|
157
|
+
v-for="slotName in slotNames.table"
|
|
158
|
+
v-slot:[slotName]="props"
|
|
159
|
+
>
|
|
160
|
+
<q-td :props="props">
|
|
161
|
+
<slot
|
|
162
|
+
:name="slotName"
|
|
163
|
+
v-bind="props"
|
|
164
|
+
/>
|
|
165
|
+
</q-td>
|
|
166
|
+
</template>
|
|
167
|
+
|
|
168
|
+
<!-- 翻页 -->
|
|
169
|
+
<template v-slot:pagination="props">
|
|
170
|
+
<n-table-pagination
|
|
171
|
+
:props="props"
|
|
172
|
+
no-power
|
|
173
|
+
dense
|
|
174
|
+
/>
|
|
175
|
+
</template>
|
|
176
|
+
</n-table>
|
|
177
|
+
</q-popup-proxy>
|
|
178
|
+
</q-field>
|
|
179
|
+
|
|
180
|
+
<!-- 弹出对话框 -->
|
|
181
|
+
<n-dialog
|
|
182
|
+
v-model="showDialog"
|
|
183
|
+
width="80%"
|
|
184
|
+
:on-confirm="onDialogConfirm"
|
|
185
|
+
@before-show="onDialogBeforeShow"
|
|
186
|
+
@show="onDialogShow"
|
|
187
|
+
@hide="onDialogHide"
|
|
188
|
+
cancel
|
|
189
|
+
v-bind="dialogProps"
|
|
190
|
+
>
|
|
191
|
+
<q-page>
|
|
192
|
+
<n-mixed-table />
|
|
193
|
+
</q-page>
|
|
194
|
+
</n-dialog>
|
|
195
|
+
</template>
|
|
196
|
+
|
|
197
|
+
<script>
|
|
198
|
+
import { ref, computed, watch, onUpdated } from 'vue'
|
|
199
|
+
|
|
200
|
+
import $n_has from 'lodash/has'
|
|
201
|
+
import $n_uniq from 'lodash/uniq'
|
|
202
|
+
import $n_cloneDeep from 'lodash/cloneDeep'
|
|
203
|
+
import $n_isFunction from 'lodash/isFunction'
|
|
204
|
+
import $n_findIndex from 'lodash/findIndex'
|
|
205
|
+
import $n_get from 'lodash/get'
|
|
206
|
+
import $n_find from 'lodash/find'
|
|
207
|
+
|
|
208
|
+
import $n_indexOf from '@netang/utils/indexOf'
|
|
209
|
+
import $n_forEach from '@netang/utils/forEach'
|
|
210
|
+
import $n_isValidArray from '@netang/utils/isValidArray'
|
|
211
|
+
import $n_join from '@netang/utils/join'
|
|
212
|
+
import $n_split from '@netang/utils/split'
|
|
213
|
+
import $n_isValidObject from '@netang/utils/isValidObject'
|
|
214
|
+
import $n_isValidValue from '@netang/utils/isValidValue'
|
|
215
|
+
import $n_isValidString from '@netang/utils/isValidString'
|
|
216
|
+
import $n_numberDeep from '@netang/utils/numberDeep'
|
|
217
|
+
import $n_sleep from '@netang/utils/sleep'
|
|
218
|
+
import $n_http from '@netang/utils/http'
|
|
219
|
+
import $n_runAsync from '@netang/utils/runAsync'
|
|
220
|
+
|
|
221
|
+
import $n_$power from '../../utils/$power'
|
|
222
|
+
import $n_$table from '../../utils/$table'
|
|
223
|
+
|
|
224
|
+
import { configs } from '../../utils/config'
|
|
225
|
+
|
|
226
|
+
import $n_getImage from '../../utils/getImage'
|
|
227
|
+
|
|
228
|
+
const {
|
|
229
|
+
// 字典常量
|
|
230
|
+
dicts,
|
|
231
|
+
} = configs
|
|
232
|
+
|
|
233
|
+
export default {
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* 标识
|
|
237
|
+
*/
|
|
238
|
+
name: 'NFieldTable',
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* 关闭组件 attribute 透传行为
|
|
242
|
+
*/
|
|
243
|
+
inheritAttrs: false,
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* 声明属性
|
|
247
|
+
*/
|
|
248
|
+
props: {
|
|
249
|
+
// 值 v-model
|
|
250
|
+
modelValue: {
|
|
251
|
+
required: true,
|
|
252
|
+
},
|
|
253
|
+
// 值字段(必填)
|
|
254
|
+
valueKey: {
|
|
255
|
+
type: String,
|
|
256
|
+
required: true,
|
|
257
|
+
},
|
|
258
|
+
// 标签字段
|
|
259
|
+
labelKey: String,
|
|
260
|
+
// 值类型
|
|
261
|
+
// string: 字符串或数字
|
|
262
|
+
// stringArray: 普通数组(包含字符串或数字的一维数组)
|
|
263
|
+
// objectArray: 对象数组(包含对象的一维数组)
|
|
264
|
+
valueType: {
|
|
265
|
+
type: String,
|
|
266
|
+
default: 'objectArray'
|
|
267
|
+
},
|
|
268
|
+
// 值分隔符(值类型为 string 有效)
|
|
269
|
+
valueSeparator: {
|
|
270
|
+
type: String,
|
|
271
|
+
default: ',',
|
|
272
|
+
},
|
|
273
|
+
|
|
274
|
+
// 请求路由路径
|
|
275
|
+
path: String,
|
|
276
|
+
// 请求地址(默认为 path)
|
|
277
|
+
url: String,
|
|
278
|
+
// 请求参数
|
|
279
|
+
query: Object,
|
|
280
|
+
// 附加请求数据
|
|
281
|
+
data: Object,
|
|
282
|
+
// 加载已选数据数组
|
|
283
|
+
// 如果有数组数据, 则初始化时从数组中选取已有的数据
|
|
284
|
+
loadSelected: [Array, Function],
|
|
285
|
+
// 初始是否不加载已选数据
|
|
286
|
+
// true, 则初始时不加载数据(同时 loadSelected 无效)
|
|
287
|
+
noDefaultLoadSelected: Boolean,
|
|
288
|
+
// 更新值时不加载已选数据
|
|
289
|
+
noUpdateLoadSelected: Boolean,
|
|
290
|
+
// 格式化显示标签
|
|
291
|
+
formatLabel: Function,
|
|
292
|
+
// 下拉表格显示的字段数组(空为:[值字段, 标签字段])
|
|
293
|
+
showKeys: Array,
|
|
294
|
+
// 隐藏搜索字段数组
|
|
295
|
+
hideSearchKeys: Array,
|
|
296
|
+
// 默认筛选字段(空为:标签字段)
|
|
297
|
+
filterKey: String,
|
|
298
|
+
// 是否开启筛选
|
|
299
|
+
filter: Boolean,
|
|
300
|
+
// 表格声明属性
|
|
301
|
+
tableProps: Object,
|
|
302
|
+
// 对话框声明属性
|
|
303
|
+
dialogProps: Object,
|
|
304
|
+
|
|
305
|
+
// 关闭对话框
|
|
306
|
+
noDialog: Boolean,
|
|
307
|
+
|
|
308
|
+
// 表格列数据
|
|
309
|
+
columns: Array,
|
|
310
|
+
// 行数据
|
|
311
|
+
rows: Array,
|
|
312
|
+
// 是否多选
|
|
313
|
+
multiple: Boolean,
|
|
314
|
+
// 多选模式下是否折叠标签
|
|
315
|
+
collapseTags: Boolean,
|
|
316
|
+
// 占位符
|
|
317
|
+
placeholder: String,
|
|
318
|
+
// 是否可清除
|
|
319
|
+
clearable: Boolean,
|
|
320
|
+
// 是否禁用
|
|
321
|
+
disable: Boolean,
|
|
322
|
+
// 是否只读
|
|
323
|
+
readonly: Boolean,
|
|
324
|
+
// 输入防抖(毫秒)
|
|
325
|
+
inputDebounce: {
|
|
326
|
+
type: [ Number, String ],
|
|
327
|
+
default: 500
|
|
328
|
+
},
|
|
329
|
+
// 自定义请求方法
|
|
330
|
+
request: Function,
|
|
331
|
+
// 每次对话框显示都请求
|
|
332
|
+
requestEveryDialogShow: Boolean,
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* 声明事件
|
|
337
|
+
*/
|
|
338
|
+
emits: [
|
|
339
|
+
'loaded',
|
|
340
|
+
'update:modelValue',
|
|
341
|
+
'update:selected',
|
|
342
|
+
],
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* 组合式
|
|
346
|
+
*/
|
|
347
|
+
setup(props, { emit, slots }) {
|
|
348
|
+
|
|
349
|
+
// ==========【计算属性】=========================================================================================
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* 插槽标识
|
|
353
|
+
*/
|
|
354
|
+
const slotNames = computed(function() {
|
|
355
|
+
|
|
356
|
+
const table = []
|
|
357
|
+
const normal = []
|
|
358
|
+
|
|
359
|
+
// 如果有插槽
|
|
360
|
+
if ($n_isValidObject(slots)) {
|
|
361
|
+
for (const key in slots) {
|
|
362
|
+
if (key !== 'append' && key !== 'control') {
|
|
363
|
+
if (key.startsWith('table-')) {
|
|
364
|
+
table.push(key.replace('table-', ''))
|
|
365
|
+
} else {
|
|
366
|
+
normal.push(key)
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return {
|
|
373
|
+
table,
|
|
374
|
+
normal,
|
|
375
|
+
}
|
|
376
|
+
})
|
|
377
|
+
|
|
378
|
+
/**
|
|
379
|
+
* 当前标签字段
|
|
380
|
+
*/
|
|
381
|
+
const currentlabelKey = computed(function() {
|
|
382
|
+
return props.labelKey || props.valueKey
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* 当前显示字段
|
|
387
|
+
*/
|
|
388
|
+
const currentShowKeys = computed(function() {
|
|
389
|
+
return $n_uniq($n_isValidArray(props.showKeys)
|
|
390
|
+
? props.showKeys
|
|
391
|
+
: [ props.valueKey, currentlabelKey.value ])
|
|
392
|
+
})
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* 当前搜索字段
|
|
396
|
+
*/
|
|
397
|
+
const currentFilterKey = computed(function() {
|
|
398
|
+
return props.filterKey || currentlabelKey.value
|
|
399
|
+
})
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* 显示值
|
|
403
|
+
*/
|
|
404
|
+
const showValue = computed(function () {
|
|
405
|
+
|
|
406
|
+
// 如果有已选数据
|
|
407
|
+
return $n_isValidArray(selected.value)
|
|
408
|
+
// 取已选数据第一条
|
|
409
|
+
? currentFormatLabel(selected.value[0])
|
|
410
|
+
: ''
|
|
411
|
+
})
|
|
412
|
+
|
|
413
|
+
// ==========【数据】============================================================================================
|
|
414
|
+
|
|
415
|
+
// 创建权限实例
|
|
416
|
+
const $power = $n_$power.create({
|
|
417
|
+
// 路由路径
|
|
418
|
+
path: $n_isValidString(props.path) ? props.path : false,
|
|
419
|
+
// 路由参数
|
|
420
|
+
query: props.query,
|
|
421
|
+
// 关闭权限页面
|
|
422
|
+
power: false,
|
|
423
|
+
// 禁止对话框注入
|
|
424
|
+
$dialog: null,
|
|
425
|
+
})
|
|
426
|
+
|
|
427
|
+
const {
|
|
428
|
+
// 当前路由路径
|
|
429
|
+
routePath,
|
|
430
|
+
} = $power
|
|
431
|
+
|
|
432
|
+
// 创建表格实例
|
|
433
|
+
const $table = $n_$table.create({
|
|
434
|
+
// 权限实例
|
|
435
|
+
$power,
|
|
436
|
+
// 请求地址
|
|
437
|
+
url: props.url,
|
|
438
|
+
// 附加请求数据
|
|
439
|
+
data: props.data,
|
|
440
|
+
// 获取表格列数据
|
|
441
|
+
columns: getTableColumns(),
|
|
442
|
+
// 表格行唯一键值
|
|
443
|
+
rowKey: props.valueKey,
|
|
444
|
+
// 行数据
|
|
445
|
+
rows: props.rows,
|
|
446
|
+
// 选择类型, 可选值 single multiple none
|
|
447
|
+
selection: props.multiple ? 'multiple' : 'single',
|
|
448
|
+
// 已选数据
|
|
449
|
+
selected: [],
|
|
450
|
+
// http 设置
|
|
451
|
+
httpSettings: {
|
|
452
|
+
// 头部请求
|
|
453
|
+
headers: {
|
|
454
|
+
// 添加头部查看请求
|
|
455
|
+
Pview: 1,
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
// 刷新后清空已选数据
|
|
459
|
+
refreshResetSelected: false,
|
|
460
|
+
// 自定义请求方法
|
|
461
|
+
async request({ httpOptions, props: httpProps }) {
|
|
462
|
+
return $n_isFunction(props.request) ?
|
|
463
|
+
// 如果有自定义请求方法
|
|
464
|
+
await $n_runAsync(props.request)({
|
|
465
|
+
// http 请求参数
|
|
466
|
+
httpOptions,
|
|
467
|
+
// 对话框是否已显示
|
|
468
|
+
showDialog: $n_get(httpProps, 'showDialog') === 1 ? true : showDialog.value,
|
|
469
|
+
}) :
|
|
470
|
+
// 否则请求数据
|
|
471
|
+
await $n_http(httpOptions)
|
|
472
|
+
},
|
|
473
|
+
})
|
|
474
|
+
|
|
475
|
+
// 创建睡眠实例
|
|
476
|
+
const sleep = $n_sleep()
|
|
477
|
+
|
|
478
|
+
// 输入框节点
|
|
479
|
+
const inputRef = ref(null)
|
|
480
|
+
|
|
481
|
+
// 输入框值
|
|
482
|
+
const inputValue = ref('')
|
|
483
|
+
|
|
484
|
+
// 弹出层节点
|
|
485
|
+
const popupRef = ref(null)
|
|
486
|
+
|
|
487
|
+
// 是否显示对话框
|
|
488
|
+
const showDialog = ref(false)
|
|
489
|
+
|
|
490
|
+
// 是否显示弹出层
|
|
491
|
+
const showPopup = ref(false)
|
|
492
|
+
|
|
493
|
+
// 当前表格列数据
|
|
494
|
+
const columns = getQuickTableColumns()
|
|
495
|
+
|
|
496
|
+
// 停止观察值
|
|
497
|
+
let stopValueWatcher = false
|
|
498
|
+
|
|
499
|
+
// 临时已选数据
|
|
500
|
+
let tempSelected = []
|
|
501
|
+
|
|
502
|
+
// 初始化已选数据
|
|
503
|
+
const selected = ref(valueToSelected(props.modelValue, true, true))
|
|
504
|
+
|
|
505
|
+
// 加载已选数据
|
|
506
|
+
if (
|
|
507
|
+
! props.noDefaultLoadSelected
|
|
508
|
+
&& props.loadSelected === void 0
|
|
509
|
+
) {
|
|
510
|
+
loadSelected()
|
|
511
|
+
.finally()
|
|
512
|
+
} else {
|
|
513
|
+
// 初始化加载成功
|
|
514
|
+
emit('loaded', selected.value)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// ==========【监听数据】=========================================================================================
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* 监听声明值
|
|
521
|
+
*/
|
|
522
|
+
watch(() => props.modelValue, async function(val) {
|
|
523
|
+
|
|
524
|
+
// 如果停止观察值
|
|
525
|
+
if (stopValueWatcher === true) {
|
|
526
|
+
// 取消停止观察值
|
|
527
|
+
stopValueWatcher = false
|
|
528
|
+
return
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// 值转已选数据
|
|
532
|
+
let newSelected = valueToSelected(val, false, false)
|
|
533
|
+
|
|
534
|
+
// 如果值类型是数组对象
|
|
535
|
+
if (props.valueType === 'objectArray') {
|
|
536
|
+
|
|
537
|
+
// 设置已选数据
|
|
538
|
+
setSelected(newSelected)
|
|
539
|
+
|
|
540
|
+
// 否则值类型是字符串或数组
|
|
541
|
+
} else {
|
|
542
|
+
|
|
543
|
+
// 初始已选数据
|
|
544
|
+
const _selected = []
|
|
545
|
+
|
|
546
|
+
// 如果值转已选数据是有效数组
|
|
547
|
+
if (newSelected.length) {
|
|
548
|
+
|
|
549
|
+
const newSelectedOld = newSelected
|
|
550
|
+
const __selected = []
|
|
551
|
+
|
|
552
|
+
// 如果有已选数据
|
|
553
|
+
const currentSelected = tempSelected.length ? tempSelected : selected.value
|
|
554
|
+
if (currentSelected.length) {
|
|
555
|
+
|
|
556
|
+
const _newSelected = []
|
|
557
|
+
|
|
558
|
+
// 遍历新已选数据
|
|
559
|
+
for (const newItem of newSelected) {
|
|
560
|
+
// 已选中的数据
|
|
561
|
+
const hasItem = $n_find(currentSelected, e => e[props.valueKey] === newItem)
|
|
562
|
+
if (hasItem) {
|
|
563
|
+
__selected.push(hasItem)
|
|
564
|
+
// 需增加的值
|
|
565
|
+
} else {
|
|
566
|
+
_newSelected.push(newItem)
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
// 设置新的需要增加的值
|
|
571
|
+
newSelected = _newSelected
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
// 需增加的值
|
|
575
|
+
if (newSelected.length) {
|
|
576
|
+
// 如果更新值时不加载已选数据
|
|
577
|
+
if (props.noUpdateLoadSelected) {
|
|
578
|
+
// 请求选择数据
|
|
579
|
+
__selected.push(...newSelected.map(e => setSelectedItem(e)))
|
|
580
|
+
} else {
|
|
581
|
+
// 请求选择数据
|
|
582
|
+
__selected.push(...await onRequestSelected(newSelected))
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// 重新筛选和排序已选数据
|
|
587
|
+
for (const item of newSelectedOld) {
|
|
588
|
+
// 已选中的数据
|
|
589
|
+
const hasItem = $n_find(__selected, e => e[props.valueKey] === item)
|
|
590
|
+
if (hasItem) {
|
|
591
|
+
_selected.push(hasItem)
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
// 设置已选数据
|
|
597
|
+
setSelected(_selected)
|
|
598
|
+
|
|
599
|
+
// 清空临时已选数据
|
|
600
|
+
tempSelected = []
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// 将已选数据转为值
|
|
604
|
+
const _value = selectedToValue(selected.value)
|
|
605
|
+
|
|
606
|
+
// 如果声明值发生变化
|
|
607
|
+
if (_value !== props.modelValue) {
|
|
608
|
+
// 停止观察值
|
|
609
|
+
stopValueWatcher = true
|
|
610
|
+
// 触发更新已选数据
|
|
611
|
+
emit('update:modelValue', _value)
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// 设置输入框焦点
|
|
615
|
+
setInputFocus()
|
|
616
|
+
|
|
617
|
+
// 设置输入框文字选中
|
|
618
|
+
setInputSelection()
|
|
619
|
+
|
|
620
|
+
}, {
|
|
621
|
+
// 深度监听
|
|
622
|
+
deep: true,
|
|
623
|
+
})
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* 监听输入框值
|
|
627
|
+
*/
|
|
628
|
+
watch(inputValue, async function (val) {
|
|
629
|
+
|
|
630
|
+
// 延迟执行
|
|
631
|
+
await sleep(props.inputDebounce)
|
|
632
|
+
|
|
633
|
+
// 是否有值
|
|
634
|
+
const hasValue = $n_isValidValue(val)
|
|
635
|
+
|
|
636
|
+
const n_search = {}
|
|
637
|
+
n_search[currentFilterKey.value] = [
|
|
638
|
+
{
|
|
639
|
+
// 比较类型
|
|
640
|
+
compare: dicts.SEARCH_COMPARE_TYPE__LIKE,
|
|
641
|
+
// 值
|
|
642
|
+
value: hasValue ? val : '',
|
|
643
|
+
}
|
|
644
|
+
]
|
|
645
|
+
|
|
646
|
+
// 设置表格传参
|
|
647
|
+
$table.setQuery({
|
|
648
|
+
n_search,
|
|
649
|
+
})
|
|
650
|
+
|
|
651
|
+
if (
|
|
652
|
+
// 如果弹出层是隐藏的
|
|
653
|
+
! showPopup.value
|
|
654
|
+
// 如果输入框有值
|
|
655
|
+
&& hasValue
|
|
656
|
+
) {
|
|
657
|
+
// 显示弹出层节点
|
|
658
|
+
showPopupRef()
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// 表格重新加载
|
|
662
|
+
await $table.tableReload()
|
|
663
|
+
})
|
|
664
|
+
|
|
665
|
+
/**
|
|
666
|
+
* 监听其他值
|
|
667
|
+
*/
|
|
668
|
+
// watch([
|
|
669
|
+
// ()=>props.path,
|
|
670
|
+
// ()=>props.url,
|
|
671
|
+
// ()=>props.query,
|
|
672
|
+
// ()=>props.data,
|
|
673
|
+
// ()=>props.showKeys,
|
|
674
|
+
// ()=>props.hideSearchKeys,
|
|
675
|
+
// ], function () {
|
|
676
|
+
// _dialogShowed = false
|
|
677
|
+
// _popupShowed = false
|
|
678
|
+
//
|
|
679
|
+
// }, {
|
|
680
|
+
// deep: true
|
|
681
|
+
// })
|
|
682
|
+
|
|
683
|
+
// ==========【方法】=============================================================================================
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* 加载已选数据
|
|
687
|
+
*/
|
|
688
|
+
async function loadSelected() {
|
|
689
|
+
if (
|
|
690
|
+
// 如果值类型不是数组对象
|
|
691
|
+
props.valueType !== 'objectArray'
|
|
692
|
+
// 如果初始加载已选数据
|
|
693
|
+
&& ! props.noDefaultLoadSelected
|
|
694
|
+
// 如果有请求路由路径
|
|
695
|
+
&& routePath
|
|
696
|
+
) {
|
|
697
|
+
// 获取值数组
|
|
698
|
+
const values = valueToSelected(props.modelValue, false, false)
|
|
699
|
+
if (values.length) {
|
|
700
|
+
// 初始的已选数据
|
|
701
|
+
const _selected = await onRequestSelected(values)
|
|
702
|
+
const _value = selectedToValue(_selected)
|
|
703
|
+
|
|
704
|
+
// 如果声明值未发生变化
|
|
705
|
+
if (_value === props.modelValue) {
|
|
706
|
+
|
|
707
|
+
// 设置已选数据
|
|
708
|
+
setSelected(_selected)
|
|
709
|
+
|
|
710
|
+
} else {
|
|
711
|
+
// 设置临时已选数据
|
|
712
|
+
tempSelected = _selected
|
|
713
|
+
// 触发更新值
|
|
714
|
+
emit('update:modelValue', _value)
|
|
715
|
+
}
|
|
716
|
+
// 初始化加载成功
|
|
717
|
+
emit('loaded', _selected)
|
|
718
|
+
return
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// 触发更新已选数据
|
|
723
|
+
emit('update:selected', selected.value)
|
|
724
|
+
// 初始化加载成功
|
|
725
|
+
emit('loaded', selected.value)
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
/**
|
|
729
|
+
* 触发更新值
|
|
730
|
+
*/
|
|
731
|
+
function emitModelValue(val) {
|
|
732
|
+
|
|
733
|
+
// 设置临时已选数据
|
|
734
|
+
tempSelected = val
|
|
735
|
+
|
|
736
|
+
// 触发更新值
|
|
737
|
+
emit('update:modelValue', selectedToValue(val))
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* 设置已选数据
|
|
742
|
+
*/
|
|
743
|
+
function setSelected(val) {
|
|
744
|
+
|
|
745
|
+
// 设置已选数据
|
|
746
|
+
selected.value = val
|
|
747
|
+
|
|
748
|
+
// 触发更新已选数据
|
|
749
|
+
emit('update:selected', val)
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* 当前格式化显示标签
|
|
754
|
+
*/
|
|
755
|
+
function currentFormatLabel(item) {
|
|
756
|
+
|
|
757
|
+
// 如果有格式化显示标签方法
|
|
758
|
+
if ($n_isFunction(props.formatLabel)) {
|
|
759
|
+
// 执行格式化显示标签方法
|
|
760
|
+
return props.formatLabel(item)
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// 否则显示该值的标签字段
|
|
764
|
+
const val = item[currentlabelKey.value]
|
|
765
|
+
return $n_isValidValue(val) ? val : item[props.valueKey]
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* 设置已选数据的单个元素
|
|
770
|
+
*/
|
|
771
|
+
function setSelectedItem(val) {
|
|
772
|
+
const obj = {}
|
|
773
|
+
obj[props.valueKey] = val
|
|
774
|
+
obj[currentlabelKey.value] = val
|
|
775
|
+
return obj
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* 值转已选数据
|
|
780
|
+
*/
|
|
781
|
+
function valueToSelected(val, isFirst, toSelected) {
|
|
782
|
+
|
|
783
|
+
// 如果值类型是数组对象
|
|
784
|
+
if (props.valueType === 'objectArray') {
|
|
785
|
+
|
|
786
|
+
// 如果是有效数组
|
|
787
|
+
if ($n_isValidArray(val)) {
|
|
788
|
+
for (const item of val) {
|
|
789
|
+
if (
|
|
790
|
+
// 如果元素不是有效对象
|
|
791
|
+
! $n_isValidObject(item)
|
|
792
|
+
// 如果元素没有值字段
|
|
793
|
+
|| ! $n_has(item, props.valueKey)
|
|
794
|
+
) {
|
|
795
|
+
return []
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
// 否则直接返回
|
|
801
|
+
return val
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
if (
|
|
805
|
+
// 如果初始化
|
|
806
|
+
isFirst
|
|
807
|
+
// 如果初始加载已选数据方法
|
|
808
|
+
&& ! props.noDefaultLoadSelected
|
|
809
|
+
// 如果有初始加载已选数据
|
|
810
|
+
&& props.loadSelected !== void 0
|
|
811
|
+
) {
|
|
812
|
+
// 将值转为数组
|
|
813
|
+
val = props.valueType === 'string' ? $n_split(val, props.valueSeparator) : val
|
|
814
|
+
|
|
815
|
+
// 如果是有效数组
|
|
816
|
+
if ($n_isValidArray(val)) {
|
|
817
|
+
val = val.filter(e => $n_isValidValue(e))
|
|
818
|
+
if (val.length) {
|
|
819
|
+
return onLoadSelected(val, isFirst)
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return []
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (
|
|
826
|
+
// 非初始化
|
|
827
|
+
! isFirst
|
|
828
|
+
// 或初始不加载已选数据
|
|
829
|
+
|| props.noDefaultLoadSelected
|
|
830
|
+
// 或没有路由路径
|
|
831
|
+
|| ! routePath
|
|
832
|
+
) {
|
|
833
|
+
// 将值转为数组
|
|
834
|
+
val = props.valueType === 'string' ? $n_split(val, props.valueSeparator) : val
|
|
835
|
+
|
|
836
|
+
// 如果是有效数组
|
|
837
|
+
if ($n_isValidArray(val)) {
|
|
838
|
+
val = val.filter(e => $n_isValidValue(e))
|
|
839
|
+
return toSelected ? val.map(e => setSelectedItem(e)) : val
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
return []
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
/**
|
|
847
|
+
* 已选数据转值
|
|
848
|
+
*/
|
|
849
|
+
function selectedToValue(val) {
|
|
850
|
+
|
|
851
|
+
// 如果值类型是数组对象
|
|
852
|
+
if (props.valueType === 'objectArray') {
|
|
853
|
+
|
|
854
|
+
// 则直接返回
|
|
855
|
+
return val
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// 值数组
|
|
859
|
+
const values = val.length
|
|
860
|
+
// 如果有已选数据
|
|
861
|
+
? (
|
|
862
|
+
props.multiple
|
|
863
|
+
// 如果是多选
|
|
864
|
+
? val.map(e => e[props.valueKey])
|
|
865
|
+
// 否则是单选
|
|
866
|
+
: [ val[0][props.valueKey] ]
|
|
867
|
+
)
|
|
868
|
+
// 否则为空
|
|
869
|
+
: []
|
|
870
|
+
|
|
871
|
+
// 如果值类型是数组
|
|
872
|
+
if (props.valueType === 'stringArray') {
|
|
873
|
+
|
|
874
|
+
// 直接返回数组
|
|
875
|
+
return values
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// 返回转为分隔符隔开的字符串
|
|
879
|
+
return $n_numberDeep($n_join(values, props.valueSeparator))
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
/**
|
|
883
|
+
* 加载已选数据
|
|
884
|
+
*/
|
|
885
|
+
function onLoadSelected(values, isFirst) {
|
|
886
|
+
|
|
887
|
+
function next(lists) {
|
|
888
|
+
const _selected = []
|
|
889
|
+
$n_forEach(lists, function (item) {
|
|
890
|
+
if (
|
|
891
|
+
$n_has(item, props.valueKey)
|
|
892
|
+
&& $n_indexOf(values, item[props.valueKey]) > -1
|
|
893
|
+
&& $n_findIndex(_selected, e => e[props.valueKey] === item[props.valueKey]) === -1
|
|
894
|
+
) {
|
|
895
|
+
_selected.push($n_cloneDeep(item))
|
|
896
|
+
}
|
|
897
|
+
})
|
|
898
|
+
return _selected
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// 如果是加载已选数据方法
|
|
902
|
+
if ($n_isFunction(props.loadSelected)) {
|
|
903
|
+
const res = props.loadSelected(values, next, isFirst)
|
|
904
|
+
if ($n_isValidArray(res)) {
|
|
905
|
+
return res
|
|
906
|
+
}
|
|
907
|
+
return []
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
return next(props.loadSelected)
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
/**
|
|
914
|
+
* 请求选择数据
|
|
915
|
+
*/
|
|
916
|
+
async function onRequestSelected(value) {
|
|
917
|
+
|
|
918
|
+
let requestValues = value
|
|
919
|
+
|
|
920
|
+
const all = {}
|
|
921
|
+
let hasAll = false
|
|
922
|
+
|
|
923
|
+
// 如果有初始加载已选数据数组
|
|
924
|
+
if (props.loadSelected !== void 0) {
|
|
925
|
+
const rows = onLoadSelected(value, false)
|
|
926
|
+
if ($n_isValidArray(rows)) {
|
|
927
|
+
|
|
928
|
+
requestValues = []
|
|
929
|
+
|
|
930
|
+
for (const item of rows) {
|
|
931
|
+
all[item[props.valueKey]] = item
|
|
932
|
+
}
|
|
933
|
+
for (const val of value) {
|
|
934
|
+
if (! $n_has(all, val)) {
|
|
935
|
+
requestValues.push(val)
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (! requestValues.length) {
|
|
939
|
+
return rows
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
hasAll = true
|
|
943
|
+
}
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// 请求参数
|
|
947
|
+
const httpOptions = {
|
|
948
|
+
url: $table.routePath,
|
|
949
|
+
data: Object.assign(
|
|
950
|
+
// 获取表格请求数据
|
|
951
|
+
$table.getTableRequestData({
|
|
952
|
+
// filter,
|
|
953
|
+
pagination: {
|
|
954
|
+
// 页码
|
|
955
|
+
page: 1,
|
|
956
|
+
// 每页的数据条数
|
|
957
|
+
rowsPerPage: value.length,
|
|
958
|
+
// 排序字段
|
|
959
|
+
sortBy: null,
|
|
960
|
+
// 是否降序排列
|
|
961
|
+
descending: true,
|
|
962
|
+
}
|
|
963
|
+
}, false),
|
|
964
|
+
{
|
|
965
|
+
// 查看字段
|
|
966
|
+
n_view: {
|
|
967
|
+
// 查看字段
|
|
968
|
+
field: props.valueKey,
|
|
969
|
+
// 查看值
|
|
970
|
+
value: requestValues,
|
|
971
|
+
},
|
|
972
|
+
}
|
|
973
|
+
),
|
|
974
|
+
// 是否开启防抖(防止重复请求)
|
|
975
|
+
debounce: false,
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// 请求数据
|
|
979
|
+
const { status, data } = $n_isFunction(props.request) ?
|
|
980
|
+
// 如果有自定义请求方法
|
|
981
|
+
await $n_runAsync(props.request)({
|
|
982
|
+
// http 请求参数
|
|
983
|
+
httpOptions,
|
|
984
|
+
// 对话框是否已显示
|
|
985
|
+
showDialog: showDialog.value,
|
|
986
|
+
}) :
|
|
987
|
+
// 否则请求数据
|
|
988
|
+
await $n_http(httpOptions)
|
|
989
|
+
|
|
990
|
+
if (status) {
|
|
991
|
+
if ($n_isValidArray($n_get(data, 'rows'))) {
|
|
992
|
+
if (! hasAll) {
|
|
993
|
+
return data.rows
|
|
994
|
+
}
|
|
995
|
+
for (const item of data.rows) {
|
|
996
|
+
all[item[props.valueKey]] = item
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
const newRows = []
|
|
1002
|
+
for (const val of value) {
|
|
1003
|
+
if ($n_has(all, val)) {
|
|
1004
|
+
newRows.push(all[val])
|
|
1005
|
+
}
|
|
1006
|
+
}
|
|
1007
|
+
return newRows
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
/**
|
|
1011
|
+
* 获取表格列数据
|
|
1012
|
+
*/
|
|
1013
|
+
function getTableColumns() {
|
|
1014
|
+
|
|
1015
|
+
let columns
|
|
1016
|
+
|
|
1017
|
+
// 如果有声明路由表格列数据
|
|
1018
|
+
if ($n_isValidArray(props.columns)) {
|
|
1019
|
+
columns = $n_cloneDeep(props.columns)
|
|
1020
|
+
|
|
1021
|
+
// 如果有路由路径
|
|
1022
|
+
} else if (routePath) {
|
|
1023
|
+
// 否则如果有路由表格列数据
|
|
1024
|
+
const rawTableColumns = $n_$table.config(routePath, 'columns')
|
|
1025
|
+
if ($n_isValidArray(rawTableColumns)) {
|
|
1026
|
+
columns = $n_cloneDeep(rawTableColumns)
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
if ($n_isValidArray(columns)) {
|
|
1031
|
+
if ($n_isValidArray(props.hideSearchKeys)) {
|
|
1032
|
+
for (const item of columns) {
|
|
1033
|
+
if (
|
|
1034
|
+
props.hideSearchKeys.indexOf(item.name) > -1
|
|
1035
|
+
&& $n_has(item, 'search')
|
|
1036
|
+
) {
|
|
1037
|
+
item.search.hide = true
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
return columns
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
return []
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
/**
|
|
1048
|
+
* 获取快捷表格列数据
|
|
1049
|
+
*/
|
|
1050
|
+
function getQuickTableColumns() {
|
|
1051
|
+
|
|
1052
|
+
const columns = []
|
|
1053
|
+
|
|
1054
|
+
// 如果有原始表格列数据
|
|
1055
|
+
if ($n_isValidArray($table.tableColumns.value)) {
|
|
1056
|
+
|
|
1057
|
+
// 克隆原始表格列数据
|
|
1058
|
+
const rawTableColumns = $n_cloneDeep($table.tableColumns.value)
|
|
1059
|
+
|
|
1060
|
+
// 快捷表格显示的属性名称数组
|
|
1061
|
+
$n_forEach(currentShowKeys.value, function (key) {
|
|
1062
|
+
for (const item of rawTableColumns) {
|
|
1063
|
+
if (item.name === key) {
|
|
1064
|
+
// 删除搜索字段
|
|
1065
|
+
if ($n_has(item, 'search')) {
|
|
1066
|
+
delete item.search
|
|
1067
|
+
}
|
|
1068
|
+
// 删除可见字段
|
|
1069
|
+
if ($n_has(item, 'visible')) {
|
|
1070
|
+
delete item.visible
|
|
1071
|
+
}
|
|
1072
|
+
columns.push(item)
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
})
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
return columns
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
/**
|
|
1082
|
+
* 移除已选数据
|
|
1083
|
+
*/
|
|
1084
|
+
function onRemoveSelected(index) {
|
|
1085
|
+
|
|
1086
|
+
const _selected = [...selected.value]
|
|
1087
|
+
_selected.splice(index, 1)
|
|
1088
|
+
|
|
1089
|
+
// 触发更新值
|
|
1090
|
+
emitModelValue(_selected)
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* 字段获取焦点触发
|
|
1095
|
+
*/
|
|
1096
|
+
function onFieldFocus(e) {
|
|
1097
|
+
|
|
1098
|
+
// 停止冒泡
|
|
1099
|
+
e.stopPropagation()
|
|
1100
|
+
|
|
1101
|
+
// 设置输入框焦点
|
|
1102
|
+
setInputFocus()
|
|
1103
|
+
|
|
1104
|
+
// window.scrollTo(window.pageXOffset || window.scrollX || document.body.scrollLeft || 0, 0)
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
/**
|
|
1108
|
+
* 字段失去焦点触发
|
|
1109
|
+
*/
|
|
1110
|
+
function onFieldBlur(e) {
|
|
1111
|
+
|
|
1112
|
+
// 停止冒泡
|
|
1113
|
+
e.stopPropagation()
|
|
1114
|
+
|
|
1115
|
+
if (
|
|
1116
|
+
// 如果开启筛选
|
|
1117
|
+
props.filter
|
|
1118
|
+
// 如果没有显示弹出层
|
|
1119
|
+
&& ! showPopup.value
|
|
1120
|
+
) {
|
|
1121
|
+
// 清空输入框值
|
|
1122
|
+
inputValue.value = ''
|
|
1123
|
+
}
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
/**
|
|
1127
|
+
* 字段清空触发
|
|
1128
|
+
*/
|
|
1129
|
+
function onFieldClear() {
|
|
1130
|
+
|
|
1131
|
+
// 触发更新值
|
|
1132
|
+
// 清空快捷表格已选数据
|
|
1133
|
+
emitModelValue([])
|
|
1134
|
+
|
|
1135
|
+
// 隐藏弹出层节点
|
|
1136
|
+
hidePopupRef()
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
/**
|
|
1140
|
+
* 显示弹出层节点
|
|
1141
|
+
*/
|
|
1142
|
+
function showPopupRef() {
|
|
1143
|
+
|
|
1144
|
+
// 如果有弹出层节点
|
|
1145
|
+
if (popupRef.value) {
|
|
1146
|
+
// 显示弹出层
|
|
1147
|
+
popupRef.value.show()
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* 隐藏弹出层节点
|
|
1153
|
+
*/
|
|
1154
|
+
function hidePopupRef() {
|
|
1155
|
+
|
|
1156
|
+
// 如果有弹出层节点
|
|
1157
|
+
if (popupRef.value) {
|
|
1158
|
+
// 隐藏弹出层
|
|
1159
|
+
popupRef.value.hide()
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* 弹出层显示回调
|
|
1165
|
+
*/
|
|
1166
|
+
let _popupShowed = false
|
|
1167
|
+
function onPopupShow() {
|
|
1168
|
+
|
|
1169
|
+
// 显示弹出层
|
|
1170
|
+
showPopup.value = true
|
|
1171
|
+
|
|
1172
|
+
// 设置输入框焦点
|
|
1173
|
+
setInputFocus()
|
|
1174
|
+
|
|
1175
|
+
// 如果每次对话框显示都请求
|
|
1176
|
+
if (props.requestEveryDialogShow) {
|
|
1177
|
+
// 表格重新加载
|
|
1178
|
+
$table.tableReload()
|
|
1179
|
+
.finally()
|
|
1180
|
+
return
|
|
1181
|
+
}
|
|
1182
|
+
|
|
1183
|
+
if (_popupShowed) {
|
|
1184
|
+
return
|
|
1185
|
+
}
|
|
1186
|
+
_popupShowed = true
|
|
1187
|
+
|
|
1188
|
+
// 表格重新加载
|
|
1189
|
+
$table.tableReload()
|
|
1190
|
+
.finally()
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
/**
|
|
1194
|
+
* 显示对话框
|
|
1195
|
+
*/
|
|
1196
|
+
function onShowDialog() {
|
|
1197
|
+
// 显示对话框
|
|
1198
|
+
showDialog.value = true
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
/**
|
|
1202
|
+
* 对话框显示前回调
|
|
1203
|
+
*/
|
|
1204
|
+
function onDialogBeforeShow() {
|
|
1205
|
+
|
|
1206
|
+
// 设置当前已选数据
|
|
1207
|
+
$table.tableSelected.value = [...selected.value]
|
|
1208
|
+
|
|
1209
|
+
// 隐藏弹出层节点
|
|
1210
|
+
hidePopupRef()
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
/**
|
|
1214
|
+
* 对话框显示回调
|
|
1215
|
+
*/
|
|
1216
|
+
let _dialogShowed = false
|
|
1217
|
+
function onDialogShow() {
|
|
1218
|
+
|
|
1219
|
+
// 如果每次对话框显示都请求
|
|
1220
|
+
if (props.requestEveryDialogShow) {
|
|
1221
|
+
// 表格重新加载
|
|
1222
|
+
$table.tableReload()
|
|
1223
|
+
.finally()
|
|
1224
|
+
return
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
if (_dialogShowed) {
|
|
1228
|
+
return
|
|
1229
|
+
}
|
|
1230
|
+
_dialogShowed = true
|
|
1231
|
+
|
|
1232
|
+
// 表格重新加载
|
|
1233
|
+
$table.tableReload()
|
|
1234
|
+
.finally()
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
/**
|
|
1238
|
+
* 对话框隐藏后回调
|
|
1239
|
+
*/
|
|
1240
|
+
function onDialogHide() {
|
|
1241
|
+
|
|
1242
|
+
let isReload = true
|
|
1243
|
+
|
|
1244
|
+
// 清空输入框值
|
|
1245
|
+
if (
|
|
1246
|
+
// 如果开启筛选
|
|
1247
|
+
props.filter
|
|
1248
|
+
// 如果有输入框值
|
|
1249
|
+
&& inputValue.value
|
|
1250
|
+
) {
|
|
1251
|
+
// 此时清空输入框后, 会自动刷新表格
|
|
1252
|
+
inputValue.value = ''
|
|
1253
|
+
|
|
1254
|
+
// 所以只需要重置搜索值即可, 不需要再重置后刷新表格
|
|
1255
|
+
isReload = false
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
// 获取表格搜索值
|
|
1259
|
+
let searchValue = $table.getTableSearchValue()
|
|
1260
|
+
if (searchValue.length) {
|
|
1261
|
+
|
|
1262
|
+
// 如果有隐藏搜索字段数组
|
|
1263
|
+
if ($n_isValidArray(props.hideSearchKeys)) {
|
|
1264
|
+
// 从搜索值数组中去除隐藏搜索字段的数组
|
|
1265
|
+
searchValue = searchValue.filter(e => $n_indexOf(e.field, props.hideSearchKeys) === -1)
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
// 表格搜索重置
|
|
1269
|
+
$table.tableSearchReset(isReload && searchValue.length, {
|
|
1270
|
+
showDialog: 1,
|
|
1271
|
+
})
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
/**
|
|
1276
|
+
* 对话框点击确认回调
|
|
1277
|
+
*/
|
|
1278
|
+
function onDialogConfirm(data) {
|
|
1279
|
+
|
|
1280
|
+
// 触发更新值
|
|
1281
|
+
emitModelValue([...data])
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
/**
|
|
1285
|
+
* 单击快捷表格行
|
|
1286
|
+
*/
|
|
1287
|
+
function quickTableRowClick(e, row) {
|
|
1288
|
+
|
|
1289
|
+
// 如果为多选
|
|
1290
|
+
if (props.multiple) {
|
|
1291
|
+
|
|
1292
|
+
// 克隆已选数据
|
|
1293
|
+
const _selected = [...selected.value]
|
|
1294
|
+
|
|
1295
|
+
const opt = {}
|
|
1296
|
+
opt[props.valueKey] = row[props.valueKey]
|
|
1297
|
+
|
|
1298
|
+
// 获取当前数据索引
|
|
1299
|
+
const itemIndex = $n_findIndex(_selected, opt)
|
|
1300
|
+
|
|
1301
|
+
// 如果不存在
|
|
1302
|
+
if (itemIndex === -1) {
|
|
1303
|
+
// 则添加
|
|
1304
|
+
_selected.push(row)
|
|
1305
|
+
|
|
1306
|
+
// 否则
|
|
1307
|
+
} else {
|
|
1308
|
+
// 删除
|
|
1309
|
+
_selected.splice(itemIndex, 1)
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
// 触发更新值
|
|
1313
|
+
emitModelValue(_selected)
|
|
1314
|
+
|
|
1315
|
+
// 否则为单选
|
|
1316
|
+
} else {
|
|
1317
|
+
|
|
1318
|
+
// 触发更新值
|
|
1319
|
+
emitModelValue([ row ])
|
|
1320
|
+
|
|
1321
|
+
// 隐藏弹出层节点
|
|
1322
|
+
hidePopupRef()
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
/**
|
|
1327
|
+
* 设置输入框文字选中
|
|
1328
|
+
*/
|
|
1329
|
+
function setInputSelection() {
|
|
1330
|
+
if (
|
|
1331
|
+
// 如果开启筛选
|
|
1332
|
+
props.filter
|
|
1333
|
+
// 如果有输入框节点
|
|
1334
|
+
&& inputRef.value
|
|
1335
|
+
// 如果输入框有值
|
|
1336
|
+
&& inputValue.value.length
|
|
1337
|
+
) {
|
|
1338
|
+
// 全选文字
|
|
1339
|
+
inputRef.value.select()
|
|
1340
|
+
// inputRef.value.setSelectionRange(0, inputValue.value.length)
|
|
1341
|
+
}
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
/**
|
|
1345
|
+
* 设置输入框焦点
|
|
1346
|
+
*/
|
|
1347
|
+
function setInputFocus() {
|
|
1348
|
+
if (
|
|
1349
|
+
// 如果开启筛选
|
|
1350
|
+
props.filter
|
|
1351
|
+
// 如果有输入框节点
|
|
1352
|
+
&& inputRef.value
|
|
1353
|
+
) {
|
|
1354
|
+
inputRef.value.focus()
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
/**
|
|
1359
|
+
* 格式化图片
|
|
1360
|
+
*/
|
|
1361
|
+
function formatImg(img, { count }) {
|
|
1362
|
+
|
|
1363
|
+
// 图片数组
|
|
1364
|
+
const imgs = []
|
|
1365
|
+
|
|
1366
|
+
// 转为图片数组
|
|
1367
|
+
const arr = $n_split(img, ',')
|
|
1368
|
+
for (const item of arr) {
|
|
1369
|
+
const src = $n_getImage(item)
|
|
1370
|
+
if (src) {
|
|
1371
|
+
imgs.push(item)
|
|
1372
|
+
if (
|
|
1373
|
+
count > 0
|
|
1374
|
+
&& imgs.length === count
|
|
1375
|
+
) {
|
|
1376
|
+
break
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
return imgs
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
// ==========【生命周期】=========================================================================================
|
|
1385
|
+
|
|
1386
|
+
/**
|
|
1387
|
+
* 在组件因为响应式状态变更而更新其 DOM 树之后调用
|
|
1388
|
+
*/
|
|
1389
|
+
onUpdated(function () {
|
|
1390
|
+
if (
|
|
1391
|
+
popupRef.value
|
|
1392
|
+
&& $n_has(popupRef.value, 'currentComponent.ref.updatePosition')
|
|
1393
|
+
) {
|
|
1394
|
+
popupRef.value.currentComponent.ref.updatePosition()
|
|
1395
|
+
}
|
|
1396
|
+
})
|
|
1397
|
+
|
|
1398
|
+
// ==========【返回】=============================================================================================
|
|
1399
|
+
|
|
1400
|
+
return {
|
|
1401
|
+
// 解构表格实例
|
|
1402
|
+
...$table,
|
|
1403
|
+
|
|
1404
|
+
// 插槽标识
|
|
1405
|
+
slotNames,
|
|
1406
|
+
// 当前标签字段
|
|
1407
|
+
currentlabelKey,
|
|
1408
|
+
// 显示值
|
|
1409
|
+
showValue,
|
|
1410
|
+
|
|
1411
|
+
// 输入框节点
|
|
1412
|
+
inputRef,
|
|
1413
|
+
// 输入框值
|
|
1414
|
+
inputValue,
|
|
1415
|
+
// 弹出层节点
|
|
1416
|
+
popupRef,
|
|
1417
|
+
// 是否显示对话框
|
|
1418
|
+
showDialog,
|
|
1419
|
+
// 是否显示弹出层
|
|
1420
|
+
showPopup,
|
|
1421
|
+
// 当前已选数据
|
|
1422
|
+
selected,
|
|
1423
|
+
// 当前表格列数据
|
|
1424
|
+
columns,
|
|
1425
|
+
|
|
1426
|
+
// 当前格式化显示标签
|
|
1427
|
+
currentFormatLabel,
|
|
1428
|
+
// 移除已选数据
|
|
1429
|
+
onRemoveSelected,
|
|
1430
|
+
|
|
1431
|
+
// 字段获取焦点触发
|
|
1432
|
+
onFieldFocus,
|
|
1433
|
+
// 字段失去焦点触发
|
|
1434
|
+
onFieldBlur,
|
|
1435
|
+
// 字段清空触发
|
|
1436
|
+
onFieldClear,
|
|
1437
|
+
|
|
1438
|
+
// 弹出层显示回调
|
|
1439
|
+
onPopupShow,
|
|
1440
|
+
|
|
1441
|
+
// 显示对话框
|
|
1442
|
+
onShowDialog,
|
|
1443
|
+
// 对话框显示前回调
|
|
1444
|
+
onDialogBeforeShow,
|
|
1445
|
+
// 对话框显示回调
|
|
1446
|
+
onDialogShow,
|
|
1447
|
+
// 对话框隐藏后回调
|
|
1448
|
+
onDialogHide,
|
|
1449
|
+
// 对话框点击确认回调
|
|
1450
|
+
onDialogConfirm,
|
|
1451
|
+
|
|
1452
|
+
// 单击快捷表格行
|
|
1453
|
+
quickTableRowClick,
|
|
1454
|
+
|
|
1455
|
+
// 触发更新值
|
|
1456
|
+
emitModelValue,
|
|
1457
|
+
// 格式化图片
|
|
1458
|
+
formatImg,
|
|
1459
|
+
}
|
|
1460
|
+
},
|
|
1461
|
+
}
|
|
1462
|
+
</script>
|
|
1463
|
+
|
|
1464
|
+
<style lang="scss">
|
|
1465
|
+
.n-field-table {
|
|
1466
|
+
.q-field__input--padding {
|
|
1467
|
+
padding-left: 4px;
|
|
1468
|
+
min-width: 50px !important;
|
|
1469
|
+
cursor: text;
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
/**
|
|
1474
|
+
* 桌面
|
|
1475
|
+
*/
|
|
1476
|
+
body.desktop {
|
|
1477
|
+
.n-field-table {
|
|
1478
|
+
&__popup-table {
|
|
1479
|
+
height: 300px;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
</style>
|