@netang/quasar 0.2.32 → 0.2.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (289) hide show
  1. package/.editorconfig +12 -12
  2. package/_docs/docs/components/field-table.md +58 -58
  3. package/_docs/docs/components/field-tree.md +21 -21
  4. package/_docs/docs/components/table.md +24 -24
  5. package/_docs/docs/utils/table.md +196 -196
  6. package/components/column-title/index.vue +38 -38
  7. package/components/data/index.vue +20 -20
  8. package/components/dialog/img-viewer/index.vue +697 -697
  9. package/components/dialog/index.vue +387 -387
  10. package/components/dragger/index.vue +203 -203
  11. package/components/drawer/index.vue +303 -303
  12. package/components/editor-code/index.vue +328 -328
  13. package/components/empty/index.vue +82 -82
  14. package/components/field-date/index.vue +860 -860
  15. package/components/field-date/methods.js +100 -100
  16. package/components/field-table/index.vue +1483 -1483
  17. package/components/field-text/index.vue +166 -166
  18. package/components/field-tree/index.vue +755 -755
  19. package/components/img/index.vue +279 -279
  20. package/components/input-number/index.vue +560 -560
  21. package/components/list-menu/index.vue +149 -149
  22. package/components/list-menu-item/index.vue +79 -79
  23. package/components/mixed-table/index.vue +532 -532
  24. package/components/mixed-table-splitter/index.vue +377 -377
  25. package/components/power-page/index.vue +96 -96
  26. package/components/price/index.vue +188 -188
  27. package/components/private/components/index.js +11 -11
  28. package/components/private/components/move-to-tree/index.vue +154 -154
  29. package/components/private/edit-power-data/index.vue +846 -846
  30. package/components/private/table-visible-columns-button/index.vue +114 -114
  31. package/components/render/index.vue +123 -123
  32. package/components/search/index.vue +231 -231
  33. package/components/search-item/index.vue +210 -210
  34. package/components/select/index.vue +177 -177
  35. package/components/splitter/index.vue +422 -422
  36. package/components/table/index.vue +513 -513
  37. package/components/table-column-fixed/index.vue +110 -110
  38. package/components/table-pagination/index.vue +192 -192
  39. package/components/table-summary/index.vue +107 -107
  40. package/components/thumbnail/index.vue +72 -72
  41. package/components/toolbar/index.vue +150 -150
  42. package/components/tree/index.vue +1728 -1728
  43. package/components/tree/virtual-scroll.vue +41 -41
  44. package/components/uploader/index.vue +196 -196
  45. package/components/uploader-query/index.vue +945 -945
  46. package/components/value-format/index.vue +274 -274
  47. package/components/virtual-scroll/index.vue +136 -136
  48. package/configs/area3.js +1 -1
  49. package/docs/404.html +33 -33
  50. package/docs/assets/404.html-60b35caa.js +1 -1
  51. package/docs/assets/404.html-d1e63d77.js +1 -1
  52. package/docs/assets/alert.html-b2a2a72f.js +5 -5
  53. package/docs/assets/alert.html-ba46d137.js +1 -1
  54. package/docs/assets/app-9f30aa4b.js +6 -6
  55. package/docs/assets/area.html-01b9b58d.js +42 -42
  56. package/docs/assets/area.html-9a4fce6a.js +1 -1
  57. package/docs/assets/arr.html-145d27e7.js +1 -1
  58. package/docs/assets/arr.html-674e65ab.js +11 -11
  59. package/docs/assets/auth.html-579fa830.js +1 -1
  60. package/docs/assets/auth.html-8544ed95.js +8 -8
  61. package/docs/assets/bus.html-c71254aa.js +1 -1
  62. package/docs/assets/bus.html-dc7d3d19.js +6 -6
  63. package/docs/assets/column-title.html-c735cb5a.js +3 -3
  64. package/docs/assets/column-title.html-e9316762.js +1 -1
  65. package/docs/assets/confirm.html-ddfdc27f.js +10 -10
  66. package/docs/assets/confirm.html-ef3e2bef.js +1 -1
  67. package/docs/assets/copy.html-d20345b6.js +1 -1
  68. package/docs/assets/copy.html-ef8c8571.js +13 -13
  69. package/docs/assets/data.html-6432175d.js +30 -30
  70. package/docs/assets/data.html-a3b05d5b.js +1 -1
  71. package/docs/assets/dialog.html-1f698e5a.js +1 -1
  72. package/docs/assets/dialog.html-62902b83.js +68 -68
  73. package/docs/assets/dialog.html-baea77c9.js +1 -1
  74. package/docs/assets/dialog.html-bb082fc4.js +1 -1
  75. package/docs/assets/dict.html-1311da3d.js +23 -23
  76. package/docs/assets/dict.html-b96fbf0c.js +1 -1
  77. package/docs/assets/dictOptions.html-7c4f40a5.js +1 -1
  78. package/docs/assets/dictOptions.html-fb99d175.js +5 -5
  79. package/docs/assets/dragger.html-668d3efa.js +1 -1
  80. package/docs/assets/dragger.html-749d585a.js +1 -1
  81. package/docs/assets/editor-code.html-6ab26ea9.js +1 -1
  82. package/docs/assets/editor-code.html-d196205d.js +1 -1
  83. package/docs/assets/empty.html-1c139131.js +1 -1
  84. package/docs/assets/empty.html-1e9c441d.js +1 -1
  85. package/docs/assets/field-date.html-069fdb13.js +1 -1
  86. package/docs/assets/field-date.html-ad204aa9.js +1 -1
  87. package/docs/assets/field-table.html-ce480f03.js +1 -1
  88. package/docs/assets/field-table.html-d9236160.js +1 -1
  89. package/docs/assets/field-text.html-7277c62f.js +1 -1
  90. package/docs/assets/field-text.html-ccb4cecf.js +1 -1
  91. package/docs/assets/field-tree.html-519bfb45.js +1 -1
  92. package/docs/assets/field-tree.html-fdc748d6.js +1 -1
  93. package/docs/assets/form.html-2b562c37.js +2 -2
  94. package/docs/assets/form.html-75104cd5.js +1 -1
  95. package/docs/assets/framework-204010b2.js +5 -5
  96. package/docs/assets/getData.html-990e3787.js +1 -1
  97. package/docs/assets/getData.html-bb72025f.js +34 -34
  98. package/docs/assets/getFile.html-42368004.js +1 -1
  99. package/docs/assets/getFile.html-99abd054.js +3 -3
  100. package/docs/assets/getImage.html-3429c5a1.js +1 -1
  101. package/docs/assets/getImage.html-4d886d83.js +3 -3
  102. package/docs/assets/getTime.html-7435f922.js +1 -1
  103. package/docs/assets/getTime.html-b37f49eb.js +20 -20
  104. package/docs/assets/img.html-7d1da657.js +1 -1
  105. package/docs/assets/img.html-fbea1105.js +1 -1
  106. package/docs/assets/index.html-1695dd7c.js +1 -1
  107. package/docs/assets/index.html-65a4aa67.js +1 -1
  108. package/docs/assets/index.html-7b98d5bd.js +1 -1
  109. package/docs/assets/index.html-c01f2648.js +1 -1
  110. package/docs/assets/input-number.html-0b250d2a.js +1 -1
  111. package/docs/assets/input-number.html-a8eb0378.js +1 -1
  112. package/docs/assets/list-menu-item.html-7f1b4611.js +1 -1
  113. package/docs/assets/list-menu-item.html-84ed5ab8.js +1 -1
  114. package/docs/assets/list-menu.html-28b4163f.js +1 -1
  115. package/docs/assets/list-menu.html-cb6ba95b.js +1 -1
  116. package/docs/assets/loading.html-dae9e39d.js +6 -6
  117. package/docs/assets/loading.html-dc74c9e6.js +1 -1
  118. package/docs/assets/notify.html-e6c4c514.js +1 -1
  119. package/docs/assets/notify.html-f2c4d914.js +8 -8
  120. package/docs/assets/power-page.html-32e02f82.js +1 -1
  121. package/docs/assets/power-page.html-485e77da.js +1 -1
  122. package/docs/assets/power.html-d258cc19.js +93 -93
  123. package/docs/assets/power.html-e490bd32.js +1 -1
  124. package/docs/assets/previewImage.html-6a6b4245.js +1 -1
  125. package/docs/assets/previewImage.html-c5b7e945.js +2 -2
  126. package/docs/assets/price.html-1882c548.js +19 -19
  127. package/docs/assets/price.html-94d3f5be.js +1 -1
  128. package/docs/assets/price.html-d213df0f.js +1 -1
  129. package/docs/assets/price.html-deaf880f.js +1 -1
  130. package/docs/assets/render.html-8efcbdd4.js +1 -1
  131. package/docs/assets/render.html-df228e38.js +1 -1
  132. package/docs/assets/rule.html-2cd57fc2.js +13 -13
  133. package/docs/assets/rule.html-61662001.js +1 -1
  134. package/docs/assets/ruleValid.html-04fe2552.js +1 -1
  135. package/docs/assets/ruleValid.html-e0a776af.js +14 -14
  136. package/docs/assets/search-0782d0d1.svg +1 -1
  137. package/docs/assets/search-item.html-3f75394c.js +1 -1
  138. package/docs/assets/search-item.html-4e942ecd.js +1 -1
  139. package/docs/assets/search.html-2807043e.js +1 -1
  140. package/docs/assets/search.html-c24f8806.js +1 -1
  141. package/docs/assets/select.html-00d0607c.js +1 -1
  142. package/docs/assets/select.html-de7731f5.js +1 -1
  143. package/docs/assets/splitter.html-56f51a70.js +1 -1
  144. package/docs/assets/splitter.html-f5c836d7.js +1 -1
  145. package/docs/assets/style-161e43ab.css +1 -1
  146. package/docs/assets/symbols.html-a6aea4bf.js +1 -1
  147. package/docs/assets/symbols.html-b1f65bad.js +21 -21
  148. package/docs/assets/table-column-fixed.html-3a69e7b2.js +1 -1
  149. package/docs/assets/table-column-fixed.html-e763c38b.js +1 -1
  150. package/docs/assets/table-pagination.html-236934d3.js +1 -1
  151. package/docs/assets/table-pagination.html-c37ee2ac.js +1 -1
  152. package/docs/assets/table-splitter.html-07eab15c.js +1 -1
  153. package/docs/assets/table-splitter.html-7670ee65.js +1 -1
  154. package/docs/assets/table-summary.html-04db434f.js +1 -1
  155. package/docs/assets/table-summary.html-943c65a0.js +1 -1
  156. package/docs/assets/table.html-36253ad7.js +1 -1
  157. package/docs/assets/table.html-7f9c5d1b.js +38 -38
  158. package/docs/assets/table.html-93d53dc8.js +1 -1
  159. package/docs/assets/table.html-ac99b9cb.js +1 -1
  160. package/docs/assets/thumbnail.html-bab1976b.js +1 -1
  161. package/docs/assets/thumbnail.html-eb64e5e8.js +1 -1
  162. package/docs/assets/timestamp.html-4e54f79b.js +13 -13
  163. package/docs/assets/timestamp.html-d0e1b88a.js +1 -1
  164. package/docs/assets/toast.html-58ecbe21.js +1 -1
  165. package/docs/assets/toast.html-c9b9d36b.js +6 -6
  166. package/docs/assets/toolbar.html-83d9f97c.js +1 -1
  167. package/docs/assets/toolbar.html-ff7b8c92.js +1 -1
  168. package/docs/assets/tree.html-d07cbe79.js +23 -23
  169. package/docs/assets/tree.html-ea04193e.js +1 -1
  170. package/docs/assets/uploader-query.html-05590718.js +1 -1
  171. package/docs/assets/uploader-query.html-3175bac5.js +1 -1
  172. package/docs/assets/uploader.html-36da4394.js +2 -2
  173. package/docs/assets/uploader.html-6b5f3079.js +1 -1
  174. package/docs/assets/uploader.html-b9340b57.js +1 -1
  175. package/docs/assets/uploader.html-bc1c22e3.js +1 -1
  176. package/docs/assets/value-format.html-8ae3d47d.js +1 -1
  177. package/docs/assets/value-format.html-afa99b3d.js +1 -1
  178. package/docs/components/column-title.html +35 -35
  179. package/docs/components/data.html +62 -62
  180. package/docs/components/dialog.html +33 -33
  181. package/docs/components/dragger.html +33 -33
  182. package/docs/components/editor-code.html +33 -33
  183. package/docs/components/empty.html +33 -33
  184. package/docs/components/field-date.html +33 -33
  185. package/docs/components/field-table.html +33 -33
  186. package/docs/components/field-text.html +33 -33
  187. package/docs/components/field-tree.html +33 -33
  188. package/docs/components/img.html +33 -33
  189. package/docs/components/input-number.html +33 -33
  190. package/docs/components/list-menu-item.html +33 -33
  191. package/docs/components/list-menu.html +33 -33
  192. package/docs/components/power-page.html +33 -33
  193. package/docs/components/price.html +33 -33
  194. package/docs/components/render.html +33 -33
  195. package/docs/components/search-item.html +33 -33
  196. package/docs/components/search.html +33 -33
  197. package/docs/components/select.html +33 -33
  198. package/docs/components/splitter.html +33 -33
  199. package/docs/components/table-column-fixed.html +33 -33
  200. package/docs/components/table-pagination.html +33 -33
  201. package/docs/components/table-splitter.html +33 -33
  202. package/docs/components/table-summary.html +33 -33
  203. package/docs/components/table.html +33 -33
  204. package/docs/components/thumbnail.html +33 -33
  205. package/docs/components/toolbar.html +33 -33
  206. package/docs/components/uploader-query.html +33 -33
  207. package/docs/components/uploader.html +33 -33
  208. package/docs/components/value-format.html +33 -33
  209. package/docs/css/index.css +3 -3
  210. package/docs/index.html +33 -33
  211. package/docs/utils/alert.html +37 -37
  212. package/docs/utils/area.html +74 -74
  213. package/docs/utils/arr.html +43 -43
  214. package/docs/utils/auth.html +40 -40
  215. package/docs/utils/bus.html +38 -38
  216. package/docs/utils/confirm.html +42 -42
  217. package/docs/utils/copy.html +45 -45
  218. package/docs/utils/dialog.html +100 -100
  219. package/docs/utils/dict.html +55 -55
  220. package/docs/utils/dictOptions.html +37 -37
  221. package/docs/utils/form.html +34 -34
  222. package/docs/utils/getData.html +66 -66
  223. package/docs/utils/getFile.html +35 -35
  224. package/docs/utils/getImage.html +35 -35
  225. package/docs/utils/getTime.html +52 -52
  226. package/docs/utils/index.html +33 -33
  227. package/docs/utils/loading.html +38 -38
  228. package/docs/utils/notify.html +40 -40
  229. package/docs/utils/power.html +125 -125
  230. package/docs/utils/previewImage.html +34 -34
  231. package/docs/utils/price.html +51 -51
  232. package/docs/utils/rule.html +45 -45
  233. package/docs/utils/ruleValid.html +46 -46
  234. package/docs/utils/symbols.html +53 -53
  235. package/docs/utils/table.html +70 -70
  236. package/docs/utils/timestamp.html +45 -45
  237. package/docs/utils/toast.html +38 -38
  238. package/docs/utils/tree.html +55 -55
  239. package/docs/utils/uploader.html +34 -34
  240. package/package.json +25 -25
  241. package/sass/common.scss +184 -184
  242. package/sass/index.scss +12 -12
  243. package/sass/line.scss +39 -39
  244. package/sass/quasar/btn.scss +46 -46
  245. package/sass/quasar/common.scss +3 -3
  246. package/sass/quasar/drawer.scss +6 -6
  247. package/sass/quasar/field.scss +259 -259
  248. package/sass/quasar/loading.scss +6 -6
  249. package/sass/quasar/table.scss +168 -168
  250. package/sass/quasar/toolbar.scss +22 -22
  251. package/sass/variables.scss +140 -140
  252. package/store/index.js +29 -29
  253. package/utils/$auth.js +128 -128
  254. package/utils/$form.js +72 -72
  255. package/utils/$power.js +1494 -1494
  256. package/utils/$render.js +75 -75
  257. package/utils/$rule.js +13 -13
  258. package/utils/$ruleValid.js +10 -10
  259. package/utils/$search.js +416 -416
  260. package/utils/$table.js +1351 -1348
  261. package/utils/$tree.js +682 -682
  262. package/utils/alert.js +12 -12
  263. package/utils/area.js +400 -400
  264. package/utils/arr.js +51 -51
  265. package/utils/bus.js +6 -6
  266. package/utils/config.js +66 -66
  267. package/utils/confirm.js +11 -11
  268. package/utils/copy.js +30 -30
  269. package/utils/dialog.js +36 -36
  270. package/utils/dict.js +21 -21
  271. package/utils/dictOptions.js +28 -28
  272. package/utils/getData.js +88 -88
  273. package/utils/getFile.js +67 -67
  274. package/utils/getImage.js +276 -276
  275. package/utils/getTime.js +113 -113
  276. package/utils/index.js +67 -67
  277. package/utils/loading.js +15 -15
  278. package/utils/notify.js +13 -13
  279. package/utils/play.js +40 -40
  280. package/utils/previewImage.js +14 -14
  281. package/utils/price.js +18 -18
  282. package/utils/symbols.js +18 -18
  283. package/utils/timestamp.js +18 -18
  284. package/utils/toast.js +13 -13
  285. package/utils/uploader.js +2114 -2114
  286. package/utils/useAuth.js +30 -30
  287. package/utils/useFileUrl.js +26 -26
  288. package/utils/useRouter.js +47 -47
  289. package/utils/useSearch.js +587 -562
@@ -1,945 +1,945 @@
1
- <template>
2
- <div class="n-uploader-query">
3
-
4
- <!-- 上传按钮 -->
5
- <slot
6
- name="button"
7
- :disable="disable || readonly"
8
- :size="currentSize"
9
- v-if="$slots.button"
10
- />
11
- <div
12
- class="n-uploader-query__button--button"
13
- v-else-if="! noButton && currentButtonType === 'button'"
14
- >
15
- <!-- 按钮组-->
16
- <q-btn-group outline>
17
- <!-- 上传本地图片 -->
18
- <q-btn
19
- class="n-button-icon"
20
- :label="buttonText || '上传'"
21
- @click="uploader.chooseUpload"
22
- color="primary"
23
- outline
24
- :disable="disable || readonly"
25
- unelevated
26
- v-bind="buttonProps"
27
- />
28
- <!-- 上传网络图片 -->
29
- <q-btn
30
- class="n-button-icon q-px-sm"
31
- icon="cloud_upload"
32
- @click="uploader.chooseUploadNet"
33
- color="primary"
34
- outline
35
- :disable="disable || readonly"
36
- unelevated
37
- v-bind="buttonProps"
38
- v-if="showUploadNetButton"
39
- />
40
- </q-btn-group>
41
- </div>
42
-
43
- <!-- 拖拽器 -->
44
- <n-dragger
45
- class="n-uploader-query__query row q-gutter-sm"
46
- v-model="query"
47
- :drag="currentDrag"
48
- @update:model-value="uploader.updateValue"
49
- v-slot="{ mousedown, fromIndex, dragStart, dragEnter, dragEnd }"
50
- >
51
- <!-- 上传图片队列 -->
52
- <template v-if="type === 'image'">
53
-
54
- <!-- 左边方块按钮 -->
55
- <template v-if="! disable && ! readonly && ! rightSquareButton">
56
- <slot
57
- name="square-button"
58
- :size="currentSize"
59
- :show="showSquareButton"
60
- v-if="$slots['square-button']"
61
- />
62
- <div
63
- class="n-uploader-query__button--square"
64
- :style="{
65
- width: toPx(currentSize),
66
- height: toPx(currentSize),
67
- }"
68
- v-show="showSquareButton"
69
- v-else-if="! noButton && currentButtonType === 'square'"
70
- >
71
- <!-- 上传本地图片 -->
72
- <div
73
- class="n-uploader-query__button--square-button cursor-pointer"
74
- @click="uploader.chooseUpload"
75
- >
76
- <q-icon
77
- name="add"
78
- :size="toPx(currentSize / 2)"
79
- />
80
- <div class="n-uploader-query__button--square-button__text" v-if="buttonText">{{buttonText}}</div>
81
- </div>
82
-
83
- <!-- 上传网络图片 -->
84
- <div
85
- class="n-uploader-query__button--square-button q-mt-xs cursor-pointer"
86
- @click="uploader.chooseUploadNet"
87
- v-if="showUploadNetButton"
88
- >
89
- <q-icon
90
- name="cloud_upload"
91
- :size="toPx(currentSize / 3)"
92
- />
93
- <div class="n-uploader-query__button--square-button__text" v-if="buttonText">{{buttonText}}</div>
94
- </div>
95
- </div>
96
- </template>
97
-
98
- <!-- 单个图片 -->
99
- <div
100
- v-for="(fileItem, fileItemIndex) in query"
101
- :key="`query-item-${fileItem.id}`"
102
- class="n-uploader-query__item n-uploader-query__item--image"
103
- :class="[
104
- {
105
- ghost: fileItemIndex === fromIndex,
106
- },
107
- itemClass,
108
- ]"
109
- :style="itemStyle"
110
- :draggable="currentDrag"
111
- @mousedown.self="mousedown($event, fileItemIndex)"
112
- @mouseup="dragEnd"
113
- @dragstart="dragStart($event, fileItemIndex)"
114
- @dragenter="dragEnter($event, fileItemIndex)"
115
- @dragend="dragEnd"
116
- >
117
- <n-img
118
- :src="currentQuery[fileItemIndex].src"
119
- :spinner-size="toPx(currentSize / 2)"
120
- :width="toPx(currentSize)"
121
- :height="toPx(currentSize)"
122
- @click="onFileItemClick(fileItem, fileItemIndex)"
123
- fit="fill"
124
- >
125
- <!-- 如果是外链 -->
126
- <span class="n-uploader-query__item__net" v-if="fileItem.isNet && ! fileItem.isNetUploaded">链接</span>
127
-
128
- <!-- 内容 -->
129
- <div
130
- class="n-uploader-query__item__inner absolute-full flex flex-center no-padding transparent"
131
- :class="{
132
- 'transparent': fileItem.status < UPLOAD_STATUS.success,
133
- }"
134
- v-if="fileItem.status !== UPLOAD_STATUS.success"
135
- >
136
- <!-- 如果上传失败 -->
137
- <div
138
- class="n-uploader-query__item__inner__msg n-uploader-query__item__inner__msg--error"
139
- v-if="fileItem.status === UPLOAD_STATUS.fail"
140
- >{{fileItem.msg}}</div>
141
-
142
- <!-- 上传中前 -->
143
- <q-circular-progress
144
- indeterminate
145
- rounded
146
- :size="toPx(currentSize / 1.5)"
147
- :thickness="0.14"
148
- color="white"
149
- v-if="fileItem.status < UPLOAD_STATUS.uploading"
150
- />
151
-
152
- <!-- 上传中 -->
153
- <q-circular-progress
154
- :value="fileItem.progress"
155
- :size="toPx(currentSize / 1.5)"
156
- :thickness="0.14"
157
- color="white"
158
- track-color="grey-5"
159
- show-value
160
- v-else-if="fileItem.status === UPLOAD_STATUS.uploading"
161
- >
162
- <q-icon
163
- class="cursor-pointer"
164
- name="pause"
165
- :size="toPx(currentSize / 3)"
166
- @click.prevent.stop="uploader.deleteFileItem(fileItem)"
167
- />
168
- </q-circular-progress>
169
- </div>
170
-
171
- <!-- 操作 -->
172
- <div
173
- class="n-uploader-query__item__settings transparent no-padding"
174
- v-if="fileItem.status !== UPLOAD_STATUS.uploading"
175
- >
176
- <!-- 操作插槽-->
177
- <slot
178
- name="settings"
179
- :file="fileItem"
180
- :index="fileItemIndex"
181
- />
182
-
183
- <!-- 预览 -->
184
- <q-icon
185
- class="n-uploader-query__item__settings__icon cursor-pointer"
186
- name="search"
187
- :size="settingsIconSize"
188
- title="预览"
189
- @click.prevent.stop="previewImage(fileItemIndex)"
190
- v-bind="settingsIconProps"
191
- v-if="! noPreview && currentQuery[fileItemIndex].preview_src"
192
- />
193
-
194
- <!-- 删除 -->
195
- <q-icon
196
- class="n-uploader-query__item__settings__icon cursor-pointer"
197
- name="close"
198
- :size="settingsIconSize"
199
- title="删除"
200
- @click.prevent.stop="uploader.deleteFileItem(fileItem)"
201
- v-bind="settingsIconProps"
202
- v-if="! noDelete && ! disable && ! readonly"
203
- />
204
-
205
- </div>
206
-
207
- <!-- 插槽-->
208
- <slot
209
- name="item-append"
210
- :file="fileItem"
211
- :index="fileItemIndex"
212
- />
213
- </n-img>
214
-
215
- </div>
216
-
217
- <!-- 右边方块按钮 -->
218
- <template v-if="! disable && ! readonly && rightSquareButton">
219
- <slot
220
- name="square-button"
221
- :size="currentSize"
222
- :show="showSquareButton"
223
- v-if="$slots['square-button']"
224
- />
225
- <div
226
- class="n-uploader-query__button--square cursor-pointer"
227
- :style="{
228
- width: toPx(currentSize),
229
- height: toPx(currentSize),
230
- }"
231
- @click="uploader.chooseUpload"
232
- v-show="showSquareButton"
233
- v-else-if="! noButton && currentButtonType === 'square'"
234
- >
235
- <q-icon
236
- name="add"
237
- :size="toPx(currentSize / 2)"
238
- />
239
- <div class="n-uploader-query__button--square__text" v-if="buttonText">{{buttonText}}</div>
240
- </div>
241
- </template>
242
- </template>
243
-
244
- <!-- 上传文件队列 -->
245
- <template v-else>
246
-
247
- <!-- 单个文件 -->
248
- <div
249
- v-for="(fileItem, fileItemIndex) in query"
250
- :key="`query-item-${fileItem.id}`"
251
- class="n-uploader-query__item n-uploader-query__item--file"
252
- :class="[
253
- {
254
- ghost: fileItemIndex === fromIndex,
255
- },
256
- itemClass,
257
- ]"
258
- :style="[
259
- {
260
- height: toPx(currentSize),
261
- },
262
- itemStyle,
263
- ]"
264
- :draggable="currentDrag"
265
- @mousedown.self="mousedown($event, fileItemIndex)"
266
- @mouseup="dragEnd"
267
- @dragstart="dragStart($event, fileItemIndex)"
268
- @dragenter="dragEnter($event, fileItemIndex)"
269
- @dragend="dragEnd"
270
- >
271
- <!-- 如果是外链 -->
272
- <span class="n-uploader-query__item__net" v-if="fileItem.isNet && ! fileItem.isNetUploaded">链接</span>
273
-
274
- <!-- 图标 -->
275
- <div
276
- class="n-uploader-query__item__icon"
277
- :style="{
278
- width: toPx(currentSize),
279
- height: toPx(currentSize),
280
- }"
281
- >
282
- <!-- 上传中前 -->
283
- <q-circular-progress
284
- class="n-uploader-query__item__icon__icon"
285
- indeterminate
286
- rounded
287
- :size="toPx(currentSize / 1.8)"
288
- :thickness="0.18"
289
- v-if="fileItem.status < UPLOAD_STATUS.uploading"
290
- />
291
-
292
- <!-- 上传中 -->
293
- <q-circular-progress
294
- class="n-uploader-query__item__icon__icon"
295
- :value="fileItem.progress"
296
- :size="toPx(currentSize / 1.8)"
297
- :thickness="0.18"
298
- show-value
299
- v-else-if="fileItem.status === UPLOAD_STATUS.uploading"
300
- >
301
- <q-icon
302
- class="cursor-pointer"
303
- name="pause"
304
- :size="toPx(currentSize / 3)"
305
- @click.prevent.stop="uploader.deleteFileItem(fileItem)"
306
- />
307
- </q-circular-progress>
308
-
309
- <!-- 文件图标 -->
310
- <q-icon
311
- class="n-uploader-query__item__icon__icon"
312
- name="description"
313
- :size="toPx(currentSize / 1.5)"
314
- v-else-if="type === 'file'"
315
- />
316
-
317
- <!-- 播放图标 -->
318
- <n-thumbnail
319
- class="rounded-borders cursor-pointer"
320
- :src="fileItem.json.p"
321
- :size="currentSize / 1.5"
322
- title="播放"
323
- @click.prevent.stop="uploader.play(fileItem)"
324
- v-else-if="fileItem.json.p"
325
- >
326
- <div class="absolute-full no-padding row items-center justify-center">
327
- <q-icon
328
- name="play_circle"
329
- :size="toPx(currentSize / 3)"
330
- />
331
- </div>
332
- </n-thumbnail>
333
- <q-icon
334
- class="n-uploader-query__item__icon__icon cursor-pointer"
335
- name="play_circle"
336
- title="播放"
337
- :size="toPx(currentSize / 1.5)"
338
- @click.prevent.stop="uploader.play(fileItem)"
339
- v-else
340
- />
341
- </div>
342
-
343
- <!-- 信息 -->
344
- <div class="n-uploader-query__item__info" @click="onFileItemClick(fileItem, fileItemIndex)">
345
- <!-- 标题 -->
346
- <div class="n-uploader-query__item__info__title ellipsis">{{getFileName(fileItem)}}</div>
347
- <!-- 错误提示 -->
348
- <div class="n-uploader-query__item__info__msg--error" v-if="fileItem.status === UPLOAD_STATUS.fail">{{fileItem.msg}}</div>
349
- </div>
350
-
351
- <!-- 操作 -->
352
- <div class="n-uploader-query__item__settings">
353
-
354
- <!-- 操作插槽-->
355
- <slot
356
- name="settings"
357
- :file="fileItem"
358
- :index="fileItemIndex"
359
- />
360
-
361
- <template v-if="fileItem.status === UPLOAD_STATUS.success">
362
-
363
- <!-- 复制地址 -->
364
- <q-icon
365
- class="n-uploader-query__item__settings__icon cursor-pointer"
366
- name="content_copy"
367
- color="white"
368
- :size="settingsIconSize"
369
- title="复制地址"
370
- @click.prevent.stop="uploader.copyUrl(fileItem)"
371
- v-bind="settingsIconProps"
372
- />
373
-
374
- <!-- 修改 -->
375
- <q-icon
376
- class="n-uploader-query__item__settings__icon cursor-pointer"
377
- name="edit"
378
- color="white"
379
- :size="settingsIconSize"
380
- title="修改"
381
- v-bind="settingsIconProps"
382
- v-if="! noEdit && ! disable && ! readonly && ! fileItem.isNet"
383
- >
384
- <q-popup-edit
385
- :model-value="fileItem.title"
386
- buttons
387
- label-set="保存"
388
- @save="uploader.editFileTitle($event, fileItem)"
389
- v-slot="scope"
390
- >
391
- <q-input
392
- v-model="scope.value"
393
- dense
394
- autofocus
395
- counter
396
- :maxlength="50"
397
- @keyup.enter="scope.set"
398
- >
399
- <template v-slot:append>
400
- <span class="text-subtitle2 text-weight-bold">.{{fileItem.ext}}</span>
401
- </template>
402
- </q-input>
403
- </q-popup-edit>
404
- </q-icon>
405
- </template>
406
-
407
- <!-- 删除 -->
408
- <q-icon
409
- class="n-uploader-query__item__settings__icon cursor-pointer"
410
- name="close"
411
- color="white"
412
- :size="settingsIconSize"
413
- title="删除"
414
- @click.prevent.stop="uploader.deleteFileItem(fileItem)"
415
- v-bind="settingsIconProps"
416
- v-if="! noDelete && ! disable && ! readonly"
417
- />
418
- </div>
419
-
420
- <!-- 插槽-->
421
- <slot
422
- name="item-append"
423
- :file="fileItem"
424
- :index="fileItemIndex"
425
- />
426
-
427
- </div>
428
- </template>
429
- </n-dragger>
430
- </div>
431
- </template>
432
-
433
- <script>
434
- import { computed, inject } from 'vue'
435
- import { useQuasar } from 'quasar'
436
-
437
- import $n_has from 'lodash/has'
438
- import $n_get from 'lodash/get'
439
-
440
- import $n_px from '@netang/utils/px'
441
- import $n_forEach from '@netang/utils/forEach'
442
- import $n_isValidArray from '@netang/utils/isValidArray'
443
- import $n_isValidString from '@netang/utils/isValidString'
444
-
445
- import $n_getImage from '../../utils/getImage'
446
- import $n_previewImage from '../../utils/previewImage'
447
-
448
- import NDragger from '../dragger'
449
- import NThumbnail from '../thumbnail'
450
-
451
- import { NUploaderKey } from '../../utils/symbols'
452
-
453
- import {
454
- // 上传状态
455
- UPLOAD_STATUS,
456
- } from '../../utils/uploader'
457
-
458
- export default {
459
-
460
- /**
461
- * 标识
462
- */
463
- name: 'NUploaderQuery',
464
-
465
- /**
466
- * 组件
467
- */
468
- components: {
469
- NDragger,
470
- NThumbnail,
471
- },
472
-
473
- /**
474
- * 声明属性
475
- */
476
- props: {
477
- // 单个文件类名
478
- itemClass: [String, Array, Object],
479
- // 单个文件样式
480
- itemStyle: [String, Array, Object],
481
- // 按钮类型, 可选值 square button
482
- buttonType: {
483
- type: String,
484
- validator: v => [ 'square', 'button' ].includes(v),
485
- },
486
- // 按钮文字
487
- buttonText: String,
488
- // 按钮声明属性
489
- buttonProps: Object,
490
- // 图片/按钮/文件 尺寸
491
- size: Number,
492
- // 是否开启拖拽
493
- drag: {
494
- type: Boolean,
495
- default: true,
496
- },
497
- // 是否禁用
498
- disable: Boolean,
499
- // 是否只读
500
- readonly: Boolean,
501
- // 是否隐藏按钮
502
- noButton: Boolean,
503
- // 是否隐藏预览按钮
504
- noPreview: Boolean,
505
- // 是否隐藏修改按钮
506
- noEdit: Boolean,
507
- // 是否隐藏删除按钮
508
- noDelete: Boolean,
509
- // 自动显示方块按钮
510
- autoShowSquareButton: Boolean,
511
- // 方块按钮在右边显示
512
- rightSquareButton: Boolean,
513
- // 设置图标尺寸
514
- settingsIconSize: {
515
- type: String,
516
- default: 'xs',
517
- },
518
- // 设置图标传参
519
- settingsIconProps: Object,
520
- // 是否显示上传网络外链按钮
521
- showUploadNetButton: Boolean,
522
- },
523
-
524
- /**
525
- * 声明事件
526
- */
527
- emits: [
528
- 'update:modelValue',
529
- 'itemClick',
530
- ],
531
-
532
- /**
533
- * 组合式
534
- */
535
- setup(props, { emit }) {
536
-
537
- // ==========【数据】============================================================================================
538
-
539
- // quasar 对象
540
- const $q = useQuasar()
541
-
542
- // 获取上传器注入数据
543
- const {
544
- // 声明属性
545
- props: uploaderProps,
546
- // 上传器
547
- uploader,
548
- // 文件队列
549
- query,
550
- } = inject(NUploaderKey)
551
-
552
- // ==========【计算属性】=========================================================================================
553
-
554
- /**
555
- * 当前上传文件队列
556
- */
557
- const currentQuery = computed(function () {
558
-
559
- // 如果不是图片
560
- if (uploaderProps.type !== 'image') {
561
- if ($n_isValidArray(query.value)) {
562
- return query.value
563
- }
564
- return []
565
- }
566
-
567
- const lists = []
568
-
569
- $n_forEach(query.value, function (fileItem) {
570
- const newItem = Object.assign({}, fileItem)
571
-
572
- let src = ''
573
- let preview_src = ''
574
-
575
- if ($n_has(fileItem, '__img')) {
576
- src = fileItem.__img
577
- preview_src = src
578
- } else if ($n_isValidString(fileItem.hash)) {
579
- src = $n_getImage(fileItem.hash, { w: $q.platform.is.mobile ? currentSize.value * 2 : currentSize.value })
580
- if (src) {
581
- // 预览地址
582
- preview_src = fileItem.hash
583
- }
584
- }
585
-
586
- lists.push(Object.assign(newItem, {
587
- // 图片地址
588
- src,
589
- // 预览地址
590
- preview_src,
591
- }))
592
- })
593
-
594
- return lists
595
- })
596
-
597
-
598
- /**
599
- * 当前是否开启拖拽
600
- */
601
- const currentDrag = computed(function() {
602
- return props.drag
603
- && query.value.length > 1
604
- && ! props.readonly
605
- && ! props.disable
606
- })
607
-
608
- /**
609
- * 当前按钮类型
610
- */
611
- const currentButtonType = computed(function () {
612
- if (props.buttonType) {
613
- return props.buttonType
614
- }
615
- return uploaderProps.type === 'image' ? 'square' : 'button'
616
- })
617
-
618
- /**
619
- * 当前尺寸
620
- */
621
- const currentSize = computed(function () {
622
- if (props.size) {
623
- return props.size
624
- }
625
- return uploaderProps.type === 'image' ? 70 : 50
626
- })
627
-
628
- /**
629
- * 是否显示方块按钮
630
- */
631
- const showSquareButton = computed(function () {
632
- // 自动显示方块按钮 && 有上传文件限制数量
633
- return props.autoShowSquareButton && uploaderProps.count > 0 ?
634
- // 如果 当前上传文件队列数量 < 上传文件限制数量
635
- currentQuery.value.length < uploaderProps.count
636
- // 始终显示
637
- : true
638
- })
639
-
640
- // ==========【方法】=============================================================================================
641
-
642
- /**
643
- * 预览图片
644
- */
645
- function previewImage(startPosition) {
646
- $n_previewImage({
647
- // 需要预览的图片 URL 数组
648
- images: currentQuery.value.map(e => e.preview_src),
649
- // 图片预览起始位置索引
650
- startPosition,
651
- })
652
- }
653
-
654
- /**
655
- * 获取文件名称
656
- */
657
- function getFileName(fileItem) {
658
- return fileItem.title + ($n_get(fileItem, 'ext') ? '.' + fileItem.ext : '')
659
- }
660
-
661
- /**
662
- * 文件点击
663
- */
664
- function onFileItemClick(file, index) {
665
- emit('itemClick', {
666
- file,
667
- index,
668
- })
669
- }
670
-
671
- // ==========【返回】=============================================================================================
672
-
673
- return {
674
- // 上传状态
675
- UPLOAD_STATUS,
676
- // 上传文件类型, 可选值 file image video audio
677
- type: uploaderProps.type,
678
- // 上传文件数量(0:不限)
679
- count: uploaderProps.count,
680
- // 文件队列
681
- query,
682
- // 当前上传文件队列
683
- currentQuery,
684
-
685
- // 当前是否开启拖拽
686
- currentDrag,
687
- // 当前按钮类型
688
- currentButtonType,
689
- // 当前尺寸
690
- currentSize,
691
- // 是否显示方块按钮
692
- showSquareButton,
693
-
694
- // 上传器
695
- uploader,
696
-
697
- // 预览图片
698
- previewImage,
699
- // 获取文件名称
700
- getFileName,
701
- // 文件点击
702
- onFileItemClick,
703
-
704
- toPx: $n_px,
705
- }
706
- },
707
- }
708
- </script>
709
-
710
- <style lang="scss">
711
- @import "@/assets/sass/variables.scss";
712
-
713
- // 上传器队列
714
- .n-uploader-query {
715
-
716
- // 上传按钮
717
- &__button {
718
-
719
- // 方块
720
- &--square {
721
- display: inline-flex;
722
- overflow: hidden;
723
- flex-direction: column;
724
-
725
- &-button {
726
- flex: 1;
727
- display: flex;
728
- vertical-align: middle;
729
- border: 1px dashed rgba(var(--n-reverse-color-rgb), 0.2);
730
- flex-direction: column;
731
- justify-content: center;
732
- align-items: center;
733
- color: rgba(var(--n-reverse-color-rgb), 0.4);
734
- border-radius: 4px;
735
- overflow: hidden;
736
-
737
- &:hover {
738
- border-color: $primary;
739
- }
740
-
741
- // 文字
742
- &__text {
743
- font-size: 12px;
744
- }
745
- }
746
- }
747
-
748
- // 按钮
749
- &--button {
750
- + .n-uploader-query__query {
751
- margin-top: 0;
752
- }
753
- }
754
- }
755
-
756
- // 上传单个文件
757
- &__item {
758
- position: relative;
759
-
760
- // 开启拖拽
761
- &[draggable="true"] {
762
- cursor: move;
763
- }
764
-
765
- // 当前拖拽占位元素
766
- &.ghost {
767
- &:after {
768
- content: "";
769
- position: absolute;
770
- top: 0;
771
- left: 0;
772
- right: 0;
773
- bottom: 0;
774
- border: 2px dashed mix(#ffffff, $primary, 40%);
775
- border-radius: 4px;
776
- background-color: rgba(255, 255, 255, 0.75);
777
- }
778
-
779
- .n-uploader-query__item__inner,
780
- .n-uploader-query__item__settings {
781
- display: none;
782
- }
783
- }
784
-
785
- &:hover {
786
- .n-uploader-query__item__settings {
787
- visibility: visible;
788
- }
789
- }
790
-
791
- // 单个图片
792
- &--image {
793
- border-radius: 4px;
794
- background-color: rgba(0,0,0,0.1);
795
- overflow: hidden;
796
- }
797
-
798
- // 单个文件
799
- &--file {
800
- position: relative;
801
- width: 300px;
802
- display: flex;
803
- flex-direction: row;
804
- align-items: center;
805
- border-radius: 4px;
806
- color: rgba(var(--n-reverse-color-rgb), 0.8);
807
- background-color: rgba(var(--n-reverse-color-rgb), 0.05);
808
-
809
- // 图标
810
- .n-uploader-query__item__icon {
811
- position: relative;
812
- display: flex;
813
- align-items: center;
814
- justify-content: center;
815
- z-index: 1;
816
-
817
- &__icon {
818
- color: rgba(var(--n-reverse-color-rgb), 0.2);
819
- }
820
- }
821
-
822
- // 信息
823
- .n-uploader-query__item__info {
824
- display: flex;
825
- flex-direction: column;
826
- line-height: 18px;
827
-
828
- &__title {
829
- max-width: 150px;
830
- }
831
-
832
- &__msg--error {
833
- color: $negative;
834
- }
835
- }
836
- }
837
-
838
- // 外链
839
- &__net {
840
- position: absolute;
841
- bottom: -1px;
842
- right: -1px;
843
- color: #ffffff;
844
- padding: 1px 3px;
845
- border-radius: 3px;
846
- background-color: var(--q-primary);
847
- transform: scale(0.7);
848
- pointer-events: none;
849
- }
850
-
851
- //操作
852
- &__settings {
853
- position: absolute;
854
- top: 5px;
855
- right: 5px;
856
- visibility: hidden;
857
-
858
- &__icon {
859
- background-color: rgba(0,0,0,0.5) !important;
860
- color: #ffffff !important;
861
- border-radius: 50%;
862
- padding: 5px;
863
-
864
- + .n-uploader-query__item__settings__icon {
865
- margin-left: 4px;
866
- }
867
-
868
- &:hover {
869
- background-color: rgba(0,0,0,0.8);
870
- }
871
- }
872
- }
873
-
874
- // 内容
875
- &__inner {
876
-
877
- &__msg {
878
- margin: 3px;
879
- padding: 2px 3px;
880
- line-height: 18px;
881
- font-size: 12px;
882
- background-color: rgba(0,0,0,0.6);
883
- border-radius: 6px;
884
-
885
- &--error {
886
- background-color: $warning;
887
- }
888
- }
889
- }
890
- }
891
- }
892
-
893
- @media (max-width: $breakpoint-xs-max){
894
- // 上传器队列
895
- .n-uploader-query {
896
- // 上传单个文件
897
- &__item {
898
- // 单个文件
899
- &--file {
900
- width: 250px;
901
- }
902
- }
903
-
904
- // 信息
905
- .n-uploader-query__item__info {
906
- &__title {
907
- max-width: 200px;
908
- }
909
- }
910
- }
911
- }
912
-
913
- /**
914
- * 手机版
915
- */
916
- body.mobile {
917
- // 上传器队列
918
- .n-uploader-query {
919
- // 上传单个文件
920
- &__item {
921
- &__settings {
922
- visibility: visible;
923
- }
924
- }
925
- }
926
- }
927
-
928
- /**
929
- * 暗黑
930
- */
931
- .body--dark {
932
- .n-uploader-query__item--file {
933
- .n-uploader-query__item__settings {
934
- // 图标
935
- &__icon {
936
- background-color: rgba(255,255,255, 0.1);
937
-
938
- &:hover {
939
- background-color: rgba(255,255,255, 0.2);
940
- }
941
- }
942
- }
943
- }
944
- }
945
- </style>
1
+ <template>
2
+ <div class="n-uploader-query">
3
+
4
+ <!-- 上传按钮 -->
5
+ <slot
6
+ name="button"
7
+ :disable="disable || readonly"
8
+ :size="currentSize"
9
+ v-if="$slots.button"
10
+ />
11
+ <div
12
+ class="n-uploader-query__button--button"
13
+ v-else-if="! noButton && currentButtonType === 'button'"
14
+ >
15
+ <!-- 按钮组-->
16
+ <q-btn-group outline>
17
+ <!-- 上传本地图片 -->
18
+ <q-btn
19
+ class="n-button-icon"
20
+ :label="buttonText || '上传'"
21
+ @click="uploader.chooseUpload"
22
+ color="primary"
23
+ outline
24
+ :disable="disable || readonly"
25
+ unelevated
26
+ v-bind="buttonProps"
27
+ />
28
+ <!-- 上传网络图片 -->
29
+ <q-btn
30
+ class="n-button-icon q-px-sm"
31
+ icon="cloud_upload"
32
+ @click="uploader.chooseUploadNet"
33
+ color="primary"
34
+ outline
35
+ :disable="disable || readonly"
36
+ unelevated
37
+ v-bind="buttonProps"
38
+ v-if="showUploadNetButton"
39
+ />
40
+ </q-btn-group>
41
+ </div>
42
+
43
+ <!-- 拖拽器 -->
44
+ <n-dragger
45
+ class="n-uploader-query__query row q-gutter-sm"
46
+ v-model="query"
47
+ :drag="currentDrag"
48
+ @update:model-value="uploader.updateValue"
49
+ v-slot="{ mousedown, fromIndex, dragStart, dragEnter, dragEnd }"
50
+ >
51
+ <!-- 上传图片队列 -->
52
+ <template v-if="type === 'image'">
53
+
54
+ <!-- 左边方块按钮 -->
55
+ <template v-if="! disable && ! readonly && ! rightSquareButton">
56
+ <slot
57
+ name="square-button"
58
+ :size="currentSize"
59
+ :show="showSquareButton"
60
+ v-if="$slots['square-button']"
61
+ />
62
+ <div
63
+ class="n-uploader-query__button--square"
64
+ :style="{
65
+ width: toPx(currentSize),
66
+ height: toPx(currentSize),
67
+ }"
68
+ v-show="showSquareButton"
69
+ v-else-if="! noButton && currentButtonType === 'square'"
70
+ >
71
+ <!-- 上传本地图片 -->
72
+ <div
73
+ class="n-uploader-query__button--square-button cursor-pointer"
74
+ @click="uploader.chooseUpload"
75
+ >
76
+ <q-icon
77
+ name="add"
78
+ :size="toPx(currentSize / 2)"
79
+ />
80
+ <div class="n-uploader-query__button--square-button__text" v-if="buttonText">{{buttonText}}</div>
81
+ </div>
82
+
83
+ <!-- 上传网络图片 -->
84
+ <div
85
+ class="n-uploader-query__button--square-button q-mt-xs cursor-pointer"
86
+ @click="uploader.chooseUploadNet"
87
+ v-if="showUploadNetButton"
88
+ >
89
+ <q-icon
90
+ name="cloud_upload"
91
+ :size="toPx(currentSize / 3)"
92
+ />
93
+ <div class="n-uploader-query__button--square-button__text" v-if="buttonText">{{buttonText}}</div>
94
+ </div>
95
+ </div>
96
+ </template>
97
+
98
+ <!-- 单个图片 -->
99
+ <div
100
+ v-for="(fileItem, fileItemIndex) in query"
101
+ :key="`query-item-${fileItem.id}`"
102
+ class="n-uploader-query__item n-uploader-query__item--image"
103
+ :class="[
104
+ {
105
+ ghost: fileItemIndex === fromIndex,
106
+ },
107
+ itemClass,
108
+ ]"
109
+ :style="itemStyle"
110
+ :draggable="currentDrag"
111
+ @mousedown.self="mousedown($event, fileItemIndex)"
112
+ @mouseup="dragEnd"
113
+ @dragstart="dragStart($event, fileItemIndex)"
114
+ @dragenter="dragEnter($event, fileItemIndex)"
115
+ @dragend="dragEnd"
116
+ >
117
+ <n-img
118
+ :src="currentQuery[fileItemIndex].src"
119
+ :spinner-size="toPx(currentSize / 2)"
120
+ :width="toPx(currentSize)"
121
+ :height="toPx(currentSize)"
122
+ @click="onFileItemClick(fileItem, fileItemIndex)"
123
+ fit="fill"
124
+ >
125
+ <!-- 如果是外链 -->
126
+ <span class="n-uploader-query__item__net" v-if="fileItem.isNet && ! fileItem.isNetUploaded">链接</span>
127
+
128
+ <!-- 内容 -->
129
+ <div
130
+ class="n-uploader-query__item__inner absolute-full flex flex-center no-padding transparent"
131
+ :class="{
132
+ 'transparent': fileItem.status < UPLOAD_STATUS.success,
133
+ }"
134
+ v-if="fileItem.status !== UPLOAD_STATUS.success"
135
+ >
136
+ <!-- 如果上传失败 -->
137
+ <div
138
+ class="n-uploader-query__item__inner__msg n-uploader-query__item__inner__msg--error"
139
+ v-if="fileItem.status === UPLOAD_STATUS.fail"
140
+ >{{fileItem.msg}}</div>
141
+
142
+ <!-- 上传中前 -->
143
+ <q-circular-progress
144
+ indeterminate
145
+ rounded
146
+ :size="toPx(currentSize / 1.5)"
147
+ :thickness="0.14"
148
+ color="white"
149
+ v-if="fileItem.status < UPLOAD_STATUS.uploading"
150
+ />
151
+
152
+ <!-- 上传中 -->
153
+ <q-circular-progress
154
+ :value="fileItem.progress"
155
+ :size="toPx(currentSize / 1.5)"
156
+ :thickness="0.14"
157
+ color="white"
158
+ track-color="grey-5"
159
+ show-value
160
+ v-else-if="fileItem.status === UPLOAD_STATUS.uploading"
161
+ >
162
+ <q-icon
163
+ class="cursor-pointer"
164
+ name="pause"
165
+ :size="toPx(currentSize / 3)"
166
+ @click.prevent.stop="uploader.deleteFileItem(fileItem)"
167
+ />
168
+ </q-circular-progress>
169
+ </div>
170
+
171
+ <!-- 操作 -->
172
+ <div
173
+ class="n-uploader-query__item__settings transparent no-padding"
174
+ v-if="fileItem.status !== UPLOAD_STATUS.uploading"
175
+ >
176
+ <!-- 操作插槽-->
177
+ <slot
178
+ name="settings"
179
+ :file="fileItem"
180
+ :index="fileItemIndex"
181
+ />
182
+
183
+ <!-- 预览 -->
184
+ <q-icon
185
+ class="n-uploader-query__item__settings__icon cursor-pointer"
186
+ name="search"
187
+ :size="settingsIconSize"
188
+ title="预览"
189
+ @click.prevent.stop="previewImage(fileItemIndex)"
190
+ v-bind="settingsIconProps"
191
+ v-if="! noPreview && currentQuery[fileItemIndex].preview_src"
192
+ />
193
+
194
+ <!-- 删除 -->
195
+ <q-icon
196
+ class="n-uploader-query__item__settings__icon cursor-pointer"
197
+ name="close"
198
+ :size="settingsIconSize"
199
+ title="删除"
200
+ @click.prevent.stop="uploader.deleteFileItem(fileItem)"
201
+ v-bind="settingsIconProps"
202
+ v-if="! noDelete && ! disable && ! readonly"
203
+ />
204
+
205
+ </div>
206
+
207
+ <!-- 插槽-->
208
+ <slot
209
+ name="item-append"
210
+ :file="fileItem"
211
+ :index="fileItemIndex"
212
+ />
213
+ </n-img>
214
+
215
+ </div>
216
+
217
+ <!-- 右边方块按钮 -->
218
+ <template v-if="! disable && ! readonly && rightSquareButton">
219
+ <slot
220
+ name="square-button"
221
+ :size="currentSize"
222
+ :show="showSquareButton"
223
+ v-if="$slots['square-button']"
224
+ />
225
+ <div
226
+ class="n-uploader-query__button--square cursor-pointer"
227
+ :style="{
228
+ width: toPx(currentSize),
229
+ height: toPx(currentSize),
230
+ }"
231
+ @click="uploader.chooseUpload"
232
+ v-show="showSquareButton"
233
+ v-else-if="! noButton && currentButtonType === 'square'"
234
+ >
235
+ <q-icon
236
+ name="add"
237
+ :size="toPx(currentSize / 2)"
238
+ />
239
+ <div class="n-uploader-query__button--square__text" v-if="buttonText">{{buttonText}}</div>
240
+ </div>
241
+ </template>
242
+ </template>
243
+
244
+ <!-- 上传文件队列 -->
245
+ <template v-else>
246
+
247
+ <!-- 单个文件 -->
248
+ <div
249
+ v-for="(fileItem, fileItemIndex) in query"
250
+ :key="`query-item-${fileItem.id}`"
251
+ class="n-uploader-query__item n-uploader-query__item--file"
252
+ :class="[
253
+ {
254
+ ghost: fileItemIndex === fromIndex,
255
+ },
256
+ itemClass,
257
+ ]"
258
+ :style="[
259
+ {
260
+ height: toPx(currentSize),
261
+ },
262
+ itemStyle,
263
+ ]"
264
+ :draggable="currentDrag"
265
+ @mousedown.self="mousedown($event, fileItemIndex)"
266
+ @mouseup="dragEnd"
267
+ @dragstart="dragStart($event, fileItemIndex)"
268
+ @dragenter="dragEnter($event, fileItemIndex)"
269
+ @dragend="dragEnd"
270
+ >
271
+ <!-- 如果是外链 -->
272
+ <span class="n-uploader-query__item__net" v-if="fileItem.isNet && ! fileItem.isNetUploaded">链接</span>
273
+
274
+ <!-- 图标 -->
275
+ <div
276
+ class="n-uploader-query__item__icon"
277
+ :style="{
278
+ width: toPx(currentSize),
279
+ height: toPx(currentSize),
280
+ }"
281
+ >
282
+ <!-- 上传中前 -->
283
+ <q-circular-progress
284
+ class="n-uploader-query__item__icon__icon"
285
+ indeterminate
286
+ rounded
287
+ :size="toPx(currentSize / 1.8)"
288
+ :thickness="0.18"
289
+ v-if="fileItem.status < UPLOAD_STATUS.uploading"
290
+ />
291
+
292
+ <!-- 上传中 -->
293
+ <q-circular-progress
294
+ class="n-uploader-query__item__icon__icon"
295
+ :value="fileItem.progress"
296
+ :size="toPx(currentSize / 1.8)"
297
+ :thickness="0.18"
298
+ show-value
299
+ v-else-if="fileItem.status === UPLOAD_STATUS.uploading"
300
+ >
301
+ <q-icon
302
+ class="cursor-pointer"
303
+ name="pause"
304
+ :size="toPx(currentSize / 3)"
305
+ @click.prevent.stop="uploader.deleteFileItem(fileItem)"
306
+ />
307
+ </q-circular-progress>
308
+
309
+ <!-- 文件图标 -->
310
+ <q-icon
311
+ class="n-uploader-query__item__icon__icon"
312
+ name="description"
313
+ :size="toPx(currentSize / 1.5)"
314
+ v-else-if="type === 'file'"
315
+ />
316
+
317
+ <!-- 播放图标 -->
318
+ <n-thumbnail
319
+ class="rounded-borders cursor-pointer"
320
+ :src="fileItem.json.p"
321
+ :size="currentSize / 1.5"
322
+ title="播放"
323
+ @click.prevent.stop="uploader.play(fileItem)"
324
+ v-else-if="fileItem.json.p"
325
+ >
326
+ <div class="absolute-full no-padding row items-center justify-center">
327
+ <q-icon
328
+ name="play_circle"
329
+ :size="toPx(currentSize / 3)"
330
+ />
331
+ </div>
332
+ </n-thumbnail>
333
+ <q-icon
334
+ class="n-uploader-query__item__icon__icon cursor-pointer"
335
+ name="play_circle"
336
+ title="播放"
337
+ :size="toPx(currentSize / 1.5)"
338
+ @click.prevent.stop="uploader.play(fileItem)"
339
+ v-else
340
+ />
341
+ </div>
342
+
343
+ <!-- 信息 -->
344
+ <div class="n-uploader-query__item__info" @click="onFileItemClick(fileItem, fileItemIndex)">
345
+ <!-- 标题 -->
346
+ <div class="n-uploader-query__item__info__title ellipsis">{{getFileName(fileItem)}}</div>
347
+ <!-- 错误提示 -->
348
+ <div class="n-uploader-query__item__info__msg--error" v-if="fileItem.status === UPLOAD_STATUS.fail">{{fileItem.msg}}</div>
349
+ </div>
350
+
351
+ <!-- 操作 -->
352
+ <div class="n-uploader-query__item__settings">
353
+
354
+ <!-- 操作插槽-->
355
+ <slot
356
+ name="settings"
357
+ :file="fileItem"
358
+ :index="fileItemIndex"
359
+ />
360
+
361
+ <template v-if="fileItem.status === UPLOAD_STATUS.success">
362
+
363
+ <!-- 复制地址 -->
364
+ <q-icon
365
+ class="n-uploader-query__item__settings__icon cursor-pointer"
366
+ name="content_copy"
367
+ color="white"
368
+ :size="settingsIconSize"
369
+ title="复制地址"
370
+ @click.prevent.stop="uploader.copyUrl(fileItem)"
371
+ v-bind="settingsIconProps"
372
+ />
373
+
374
+ <!-- 修改 -->
375
+ <q-icon
376
+ class="n-uploader-query__item__settings__icon cursor-pointer"
377
+ name="edit"
378
+ color="white"
379
+ :size="settingsIconSize"
380
+ title="修改"
381
+ v-bind="settingsIconProps"
382
+ v-if="! noEdit && ! disable && ! readonly && ! fileItem.isNet"
383
+ >
384
+ <q-popup-edit
385
+ :model-value="fileItem.title"
386
+ buttons
387
+ label-set="保存"
388
+ @save="uploader.editFileTitle($event, fileItem)"
389
+ v-slot="scope"
390
+ >
391
+ <q-input
392
+ v-model="scope.value"
393
+ dense
394
+ autofocus
395
+ counter
396
+ :maxlength="50"
397
+ @keyup.enter="scope.set"
398
+ >
399
+ <template v-slot:append>
400
+ <span class="text-subtitle2 text-weight-bold">.{{fileItem.ext}}</span>
401
+ </template>
402
+ </q-input>
403
+ </q-popup-edit>
404
+ </q-icon>
405
+ </template>
406
+
407
+ <!-- 删除 -->
408
+ <q-icon
409
+ class="n-uploader-query__item__settings__icon cursor-pointer"
410
+ name="close"
411
+ color="white"
412
+ :size="settingsIconSize"
413
+ title="删除"
414
+ @click.prevent.stop="uploader.deleteFileItem(fileItem)"
415
+ v-bind="settingsIconProps"
416
+ v-if="! noDelete && ! disable && ! readonly"
417
+ />
418
+ </div>
419
+
420
+ <!-- 插槽-->
421
+ <slot
422
+ name="item-append"
423
+ :file="fileItem"
424
+ :index="fileItemIndex"
425
+ />
426
+
427
+ </div>
428
+ </template>
429
+ </n-dragger>
430
+ </div>
431
+ </template>
432
+
433
+ <script>
434
+ import { computed, inject } from 'vue'
435
+ import { useQuasar } from 'quasar'
436
+
437
+ import $n_has from 'lodash/has'
438
+ import $n_get from 'lodash/get'
439
+
440
+ import $n_px from '@netang/utils/px'
441
+ import $n_forEach from '@netang/utils/forEach'
442
+ import $n_isValidArray from '@netang/utils/isValidArray'
443
+ import $n_isValidString from '@netang/utils/isValidString'
444
+
445
+ import $n_getImage from '../../utils/getImage'
446
+ import $n_previewImage from '../../utils/previewImage'
447
+
448
+ import NDragger from '../dragger'
449
+ import NThumbnail from '../thumbnail'
450
+
451
+ import { NUploaderKey } from '../../utils/symbols'
452
+
453
+ import {
454
+ // 上传状态
455
+ UPLOAD_STATUS,
456
+ } from '../../utils/uploader'
457
+
458
+ export default {
459
+
460
+ /**
461
+ * 标识
462
+ */
463
+ name: 'NUploaderQuery',
464
+
465
+ /**
466
+ * 组件
467
+ */
468
+ components: {
469
+ NDragger,
470
+ NThumbnail,
471
+ },
472
+
473
+ /**
474
+ * 声明属性
475
+ */
476
+ props: {
477
+ // 单个文件类名
478
+ itemClass: [String, Array, Object],
479
+ // 单个文件样式
480
+ itemStyle: [String, Array, Object],
481
+ // 按钮类型, 可选值 square button
482
+ buttonType: {
483
+ type: String,
484
+ validator: v => [ 'square', 'button' ].includes(v),
485
+ },
486
+ // 按钮文字
487
+ buttonText: String,
488
+ // 按钮声明属性
489
+ buttonProps: Object,
490
+ // 图片/按钮/文件 尺寸
491
+ size: Number,
492
+ // 是否开启拖拽
493
+ drag: {
494
+ type: Boolean,
495
+ default: true,
496
+ },
497
+ // 是否禁用
498
+ disable: Boolean,
499
+ // 是否只读
500
+ readonly: Boolean,
501
+ // 是否隐藏按钮
502
+ noButton: Boolean,
503
+ // 是否隐藏预览按钮
504
+ noPreview: Boolean,
505
+ // 是否隐藏修改按钮
506
+ noEdit: Boolean,
507
+ // 是否隐藏删除按钮
508
+ noDelete: Boolean,
509
+ // 自动显示方块按钮
510
+ autoShowSquareButton: Boolean,
511
+ // 方块按钮在右边显示
512
+ rightSquareButton: Boolean,
513
+ // 设置图标尺寸
514
+ settingsIconSize: {
515
+ type: String,
516
+ default: 'xs',
517
+ },
518
+ // 设置图标传参
519
+ settingsIconProps: Object,
520
+ // 是否显示上传网络外链按钮
521
+ showUploadNetButton: Boolean,
522
+ },
523
+
524
+ /**
525
+ * 声明事件
526
+ */
527
+ emits: [
528
+ 'update:modelValue',
529
+ 'itemClick',
530
+ ],
531
+
532
+ /**
533
+ * 组合式
534
+ */
535
+ setup(props, { emit }) {
536
+
537
+ // ==========【数据】============================================================================================
538
+
539
+ // quasar 对象
540
+ const $q = useQuasar()
541
+
542
+ // 获取上传器注入数据
543
+ const {
544
+ // 声明属性
545
+ props: uploaderProps,
546
+ // 上传器
547
+ uploader,
548
+ // 文件队列
549
+ query,
550
+ } = inject(NUploaderKey)
551
+
552
+ // ==========【计算属性】=========================================================================================
553
+
554
+ /**
555
+ * 当前上传文件队列
556
+ */
557
+ const currentQuery = computed(function () {
558
+
559
+ // 如果不是图片
560
+ if (uploaderProps.type !== 'image') {
561
+ if ($n_isValidArray(query.value)) {
562
+ return query.value
563
+ }
564
+ return []
565
+ }
566
+
567
+ const lists = []
568
+
569
+ $n_forEach(query.value, function (fileItem) {
570
+ const newItem = Object.assign({}, fileItem)
571
+
572
+ let src = ''
573
+ let preview_src = ''
574
+
575
+ if ($n_has(fileItem, '__img')) {
576
+ src = fileItem.__img
577
+ preview_src = src
578
+ } else if ($n_isValidString(fileItem.hash)) {
579
+ src = $n_getImage(fileItem.hash, { w: $q.platform.is.mobile ? currentSize.value * 2 : currentSize.value })
580
+ if (src) {
581
+ // 预览地址
582
+ preview_src = fileItem.hash
583
+ }
584
+ }
585
+
586
+ lists.push(Object.assign(newItem, {
587
+ // 图片地址
588
+ src,
589
+ // 预览地址
590
+ preview_src,
591
+ }))
592
+ })
593
+
594
+ return lists
595
+ })
596
+
597
+
598
+ /**
599
+ * 当前是否开启拖拽
600
+ */
601
+ const currentDrag = computed(function() {
602
+ return props.drag
603
+ && query.value.length > 1
604
+ && ! props.readonly
605
+ && ! props.disable
606
+ })
607
+
608
+ /**
609
+ * 当前按钮类型
610
+ */
611
+ const currentButtonType = computed(function () {
612
+ if (props.buttonType) {
613
+ return props.buttonType
614
+ }
615
+ return uploaderProps.type === 'image' ? 'square' : 'button'
616
+ })
617
+
618
+ /**
619
+ * 当前尺寸
620
+ */
621
+ const currentSize = computed(function () {
622
+ if (props.size) {
623
+ return props.size
624
+ }
625
+ return uploaderProps.type === 'image' ? 70 : 50
626
+ })
627
+
628
+ /**
629
+ * 是否显示方块按钮
630
+ */
631
+ const showSquareButton = computed(function () {
632
+ // 自动显示方块按钮 && 有上传文件限制数量
633
+ return props.autoShowSquareButton && uploaderProps.count > 0 ?
634
+ // 如果 当前上传文件队列数量 < 上传文件限制数量
635
+ currentQuery.value.length < uploaderProps.count
636
+ // 始终显示
637
+ : true
638
+ })
639
+
640
+ // ==========【方法】=============================================================================================
641
+
642
+ /**
643
+ * 预览图片
644
+ */
645
+ function previewImage(startPosition) {
646
+ $n_previewImage({
647
+ // 需要预览的图片 URL 数组
648
+ images: currentQuery.value.map(e => e.preview_src),
649
+ // 图片预览起始位置索引
650
+ startPosition,
651
+ })
652
+ }
653
+
654
+ /**
655
+ * 获取文件名称
656
+ */
657
+ function getFileName(fileItem) {
658
+ return fileItem.title + ($n_get(fileItem, 'ext') ? '.' + fileItem.ext : '')
659
+ }
660
+
661
+ /**
662
+ * 文件点击
663
+ */
664
+ function onFileItemClick(file, index) {
665
+ emit('itemClick', {
666
+ file,
667
+ index,
668
+ })
669
+ }
670
+
671
+ // ==========【返回】=============================================================================================
672
+
673
+ return {
674
+ // 上传状态
675
+ UPLOAD_STATUS,
676
+ // 上传文件类型, 可选值 file image video audio
677
+ type: uploaderProps.type,
678
+ // 上传文件数量(0:不限)
679
+ count: uploaderProps.count,
680
+ // 文件队列
681
+ query,
682
+ // 当前上传文件队列
683
+ currentQuery,
684
+
685
+ // 当前是否开启拖拽
686
+ currentDrag,
687
+ // 当前按钮类型
688
+ currentButtonType,
689
+ // 当前尺寸
690
+ currentSize,
691
+ // 是否显示方块按钮
692
+ showSquareButton,
693
+
694
+ // 上传器
695
+ uploader,
696
+
697
+ // 预览图片
698
+ previewImage,
699
+ // 获取文件名称
700
+ getFileName,
701
+ // 文件点击
702
+ onFileItemClick,
703
+
704
+ toPx: $n_px,
705
+ }
706
+ },
707
+ }
708
+ </script>
709
+
710
+ <style lang="scss">
711
+ @import "@/assets/sass/variables.scss";
712
+
713
+ // 上传器队列
714
+ .n-uploader-query {
715
+
716
+ // 上传按钮
717
+ &__button {
718
+
719
+ // 方块
720
+ &--square {
721
+ display: inline-flex;
722
+ overflow: hidden;
723
+ flex-direction: column;
724
+
725
+ &-button {
726
+ flex: 1;
727
+ display: flex;
728
+ vertical-align: middle;
729
+ border: 1px dashed rgba(var(--n-reverse-color-rgb), 0.2);
730
+ flex-direction: column;
731
+ justify-content: center;
732
+ align-items: center;
733
+ color: rgba(var(--n-reverse-color-rgb), 0.4);
734
+ border-radius: 4px;
735
+ overflow: hidden;
736
+
737
+ &:hover {
738
+ border-color: $primary;
739
+ }
740
+
741
+ // 文字
742
+ &__text {
743
+ font-size: 12px;
744
+ }
745
+ }
746
+ }
747
+
748
+ // 按钮
749
+ &--button {
750
+ + .n-uploader-query__query {
751
+ margin-top: 0;
752
+ }
753
+ }
754
+ }
755
+
756
+ // 上传单个文件
757
+ &__item {
758
+ position: relative;
759
+
760
+ // 开启拖拽
761
+ &[draggable="true"] {
762
+ cursor: move;
763
+ }
764
+
765
+ // 当前拖拽占位元素
766
+ &.ghost {
767
+ &:after {
768
+ content: "";
769
+ position: absolute;
770
+ top: 0;
771
+ left: 0;
772
+ right: 0;
773
+ bottom: 0;
774
+ border: 2px dashed mix(#ffffff, $primary, 40%);
775
+ border-radius: 4px;
776
+ background-color: rgba(255, 255, 255, 0.75);
777
+ }
778
+
779
+ .n-uploader-query__item__inner,
780
+ .n-uploader-query__item__settings {
781
+ display: none;
782
+ }
783
+ }
784
+
785
+ &:hover {
786
+ .n-uploader-query__item__settings {
787
+ visibility: visible;
788
+ }
789
+ }
790
+
791
+ // 单个图片
792
+ &--image {
793
+ border-radius: 4px;
794
+ background-color: rgba(0,0,0,0.1);
795
+ overflow: hidden;
796
+ }
797
+
798
+ // 单个文件
799
+ &--file {
800
+ position: relative;
801
+ width: 300px;
802
+ display: flex;
803
+ flex-direction: row;
804
+ align-items: center;
805
+ border-radius: 4px;
806
+ color: rgba(var(--n-reverse-color-rgb), 0.8);
807
+ background-color: rgba(var(--n-reverse-color-rgb), 0.05);
808
+
809
+ // 图标
810
+ .n-uploader-query__item__icon {
811
+ position: relative;
812
+ display: flex;
813
+ align-items: center;
814
+ justify-content: center;
815
+ z-index: 1;
816
+
817
+ &__icon {
818
+ color: rgba(var(--n-reverse-color-rgb), 0.2);
819
+ }
820
+ }
821
+
822
+ // 信息
823
+ .n-uploader-query__item__info {
824
+ display: flex;
825
+ flex-direction: column;
826
+ line-height: 18px;
827
+
828
+ &__title {
829
+ max-width: 150px;
830
+ }
831
+
832
+ &__msg--error {
833
+ color: $negative;
834
+ }
835
+ }
836
+ }
837
+
838
+ // 外链
839
+ &__net {
840
+ position: absolute;
841
+ bottom: -1px;
842
+ right: -1px;
843
+ color: #ffffff;
844
+ padding: 1px 3px;
845
+ border-radius: 3px;
846
+ background-color: var(--q-primary);
847
+ transform: scale(0.7);
848
+ pointer-events: none;
849
+ }
850
+
851
+ //操作
852
+ &__settings {
853
+ position: absolute;
854
+ top: 5px;
855
+ right: 5px;
856
+ visibility: hidden;
857
+
858
+ &__icon {
859
+ background-color: rgba(0,0,0,0.5) !important;
860
+ color: #ffffff !important;
861
+ border-radius: 50%;
862
+ padding: 5px;
863
+
864
+ + .n-uploader-query__item__settings__icon {
865
+ margin-left: 4px;
866
+ }
867
+
868
+ &:hover {
869
+ background-color: rgba(0,0,0,0.8);
870
+ }
871
+ }
872
+ }
873
+
874
+ // 内容
875
+ &__inner {
876
+
877
+ &__msg {
878
+ margin: 3px;
879
+ padding: 2px 3px;
880
+ line-height: 18px;
881
+ font-size: 12px;
882
+ background-color: rgba(0,0,0,0.6);
883
+ border-radius: 6px;
884
+
885
+ &--error {
886
+ background-color: $warning;
887
+ }
888
+ }
889
+ }
890
+ }
891
+ }
892
+
893
+ @media (max-width: $breakpoint-xs-max){
894
+ // 上传器队列
895
+ .n-uploader-query {
896
+ // 上传单个文件
897
+ &__item {
898
+ // 单个文件
899
+ &--file {
900
+ width: 250px;
901
+ }
902
+ }
903
+
904
+ // 信息
905
+ .n-uploader-query__item__info {
906
+ &__title {
907
+ max-width: 200px;
908
+ }
909
+ }
910
+ }
911
+ }
912
+
913
+ /**
914
+ * 手机版
915
+ */
916
+ body.mobile {
917
+ // 上传器队列
918
+ .n-uploader-query {
919
+ // 上传单个文件
920
+ &__item {
921
+ &__settings {
922
+ visibility: visible;
923
+ }
924
+ }
925
+ }
926
+ }
927
+
928
+ /**
929
+ * 暗黑
930
+ */
931
+ .body--dark {
932
+ .n-uploader-query__item--file {
933
+ .n-uploader-query__item__settings {
934
+ // 图标
935
+ &__icon {
936
+ background-color: rgba(255,255,255, 0.1);
937
+
938
+ &:hover {
939
+ background-color: rgba(255,255,255, 0.2);
940
+ }
941
+ }
942
+ }
943
+ }
944
+ }
945
+ </style>