vxe-pc-ui 4.14.4 → 4.14.6

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 (480) hide show
  1. package/LICENSE +21 -21
  2. package/README.en.md +72 -72
  3. package/README.ja-JP.md +72 -72
  4. package/README.md +364 -364
  5. package/README.zh-TW.md +73 -73
  6. package/es/tree/src/tree.js +31 -2
  7. package/es/tree-select/src/tree-select.js +2 -0
  8. package/es/ui/index.js +1 -1
  9. package/es/ui/src/log.js +1 -1
  10. package/lib/index.umd.js +2359 -2257
  11. package/lib/index.umd.min.js +1 -1
  12. package/lib/tree/src/tree.js +27 -2
  13. package/lib/tree/src/tree.min.js +1 -1
  14. package/lib/tree-select/src/tree-select.js +2 -0
  15. package/lib/tree-select/src/tree-select.min.js +1 -1
  16. package/lib/ui/index.js +1 -1
  17. package/lib/ui/index.min.js +1 -1
  18. package/lib/ui/src/log.js +1 -1
  19. package/lib/ui/src/log.min.js +1 -1
  20. package/package.json +88 -88
  21. package/packages/alert/index.ts +16 -16
  22. package/packages/alert/src/alert.ts +124 -124
  23. package/packages/anchor/index.ts +16 -16
  24. package/packages/anchor/src/anchor-link.ts +121 -121
  25. package/packages/anchor/src/anchor.ts +237 -237
  26. package/packages/anchor/src/util.ts +23 -23
  27. package/packages/anchor-link/index.ts +16 -16
  28. package/packages/avatar/index.ts +16 -16
  29. package/packages/avatar/src/avatar.ts +149 -149
  30. package/packages/backtop/index.ts +16 -16
  31. package/packages/backtop/src/backtop.ts +314 -314
  32. package/packages/badge/index.ts +16 -16
  33. package/packages/badge/src/badge.ts +100 -100
  34. package/packages/breadcrumb/index.ts +16 -16
  35. package/packages/breadcrumb/src/breadcrumb-item.ts +106 -106
  36. package/packages/breadcrumb/src/breadcrumb.ts +92 -92
  37. package/packages/breadcrumb-item/index.ts +16 -16
  38. package/packages/button/index.ts +16 -16
  39. package/packages/button/src/button-group.ts +110 -110
  40. package/packages/button/src/button.ts +841 -841
  41. package/packages/button-group/index.ts +16 -16
  42. package/packages/calendar/index.ts +16 -16
  43. package/packages/calendar/src/calendar.ts +1351 -1351
  44. package/packages/card/index.ts +16 -16
  45. package/packages/card/src/card.ts +175 -175
  46. package/packages/carousel/index.ts +16 -16
  47. package/packages/carousel/src/carousel-item.ts +102 -102
  48. package/packages/carousel/src/carousel.ts +414 -414
  49. package/packages/carousel/src/util.ts +21 -21
  50. package/packages/carousel-item/index.ts +16 -16
  51. package/packages/cascader/index.ts +16 -16
  52. package/packages/cascader/src/cascader.ts +741 -741
  53. package/packages/checkbox/index.ts +16 -16
  54. package/packages/checkbox/src/button.ts +144 -144
  55. package/packages/checkbox/src/checkbox.ts +154 -154
  56. package/packages/checkbox/src/group.ts +222 -222
  57. package/packages/checkbox-button/index.ts +16 -16
  58. package/packages/checkbox-group/index.ts +16 -16
  59. package/packages/col/index.ts +16 -16
  60. package/packages/collapse/index.ts +16 -16
  61. package/packages/collapse/src/collapse-pane.ts +114 -114
  62. package/packages/collapse/src/collapse.ts +284 -284
  63. package/packages/collapse/src/util.ts +21 -21
  64. package/packages/collapse-pane/index.ts +16 -16
  65. package/packages/color-picker/index.ts +16 -16
  66. package/packages/color-picker/src/color-picker.ts +1109 -1109
  67. package/packages/color-picker/src/util.ts +198 -198
  68. package/packages/components.ts +307 -307
  69. package/packages/context-menu/index.ts +54 -54
  70. package/packages/context-menu/src/context-menu.ts +681 -681
  71. package/packages/countdown/index.ts +16 -16
  72. package/packages/countdown/src/countdown.ts +262 -262
  73. package/packages/date-panel/index.ts +16 -16
  74. package/packages/date-panel/src/date-panel.ts +1809 -1809
  75. package/packages/date-panel/src/util.ts +244 -244
  76. package/packages/date-picker/index.ts +16 -16
  77. package/packages/date-picker/src/date-picker.ts +1071 -1071
  78. package/packages/date-range-picker/index.ts +16 -16
  79. package/packages/date-range-picker/src/date-range-picker.ts +1280 -1280
  80. package/packages/drawer/index.ts +77 -77
  81. package/packages/drawer/src/drawer.ts +657 -657
  82. package/packages/dynamics/index.ts +89 -89
  83. package/packages/empty/index.ts +16 -16
  84. package/packages/empty/src/empty.ts +100 -100
  85. package/packages/form/index.ts +16 -16
  86. package/packages/form/render/index.ts +598 -598
  87. package/packages/form/src/form-config-item.ts +72 -72
  88. package/packages/form/src/form-group.ts +86 -86
  89. package/packages/form/src/form-item.ts +174 -174
  90. package/packages/form/src/form.ts +987 -987
  91. package/packages/form/src/itemInfo.ts +80 -80
  92. package/packages/form/src/render.ts +387 -387
  93. package/packages/form/src/util.ts +93 -93
  94. package/packages/form-gather/index.ts +26 -26
  95. package/packages/form-group/index.ts +16 -16
  96. package/packages/form-item/index.ts +16 -16
  97. package/packages/icon/index.ts +16 -16
  98. package/packages/icon/src/icon.ts +75 -75
  99. package/packages/icon-picker/index.ts +16 -16
  100. package/packages/icon-picker/src/icon-picker.ts +626 -626
  101. package/packages/image/index.ts +16 -16
  102. package/packages/image/src/group.ts +153 -153
  103. package/packages/image/src/image.ts +298 -298
  104. package/packages/image/src/preview.ts +672 -672
  105. package/packages/image/src/util.ts +59 -59
  106. package/packages/image-group/index.ts +16 -16
  107. package/packages/image-preview/index.ts +19 -19
  108. package/packages/index.ts +4 -4
  109. package/packages/input/index.ts +16 -16
  110. package/packages/input/src/input.ts +2788 -2788
  111. package/packages/language/ar-EG.ts +840 -840
  112. package/packages/language/de-DE.ts +840 -840
  113. package/packages/language/en-US.ts +840 -840
  114. package/packages/language/es-ES.ts +840 -840
  115. package/packages/language/fr-FR.ts +840 -840
  116. package/packages/language/hu-HU.ts +840 -840
  117. package/packages/language/hy-AM.ts +840 -840
  118. package/packages/language/id-ID.ts +840 -840
  119. package/packages/language/it-IT.ts +840 -840
  120. package/packages/language/ja-JP.ts +840 -840
  121. package/packages/language/ko-KR.ts +840 -840
  122. package/packages/language/ms-MY.ts +840 -840
  123. package/packages/language/nb-NO.ts +840 -840
  124. package/packages/language/pt-BR.ts +840 -840
  125. package/packages/language/ru-RU.ts +840 -840
  126. package/packages/language/th-TH.ts +840 -840
  127. package/packages/language/ug-CN.ts +840 -840
  128. package/packages/language/uk-UA.ts +840 -840
  129. package/packages/language/uz-UZ.ts +840 -840
  130. package/packages/language/vi-VN.ts +840 -840
  131. package/packages/language/zh-CHT.ts +840 -840
  132. package/packages/language/zh-CN.ts +840 -840
  133. package/packages/language/zh-HK.ts +3 -3
  134. package/packages/language/zh-MO.ts +3 -3
  135. package/packages/language/zh-TC.ts +3 -3
  136. package/packages/language/zh-TW.ts +3 -3
  137. package/packages/layout-aside/index.ts +16 -16
  138. package/packages/layout-aside/src/layout-aside.ts +123 -123
  139. package/packages/layout-body/index.ts +16 -16
  140. package/packages/layout-body/src/layout-body.ts +142 -142
  141. package/packages/layout-container/index.ts +16 -16
  142. package/packages/layout-container/src/layout-container.ts +82 -82
  143. package/packages/layout-footer/index.ts +16 -16
  144. package/packages/layout-footer/src/layout-footer.ts +74 -74
  145. package/packages/layout-header/index.ts +16 -16
  146. package/packages/layout-header/src/layout-header.ts +73 -73
  147. package/packages/link/index.ts +16 -16
  148. package/packages/link/src/link.ts +161 -161
  149. package/packages/list/index.ts +16 -16
  150. package/packages/list/src/list.ts +442 -442
  151. package/packages/loading/index.ts +34 -34
  152. package/packages/loading/src/loading.ts +152 -152
  153. package/packages/mention/index.ts +16 -16
  154. package/packages/mention/src/mention.ts +71 -71
  155. package/packages/menu/index.ts +16 -16
  156. package/packages/menu/src/menu.ts +581 -581
  157. package/packages/modal/index.ts +136 -136
  158. package/packages/modal/src/modal.ts +1494 -1494
  159. package/packages/notice-bar/index.ts +16 -16
  160. package/packages/notice-bar/src/notice-bar.ts +181 -181
  161. package/packages/number-input/index.ts +16 -16
  162. package/packages/number-input/src/number-input.ts +1096 -1096
  163. package/packages/number-input/src/util.ts +12 -12
  164. package/packages/optgroup/index.ts +16 -16
  165. package/packages/option/index.ts +16 -16
  166. package/packages/pager/index.ts +16 -16
  167. package/packages/pager/src/pager.ts +769 -769
  168. package/packages/password-input/index.ts +16 -16
  169. package/packages/password-input/src/password-input.ts +378 -378
  170. package/packages/print/index.ts +18 -18
  171. package/packages/print/src/page-break.ts +92 -92
  172. package/packages/print/src/print.ts +272 -272
  173. package/packages/print/src/util.ts +284 -284
  174. package/packages/print-page-break/index.ts +16 -16
  175. package/packages/pulldown/index.ts +16 -16
  176. package/packages/pulldown/src/pulldown.ts +457 -457
  177. package/packages/radio/index.ts +16 -16
  178. package/packages/radio/src/button.ts +173 -173
  179. package/packages/radio/src/group.ts +213 -213
  180. package/packages/radio/src/radio.ts +180 -180
  181. package/packages/radio-button/index.ts +16 -16
  182. package/packages/radio-group/index.ts +16 -16
  183. package/packages/rate/index.ts +16 -16
  184. package/packages/rate/src/rate.ts +192 -192
  185. package/packages/result/index.ts +16 -16
  186. package/packages/result/src/result.ts +112 -112
  187. package/packages/row/index.ts +16 -16
  188. package/packages/row/src/col.ts +136 -136
  189. package/packages/row/src/row.ts +119 -119
  190. package/packages/segmented/index.ts +16 -16
  191. package/packages/segmented/src/segmented.ts +264 -264
  192. package/packages/select/index.ts +16 -16
  193. package/packages/select/src/optgroup.ts +49 -49
  194. package/packages/select/src/option-info.ts +20 -20
  195. package/packages/select/src/option.ts +47 -47
  196. package/packages/select/src/select.ts +1699 -1699
  197. package/packages/select/src/util.ts +47 -47
  198. package/packages/slider/index.ts +16 -16
  199. package/packages/slider/src/slider.ts +304 -304
  200. package/packages/split/index.ts +16 -16
  201. package/packages/split-pane/index.ts +17 -17
  202. package/packages/splitter/index.ts +16 -16
  203. package/packages/splitter/src/splitter-panel.ts +145 -145
  204. package/packages/splitter/src/splitter.ts +1009 -1009
  205. package/packages/splitter/src/util.ts +21 -21
  206. package/packages/splitter-panel/index.ts +16 -16
  207. package/packages/steps/index.ts +16 -16
  208. package/packages/steps/src/steps.ts +68 -68
  209. package/packages/switch/index.ts +16 -16
  210. package/packages/switch/src/switch.ts +237 -237
  211. package/packages/tab-pane/index.ts +16 -16
  212. package/packages/table-select/index.ts +16 -16
  213. package/packages/table-select/src/table-select.ts +800 -800
  214. package/packages/tabs/index.ts +16 -16
  215. package/packages/tabs/src/tab-pane.ts +117 -117
  216. package/packages/tabs/src/tabs.ts +940 -940
  217. package/packages/tabs/src/util.ts +21 -21
  218. package/packages/tag/index.ts +16 -16
  219. package/packages/tag/src/tag.ts +187 -187
  220. package/packages/text/index.ts +16 -16
  221. package/packages/text/src/text.ts +260 -260
  222. package/packages/text-ellipsis/index.ts +16 -16
  223. package/packages/text-ellipsis/src/text-ellipsis.ts +282 -282
  224. package/packages/textarea/index.ts +16 -16
  225. package/packages/textarea/src/textarea.ts +373 -373
  226. package/packages/timeline/index.ts +16 -16
  227. package/packages/timeline/src/timeline-item.ts +67 -67
  228. package/packages/timeline/src/timeline.ts +71 -71
  229. package/packages/timeline-item/index.ts +16 -16
  230. package/packages/tip/index.ts +19 -19
  231. package/packages/tip/src/tip.ts +129 -129
  232. package/packages/tooltip/index.ts +16 -16
  233. package/packages/tooltip/src/tooltip.ts +589 -589
  234. package/packages/tour/index.ts +16 -16
  235. package/packages/tour/src/tour.ts +71 -71
  236. package/packages/tree/index.ts +16 -16
  237. package/packages/tree/src/store.ts +14 -14
  238. package/packages/tree/src/tree.ts +2825 -2795
  239. package/packages/tree/src/util.ts +45 -45
  240. package/packages/tree-select/index.ts +16 -16
  241. package/packages/tree-select/src/tree-select.ts +979 -977
  242. package/packages/ui/index.ts +697 -697
  243. package/packages/ui/src/anime.ts +52 -52
  244. package/packages/ui/src/comp.ts +3 -3
  245. package/packages/ui/src/dom.ts +279 -279
  246. package/packages/ui/src/log.ts +6 -6
  247. package/packages/ui/src/utils.ts +49 -49
  248. package/packages/ui/src/vn.ts +39 -39
  249. package/packages/upload/index.ts +20 -20
  250. package/packages/upload/src/upload.ts +1919 -1919
  251. package/packages/upload/src/util.ts +109 -109
  252. package/packages/watermark/index.ts +31 -31
  253. package/packages/watermark/src/util.ts +176 -176
  254. package/packages/watermark/src/watermark.ts +168 -168
  255. package/styles/all.scss +90 -90
  256. package/styles/base.scss +16 -16
  257. package/styles/components/alert.scss +101 -101
  258. package/styles/components/anchor.scss +44 -44
  259. package/styles/components/avatar.scss +115 -115
  260. package/styles/components/backtop.scss +82 -82
  261. package/styles/components/badge.scss +45 -45
  262. package/styles/components/breadcrumb.scss +29 -29
  263. package/styles/components/button-group.scss +30 -30
  264. package/styles/components/button.scss +415 -415
  265. package/styles/components/calendar.scss +471 -471
  266. package/styles/components/card.scss +121 -121
  267. package/styles/components/carousel.scss +184 -184
  268. package/styles/components/cascader.scss +140 -140
  269. package/styles/components/checkbox-button.scss +57 -57
  270. package/styles/components/checkbox.scss +81 -81
  271. package/styles/components/collapse.scss +56 -56
  272. package/styles/components/color-picker.scss +409 -409
  273. package/styles/components/context-menu.scss +102 -102
  274. package/styles/components/countdown.scss +35 -35
  275. package/styles/components/date-panel.scss +505 -505
  276. package/styles/components/date-picker.scss +247 -247
  277. package/styles/components/date-range-picker.scss +252 -252
  278. package/styles/components/drawer.scss +298 -298
  279. package/styles/components/empty.scss +79 -79
  280. package/styles/components/form.scss +668 -668
  281. package/styles/components/icon-picker.scss +211 -211
  282. package/styles/components/icon.scss +1048 -1048
  283. package/styles/components/image-group.scss +2 -2
  284. package/styles/components/image-preview.scss +215 -215
  285. package/styles/components/image.scss +16 -16
  286. package/styles/components/input.scss +846 -846
  287. package/styles/components/layout-aside.scss +22 -22
  288. package/styles/components/layout-body.scss +14 -14
  289. package/styles/components/layout-container.scss +13 -13
  290. package/styles/components/layout-footer.scss +14 -14
  291. package/styles/components/layout-header.scss +11 -11
  292. package/styles/components/link.scss +115 -115
  293. package/styles/components/list.scss +40 -40
  294. package/styles/components/loading.scss +137 -137
  295. package/styles/components/menu.scss +150 -150
  296. package/styles/components/modal.scss +480 -480
  297. package/styles/components/notice-bar.scss +91 -91
  298. package/styles/components/number-input.scss +283 -283
  299. package/styles/components/old-icon.scss +4 -4
  300. package/styles/components/pager.scss +282 -282
  301. package/styles/components/password-input.scss +374 -374
  302. package/styles/components/print.scss +3 -3
  303. package/styles/components/pulldown.scss +75 -75
  304. package/styles/components/radio-button.scss +57 -57
  305. package/styles/components/radio.scss +79 -79
  306. package/styles/components/rate.scss +76 -76
  307. package/styles/components/result.scss +91 -91
  308. package/styles/components/row.scss +69 -69
  309. package/styles/components/segmented.scss +215 -215
  310. package/styles/components/select.scss +244 -244
  311. package/styles/components/slider.scss +139 -139
  312. package/styles/components/split.scss +1 -1
  313. package/styles/components/splitter.scss +318 -318
  314. package/styles/components/switch.scss +128 -128
  315. package/styles/components/table-select.scss +105 -105
  316. package/styles/components/tabs.scss +745 -745
  317. package/styles/components/tag.scss +184 -184
  318. package/styles/components/text-ellipsis.scss +130 -130
  319. package/styles/components/text.scss +123 -123
  320. package/styles/components/textarea.scss +106 -106
  321. package/styles/components/tip.scss +97 -97
  322. package/styles/components/tooltip.scss +141 -141
  323. package/styles/components/tree-select.scss +166 -166
  324. package/styles/components/tree.scss +294 -294
  325. package/styles/components/upload.scss +497 -497
  326. package/styles/components/watermark.scss +26 -26
  327. package/styles/helpers/baseMixin.scss +95 -95
  328. package/styles/helpers/baseVar.scss +3 -3
  329. package/styles/helpers/placement.scss +38 -38
  330. package/styles/theme/base.scss +214 -214
  331. package/styles/theme/dark.scss +119 -119
  332. package/styles/theme/light.scss +118 -118
  333. package/styles/variable.scss +111 -111
  334. package/types/all.d.ts +327 -327
  335. package/types/components/alert.d.ts +87 -87
  336. package/types/components/anchor-link.d.ts +91 -91
  337. package/types/components/anchor.d.ts +104 -104
  338. package/types/components/avatar.d.ts +88 -88
  339. package/types/components/backtop.d.ts +122 -122
  340. package/types/components/badge.d.ts +76 -76
  341. package/types/components/breadcrumb-item.d.ts +80 -80
  342. package/types/components/breadcrumb.d.ts +87 -87
  343. package/types/components/button-group.d.ts +120 -120
  344. package/types/components/button.d.ts +323 -323
  345. package/types/components/calendar.d.ts +264 -264
  346. package/types/components/card.d.ts +93 -93
  347. package/types/components/carousel-item.d.ts +75 -75
  348. package/types/components/carousel.d.ts +134 -134
  349. package/types/components/cascader.d.ts +263 -263
  350. package/types/components/checkbox-button.d.ts +103 -103
  351. package/types/components/checkbox-group.d.ts +143 -143
  352. package/types/components/checkbox.d.ts +123 -123
  353. package/types/components/col.d.ts +80 -80
  354. package/types/components/colgroup.d.ts +137 -137
  355. package/types/components/collapse-pane.d.ts +89 -89
  356. package/types/components/collapse.d.ts +121 -121
  357. package/types/components/color-picker.d.ts +176 -176
  358. package/types/components/column.d.ts +841 -841
  359. package/types/components/context-menu.d.ts +289 -289
  360. package/types/components/countdown.d.ts +112 -112
  361. package/types/components/date-panel.d.ts +280 -280
  362. package/types/components/date-picker.d.ts +332 -332
  363. package/types/components/date-range-picker.d.ts +352 -352
  364. package/types/components/drawer.d.ts +299 -299
  365. package/types/components/empty.d.ts +78 -78
  366. package/types/components/flow-design.d.ts +85 -85
  367. package/types/components/flow-view.d.ts +85 -85
  368. package/types/components/form-design.d.ts +376 -376
  369. package/types/components/form-gather.d.ts +124 -124
  370. package/types/components/form-group.d.ts +77 -77
  371. package/types/components/form-item.d.ts +411 -411
  372. package/types/components/form-view.d.ts +183 -183
  373. package/types/components/form.d.ts +468 -468
  374. package/types/components/gantt-module/gantt-view.d.ts +177 -177
  375. package/types/components/gantt-module/index.d.ts +1 -1
  376. package/types/components/gantt-plugins/extend-gantt-chart.d.ts +131 -131
  377. package/types/components/gantt-plugins/index.d.ts +1 -1
  378. package/types/components/gantt.d.ts +1194 -1185
  379. package/types/components/grid.d.ts +1040 -1040
  380. package/types/components/icon-picker.d.ts +196 -196
  381. package/types/components/icon.d.ts +87 -87
  382. package/types/components/image-group.d.ts +127 -127
  383. package/types/components/image-preview.d.ts +167 -167
  384. package/types/components/image.d.ts +173 -173
  385. package/types/components/input.d.ts +435 -435
  386. package/types/components/layout-aside.d.ts +80 -80
  387. package/types/components/layout-body.d.ts +91 -91
  388. package/types/components/layout-container.d.ts +73 -73
  389. package/types/components/layout-footer.d.ts +73 -73
  390. package/types/components/layout-header.d.ts +69 -69
  391. package/types/components/link.d.ts +111 -111
  392. package/types/components/list-design.d.ts +190 -190
  393. package/types/components/list-view.d.ts +199 -199
  394. package/types/components/list.d.ts +204 -204
  395. package/types/components/loading.d.ts +103 -103
  396. package/types/components/mention.d.ts +77 -77
  397. package/types/components/menu.d.ts +211 -211
  398. package/types/components/modal.d.ts +542 -542
  399. package/types/components/notice-bar.d.ts +102 -102
  400. package/types/components/number-input.d.ts +309 -309
  401. package/types/components/optgroup.d.ts +88 -88
  402. package/types/components/option.d.ts +103 -103
  403. package/types/components/pager.d.ts +335 -335
  404. package/types/components/password-input.d.ts +142 -142
  405. package/types/components/print-page-break.d.ts +69 -69
  406. package/types/components/print.d.ts +206 -206
  407. package/types/components/pulldown.d.ts +231 -231
  408. package/types/components/radio-button.d.ts +114 -114
  409. package/types/components/radio-group.d.ts +144 -144
  410. package/types/components/radio.d.ts +129 -129
  411. package/types/components/rate.d.ts +88 -88
  412. package/types/components/result.d.ts +84 -84
  413. package/types/components/row.d.ts +79 -79
  414. package/types/components/segmented.d.ts +123 -123
  415. package/types/components/select.d.ts +527 -527
  416. package/types/components/slider.d.ts +126 -126
  417. package/types/components/split-pane.d.ts +133 -133
  418. package/types/components/split.d.ts +312 -312
  419. package/types/components/splitter-panel.d.ts +105 -105
  420. package/types/components/splitter.d.ts +288 -288
  421. package/types/components/steps.d.ts +68 -68
  422. package/types/components/switch.d.ts +133 -133
  423. package/types/components/tab-pane.d.ts +114 -114
  424. package/types/components/table-module/custom.d.ts +123 -123
  425. package/types/components/table-module/edit.d.ts +243 -243
  426. package/types/components/table-module/export.d.ts +96 -96
  427. package/types/components/table-module/filter.d.ts +140 -140
  428. package/types/components/table-module/index.d.ts +7 -7
  429. package/types/components/table-module/keyboard.d.ts +26 -26
  430. package/types/components/table-module/menu.d.ts +28 -28
  431. package/types/components/table-module/validator.d.ts +53 -53
  432. package/types/components/table-plugins/extend-cell-area.d.ts +770 -770
  433. package/types/components/table-plugins/extend-pivot-table.d.ts +58 -58
  434. package/types/components/table-plugins/filters-combination.d.ts +15 -15
  435. package/types/components/table-plugins/filters-complex-input.d.ts +9 -9
  436. package/types/components/table-plugins/index.d.ts +4 -4
  437. package/types/components/table-select.d.ts +219 -219
  438. package/types/components/table.d.ts +7465 -7465
  439. package/types/components/tabs.d.ts +332 -332
  440. package/types/components/tag.d.ts +114 -114
  441. package/types/components/text-ellipsis.d.ts +112 -112
  442. package/types/components/text.d.ts +122 -122
  443. package/types/components/textarea.d.ts +247 -247
  444. package/types/components/timeline-item.d.ts +75 -75
  445. package/types/components/timeline.d.ts +77 -77
  446. package/types/components/tip.d.ts +83 -83
  447. package/types/components/toolbar.d.ts +336 -336
  448. package/types/components/tooltip.d.ts +180 -180
  449. package/types/components/tour.d.ts +77 -77
  450. package/types/components/tree-select.d.ts +310 -310
  451. package/types/components/tree.d.ts +843 -833
  452. package/types/components/upload.d.ts +437 -437
  453. package/types/components/watermark.d.ts +120 -120
  454. package/types/handles/form-design.d.ts +50 -50
  455. package/types/handles/index.d.ts +3 -3
  456. package/types/handles/list-design.d.ts +2 -2
  457. package/types/handles/table.d.ts +15 -15
  458. package/types/index.d.ts +8 -8
  459. package/types/ui/commands.d.ts +57 -57
  460. package/types/ui/formats.d.ts +62 -62
  461. package/types/ui/global-config.d.ts +254 -254
  462. package/types/ui/global-icon.d.ts +292 -292
  463. package/types/ui/hooks.d.ts +13 -13
  464. package/types/ui/index.d.ts +96 -96
  465. package/types/ui/interceptor.d.ts +52 -52
  466. package/types/ui/menus.d.ts +77 -77
  467. package/types/ui/renderer.d.ts +1041 -1041
  468. package/types/ui/validators.d.ts +38 -38
  469. /package/es/icon/{iconfont.1778169084473.ttf → iconfont.1778317220469.ttf} +0 -0
  470. /package/es/icon/{iconfont.1778169084473.woff → iconfont.1778317220469.woff} +0 -0
  471. /package/es/icon/{iconfont.1778169084473.woff2 → iconfont.1778317220469.woff2} +0 -0
  472. /package/es/{iconfont.1778169084473.ttf → iconfont.1778317220469.ttf} +0 -0
  473. /package/es/{iconfont.1778169084473.woff → iconfont.1778317220469.woff} +0 -0
  474. /package/es/{iconfont.1778169084473.woff2 → iconfont.1778317220469.woff2} +0 -0
  475. /package/lib/icon/style/{iconfont.1778169084473.ttf → iconfont.1778317220469.ttf} +0 -0
  476. /package/lib/icon/style/{iconfont.1778169084473.woff → iconfont.1778317220469.woff} +0 -0
  477. /package/lib/icon/style/{iconfont.1778169084473.woff2 → iconfont.1778317220469.woff2} +0 -0
  478. /package/lib/{iconfont.1778169084473.ttf → iconfont.1778317220469.ttf} +0 -0
  479. /package/lib/{iconfont.1778169084473.woff → iconfont.1778317220469.woff} +0 -0
  480. /package/lib/{iconfont.1778169084473.woff2 → iconfont.1778317220469.woff2} +0 -0
@@ -1,1919 +1,1919 @@
1
- import { ref, h, reactive, watch, computed, TransitionGroup, PropType, inject, onBeforeUnmount, onMounted, nextTick } from 'vue'
2
- import { defineVxeComponent } from '../../ui/src/comp'
3
- import XEUtils from 'xe-utils'
4
- import { VxeUI, getConfig, getI18n, getIcon, useSize, createEvent, globalEvents, renderEmptyElement } from '../../ui'
5
- import { getSlotVNs } from '../../ui/src/vn'
6
- import { errLog, warnLog } from '../../ui/src/log'
7
- import { initTpImg, getTpImg, getEventTargetNode, toCssUnit } from '../../ui/src/dom'
8
- import { readLocalFile } from './util'
9
- import VxeButtonComponent from '../../button/src/button'
10
-
11
- import type { VxeUploadDefines, VxeUploadPropTypes, UploadReactData, UploadInternalData, UploadPrivateMethods, UploadMethods, VxeUploadEmits, UploadPrivateRef, VxeUploadPrivateComputed, VxeUploadConstructor, VxeUploadPrivateMethods, VxeFormDefines, VxeFormConstructor, VxeFormPrivateMethods, ValueOf, VxeComponentEventParams } from '../../../types'
12
- import type { VxeTableConstructor, VxeTablePrivateMethods } from '../../../types/components/table'
13
-
14
- function createReactData (): UploadReactData {
15
- return {
16
- isDragUploadStatus: false,
17
- showMorePopup: false,
18
- isActivated: false,
19
- fileList: [],
20
- fileCacheMaps: {},
21
- isDragMove: false,
22
- dragIndex: -1,
23
- dragTipText: ''
24
- }
25
- }
26
-
27
- function createInternalData (): UploadInternalData {
28
- return {
29
- moreId: XEUtils.uniqueId('upload'),
30
- imagePreviewTypes: ['jpg', 'jpeg', 'png', 'gif'],
31
- prevDragIndex: -1
32
- // prevDragPos: ''
33
- }
34
- }
35
-
36
- export default defineVxeComponent({
37
- name: 'VxeUpload',
38
- props: {
39
- modelValue: [Array, String, Object] as PropType<VxeUploadPropTypes.ModelValue>,
40
- showList: {
41
- type: Boolean as PropType<VxeUploadPropTypes.ShowList>,
42
- default: () => getConfig().upload.showList
43
- },
44
- moreConfig: Object as PropType<VxeUploadPropTypes.MoreConfig>,
45
- readonly: {
46
- type: Boolean as PropType<VxeUploadPropTypes.Readonly>,
47
- default: null
48
- },
49
- disabled: {
50
- type: Boolean as PropType<VxeUploadPropTypes.Disabled>,
51
- default: null
52
- },
53
- autoSubmit: {
54
- type: Boolean as PropType<VxeUploadPropTypes.AutoSubmit>,
55
- default: () => getConfig().upload.autoSubmit
56
- },
57
- mode: {
58
- type: String as PropType<VxeUploadPropTypes.Mode>,
59
- default: () => getConfig().upload.mode
60
- },
61
- imageTypes: {
62
- type: Array as PropType<VxeUploadPropTypes.ImageTypes>,
63
- default: () => XEUtils.clone(getConfig().upload.imageTypes, true)
64
- },
65
- imageConfig: {
66
- type: Object as PropType<VxeUploadPropTypes.ImageConfig>,
67
- default: () => XEUtils.clone(getConfig().upload.imageConfig, true)
68
- },
69
- /**
70
- * 已废弃,被 image-config 替换
71
- * @deprecated
72
- */
73
- imageStyle: {
74
- type: Object as PropType<VxeUploadPropTypes.ImageStyle>,
75
- default: () => XEUtils.clone(getConfig().upload.imageStyle, true)
76
- },
77
- fileTypes: {
78
- type: Array as PropType<VxeUploadPropTypes.FileTypes>,
79
- default: () => XEUtils.clone(getConfig().upload.fileTypes, true)
80
- },
81
- dragSort: Boolean as PropType<VxeUploadPropTypes.DragSort>,
82
- dragToUpload: {
83
- type: Boolean as PropType<VxeUploadPropTypes.DragToUpload>,
84
- default: () => XEUtils.clone(getConfig().upload.dragToUpload, true)
85
- },
86
- dragPlaceholder: {
87
- type: String as PropType<VxeUploadPropTypes.DragPlaceholder>,
88
- default: () => getConfig().upload.dragPlaceholder
89
- },
90
- pasteToUpload: {
91
- type: Boolean as PropType<VxeUploadPropTypes.PasteToUpload>,
92
- default: () => XEUtils.clone(getConfig().upload.pasteToUpload, true)
93
- },
94
- keyField: String as PropType<VxeUploadPropTypes.KeyField>,
95
- singleMode: Boolean as PropType<VxeUploadPropTypes.SingleMode>,
96
- urlMode: Boolean as PropType<VxeUploadPropTypes.UrlMode>,
97
- urlArgs: {
98
- type: Boolean as PropType<VxeUploadPropTypes.UrlArgs>,
99
- default: () => getConfig().upload.urlArgs
100
- },
101
- multiple: Boolean as PropType<VxeUploadPropTypes.Multiple>,
102
- limitSize: {
103
- type: [String, Number] as PropType<VxeUploadPropTypes.LimitSize>,
104
- default: () => getConfig().upload.limitSize
105
- },
106
- showLimitSize: {
107
- type: Boolean as PropType<VxeUploadPropTypes.ShowLimitSize>,
108
- default: () => getConfig().upload.showLimitSize
109
- },
110
- limitSizeText: {
111
- type: [String, Number, Function] as PropType<VxeUploadPropTypes.LimitSizeText>,
112
- default: () => getConfig().upload.limitSizeText
113
- },
114
- limitCount: {
115
- type: [String, Number] as PropType<VxeUploadPropTypes.LimitCount>,
116
- default: () => getConfig().upload.limitCount
117
- },
118
- showLimitCount: {
119
- type: Boolean as PropType<VxeUploadPropTypes.ShowLimitCount>,
120
- default: () => getConfig().upload.showLimitCount
121
- },
122
- limitCountText: {
123
- type: [String, Number, Function] as PropType<VxeUploadPropTypes.LimitCountText>,
124
- default: () => getConfig().upload.limitCountText
125
- },
126
- nameField: {
127
- type: String as PropType<VxeUploadPropTypes.NameField>,
128
- default: () => getConfig().upload.nameField
129
- },
130
- typeField: {
131
- type: String as PropType<VxeUploadPropTypes.TypeField>,
132
- default: () => getConfig().upload.typeField
133
- },
134
- urlField: {
135
- type: String as PropType<VxeUploadPropTypes.UrlField>,
136
- default: () => getConfig().upload.urlField
137
- },
138
- sizeField: {
139
- type: String as PropType<VxeUploadPropTypes.SizeField>,
140
- default: () => getConfig().upload.sizeField
141
- },
142
- showErrorStatus: {
143
- type: Boolean as PropType<VxeUploadPropTypes.ShowErrorStatus>,
144
- default: () => getConfig().upload.showErrorStatus
145
- },
146
- showProgress: {
147
- type: Boolean as PropType<VxeUploadPropTypes.ShowProgress>,
148
- default: () => getConfig().upload.showProgress
149
- },
150
- progressText: {
151
- type: [String, Number, Function] as PropType<VxeUploadPropTypes.ProgressText>,
152
- default: () => getConfig().upload.progressText
153
- },
154
- previewImageConfig: Object as PropType<VxeUploadPropTypes.PreviewImageConfig>,
155
- showSubmitButton: Boolean as PropType<VxeUploadPropTypes.ShowSubmitButton>,
156
- autoHiddenButton: {
157
- type: Boolean as PropType<VxeUploadPropTypes.AutoHiddenButton>,
158
- default: () => getConfig().upload.autoHiddenButton
159
- },
160
- showUploadButton: {
161
- type: Boolean as PropType<VxeUploadPropTypes.ShowUploadButton>,
162
- default: () => getConfig().upload.showUploadButton
163
- },
164
- buttonText: {
165
- type: [String, Number, Function] as PropType<VxeUploadPropTypes.ButtonText>,
166
- default: () => getConfig().upload.buttonText
167
- },
168
- buttonIcon: {
169
- type: String as PropType<VxeUploadPropTypes.ButtonIcon>,
170
- default: () => getConfig().upload.buttonIcon
171
- },
172
- showButtonText: {
173
- type: Boolean as PropType<VxeUploadPropTypes.ShowButtonText>,
174
- default: () => getConfig().upload.showButtonText
175
- },
176
- showButtonIcon: {
177
- type: Boolean as PropType<VxeUploadPropTypes.ShowButtonIcon>,
178
- default: () => getConfig().upload.showButtonIcon
179
- },
180
- showRemoveButton: {
181
- type: Boolean as PropType<VxeUploadPropTypes.ShowRemoveButton>,
182
- default: () => getConfig().upload.showRemoveButton
183
- },
184
- showDownloadButton: {
185
- type: Boolean as PropType<VxeUploadPropTypes.ShowDownloadButton>,
186
- default: () => getConfig().upload.showDownloadButton
187
- },
188
- showPreview: {
189
- type: Boolean as PropType<VxeUploadPropTypes.ShowPreview>,
190
- default: () => getConfig().upload.showPreview
191
- },
192
- showTip: {
193
- type: Boolean as PropType<VxeUploadPropTypes.ShowTip>,
194
- default: () => null
195
- },
196
- maxSimultaneousUploads: {
197
- type: Number as PropType<VxeUploadPropTypes.MaxSimultaneousUploads>,
198
- default: () => getConfig().upload.maxSimultaneousUploads
199
- },
200
- tipText: [String, Number, Function] as PropType<VxeUploadPropTypes.TipText>,
201
- hintText: String as PropType<VxeUploadPropTypes.HintText>,
202
- previewMethod: Function as PropType<VxeUploadPropTypes.PreviewMethod>,
203
- beforeSelectMethod: Function as PropType<VxeUploadPropTypes.BeforeSelectMethod>,
204
- uploadMethod: Function as PropType<VxeUploadPropTypes.UploadMethod>,
205
- beforeRemoveMethod: Function as PropType<VxeUploadPropTypes.BeforeRemoveMethod>,
206
- removeMethod: Function as PropType<VxeUploadPropTypes.RemoveMethod>,
207
- beforeDownloadMethod: Function as PropType<VxeUploadPropTypes.BeforeDownloadMethod>,
208
- downloadMethod: Function as PropType<VxeUploadPropTypes.DownloadMethod>,
209
- getUrlMethod: Function as PropType<VxeUploadPropTypes.GetUrlMethod>,
210
- getThumbnailUrlMethod: Function as PropType<VxeUploadPropTypes.GetThumbnailUrlMethod>,
211
- size: {
212
- type: String as PropType<VxeUploadPropTypes.Size>,
213
- default: () => getConfig().upload.size || getConfig().size
214
- }
215
- },
216
- emits: [
217
- 'update:modelValue',
218
- 'add',
219
- 'remove',
220
- 'remove-fail',
221
- 'download',
222
- 'download-fail',
223
- 'upload-success',
224
- 'upload-error',
225
- 'sort-dragend',
226
- 'more-visible'
227
- ] as VxeUploadEmits,
228
- setup (props, context) {
229
- const { emit, slots } = context
230
-
231
- const $xeForm = inject<VxeFormConstructor & VxeFormPrivateMethods | null>('$xeForm', null)
232
- const formItemInfo = inject<VxeFormDefines.ProvideItemInfo | null>('xeFormItemInfo', null)
233
- const $xeTable = inject<(VxeTableConstructor & VxeTablePrivateMethods) | null>('$xeTable', null)
234
-
235
- const xID = XEUtils.uniqueId()
236
-
237
- const { computeSize } = useSize(props)
238
-
239
- const refElem = ref<HTMLDivElement>()
240
- const refPopupElem = ref<HTMLDivElement>()
241
- const refDragLineElem = ref<HTMLDivElement>()
242
- const refModalDragLineElem = ref<HTMLDivElement>()
243
-
244
- const reactData = reactive(createReactData())
245
-
246
- const internalData = createInternalData()
247
-
248
- const refMaps: UploadPrivateRef = {
249
- refElem
250
- }
251
-
252
- const computeFormReadonly = computed(() => {
253
- const { readonly } = props
254
- if (readonly === null) {
255
- if ($xeForm) {
256
- return $xeForm.props.readonly
257
- }
258
- return false
259
- }
260
- return readonly
261
- })
262
-
263
- const computeIsDisabled = computed(() => {
264
- const { disabled } = props
265
- if (disabled === null) {
266
- if ($xeForm) {
267
- return $xeForm.props.disabled
268
- }
269
- return false
270
- }
271
- return disabled
272
- })
273
-
274
- const computeKeyField = computed(() => {
275
- return props.keyField || '_X_KEY'
276
- })
277
-
278
- const computeIsImage = computed(() => {
279
- return props.mode === 'image'
280
- })
281
-
282
- const computeNameProp = computed(() => {
283
- return props.nameField || 'name'
284
- })
285
-
286
- const computeTypeProp = computed(() => {
287
- return props.typeField || 'type'
288
- })
289
-
290
- const computeUrlProp = computed(() => {
291
- return props.urlField || 'url'
292
- })
293
-
294
- const computeSizeProp = computed(() => {
295
- return props.sizeField || 'size'
296
- })
297
-
298
- const computeLimitMaxSize = computed(() => {
299
- return XEUtils.toNumber(props.limitSize) * 1024 * 1024
300
- })
301
-
302
- const computeLimitMaxCount = computed(() => {
303
- return props.multiple ? XEUtils.toNumber(props.limitCount) : 1
304
- })
305
-
306
- const computePreviewImageOpts = computed(() => {
307
- const { showDownloadButton } = props
308
- return Object.assign({
309
- showDownloadButton
310
- }, getConfig().upload.previewImageConfig, props.previewImageConfig)
311
- })
312
-
313
- const computeOverCount = computed(() => {
314
- const { multiple } = props
315
- const { fileList } = reactData
316
- const limitMaxCount = computeLimitMaxCount.value
317
- if (multiple) {
318
- if (limitMaxCount) {
319
- return fileList.length >= limitMaxCount
320
- }
321
- return true
322
- }
323
- return fileList.length >= 1
324
- })
325
-
326
- const computeLimitSizeUnit = computed(() => {
327
- const limitSize = XEUtils.toNumber(props.limitSize)
328
- if (limitSize) {
329
- if (limitSize > 1048576) {
330
- return `${limitSize / 1048576}T`
331
- }
332
- if (limitSize > 1024) {
333
- return `${limitSize / 1024}G`
334
- }
335
- return `${limitSize}M`
336
- }
337
- return ''
338
- })
339
-
340
- const computedShowTipText = computed(() => {
341
- const { showTip, tipText } = props
342
- if (XEUtils.isBoolean(showTip)) {
343
- return showTip
344
- }
345
- const defShowTip = getConfig().upload.showTip
346
- if (XEUtils.isBoolean(defShowTip)) {
347
- return defShowTip
348
- }
349
- if (tipText) {
350
- return true
351
- }
352
- return false
353
- })
354
-
355
- const computedDefTipText = computed(() => {
356
- const { limitSize, fileTypes, multiple, limitCount } = props
357
- const tipText = props.tipText || props.hintText
358
- const isImage = computeIsImage.value
359
- const limitSizeUnit = computeLimitSizeUnit.value
360
- if (XEUtils.isString(tipText)) {
361
- return tipText
362
- }
363
- if (XEUtils.isFunction(tipText)) {
364
- return `${tipText({})}`
365
- }
366
- const defTips: string[] = []
367
- if (isImage) {
368
- if (multiple && limitCount) {
369
- defTips.push(getI18n('vxe.upload.imgCountHint', [limitCount]))
370
- }
371
- if (limitSize && limitSizeUnit) {
372
- defTips.push(getI18n('vxe.upload.imgSizeHint', [limitSizeUnit]))
373
- }
374
- } else {
375
- if (fileTypes && fileTypes.length) {
376
- defTips.push(getI18n('vxe.upload.fileTypeHint', [fileTypes.join('/')]))
377
- }
378
- if (limitSize && limitSizeUnit) {
379
- defTips.push(getI18n('vxe.upload.fileSizeHint', [limitSizeUnit]))
380
- }
381
- if (multiple && limitCount) {
382
- defTips.push(getI18n('vxe.upload.fileCountHint', [limitCount]))
383
- }
384
- }
385
- return defTips.join(getI18n('vxe.base.comma'))
386
- })
387
-
388
- const computeImageOpts = computed(() => {
389
- return Object.assign({}, props.imageConfig || props.imageStyle)
390
- })
391
-
392
- const computeImgStyle = computed(() => {
393
- const imageOpts = computeImageOpts.value
394
- const { width, height } = imageOpts
395
- const stys: Record<string, string> = {}
396
- if (width) {
397
- stys.width = toCssUnit(width)
398
- }
399
- if (height) {
400
- stys.height = toCssUnit(height)
401
- }
402
- return stys
403
- })
404
-
405
- const computeMoreOpts = computed(() => {
406
- return Object.assign({ showMoreButton: true }, props.moreConfig)
407
- })
408
-
409
- const computeMaps: VxeUploadPrivateComputed = {
410
- }
411
-
412
- const $xeUpload = {
413
- xID,
414
- props,
415
- context,
416
- reactData,
417
- internalData,
418
-
419
- getRefMaps: () => refMaps,
420
- getComputeMaps: () => computeMaps
421
- } as unknown as VxeUploadConstructor & VxeUploadPrivateMethods
422
-
423
- const getUniqueKey = () => {
424
- return XEUtils.uniqueId()
425
- }
426
-
427
- const getFieldKey = (item: VxeUploadDefines.FileObjItem) => {
428
- const keyField = computeKeyField.value
429
- return item[keyField]
430
- }
431
-
432
- const updateFileList = () => {
433
- const { modelValue, multiple } = props
434
- const formReadonly = computeFormReadonly.value
435
- const keyField = computeKeyField.value
436
- const nameProp = computeNameProp.value
437
- const typeProp = computeTypeProp.value
438
- const urlProp = computeUrlProp.value
439
- const sizeProp = computeSizeProp.value
440
- const fileList = modelValue
441
- ? (modelValue ? (XEUtils.isArray(modelValue) ? modelValue : [modelValue]) : []).map(item => {
442
- if (!item || XEUtils.isString(item)) {
443
- const url = `${item || ''}`
444
- const urlObj = XEUtils.parseUrl(item)
445
- const name = (urlObj ? urlObj.searchQuery[nameProp] : '') || parseFileName(url)
446
- return {
447
- [nameProp]: name,
448
- [typeProp]: (urlObj ? urlObj.searchQuery[typeProp] : '') || parseFileType(name),
449
- [urlProp]: url,
450
- [sizeProp]: XEUtils.toNumber(urlObj ? urlObj.searchQuery[sizeProp] : 0) || 0,
451
- [keyField]: getUniqueKey()
452
- }
453
- }
454
- const name = item[nameProp] || ''
455
- item[nameProp] = name
456
- item[typeProp] = item[typeProp] || parseFileType(name)
457
- item[urlProp] = item[urlProp] || ''
458
- item[sizeProp] = item[sizeProp] || 0
459
- item[keyField] = item[keyField] || getUniqueKey()
460
- return item
461
- })
462
- : []
463
- reactData.fileList = (formReadonly || multiple) ? fileList : (fileList.slice(0, 1))
464
- }
465
-
466
- const parseFileName = (url: string) => {
467
- return decodeURIComponent(`${url || ''}`).split('/').pop() || ''
468
- }
469
-
470
- const parseFileType = (name: string) => {
471
- // 这里不用split('.').pop()因为没有后缀时会返回自身
472
- const index = name.lastIndexOf('.')
473
- if (index > 0) {
474
- return name.substring(index + 1).toLowerCase()
475
- }
476
- return ''
477
- }
478
-
479
- const dispatchEvent = (type: ValueOf<VxeUploadEmits>, params: Record<string, any>, evnt: Event | null) => {
480
- emit(type, createEvent(evnt, { $upload: $xeUpload }, params))
481
- }
482
-
483
- const emitModel = (value: any) => {
484
- emit('update:modelValue', value)
485
- }
486
-
487
- const handleChange = (value: VxeUploadDefines.FileObjItem[]) => {
488
- const { singleMode, urlMode, urlArgs } = props
489
- const urlProp = computeUrlProp.value
490
- const nameProp = computeNameProp.value
491
- let restList = value ? value.slice(0) : []
492
- if (urlMode) {
493
- restList = restList.map(item => {
494
- const url = item[urlProp]
495
- if (url && urlArgs) {
496
- const urlObj = XEUtils.parseUrl(url)
497
- if (!urlObj.searchQuery[nameProp]) {
498
- if (url.indexOf('blob:') === -1) {
499
- return `${url}${url.indexOf('?') === -1 ? '?' : '&'}${nameProp}=${encodeURIComponent(item[nameProp] || '')}`
500
- }
501
- }
502
- }
503
- return url
504
- })
505
- }
506
- emitModel(singleMode ? (restList[0] || null) : restList)
507
- }
508
-
509
- const getThumbnailFileUrl = (item: VxeUploadDefines.FileObjItem) => {
510
- const getThumbnailUrlFn = props.getThumbnailUrlMethod || getConfig().upload.getThumbnailUrlMethod
511
- if (getThumbnailUrlFn) {
512
- return getThumbnailUrlFn({
513
- $upload: $xeUpload,
514
- option: item
515
- })
516
- }
517
- return getFileUrl(item)
518
- }
519
-
520
- const getFileUrl = (item: VxeUploadDefines.FileObjItem) => {
521
- const getUrlFn = props.getUrlMethod || getConfig().upload.getUrlMethod
522
- const urlProp = computeUrlProp.value
523
- return getUrlFn
524
- ? getUrlFn({
525
- $upload: $xeUpload,
526
- option: item
527
- })
528
- : item[urlProp]
529
- }
530
-
531
- const handleDefaultFilePreview = (item: VxeUploadDefines.FileObjItem) => {
532
- const { imageTypes, showDownloadButton } = props
533
- const typeProp = computeTypeProp.value
534
- const previewImageOpts = computePreviewImageOpts.value
535
- const beforeDownloadFn = props.beforeDownloadMethod || getConfig().upload.beforeDownloadMethod
536
- const { imagePreviewTypes } = internalData
537
- // 如果是预览图片
538
- if (imagePreviewTypes.concat(imageTypes || []).some(type => `${type}`.toLowerCase() === `${item[typeProp]}`.toLowerCase())) {
539
- if (VxeUI.previewImage) {
540
- VxeUI.previewImage({
541
- ...previewImageOpts,
542
- urlList: [getFileUrl(item)],
543
- showDownloadButton,
544
- beforeDownloadMethod: beforeDownloadFn
545
- ? () => {
546
- return beforeDownloadFn({
547
- $upload: $xeUpload,
548
- option: item
549
- })
550
- }
551
- : undefined
552
- })
553
- }
554
- }
555
- }
556
-
557
- const handlePreviewFileEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem) => {
558
- const previewFn = props.previewMethod || getConfig().upload.previewMethod
559
- if (props.showPreview) {
560
- if (previewFn) {
561
- previewFn({
562
- $upload: $xeUpload,
563
- option: item
564
- })
565
- } else {
566
- handleDefaultFilePreview(item)
567
- }
568
- }
569
- }
570
-
571
- const handlePreviewImageEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem, index: number) => {
572
- const { showDownloadButton } = props
573
- const { fileList } = reactData
574
- const previewImageOpts = computePreviewImageOpts.value
575
- const previewFn = props.previewMethod || getConfig().upload.previewMethod
576
- const beforeDownloadFn = props.beforeDownloadMethod || getConfig().upload.beforeDownloadMethod
577
- if (props.showPreview) {
578
- if (previewFn) {
579
- previewFn({
580
- $upload: $xeUpload,
581
- option: item
582
- })
583
- } else if (VxeUI.previewImage) {
584
- VxeUI.previewImage({
585
- ...previewImageOpts,
586
- urlList: fileList.map(item => getFileUrl(item)),
587
- activeIndex: index,
588
- showDownloadButton,
589
- beforeDownloadMethod: beforeDownloadFn
590
- ? ({ index }) => {
591
- return beforeDownloadFn({
592
- $upload: $xeUpload,
593
- option: fileList[index]
594
- })
595
- }
596
- : undefined
597
- })
598
- }
599
- }
600
- }
601
-
602
- const handleUploadResult = (item: VxeUploadDefines.FileObjItem, file: File) => {
603
- const { showErrorStatus } = props
604
- const fileKey = getFieldKey(item)
605
- const uploadFn = props.uploadMethod || getConfig().upload.uploadMethod
606
- if (uploadFn) {
607
- return Promise.resolve(
608
- uploadFn({
609
- $upload: $xeUpload,
610
- file,
611
- option: item,
612
- updateProgress (percentNum) {
613
- const { fileCacheMaps } = reactData
614
- const cacheItem = fileCacheMaps[getFieldKey(item)]
615
- if (cacheItem) {
616
- cacheItem.percent = Math.max(0, Math.min(99, XEUtils.toNumber(percentNum)))
617
- }
618
- }
619
- })
620
- ).then(res => {
621
- const { fileCacheMaps } = reactData
622
- const cacheItem = fileCacheMaps[fileKey]
623
- if (cacheItem) {
624
- cacheItem.percent = 100
625
- cacheItem.status = 'success'
626
- }
627
- Object.assign(item, res)
628
- dispatchEvent('upload-success', { option: item, data: res }, null)
629
- }).catch((res) => {
630
- const { fileCacheMaps } = reactData
631
- const cacheItem = fileCacheMaps[fileKey]
632
- if (cacheItem) {
633
- cacheItem.status = 'error'
634
- }
635
- if (showErrorStatus) {
636
- Object.assign(item, res)
637
- } else {
638
- reactData.fileList = reactData.fileList.filter(obj => getFieldKey(obj) !== fileKey)
639
- delete fileCacheMaps[fileKey]
640
- }
641
- dispatchEvent('upload-error', { option: item, data: res }, null)
642
- }).finally(() => {
643
- const { fileCacheMaps } = reactData
644
- const cacheItem = fileCacheMaps[fileKey]
645
- if (cacheItem) {
646
- cacheItem.loading = false
647
- }
648
- })
649
- } else {
650
- const { fileCacheMaps } = reactData
651
- const cacheItem = fileCacheMaps[fileKey]
652
- if (cacheItem) {
653
- cacheItem.loading = false
654
- }
655
- }
656
- return Promise.resolve()
657
- }
658
-
659
- const handleReUpload = (item: VxeUploadDefines.FileObjItem) => {
660
- const { uploadMethod, urlMode } = props
661
- const { fileCacheMaps } = reactData
662
- const fileKey = getFieldKey(item)
663
- const cacheItem = fileCacheMaps[fileKey]
664
- const uploadFn = uploadMethod || getConfig().upload.uploadMethod
665
- if (uploadFn && cacheItem) {
666
- const file = cacheItem.file
667
- cacheItem.loading = true
668
- cacheItem.status = 'pending'
669
- cacheItem.percent = 0
670
- handleUploadResult(item, file).then(() => {
671
- if (urlMode) {
672
- handleChange(reactData.fileList)
673
- }
674
- })
675
- }
676
- }
677
- const handleUploadFile = (files: File[], evnt: Event | null) => {
678
- const { multiple, urlMode, showLimitSize, limitSizeText, showLimitCount, limitCountText, autoSubmit } = props
679
- const { fileList } = reactData
680
- const beforeSelectFn = props.beforeSelectMethod || getConfig().upload.beforeSelectMethod
681
- const uploadFn = props.uploadMethod || getConfig().upload.uploadMethod
682
- const keyField = computeKeyField.value
683
- const nameProp = computeNameProp.value
684
- const typeProp = computeTypeProp.value
685
- const urlProp = computeUrlProp.value
686
- const sizeProp = computeSizeProp.value
687
- const limitMaxSize = computeLimitMaxSize.value
688
- const limitMaxCount = computeLimitMaxCount.value
689
- const limitSizeUnit = computeLimitSizeUnit.value
690
- let selectFiles = files
691
-
692
- if (multiple && limitMaxCount) {
693
- // 校验文件数量
694
- if (showLimitCount && fileList.length >= limitMaxCount) {
695
- if (VxeUI.modal) {
696
- VxeUI.modal.notification({
697
- title: getI18n('vxe.modal.errTitle'),
698
- status: 'error',
699
- content: limitCountText ? `${XEUtils.isFunction(limitCountText) ? limitCountText({ maxCount: limitMaxCount }) : limitCountText}` : getI18n('vxe.upload.overCountErr', [limitMaxCount])
700
- })
701
- }
702
- return
703
- }
704
- const overNum = selectFiles.length - (limitMaxCount - fileList.length)
705
- if (showLimitCount && overNum > 0) {
706
- const overExtraList = selectFiles.slice(limitMaxCount - fileList.length)
707
- if (limitCountText) {
708
- VxeUI.modal.notification({
709
- title: getI18n('vxe.modal.errTitle'),
710
- status: 'error',
711
- content: `${XEUtils.isFunction(limitCountText) ? limitCountText({ maxCount: limitMaxCount }) : limitCountText}`
712
- })
713
- } else if (VxeUI.modal) {
714
- VxeUI.modal.notification({
715
- title: getI18n('vxe.modal.errTitle'),
716
- status: 'error',
717
- width: null,
718
- slots: {
719
- default () {
720
- return h('div', {
721
- class: 'vxe-upload--file-message-over-error'
722
- }, [
723
- h('div', {}, getI18n('vxe.upload.overCountExtraErr', [limitMaxCount, overNum])),
724
- h('div', {
725
- class: 'vxe-upload--file-message-over-extra'
726
- }, overExtraList.map((file, index) => {
727
- return h('div', {
728
- key: index,
729
- class: 'vxe-upload--file-message-over-extra-item'
730
- }, file.name)
731
- }))
732
- ])
733
- }
734
- }
735
- })
736
- }
737
- }
738
- selectFiles = selectFiles.slice(0, limitMaxCount - fileList.length)
739
- }
740
-
741
- // 校验文件大小
742
- if (showLimitSize && limitMaxSize) {
743
- for (let i = 0; i < files.length; i++) {
744
- const file = files[0]
745
- if (file.size > limitMaxSize) {
746
- if (VxeUI.modal) {
747
- VxeUI.modal.notification({
748
- title: getI18n('vxe.modal.errTitle'),
749
- status: 'error',
750
- content: limitSizeText ? `${XEUtils.isFunction(limitSizeText) ? limitSizeText({ maxSize: limitMaxSize }) : limitSizeText}` : getI18n('vxe.upload.overSizeErr', [limitSizeUnit])
751
- })
752
- }
753
- return
754
- }
755
- }
756
- }
757
-
758
- const cacheMaps = Object.assign({}, reactData.fileCacheMaps)
759
- const newFileList = multiple ? fileList : []
760
- const uploadPromiseRests: any[] = []
761
- selectFiles.forEach(file => {
762
- const { name } = file
763
- const fileKey = getUniqueKey()
764
- const fileObj: VxeUploadDefines.FileObjItem = {
765
- [nameProp]: name,
766
- [typeProp]: parseFileType(name),
767
- [sizeProp]: file.size,
768
- [urlProp]: URL.createObjectURL(file),
769
- [keyField]: fileKey
770
- }
771
- if (uploadFn) {
772
- cacheMaps[fileKey] = {
773
- file: file,
774
- loading: !!autoSubmit,
775
- status: 'pending',
776
- percent: 0
777
- }
778
- }
779
- const item = reactive(fileObj)
780
- if (!beforeSelectFn || beforeSelectFn({ $upload: $xeUpload, file })) {
781
- if (uploadFn && autoSubmit) {
782
- uploadPromiseRests.push(
783
- handleUploadResult(item, file)
784
- )
785
- }
786
- newFileList.push(item)
787
- }
788
- })
789
- reactData.fileList = newFileList
790
- reactData.fileCacheMaps = cacheMaps
791
- newFileList.forEach(item => {
792
- dispatchEvent('add', { option: item }, evnt)
793
- })
794
- Promise.all(urlMode ? uploadPromiseRests : []).then(() => {
795
- const restFileList = reactData.fileList
796
- handleChange(restFileList)
797
- // 自动更新校验状态
798
- if ($xeForm && formItemInfo) {
799
- $xeForm.triggerItemEvent(evnt as any, formItemInfo.itemConfig.field, restFileList)
800
- }
801
- })
802
- }
803
-
804
- const handleChoose = (evnt: MouseEvent | null) => {
805
- const { multiple, imageTypes, fileTypes } = props
806
- const isDisabled = computeIsDisabled.value
807
- const isImage = computeIsImage.value
808
- if (isDisabled) {
809
- return Promise.resolve({
810
- status: false,
811
- files: [],
812
- file: null
813
- })
814
- }
815
- return readLocalFile({
816
- multiple,
817
- types: isImage ? imageTypes : fileTypes
818
- }).then((params) => {
819
- handleUploadFile(params.files, evnt)
820
- return params
821
- })
822
- }
823
-
824
- const clickEvent = (evnt: MouseEvent) => {
825
- handleChoose(evnt).catch(() => {
826
- // 错误文件类型
827
- })
828
- }
829
-
830
- const handleRemoveEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem, index: number) => {
831
- const { fileList } = reactData
832
- fileList.splice(index, 1)
833
- handleChange(fileList)
834
- // 自动更新校验状态
835
- if ($xeForm && formItemInfo) {
836
- $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, fileList)
837
- }
838
- dispatchEvent('remove', { option: item }, evnt)
839
- }
840
-
841
- const removeFileEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem, index: number) => {
842
- const beforeRemoveFn = props.beforeRemoveMethod || getConfig().upload.beforeRemoveMethod
843
- const removeFn = props.removeMethod || getConfig().upload.removeMethod
844
- Promise.resolve(
845
- beforeRemoveFn
846
- ? beforeRemoveFn({
847
- $upload: $xeUpload,
848
- option: item
849
- })
850
- : true
851
- ).then(status => {
852
- if (status) {
853
- if (removeFn) {
854
- Promise.resolve(
855
- removeFn({
856
- $upload: $xeUpload,
857
- option: item
858
- })
859
- ).then(() => {
860
- handleRemoveEvent(evnt, item, index)
861
- }).catch(e => e)
862
- } else {
863
- handleRemoveEvent(evnt, item, index)
864
- }
865
- } else {
866
- dispatchEvent('remove-fail', { option: item }, evnt)
867
- }
868
- })
869
- }
870
-
871
- const handleDownloadEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem) => {
872
- dispatchEvent('download', { option: item }, evnt)
873
- }
874
-
875
- const downloadFileEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem) => {
876
- const beforeDownloadFn = props.beforeDownloadMethod || getConfig().upload.beforeDownloadMethod
877
- const downloadFn = props.downloadMethod || getConfig().upload.downloadMethod
878
- Promise.resolve(
879
- beforeDownloadFn
880
- ? beforeDownloadFn({
881
- $upload: $xeUpload,
882
- option: item
883
- })
884
- : true
885
- ).then(status => {
886
- if (status) {
887
- if (downloadFn) {
888
- Promise.resolve(
889
- downloadFn({
890
- $upload: $xeUpload,
891
- option: item
892
- })
893
- ).then(() => {
894
- handleDownloadEvent(evnt, item)
895
- }).catch(e => e)
896
- } else {
897
- handleDownloadEvent(evnt, item)
898
- }
899
- } else {
900
- dispatchEvent('download-fail', { option: item }, evnt)
901
- }
902
- })
903
- }
904
-
905
- const handleUploadDragleaveEvent = (evnt: DragEvent) => {
906
- const targetElem = evnt.currentTarget as HTMLDivElement
907
- const { clientX, clientY } = evnt
908
- if (targetElem) {
909
- const { x: targetX, y: targetY, height: targetHeight, width: targetWidth } = targetElem.getBoundingClientRect()
910
- if (clientX < targetX || clientX > targetX + targetWidth || clientY < targetY || clientY > targetY + targetHeight) {
911
- reactData.isDragUploadStatus = false
912
- }
913
- }
914
- }
915
-
916
- const handleUploadDragoverEvent = (evnt: DragEvent) => {
917
- const dataTransfer = evnt.dataTransfer
918
- if (dataTransfer) {
919
- const { items } = dataTransfer
920
- if (items && items.length) {
921
- evnt.preventDefault()
922
- reactData.isDragUploadStatus = true
923
- }
924
- }
925
- }
926
-
927
- const uploadTransferFileEvent = (evnt: Event, files: File[]) => {
928
- const { imageTypes, fileTypes } = props
929
- const { imagePreviewTypes } = internalData
930
- const isImage = computeIsImage.value
931
- if (isImage) {
932
- const pasteImgTypes = imagePreviewTypes.concat(imageTypes && imageTypes.length ? imageTypes : [])
933
- files = files.filter(file => {
934
- const fileType = `${file.type.split('/')[1] || ''}`.toLowerCase()
935
- if (pasteImgTypes.some(type => `${type}`.toLowerCase() === fileType)) {
936
- return true
937
- }
938
- return false
939
- })
940
- } else {
941
- if (fileTypes && fileTypes.length) {
942
- const errTypes: string[] = []
943
- files.forEach(file => {
944
- const fileType = parseFileType(file.name)
945
- if (!fileTypes.some(type => `${type}`.toLowerCase() === fileType)) {
946
- errTypes.push(fileType)
947
- }
948
- })
949
- if (errTypes.length) {
950
- if (VxeUI.modal) {
951
- VxeUI.modal.message({
952
- content: getI18n('vxe.error.notType', [errTypes.join(', ')]),
953
- status: 'error'
954
- })
955
- }
956
- return
957
- }
958
- }
959
- }
960
- // 如果全部不满足条件
961
- if (!files.length) {
962
- if (VxeUI.modal) {
963
- VxeUI.modal.notification({
964
- title: getI18n('vxe.modal.errTitle'),
965
- status: 'error',
966
- content: getI18n('vxe.upload.uploadTypeErr')
967
- })
968
- }
969
- return
970
- }
971
- handleUploadFile(files, evnt)
972
- }
973
-
974
- const handleUploadDropEvent = (evnt: DragEvent) => {
975
- const dataTransfer = evnt.dataTransfer
976
- if (dataTransfer) {
977
- const { items } = dataTransfer
978
- if (items && items.length) {
979
- evnt.preventDefault()
980
- const files = handleTransferFiles(items)
981
- if (files.length) {
982
- uploadTransferFileEvent(evnt, files)
983
- }
984
- }
985
- }
986
- reactData.isDragUploadStatus = false
987
- }
988
-
989
- const handleTransferFiles = (items: DataTransferItemList) => {
990
- const files: File[] = []
991
- XEUtils.arrayEach(items, item => {
992
- const file = item.getAsFile()
993
- if (file) {
994
- files.push(file)
995
- }
996
- })
997
- return files
998
- }
999
-
1000
- const handleMoreEvent = (evntParams: VxeComponentEventParams) => {
1001
- const formReadonly = computeFormReadonly.value
1002
- const isImage = computeIsImage.value
1003
-
1004
- const evnt = evntParams.$event
1005
- if (VxeUI.modal) {
1006
- VxeUI.modal.open({
1007
- id: internalData.moreId,
1008
- title: formReadonly ? getI18n('vxe.upload.morePopup.readTitle') : getI18n(`vxe.upload.morePopup.${isImage ? 'imageTitle' : 'fileTitle'}`),
1009
- width: 660,
1010
- height: 500,
1011
- escClosable: true,
1012
- showMaximize: true,
1013
- resize: true,
1014
- maskClosable: true,
1015
- slots: {
1016
- default () {
1017
- const { showErrorStatus, dragToUpload, dragSort, dragPlaceholder } = props
1018
- const { isActivated, isDragMove, isDragUploadStatus, dragIndex } = reactData
1019
- const { fileList } = reactData
1020
- const isDisabled = computeIsDisabled.value
1021
- const moreContSlot = slots.moreContent || slots['more-content']
1022
-
1023
- const ons: Record<string, any> = {}
1024
- if (dragToUpload && dragIndex === -1) {
1025
- ons.onDragover = handleUploadDragoverEvent
1026
- ons.onDragleave = handleUploadDragleaveEvent
1027
- ons.onDrop = handleUploadDropEvent
1028
- }
1029
-
1030
- return h('div', {
1031
- ref: refPopupElem,
1032
- class: ['vxe-upload--more-popup', {
1033
- 'is--readonly': formReadonly,
1034
- 'is--disabled': isDisabled,
1035
- 'is--active': isActivated,
1036
- 'show--error': showErrorStatus,
1037
- 'is--drag': isDragUploadStatus
1038
- }],
1039
- ...ons
1040
- }, moreContSlot
1041
- ? getSlotVNs(moreContSlot({ options: fileList }))
1042
- : [
1043
- isImage
1044
- ? (
1045
- dragSort
1046
- ? h(TransitionGroup, {
1047
- name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
1048
- tag: 'div',
1049
- class: 'vxe-upload--image-more-list'
1050
- }, {
1051
- default: () => renderImageItemList(fileList, true).concat(renderImageAction(true))
1052
- })
1053
- : h('div', {
1054
- class: 'vxe-upload--image-more-list'
1055
- }, renderImageItemList(fileList, true).concat(renderImageAction(true)))
1056
- )
1057
- : h('div', {
1058
- class: 'vxe-upload--file-more-list'
1059
- }, [
1060
- renderFileAction(true),
1061
- dragSort
1062
- ? h(TransitionGroup, {
1063
- name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
1064
- tag: 'div',
1065
- class: 'vxe-upload--file-list'
1066
- }, {
1067
- default: () => renderFileItemList(fileList, false)
1068
- })
1069
- : h('div', {
1070
- class: 'vxe-upload--file-list'
1071
- }, renderFileItemList(fileList, true))
1072
- ]),
1073
- dragSort
1074
- ? h('div', {
1075
- ref: refModalDragLineElem,
1076
- class: 'vxe-upload--drag-line'
1077
- })
1078
- : renderEmptyElement($xeUpload),
1079
- isDragUploadStatus
1080
- ? h('div', {
1081
- class: 'vxe-upload--drag-placeholder'
1082
- }, dragPlaceholder || getI18n('vxe.upload.dragPlaceholder'))
1083
- : renderEmptyElement($xeUpload)
1084
- ])
1085
- }
1086
- },
1087
- onShow () {
1088
- reactData.showMorePopup = true
1089
- },
1090
- onHide ({ $event }) {
1091
- reactData.showMorePopup = false
1092
- if ($event) {
1093
- dispatchEvent('more-visible', { visible: false }, $event)
1094
- }
1095
- }
1096
- })
1097
- if (evnt) {
1098
- dispatchEvent('more-visible', { visible: true }, evnt)
1099
- }
1100
- }
1101
- }
1102
-
1103
- const showDropTip = (evnt: DragEvent, dragEl: HTMLElement, dragPos: string) => {
1104
- const { showMorePopup } = reactData
1105
- const el = refElem.value
1106
- const popupEl = refPopupElem.value
1107
- const wrapperEl = showMorePopup ? popupEl : el
1108
- if (!wrapperEl) {
1109
- return
1110
- }
1111
- const wrapperRect = wrapperEl.getBoundingClientRect()
1112
- const ddLineEl = refDragLineElem.value
1113
- const mdLineEl = refModalDragLineElem.value
1114
- const currDLineEl = showMorePopup ? mdLineEl : ddLineEl
1115
- if (currDLineEl) {
1116
- const dragRect = dragEl.getBoundingClientRect()
1117
- currDLineEl.style.display = 'block'
1118
- currDLineEl.style.top = `${Math.max(1, dragRect.y - wrapperRect.y)}px`
1119
- currDLineEl.style.left = `${Math.max(1, dragRect.x - wrapperRect.x)}px`
1120
- currDLineEl.style.height = `${dragRect.height}px`
1121
- currDLineEl.style.width = `${dragRect.width - 1}px`
1122
- currDLineEl.setAttribute('drag-pos', dragPos)
1123
- }
1124
- }
1125
-
1126
- const hideDropTip = () => {
1127
- const ddLineEl = refDragLineElem.value
1128
- const mdLineEl = refModalDragLineElem.value
1129
- if (ddLineEl) {
1130
- ddLineEl.style.display = ''
1131
- }
1132
- if (mdLineEl) {
1133
- mdLineEl.style.display = ''
1134
- }
1135
- }
1136
-
1137
- // 拖拽
1138
- const handleDragSortDragstartEvent = (evnt: DragEvent) => {
1139
- evnt.stopPropagation()
1140
- if (evnt.dataTransfer) {
1141
- evnt.dataTransfer.setDragImage(getTpImg(), 0, 0)
1142
- }
1143
- const dragEl = evnt.currentTarget as HTMLElement
1144
- const parentEl = dragEl.parentElement as HTMLDivElement
1145
- const dragIndex = XEUtils.findIndexOf(Array.from(parentEl.children), item => dragEl === item)
1146
- reactData.isDragMove = true
1147
- reactData.dragIndex = dragIndex
1148
- setTimeout(() => {
1149
- reactData.isDragMove = false
1150
- }, 500)
1151
- }
1152
-
1153
- const handleDragSortDragoverEvent = (evnt: DragEvent) => {
1154
- evnt.stopPropagation()
1155
- evnt.preventDefault()
1156
- const { dragIndex } = reactData
1157
- if (dragIndex === -1) {
1158
- return
1159
- }
1160
- const isImage = computeIsImage.value
1161
- const dragEl = evnt.currentTarget as HTMLElement
1162
- const parentEl = dragEl.parentElement as HTMLDivElement
1163
- const currIndex = XEUtils.findIndexOf(Array.from(parentEl.children), item => dragEl === item)
1164
- let dragPos: 'top' | 'bottom' | 'left' | 'right' | '' = ''
1165
- if (isImage) {
1166
- const offsetX = evnt.clientX - dragEl.getBoundingClientRect().x
1167
- dragPos = offsetX < dragEl.clientWidth / 2 ? 'left' : 'right'
1168
- } else {
1169
- const offsetY = evnt.clientY - dragEl.getBoundingClientRect().y
1170
- dragPos = offsetY < dragEl.clientHeight / 2 ? 'top' : 'bottom'
1171
- }
1172
- if (dragIndex === currIndex) {
1173
- showDropTip(evnt, dragEl, dragPos)
1174
- return
1175
- }
1176
- showDropTip(evnt, dragEl, dragPos)
1177
- internalData.prevDragIndex = currIndex
1178
- internalData.prevDragPos = dragPos
1179
- }
1180
-
1181
- const handleDragSortDragendEvent = (evnt: DragEvent) => {
1182
- const { fileList, dragIndex } = reactData
1183
- const { prevDragIndex, prevDragPos } = internalData
1184
- const oldIndex = dragIndex
1185
- const targetIndex = prevDragIndex
1186
- const dragOffsetIndex = prevDragPos === 'bottom' || prevDragPos === 'right' ? 1 : 0
1187
- const oldItem = fileList[oldIndex]
1188
- const newItem = fileList[targetIndex]
1189
- if (oldItem && newItem) {
1190
- fileList.splice(oldIndex, 1)
1191
- const ptfIndex = XEUtils.findIndexOf(fileList, item => newItem === item)
1192
- const nIndex = ptfIndex + dragOffsetIndex
1193
- fileList.splice(nIndex, 0, oldItem)
1194
- dispatchEvent('sort-dragend', {
1195
- oldItem: oldItem,
1196
- newItem: newItem,
1197
- dragPos: prevDragPos as any,
1198
- offsetIndex: dragOffsetIndex,
1199
- _index: {
1200
- newIndex: nIndex,
1201
- oldIndex: oldIndex
1202
- }
1203
- }, evnt)
1204
- }
1205
- hideDropTip()
1206
- reactData.dragIndex = -1
1207
- }
1208
-
1209
- const handleItemMousedownEvent = (evnt: MouseEvent) => {
1210
- if ($xeTable) {
1211
- evnt.stopPropagation()
1212
- }
1213
- reactData.isActivated = true
1214
- }
1215
-
1216
- const handleGlobalPasteEvent = (evnt: ClipboardEvent) => {
1217
- const { pasteToUpload } = props
1218
- const { isActivated } = reactData
1219
- if (!isActivated || !pasteToUpload) {
1220
- return
1221
- }
1222
- const clipboardData: DataTransfer = evnt.clipboardData || (evnt as any).originalEvent.clipboardData
1223
- if (!clipboardData) {
1224
- return
1225
- }
1226
- const { items } = clipboardData
1227
- if (!items) {
1228
- return
1229
- }
1230
- const files = handleTransferFiles(items)
1231
- if (files.length) {
1232
- evnt.preventDefault()
1233
- uploadTransferFileEvent(evnt, files)
1234
- }
1235
- }
1236
-
1237
- const handleGlobalClickEvent = (evnt: MouseEvent) => {
1238
- const el = refElem.value
1239
- const popupEl = refPopupElem.value
1240
- let isActivated = getEventTargetNode(evnt, el).flag
1241
- if (!isActivated && popupEl) {
1242
- const parentEl = popupEl.parentElement || popupEl
1243
- const modalEl = parentEl ? parentEl.parentElement : parentEl
1244
- isActivated = getEventTargetNode(evnt, modalEl).flag
1245
- }
1246
- reactData.isActivated = isActivated
1247
- }
1248
-
1249
- const handleGlobalBlurEvent = () => {
1250
- reactData.isActivated = false
1251
- }
1252
-
1253
- const uploadMethods: UploadMethods = {
1254
- dispatchEvent,
1255
- choose () {
1256
- return handleChoose(null)
1257
- },
1258
- getPendingFiles () {
1259
- const { fileList, fileCacheMaps } = reactData
1260
- const pendingFiles: File[] = []
1261
- fileList.forEach(item => {
1262
- const fileKey = getFieldKey(item)
1263
- const cacheItem = fileCacheMaps[fileKey]
1264
- if (cacheItem && cacheItem.status === 'pending') {
1265
- pendingFiles.push(cacheItem.file)
1266
- }
1267
- })
1268
- return pendingFiles
1269
- },
1270
- submit (isFull) {
1271
- const { maxSimultaneousUploads } = props
1272
- const msNum = XEUtils.toNumber(maxSimultaneousUploads || 1) || 1
1273
- const { fileList, fileCacheMaps } = reactData
1274
- const allPendingList = fileList.filter(item => {
1275
- const fileKey = getFieldKey(item)
1276
- const cacheItem = fileCacheMaps[fileKey]
1277
- return cacheItem && (cacheItem.status === 'pending' || (isFull && cacheItem.status === 'error'))
1278
- })
1279
-
1280
- const handleSubmit = (item: VxeUploadDefines.FileObjItem): Promise<void> => {
1281
- const fileKey = getFieldKey(item)
1282
- const cacheItem = fileCacheMaps[fileKey]
1283
- if (cacheItem) {
1284
- const file = cacheItem.file
1285
- if (file && (cacheItem.status === 'pending' || (isFull && cacheItem.status === 'error'))) {
1286
- cacheItem.loading = true
1287
- cacheItem.percent = 0
1288
- return handleUploadResult(item, file).then(handleNextSubmit)
1289
- }
1290
- }
1291
- return handleNextSubmit()
1292
- }
1293
-
1294
- const handleNextSubmit = (): Promise<void> => {
1295
- if (allPendingList.length) {
1296
- const item = allPendingList[0]
1297
- allPendingList.splice(0, 1)
1298
- return handleSubmit(item).then(handleNextSubmit)
1299
- }
1300
- return Promise.resolve()
1301
- }
1302
-
1303
- return Promise.all(allPendingList.splice(0, msNum).map(handleSubmit)).then(() => {
1304
- // 完成
1305
- })
1306
- },
1307
- getMoreVisible () {
1308
- return reactData.showMorePopup
1309
- },
1310
- openMore () {
1311
- handleMoreEvent({ $event: new Event('click') })
1312
- return nextTick()
1313
- },
1314
- openMoreByEvent (evnt) {
1315
- handleMoreEvent({ $event: evnt })
1316
- return nextTick()
1317
- },
1318
- closeMore () {
1319
- if (VxeUI.modal) {
1320
- VxeUI.modal.close(internalData.moreId)
1321
- }
1322
- return nextTick()
1323
- }
1324
- }
1325
-
1326
- const uploadPrivateMethods: UploadPrivateMethods = {
1327
- }
1328
-
1329
- Object.assign($xeUpload, uploadMethods, uploadPrivateMethods)
1330
-
1331
- const renderFileItemList = (currList: VxeUploadDefines.FileObjItem[], isMoreView: boolean) => {
1332
- const { showRemoveButton, showDownloadButton, showProgress, progressText, showPreview, showErrorStatus, dragSort, autoSubmit, showSubmitButton } = props
1333
- const { fileList, fileCacheMaps } = reactData
1334
- const isDisabled = computeIsDisabled.value
1335
- const formReadonly = computeFormReadonly.value
1336
- const nameProp = computeNameProp.value
1337
- const typeProp = computeTypeProp.value
1338
- const optionSlot = slots.option
1339
- const actionSlot = slots.action
1340
- const cornerSlot = slots.corner
1341
- const nameSlot = slots.name
1342
-
1343
- const ons: Record<string, any> = {}
1344
- if (dragSort && currList.length > 1) {
1345
- ons.onDragstart = handleDragSortDragstartEvent
1346
- ons.onDragover = handleDragSortDragoverEvent
1347
- ons.onDragend = handleDragSortDragendEvent
1348
- }
1349
-
1350
- return currList.map((item, index) => {
1351
- const fileKey = getFieldKey(item)
1352
- const cacheItem = fileCacheMaps[fileKey]
1353
- let isLoading = false
1354
- let isError = false
1355
- let isPending = false
1356
- const fileName = `${item[nameProp] || ''}`
1357
- if (cacheItem) {
1358
- isLoading = cacheItem.loading
1359
- isError = cacheItem.status === 'error'
1360
- isPending = cacheItem.status === 'pending'
1361
- }
1362
- return h('div', {
1363
- key: dragSort ? fileKey : index,
1364
- class: ['vxe-upload--file-item', {
1365
- 'is--preview': showPreview,
1366
- 'is--loading': isLoading,
1367
- 'is--pending': isPending,
1368
- 'is--error': isError
1369
- }],
1370
- fileid: fileKey,
1371
- draggable: dragSort ? true : null,
1372
- ...ons
1373
- }, optionSlot
1374
- ? getSlotVNs(optionSlot({ option: item, isMoreView, options: fileList }))
1375
- : [
1376
- h('div', {
1377
- class: 'vxe-upload--file-item-icon'
1378
- }, [
1379
- h('i', {
1380
- class: getIcon()[`UPLOAD_FILE_TYPE_${`${item[typeProp]}`.toLocaleUpperCase() as 'DEFAULT'}`] || getIcon().UPLOAD_FILE_TYPE_DEFAULT
1381
- })
1382
- ]),
1383
- h('div', {
1384
- class: 'vxe-upload--file-item-name',
1385
- title: fileName,
1386
- onClick (evnt) {
1387
- if (!isLoading && !isError) {
1388
- handlePreviewFileEvent(evnt, item)
1389
- }
1390
- }
1391
- }, nameSlot ? getSlotVNs(nameSlot({ option: item, isMoreView, options: fileList })) : fileName),
1392
- isLoading
1393
- ? h('div', {
1394
- class: 'vxe-upload--file-item-loading-icon'
1395
- }, [
1396
- h('i', {
1397
- class: getIcon().UPLOAD_LOADING
1398
- })
1399
- ])
1400
- : renderEmptyElement($xeUpload),
1401
- showProgress && isLoading && cacheItem
1402
- ? h('div', {
1403
- class: 'vxe-upload--file-item-loading-text'
1404
- }, progressText ? XEUtils.toFormatString(`${XEUtils.isFunction(progressText) ? progressText({}) : progressText}`, { percent: cacheItem.percent }) : getI18n('vxe.upload.uploadProgress', [cacheItem.percent]))
1405
- : renderEmptyElement($xeUpload),
1406
- !isLoading && ((isError && showErrorStatus) || (isPending && showSubmitButton && !autoSubmit))
1407
- ? h('div', {
1408
- class: 'vxe-upload--file-item-rebtn'
1409
- }, [
1410
- h(VxeButtonComponent, {
1411
- icon: isError ? getIcon().UPLOAD_IMAGE_RE_UPLOAD : getIcon().UPLOAD_IMAGE_UPLOAD,
1412
- mode: 'text',
1413
- status: 'primary',
1414
- content: isError ? getI18n('vxe.upload.reUpload') : getI18n('vxe.upload.manualUpload'),
1415
- onClick () {
1416
- handleReUpload(item)
1417
- }
1418
- })
1419
- ])
1420
- : renderEmptyElement($xeUpload),
1421
- h('div', {
1422
- class: 'vxe-upload--file-item-btn-wrapper'
1423
- }, actionSlot
1424
- ? getSlotVNs(actionSlot({ option: item, isMoreView, options: fileList, readonly: formReadonly }))
1425
- : [
1426
- cornerSlot
1427
- ? h('div', {
1428
- class: 'vxe-upload--file-item-action'
1429
- }, getSlotVNs(cornerSlot({ option: item, isMoreView, options: fileList, readonly: formReadonly })))
1430
- : renderEmptyElement($xeUpload),
1431
- showDownloadButton && !(isLoading || isPending)
1432
- ? h('div', {
1433
- class: 'vxe-upload--file-item-download-btn',
1434
- onClick (evnt: MouseEvent) {
1435
- downloadFileEvent(evnt, item)
1436
- }
1437
- }, [
1438
- h('i', {
1439
- class: getIcon().UPLOAD_FILE_DOWNLOAD
1440
- })
1441
- ])
1442
- : renderEmptyElement($xeUpload),
1443
- showRemoveButton && !formReadonly && !isDisabled && !isLoading
1444
- ? h('div', {
1445
- class: 'vxe-upload--file-item-remove-btn',
1446
- onClick (evnt: MouseEvent) {
1447
- removeFileEvent(evnt, item, index)
1448
- }
1449
- }, [
1450
- h('i', {
1451
- class: getIcon().UPLOAD_FILE_REMOVE
1452
- })
1453
- ])
1454
- : renderEmptyElement($xeUpload)
1455
- ])
1456
- ])
1457
- })
1458
- }
1459
-
1460
- const renderFileAction = (isMoreView: boolean) => {
1461
- const { showUploadButton, buttonText, buttonIcon, showButtonText, showButtonIcon, autoHiddenButton } = props
1462
- const { fileList } = reactData
1463
- const isDisabled = computeIsDisabled.value
1464
- const formReadonly = computeFormReadonly.value
1465
- const showTipText = computedShowTipText.value
1466
- const defTipText = computedDefTipText.value
1467
- const overCount = computeOverCount.value
1468
- const defaultSlot = slots.default
1469
- const tipSlot = slots.tip || slots.hint
1470
-
1471
- if (formReadonly || !showUploadButton) {
1472
- return renderEmptyElement($xeUpload)
1473
- }
1474
- return h('div', {
1475
- class: 'vxe-upload--file-action'
1476
- }, [
1477
- autoHiddenButton && overCount
1478
- ? renderEmptyElement($xeUpload)
1479
- : h('div', {
1480
- class: 'vxe-upload--file-action-btn',
1481
- onClick: clickEvent
1482
- }, defaultSlot
1483
- ? getSlotVNs(defaultSlot({ isMoreView, options: fileList, $upload: $xeUpload }))
1484
- : [
1485
- h(VxeButtonComponent, {
1486
- class: 'vxe-upload--file-action-button',
1487
- content: (isMoreView || showButtonText) ? (buttonText ? `${XEUtils.isFunction(buttonText) ? buttonText({}) : buttonText}` : getI18n('vxe.upload.fileBtnText')) : '',
1488
- icon: showButtonIcon ? (buttonIcon || getIcon().UPLOAD_FILE_ADD) : '',
1489
- disabled: isDisabled
1490
- })
1491
- ]),
1492
- showTipText && (defTipText || tipSlot)
1493
- ? h('div', {
1494
- class: 'vxe-upload--file-action-tip'
1495
- }, tipSlot ? getSlotVNs(tipSlot({ isMoreView, options: fileList, $upload: $xeUpload })) : `${defTipText}`)
1496
- : renderEmptyElement($xeUpload)
1497
- ])
1498
- }
1499
-
1500
- const rendeFileMode = () => {
1501
- const { showList, moreConfig, dragSort } = props
1502
- const { fileList, isDragMove } = reactData
1503
- const moreOpts = computeMoreOpts.value
1504
- const { maxCount, showMoreButton, layout, moreButtonText } = moreOpts
1505
- const isHorizontal = layout === 'horizontal'
1506
- const moreBtnSlot = slots.moreButton || slots['more-button']
1507
-
1508
- let currList = fileList
1509
- let overMaxNum = 0
1510
- let isMoreMax = false
1511
- let isMiniMore = false
1512
- if (XEUtils.isNumber(maxCount) && fileList.length > maxCount) {
1513
- isMoreMax = true
1514
- isMiniMore = maxCount === 0
1515
- overMaxNum = fileList.length - maxCount
1516
- currList = fileList.slice(0, maxCount)
1517
- }
1518
-
1519
- return h('div', {
1520
- key: 'all',
1521
- class: 'vxe-upload--file-wrapper'
1522
- }, showList
1523
- ? [
1524
- showMoreButton && moreConfig && isHorizontal
1525
- ? renderEmptyElement($xeUpload)
1526
- : renderFileAction(true),
1527
- h('div', {
1528
- class: ['vxe-upload--file-list-wrapper', {
1529
- 'is--horizontal': isHorizontal
1530
- }]
1531
- }, [
1532
- currList.length
1533
- ? (
1534
- dragSort
1535
- ? h(TransitionGroup, {
1536
- name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
1537
- tag: 'div',
1538
- class: 'vxe-upload--file-list'
1539
- }, {
1540
- default: () => renderFileItemList(currList, false)
1541
- })
1542
- : h('div', {
1543
- class: 'vxe-upload--file-list'
1544
- }, renderFileItemList(currList, false))
1545
- )
1546
- : renderEmptyElement($xeUpload),
1547
- showMoreButton && overMaxNum
1548
- ? h('div', {
1549
- class: 'vxe-upload--file-over-more'
1550
- }, moreBtnSlot
1551
- ? getSlotVNs(moreBtnSlot({ options: fileList }))
1552
- : [
1553
- h(VxeButtonComponent, {
1554
- mode: 'text',
1555
- content: moreButtonText ? (XEUtils.isFunction(moreButtonText) ? moreButtonText({ $upload: $xeUpload, options: fileList }) : XEUtils.toFormatString(moreButtonText, [fileList.length])) : getI18n(isMoreMax && isMiniMore ? 'vxe.upload.moreFileBtnText' : 'vxe.upload.moreBtnText', [fileList.length]),
1556
- status: 'primary',
1557
- onClick: handleMoreEvent
1558
- })
1559
- ])
1560
- : renderEmptyElement($xeUpload),
1561
- showMoreButton && moreConfig && isHorizontal
1562
- ? renderFileAction(false)
1563
- : renderEmptyElement($xeUpload)
1564
- ])
1565
- ]
1566
- : [
1567
- renderFileAction(false)
1568
- ])
1569
- }
1570
-
1571
- const renderImageItemList = (currList: VxeUploadDefines.FileObjItem[], isMoreView: boolean) => {
1572
- const { showRemoveButton, showProgress, progressText, showPreview, showErrorStatus, dragSort, autoSubmit, showSubmitButton } = props
1573
- const { fileList, fileCacheMaps } = reactData
1574
- const isDisabled = computeIsDisabled.value
1575
- const formReadonly = computeFormReadonly.value
1576
- const imageOpts = computeImageOpts.value
1577
- const imgStyle = computeImgStyle.value
1578
- const optionSlot = slots.option
1579
- const actionSlot = slots.action
1580
- const cornerSlot = slots.corner
1581
-
1582
- const ons: Record<string, any> = {
1583
- onMousedown: handleItemMousedownEvent
1584
- }
1585
- if (dragSort && currList.length > 1) {
1586
- ons.onDragstart = handleDragSortDragstartEvent
1587
- ons.onDragover = handleDragSortDragoverEvent
1588
- ons.onDragend = handleDragSortDragendEvent
1589
- }
1590
-
1591
- return currList.map((item, index) => {
1592
- const fileKey = getFieldKey(item)
1593
- const cacheItem = fileCacheMaps[fileKey]
1594
- let isLoading = false
1595
- let isError = false
1596
- let isPending = false
1597
- if (cacheItem) {
1598
- isLoading = cacheItem.loading
1599
- isError = cacheItem.status === 'error'
1600
- isPending = cacheItem.status === 'pending'
1601
- }
1602
- return h('div', {
1603
- key: dragSort ? fileKey : index,
1604
- class: ['vxe-upload--image-item', {
1605
- 'is--preview': showPreview,
1606
- 'is--circle': imageOpts.circle,
1607
- 'is--loading': isLoading,
1608
- 'is--pending': isPending,
1609
- 'is--error': isError
1610
- }],
1611
- fileid: fileKey,
1612
- draggable: dragSort ? true : null,
1613
- ...ons
1614
- }, optionSlot
1615
- ? getSlotVNs(optionSlot({ option: item, isMoreView, options: fileList }))
1616
- : [
1617
- h('div', {
1618
- class: 'vxe-upload--image-item-box',
1619
- style: isMoreView ? null : imgStyle,
1620
- onClick (evnt) {
1621
- if (!isLoading && !isError) {
1622
- handlePreviewImageEvent(evnt, item, index)
1623
- }
1624
- }
1625
- }, [
1626
- isLoading && cacheItem
1627
- ? h('div', {
1628
- class: 'vxe-upload--image-item-loading'
1629
- }, [
1630
- h('div', {
1631
- class: 'vxe-upload--image-item-loading-icon'
1632
- }, [
1633
- h('i', {
1634
- class: getIcon().UPLOAD_LOADING
1635
- })
1636
- ]),
1637
- showProgress
1638
- ? h('div', {
1639
- class: 'vxe-upload--image-item-loading-text'
1640
- }, progressText ? XEUtils.toFormatString(`${XEUtils.isFunction(progressText) ? progressText({}) : progressText}`, { percent: cacheItem.percent }) : getI18n('vxe.upload.uploadProgress', [cacheItem.percent]))
1641
- : renderEmptyElement($xeUpload)
1642
- ])
1643
- : renderEmptyElement($xeUpload),
1644
- h('div', {
1645
- class: 'vxe-upload--image-item-img-wrapper',
1646
- title: getI18n('vxe.upload.viewItemTitle')
1647
- }, [
1648
- h('img', {
1649
- class: 'vxe-upload--image-item-img',
1650
- src: getThumbnailFileUrl(item)
1651
- })
1652
- ]),
1653
- !isLoading && ((isError && showErrorStatus) || (isPending && showSubmitButton && !autoSubmit))
1654
- ? h('div', {
1655
- class: 'vxe-upload--image-item-rebtn'
1656
- }, [
1657
- h(VxeButtonComponent, {
1658
- icon: isError ? getIcon().UPLOAD_IMAGE_RE_UPLOAD : getIcon().UPLOAD_IMAGE_UPLOAD,
1659
- mode: 'text',
1660
- status: 'primary',
1661
- content: isError ? getI18n('vxe.upload.reUpload') : getI18n('vxe.upload.manualUpload'),
1662
- onClick () {
1663
- handleReUpload(item)
1664
- }
1665
- })
1666
- ])
1667
- : renderEmptyElement($xeUpload),
1668
- h('div', {
1669
- class: 'vxe-upload--image-item-btn-wrapper',
1670
- onClick (evnt) {
1671
- evnt.stopPropagation()
1672
- }
1673
- }, actionSlot
1674
- ? getSlotVNs(actionSlot({ option: item, isMoreView, options: fileList, readonly: formReadonly }))
1675
- : [
1676
- cornerSlot
1677
- ? h('div', {
1678
- class: 'vxe-upload--file-item-action'
1679
- }, getSlotVNs(cornerSlot({ option: item, isMoreView, options: fileList, readonly: formReadonly })))
1680
- : renderEmptyElement($xeUpload),
1681
- showRemoveButton && !formReadonly && !isDisabled && !isLoading
1682
- ? h('div', {
1683
- class: 'vxe-upload--image-item-remove-btn',
1684
- onClick (evnt: MouseEvent) {
1685
- evnt.stopPropagation()
1686
- removeFileEvent(evnt, item, index)
1687
- }
1688
- }, [
1689
- h('i', {
1690
- class: getIcon().UPLOAD_IMAGE_REMOVE
1691
- })
1692
- ])
1693
- : renderEmptyElement($xeUpload)
1694
- ])
1695
- ])
1696
- ])
1697
- })
1698
- }
1699
-
1700
- const renderImageAction = (isMoreView: boolean) => {
1701
- const { showUploadButton, buttonText, buttonIcon, showButtonText, showButtonIcon, autoHiddenButton } = props
1702
- const { fileList } = reactData
1703
- const formReadonly = computeFormReadonly.value
1704
- const showTipText = computedShowTipText.value
1705
- const defTipText = computedDefTipText.value
1706
- const overCount = computeOverCount.value
1707
- const imgStyle = computeImgStyle.value
1708
- const defaultSlot = slots.default
1709
- const tipSlot = slots.tip || slots.hint
1710
-
1711
- if (formReadonly || !showUploadButton || (autoHiddenButton && overCount)) {
1712
- return renderEmptyElement($xeUpload)
1713
- }
1714
- return h('div', {
1715
- key: 'action',
1716
- class: 'vxe-upload--image-action'
1717
- }, [
1718
- h('div', {
1719
- class: 'vxe-upload--image-action-btn',
1720
- onClick: clickEvent
1721
- }, defaultSlot
1722
- ? defaultSlot({ isMoreView, options: fileList, $upload: $xeUpload })
1723
- : [
1724
- h('div', {
1725
- class: 'vxe-upload--image-action-box',
1726
- style: isMoreView ? null : imgStyle
1727
- }, [
1728
- showButtonIcon
1729
- ? h('div', {
1730
- class: 'vxe-upload--image-action-icon'
1731
- }, [
1732
- h('i', {
1733
- class: buttonIcon || getIcon().UPLOAD_IMAGE_ADD
1734
- })
1735
- ])
1736
- : renderEmptyElement($xeUpload),
1737
- isMoreView || showButtonText
1738
- ? h('div', {
1739
- class: 'vxe-upload--image-action-content'
1740
- }, buttonText ? `${XEUtils.isFunction(buttonText) ? buttonText({}) : buttonText}` : getI18n('vxe.upload.imgBtnText'))
1741
- : renderEmptyElement($xeUpload),
1742
- showTipText && (defTipText || tipSlot)
1743
- ? h('div', {
1744
- class: 'vxe-upload--image-action-hint'
1745
- }, tipSlot ? getSlotVNs(tipSlot({ isMoreView, options: fileList, $upload: $xeUpload })) : `${defTipText}`)
1746
- : renderEmptyElement($xeUpload)
1747
- ])
1748
- ])
1749
- ])
1750
- }
1751
-
1752
- const renderImageMode = () => {
1753
- const { showList, dragSort } = props
1754
- const { fileList, isDragMove } = reactData
1755
- const moreOpts = computeMoreOpts.value
1756
- const moreBtnSlot = slots.moreButton || slots['more-button']
1757
-
1758
- const { maxCount, showMoreButton, moreButtonText } = moreOpts
1759
- let currList = fileList
1760
- let overMaxNum = 0
1761
- let isMoreMax = false
1762
- let isMiniMore = false
1763
- if (XEUtils.isNumber(maxCount) && fileList.length > maxCount) {
1764
- isMoreMax = true
1765
- isMiniMore = maxCount === 0
1766
- overMaxNum = fileList.length - maxCount
1767
- currList = fileList.slice(0, maxCount)
1768
- }
1769
-
1770
- return h('div', {
1771
- key: 'image',
1772
- class: 'vxe-upload--image-wrapper'
1773
- }, showList
1774
- ? [
1775
- dragSort
1776
- ? h(TransitionGroup, {
1777
- name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
1778
- tag: 'div',
1779
- class: 'vxe-upload--image-list'
1780
- }, {
1781
- default: () => renderImageItemList(currList, false).concat([
1782
- showMoreButton && overMaxNum
1783
- ? h('div', {
1784
- key: 'om',
1785
- class: 'vxe-upload--image-over-more'
1786
- }, moreBtnSlot
1787
- ? getSlotVNs(moreBtnSlot({ options: fileList }))
1788
- : [
1789
- h(VxeButtonComponent, {
1790
- mode: 'text',
1791
- content: moreButtonText ? (XEUtils.isFunction(moreButtonText) ? moreButtonText({ $upload: $xeUpload, options: fileList }) : XEUtils.toFormatString(moreButtonText, [fileList.length])) : getI18n(isMoreMax && isMiniMore ? 'vxe.upload.moreImgBtnText' : 'vxe.upload.moreBtnText', [fileList.length]),
1792
- status: 'primary',
1793
- onClick: handleMoreEvent
1794
- })
1795
- ])
1796
- : renderEmptyElement($xeUpload),
1797
- renderImageAction(false)
1798
- ])
1799
- })
1800
- : h('div', {
1801
- class: 'vxe-upload--image-list'
1802
- }, renderImageItemList(currList, false).concat([
1803
- showMoreButton && overMaxNum
1804
- ? h('div', {
1805
- class: 'vxe-upload--image-over-more'
1806
- }, moreBtnSlot
1807
- ? getSlotVNs(moreBtnSlot({ options: fileList }))
1808
- : [
1809
- h(VxeButtonComponent, {
1810
- mode: 'text',
1811
- content: moreButtonText ? (XEUtils.isFunction(moreButtonText) ? moreButtonText({ $upload: $xeUpload, options: fileList }) : XEUtils.toFormatString(moreButtonText, [fileList.length])) : getI18n(isMoreMax && isMiniMore ? 'vxe.upload.moreImgBtnText' : 'vxe.upload.moreBtnText', [fileList.length]),
1812
- status: 'primary',
1813
- onClick: handleMoreEvent
1814
- })
1815
- ])
1816
- : renderEmptyElement($xeUpload),
1817
- renderImageAction(false)
1818
- ]))
1819
- ]
1820
- : [
1821
- h('div', {
1822
- class: 'vxe-upload--image-list'
1823
- }, [
1824
- renderImageAction(false)
1825
- ])
1826
- ])
1827
- }
1828
-
1829
- const renderVN = () => {
1830
- const { showErrorStatus, dragToUpload, pasteToUpload, dragSort, dragPlaceholder } = props
1831
- const { isDragUploadStatus, showMorePopup, isActivated, dragIndex } = reactData
1832
- const vSize = computeSize.value
1833
- const isDisabled = computeIsDisabled.value
1834
- const formReadonly = computeFormReadonly.value
1835
- const isImage = computeIsImage.value
1836
-
1837
- const ons: Record<string, any> = {
1838
- onMousedown: handleItemMousedownEvent
1839
- }
1840
- if (dragToUpload && dragIndex === -1) {
1841
- ons.onDragover = handleUploadDragoverEvent
1842
- ons.onDragleave = handleUploadDragleaveEvent
1843
- ons.onDrop = handleUploadDropEvent
1844
- }
1845
-
1846
- return h('div', {
1847
- ref: refElem,
1848
- class: ['vxe-upload', {
1849
- [`size--${vSize}`]: vSize,
1850
- 'is--active': isActivated,
1851
- 'is--readonly': formReadonly,
1852
- 'is--disabled': isDisabled,
1853
- 'is--paste': pasteToUpload,
1854
- 'show--error': showErrorStatus,
1855
- 'is--drag': isDragUploadStatus
1856
- }],
1857
- ...ons
1858
- }, [
1859
- isImage ? renderImageMode() : rendeFileMode(),
1860
- dragSort
1861
- ? h('div', {
1862
- ref: refDragLineElem,
1863
- class: 'vxe-upload--drag-line'
1864
- })
1865
- : renderEmptyElement($xeUpload),
1866
- isDragUploadStatus && !showMorePopup
1867
- ? h('div', {
1868
- class: 'vxe-upload--drag-placeholder'
1869
- }, dragPlaceholder || getI18n('vxe.upload.dragPlaceholder'))
1870
- : renderEmptyElement($xeUpload)
1871
- ])
1872
- }
1873
-
1874
- const listFlag = ref(0)
1875
- watch(() => props.modelValue ? props.modelValue.length : 0, () => {
1876
- listFlag.value++
1877
- })
1878
- watch(() => props.modelValue, () => {
1879
- listFlag.value++
1880
- })
1881
- watch(listFlag, () => {
1882
- updateFileList()
1883
- })
1884
-
1885
- onMounted(() => {
1886
- if (props.multiple && props.singleMode) {
1887
- errLog('vxe.error.errConflicts', ['[upload] multiple', 'single-mode'])
1888
- }
1889
- if (props.imageStyle) {
1890
- warnLog('vxe.error.delProp', ['[upload] image-style', 'image-config'])
1891
- }
1892
-
1893
- if (props.dragSort) {
1894
- initTpImg()
1895
- }
1896
- globalEvents.on($xeUpload, 'paste', handleGlobalPasteEvent)
1897
- globalEvents.on($xeUpload, 'click', handleGlobalClickEvent)
1898
- globalEvents.on($xeUpload, 'blur', handleGlobalBlurEvent)
1899
- })
1900
-
1901
- onBeforeUnmount(() => {
1902
- reactData.isDragUploadStatus = false
1903
- globalEvents.off($xeUpload, 'paste')
1904
- globalEvents.off($xeUpload, 'click')
1905
- globalEvents.off($xeUpload, 'blur')
1906
- XEUtils.assign(reactData, createReactData())
1907
- XEUtils.assign(internalData, createInternalData())
1908
- })
1909
-
1910
- updateFileList()
1911
-
1912
- $xeUpload.renderVN = renderVN
1913
-
1914
- return $xeUpload
1915
- },
1916
- render () {
1917
- return this.renderVN()
1918
- }
1919
- })
1
+ import { ref, h, reactive, watch, computed, TransitionGroup, PropType, inject, onBeforeUnmount, onMounted, nextTick } from 'vue'
2
+ import { defineVxeComponent } from '../../ui/src/comp'
3
+ import XEUtils from 'xe-utils'
4
+ import { VxeUI, getConfig, getI18n, getIcon, useSize, createEvent, globalEvents, renderEmptyElement } from '../../ui'
5
+ import { getSlotVNs } from '../../ui/src/vn'
6
+ import { errLog, warnLog } from '../../ui/src/log'
7
+ import { initTpImg, getTpImg, getEventTargetNode, toCssUnit } from '../../ui/src/dom'
8
+ import { readLocalFile } from './util'
9
+ import VxeButtonComponent from '../../button/src/button'
10
+
11
+ import type { VxeUploadDefines, VxeUploadPropTypes, UploadReactData, UploadInternalData, UploadPrivateMethods, UploadMethods, VxeUploadEmits, UploadPrivateRef, VxeUploadPrivateComputed, VxeUploadConstructor, VxeUploadPrivateMethods, VxeFormDefines, VxeFormConstructor, VxeFormPrivateMethods, ValueOf, VxeComponentEventParams } from '../../../types'
12
+ import type { VxeTableConstructor, VxeTablePrivateMethods } from '../../../types/components/table'
13
+
14
+ function createReactData (): UploadReactData {
15
+ return {
16
+ isDragUploadStatus: false,
17
+ showMorePopup: false,
18
+ isActivated: false,
19
+ fileList: [],
20
+ fileCacheMaps: {},
21
+ isDragMove: false,
22
+ dragIndex: -1,
23
+ dragTipText: ''
24
+ }
25
+ }
26
+
27
+ function createInternalData (): UploadInternalData {
28
+ return {
29
+ moreId: XEUtils.uniqueId('upload'),
30
+ imagePreviewTypes: ['jpg', 'jpeg', 'png', 'gif'],
31
+ prevDragIndex: -1
32
+ // prevDragPos: ''
33
+ }
34
+ }
35
+
36
+ export default defineVxeComponent({
37
+ name: 'VxeUpload',
38
+ props: {
39
+ modelValue: [Array, String, Object] as PropType<VxeUploadPropTypes.ModelValue>,
40
+ showList: {
41
+ type: Boolean as PropType<VxeUploadPropTypes.ShowList>,
42
+ default: () => getConfig().upload.showList
43
+ },
44
+ moreConfig: Object as PropType<VxeUploadPropTypes.MoreConfig>,
45
+ readonly: {
46
+ type: Boolean as PropType<VxeUploadPropTypes.Readonly>,
47
+ default: null
48
+ },
49
+ disabled: {
50
+ type: Boolean as PropType<VxeUploadPropTypes.Disabled>,
51
+ default: null
52
+ },
53
+ autoSubmit: {
54
+ type: Boolean as PropType<VxeUploadPropTypes.AutoSubmit>,
55
+ default: () => getConfig().upload.autoSubmit
56
+ },
57
+ mode: {
58
+ type: String as PropType<VxeUploadPropTypes.Mode>,
59
+ default: () => getConfig().upload.mode
60
+ },
61
+ imageTypes: {
62
+ type: Array as PropType<VxeUploadPropTypes.ImageTypes>,
63
+ default: () => XEUtils.clone(getConfig().upload.imageTypes, true)
64
+ },
65
+ imageConfig: {
66
+ type: Object as PropType<VxeUploadPropTypes.ImageConfig>,
67
+ default: () => XEUtils.clone(getConfig().upload.imageConfig, true)
68
+ },
69
+ /**
70
+ * 已废弃,被 image-config 替换
71
+ * @deprecated
72
+ */
73
+ imageStyle: {
74
+ type: Object as PropType<VxeUploadPropTypes.ImageStyle>,
75
+ default: () => XEUtils.clone(getConfig().upload.imageStyle, true)
76
+ },
77
+ fileTypes: {
78
+ type: Array as PropType<VxeUploadPropTypes.FileTypes>,
79
+ default: () => XEUtils.clone(getConfig().upload.fileTypes, true)
80
+ },
81
+ dragSort: Boolean as PropType<VxeUploadPropTypes.DragSort>,
82
+ dragToUpload: {
83
+ type: Boolean as PropType<VxeUploadPropTypes.DragToUpload>,
84
+ default: () => XEUtils.clone(getConfig().upload.dragToUpload, true)
85
+ },
86
+ dragPlaceholder: {
87
+ type: String as PropType<VxeUploadPropTypes.DragPlaceholder>,
88
+ default: () => getConfig().upload.dragPlaceholder
89
+ },
90
+ pasteToUpload: {
91
+ type: Boolean as PropType<VxeUploadPropTypes.PasteToUpload>,
92
+ default: () => XEUtils.clone(getConfig().upload.pasteToUpload, true)
93
+ },
94
+ keyField: String as PropType<VxeUploadPropTypes.KeyField>,
95
+ singleMode: Boolean as PropType<VxeUploadPropTypes.SingleMode>,
96
+ urlMode: Boolean as PropType<VxeUploadPropTypes.UrlMode>,
97
+ urlArgs: {
98
+ type: Boolean as PropType<VxeUploadPropTypes.UrlArgs>,
99
+ default: () => getConfig().upload.urlArgs
100
+ },
101
+ multiple: Boolean as PropType<VxeUploadPropTypes.Multiple>,
102
+ limitSize: {
103
+ type: [String, Number] as PropType<VxeUploadPropTypes.LimitSize>,
104
+ default: () => getConfig().upload.limitSize
105
+ },
106
+ showLimitSize: {
107
+ type: Boolean as PropType<VxeUploadPropTypes.ShowLimitSize>,
108
+ default: () => getConfig().upload.showLimitSize
109
+ },
110
+ limitSizeText: {
111
+ type: [String, Number, Function] as PropType<VxeUploadPropTypes.LimitSizeText>,
112
+ default: () => getConfig().upload.limitSizeText
113
+ },
114
+ limitCount: {
115
+ type: [String, Number] as PropType<VxeUploadPropTypes.LimitCount>,
116
+ default: () => getConfig().upload.limitCount
117
+ },
118
+ showLimitCount: {
119
+ type: Boolean as PropType<VxeUploadPropTypes.ShowLimitCount>,
120
+ default: () => getConfig().upload.showLimitCount
121
+ },
122
+ limitCountText: {
123
+ type: [String, Number, Function] as PropType<VxeUploadPropTypes.LimitCountText>,
124
+ default: () => getConfig().upload.limitCountText
125
+ },
126
+ nameField: {
127
+ type: String as PropType<VxeUploadPropTypes.NameField>,
128
+ default: () => getConfig().upload.nameField
129
+ },
130
+ typeField: {
131
+ type: String as PropType<VxeUploadPropTypes.TypeField>,
132
+ default: () => getConfig().upload.typeField
133
+ },
134
+ urlField: {
135
+ type: String as PropType<VxeUploadPropTypes.UrlField>,
136
+ default: () => getConfig().upload.urlField
137
+ },
138
+ sizeField: {
139
+ type: String as PropType<VxeUploadPropTypes.SizeField>,
140
+ default: () => getConfig().upload.sizeField
141
+ },
142
+ showErrorStatus: {
143
+ type: Boolean as PropType<VxeUploadPropTypes.ShowErrorStatus>,
144
+ default: () => getConfig().upload.showErrorStatus
145
+ },
146
+ showProgress: {
147
+ type: Boolean as PropType<VxeUploadPropTypes.ShowProgress>,
148
+ default: () => getConfig().upload.showProgress
149
+ },
150
+ progressText: {
151
+ type: [String, Number, Function] as PropType<VxeUploadPropTypes.ProgressText>,
152
+ default: () => getConfig().upload.progressText
153
+ },
154
+ previewImageConfig: Object as PropType<VxeUploadPropTypes.PreviewImageConfig>,
155
+ showSubmitButton: Boolean as PropType<VxeUploadPropTypes.ShowSubmitButton>,
156
+ autoHiddenButton: {
157
+ type: Boolean as PropType<VxeUploadPropTypes.AutoHiddenButton>,
158
+ default: () => getConfig().upload.autoHiddenButton
159
+ },
160
+ showUploadButton: {
161
+ type: Boolean as PropType<VxeUploadPropTypes.ShowUploadButton>,
162
+ default: () => getConfig().upload.showUploadButton
163
+ },
164
+ buttonText: {
165
+ type: [String, Number, Function] as PropType<VxeUploadPropTypes.ButtonText>,
166
+ default: () => getConfig().upload.buttonText
167
+ },
168
+ buttonIcon: {
169
+ type: String as PropType<VxeUploadPropTypes.ButtonIcon>,
170
+ default: () => getConfig().upload.buttonIcon
171
+ },
172
+ showButtonText: {
173
+ type: Boolean as PropType<VxeUploadPropTypes.ShowButtonText>,
174
+ default: () => getConfig().upload.showButtonText
175
+ },
176
+ showButtonIcon: {
177
+ type: Boolean as PropType<VxeUploadPropTypes.ShowButtonIcon>,
178
+ default: () => getConfig().upload.showButtonIcon
179
+ },
180
+ showRemoveButton: {
181
+ type: Boolean as PropType<VxeUploadPropTypes.ShowRemoveButton>,
182
+ default: () => getConfig().upload.showRemoveButton
183
+ },
184
+ showDownloadButton: {
185
+ type: Boolean as PropType<VxeUploadPropTypes.ShowDownloadButton>,
186
+ default: () => getConfig().upload.showDownloadButton
187
+ },
188
+ showPreview: {
189
+ type: Boolean as PropType<VxeUploadPropTypes.ShowPreview>,
190
+ default: () => getConfig().upload.showPreview
191
+ },
192
+ showTip: {
193
+ type: Boolean as PropType<VxeUploadPropTypes.ShowTip>,
194
+ default: () => null
195
+ },
196
+ maxSimultaneousUploads: {
197
+ type: Number as PropType<VxeUploadPropTypes.MaxSimultaneousUploads>,
198
+ default: () => getConfig().upload.maxSimultaneousUploads
199
+ },
200
+ tipText: [String, Number, Function] as PropType<VxeUploadPropTypes.TipText>,
201
+ hintText: String as PropType<VxeUploadPropTypes.HintText>,
202
+ previewMethod: Function as PropType<VxeUploadPropTypes.PreviewMethod>,
203
+ beforeSelectMethod: Function as PropType<VxeUploadPropTypes.BeforeSelectMethod>,
204
+ uploadMethod: Function as PropType<VxeUploadPropTypes.UploadMethod>,
205
+ beforeRemoveMethod: Function as PropType<VxeUploadPropTypes.BeforeRemoveMethod>,
206
+ removeMethod: Function as PropType<VxeUploadPropTypes.RemoveMethod>,
207
+ beforeDownloadMethod: Function as PropType<VxeUploadPropTypes.BeforeDownloadMethod>,
208
+ downloadMethod: Function as PropType<VxeUploadPropTypes.DownloadMethod>,
209
+ getUrlMethod: Function as PropType<VxeUploadPropTypes.GetUrlMethod>,
210
+ getThumbnailUrlMethod: Function as PropType<VxeUploadPropTypes.GetThumbnailUrlMethod>,
211
+ size: {
212
+ type: String as PropType<VxeUploadPropTypes.Size>,
213
+ default: () => getConfig().upload.size || getConfig().size
214
+ }
215
+ },
216
+ emits: [
217
+ 'update:modelValue',
218
+ 'add',
219
+ 'remove',
220
+ 'remove-fail',
221
+ 'download',
222
+ 'download-fail',
223
+ 'upload-success',
224
+ 'upload-error',
225
+ 'sort-dragend',
226
+ 'more-visible'
227
+ ] as VxeUploadEmits,
228
+ setup (props, context) {
229
+ const { emit, slots } = context
230
+
231
+ const $xeForm = inject<VxeFormConstructor & VxeFormPrivateMethods | null>('$xeForm', null)
232
+ const formItemInfo = inject<VxeFormDefines.ProvideItemInfo | null>('xeFormItemInfo', null)
233
+ const $xeTable = inject<(VxeTableConstructor & VxeTablePrivateMethods) | null>('$xeTable', null)
234
+
235
+ const xID = XEUtils.uniqueId()
236
+
237
+ const { computeSize } = useSize(props)
238
+
239
+ const refElem = ref<HTMLDivElement>()
240
+ const refPopupElem = ref<HTMLDivElement>()
241
+ const refDragLineElem = ref<HTMLDivElement>()
242
+ const refModalDragLineElem = ref<HTMLDivElement>()
243
+
244
+ const reactData = reactive(createReactData())
245
+
246
+ const internalData = createInternalData()
247
+
248
+ const refMaps: UploadPrivateRef = {
249
+ refElem
250
+ }
251
+
252
+ const computeFormReadonly = computed(() => {
253
+ const { readonly } = props
254
+ if (readonly === null) {
255
+ if ($xeForm) {
256
+ return $xeForm.props.readonly
257
+ }
258
+ return false
259
+ }
260
+ return readonly
261
+ })
262
+
263
+ const computeIsDisabled = computed(() => {
264
+ const { disabled } = props
265
+ if (disabled === null) {
266
+ if ($xeForm) {
267
+ return $xeForm.props.disabled
268
+ }
269
+ return false
270
+ }
271
+ return disabled
272
+ })
273
+
274
+ const computeKeyField = computed(() => {
275
+ return props.keyField || '_X_KEY'
276
+ })
277
+
278
+ const computeIsImage = computed(() => {
279
+ return props.mode === 'image'
280
+ })
281
+
282
+ const computeNameProp = computed(() => {
283
+ return props.nameField || 'name'
284
+ })
285
+
286
+ const computeTypeProp = computed(() => {
287
+ return props.typeField || 'type'
288
+ })
289
+
290
+ const computeUrlProp = computed(() => {
291
+ return props.urlField || 'url'
292
+ })
293
+
294
+ const computeSizeProp = computed(() => {
295
+ return props.sizeField || 'size'
296
+ })
297
+
298
+ const computeLimitMaxSize = computed(() => {
299
+ return XEUtils.toNumber(props.limitSize) * 1024 * 1024
300
+ })
301
+
302
+ const computeLimitMaxCount = computed(() => {
303
+ return props.multiple ? XEUtils.toNumber(props.limitCount) : 1
304
+ })
305
+
306
+ const computePreviewImageOpts = computed(() => {
307
+ const { showDownloadButton } = props
308
+ return Object.assign({
309
+ showDownloadButton
310
+ }, getConfig().upload.previewImageConfig, props.previewImageConfig)
311
+ })
312
+
313
+ const computeOverCount = computed(() => {
314
+ const { multiple } = props
315
+ const { fileList } = reactData
316
+ const limitMaxCount = computeLimitMaxCount.value
317
+ if (multiple) {
318
+ if (limitMaxCount) {
319
+ return fileList.length >= limitMaxCount
320
+ }
321
+ return true
322
+ }
323
+ return fileList.length >= 1
324
+ })
325
+
326
+ const computeLimitSizeUnit = computed(() => {
327
+ const limitSize = XEUtils.toNumber(props.limitSize)
328
+ if (limitSize) {
329
+ if (limitSize > 1048576) {
330
+ return `${limitSize / 1048576}T`
331
+ }
332
+ if (limitSize > 1024) {
333
+ return `${limitSize / 1024}G`
334
+ }
335
+ return `${limitSize}M`
336
+ }
337
+ return ''
338
+ })
339
+
340
+ const computedShowTipText = computed(() => {
341
+ const { showTip, tipText } = props
342
+ if (XEUtils.isBoolean(showTip)) {
343
+ return showTip
344
+ }
345
+ const defShowTip = getConfig().upload.showTip
346
+ if (XEUtils.isBoolean(defShowTip)) {
347
+ return defShowTip
348
+ }
349
+ if (tipText) {
350
+ return true
351
+ }
352
+ return false
353
+ })
354
+
355
+ const computedDefTipText = computed(() => {
356
+ const { limitSize, fileTypes, multiple, limitCount } = props
357
+ const tipText = props.tipText || props.hintText
358
+ const isImage = computeIsImage.value
359
+ const limitSizeUnit = computeLimitSizeUnit.value
360
+ if (XEUtils.isString(tipText)) {
361
+ return tipText
362
+ }
363
+ if (XEUtils.isFunction(tipText)) {
364
+ return `${tipText({})}`
365
+ }
366
+ const defTips: string[] = []
367
+ if (isImage) {
368
+ if (multiple && limitCount) {
369
+ defTips.push(getI18n('vxe.upload.imgCountHint', [limitCount]))
370
+ }
371
+ if (limitSize && limitSizeUnit) {
372
+ defTips.push(getI18n('vxe.upload.imgSizeHint', [limitSizeUnit]))
373
+ }
374
+ } else {
375
+ if (fileTypes && fileTypes.length) {
376
+ defTips.push(getI18n('vxe.upload.fileTypeHint', [fileTypes.join('/')]))
377
+ }
378
+ if (limitSize && limitSizeUnit) {
379
+ defTips.push(getI18n('vxe.upload.fileSizeHint', [limitSizeUnit]))
380
+ }
381
+ if (multiple && limitCount) {
382
+ defTips.push(getI18n('vxe.upload.fileCountHint', [limitCount]))
383
+ }
384
+ }
385
+ return defTips.join(getI18n('vxe.base.comma'))
386
+ })
387
+
388
+ const computeImageOpts = computed(() => {
389
+ return Object.assign({}, props.imageConfig || props.imageStyle)
390
+ })
391
+
392
+ const computeImgStyle = computed(() => {
393
+ const imageOpts = computeImageOpts.value
394
+ const { width, height } = imageOpts
395
+ const stys: Record<string, string> = {}
396
+ if (width) {
397
+ stys.width = toCssUnit(width)
398
+ }
399
+ if (height) {
400
+ stys.height = toCssUnit(height)
401
+ }
402
+ return stys
403
+ })
404
+
405
+ const computeMoreOpts = computed(() => {
406
+ return Object.assign({ showMoreButton: true }, props.moreConfig)
407
+ })
408
+
409
+ const computeMaps: VxeUploadPrivateComputed = {
410
+ }
411
+
412
+ const $xeUpload = {
413
+ xID,
414
+ props,
415
+ context,
416
+ reactData,
417
+ internalData,
418
+
419
+ getRefMaps: () => refMaps,
420
+ getComputeMaps: () => computeMaps
421
+ } as unknown as VxeUploadConstructor & VxeUploadPrivateMethods
422
+
423
+ const getUniqueKey = () => {
424
+ return XEUtils.uniqueId()
425
+ }
426
+
427
+ const getFieldKey = (item: VxeUploadDefines.FileObjItem) => {
428
+ const keyField = computeKeyField.value
429
+ return item[keyField]
430
+ }
431
+
432
+ const updateFileList = () => {
433
+ const { modelValue, multiple } = props
434
+ const formReadonly = computeFormReadonly.value
435
+ const keyField = computeKeyField.value
436
+ const nameProp = computeNameProp.value
437
+ const typeProp = computeTypeProp.value
438
+ const urlProp = computeUrlProp.value
439
+ const sizeProp = computeSizeProp.value
440
+ const fileList = modelValue
441
+ ? (modelValue ? (XEUtils.isArray(modelValue) ? modelValue : [modelValue]) : []).map(item => {
442
+ if (!item || XEUtils.isString(item)) {
443
+ const url = `${item || ''}`
444
+ const urlObj = XEUtils.parseUrl(item)
445
+ const name = (urlObj ? urlObj.searchQuery[nameProp] : '') || parseFileName(url)
446
+ return {
447
+ [nameProp]: name,
448
+ [typeProp]: (urlObj ? urlObj.searchQuery[typeProp] : '') || parseFileType(name),
449
+ [urlProp]: url,
450
+ [sizeProp]: XEUtils.toNumber(urlObj ? urlObj.searchQuery[sizeProp] : 0) || 0,
451
+ [keyField]: getUniqueKey()
452
+ }
453
+ }
454
+ const name = item[nameProp] || ''
455
+ item[nameProp] = name
456
+ item[typeProp] = item[typeProp] || parseFileType(name)
457
+ item[urlProp] = item[urlProp] || ''
458
+ item[sizeProp] = item[sizeProp] || 0
459
+ item[keyField] = item[keyField] || getUniqueKey()
460
+ return item
461
+ })
462
+ : []
463
+ reactData.fileList = (formReadonly || multiple) ? fileList : (fileList.slice(0, 1))
464
+ }
465
+
466
+ const parseFileName = (url: string) => {
467
+ return decodeURIComponent(`${url || ''}`).split('/').pop() || ''
468
+ }
469
+
470
+ const parseFileType = (name: string) => {
471
+ // 这里不用split('.').pop()因为没有后缀时会返回自身
472
+ const index = name.lastIndexOf('.')
473
+ if (index > 0) {
474
+ return name.substring(index + 1).toLowerCase()
475
+ }
476
+ return ''
477
+ }
478
+
479
+ const dispatchEvent = (type: ValueOf<VxeUploadEmits>, params: Record<string, any>, evnt: Event | null) => {
480
+ emit(type, createEvent(evnt, { $upload: $xeUpload }, params))
481
+ }
482
+
483
+ const emitModel = (value: any) => {
484
+ emit('update:modelValue', value)
485
+ }
486
+
487
+ const handleChange = (value: VxeUploadDefines.FileObjItem[]) => {
488
+ const { singleMode, urlMode, urlArgs } = props
489
+ const urlProp = computeUrlProp.value
490
+ const nameProp = computeNameProp.value
491
+ let restList = value ? value.slice(0) : []
492
+ if (urlMode) {
493
+ restList = restList.map(item => {
494
+ const url = item[urlProp]
495
+ if (url && urlArgs) {
496
+ const urlObj = XEUtils.parseUrl(url)
497
+ if (!urlObj.searchQuery[nameProp]) {
498
+ if (url.indexOf('blob:') === -1) {
499
+ return `${url}${url.indexOf('?') === -1 ? '?' : '&'}${nameProp}=${encodeURIComponent(item[nameProp] || '')}`
500
+ }
501
+ }
502
+ }
503
+ return url
504
+ })
505
+ }
506
+ emitModel(singleMode ? (restList[0] || null) : restList)
507
+ }
508
+
509
+ const getThumbnailFileUrl = (item: VxeUploadDefines.FileObjItem) => {
510
+ const getThumbnailUrlFn = props.getThumbnailUrlMethod || getConfig().upload.getThumbnailUrlMethod
511
+ if (getThumbnailUrlFn) {
512
+ return getThumbnailUrlFn({
513
+ $upload: $xeUpload,
514
+ option: item
515
+ })
516
+ }
517
+ return getFileUrl(item)
518
+ }
519
+
520
+ const getFileUrl = (item: VxeUploadDefines.FileObjItem) => {
521
+ const getUrlFn = props.getUrlMethod || getConfig().upload.getUrlMethod
522
+ const urlProp = computeUrlProp.value
523
+ return getUrlFn
524
+ ? getUrlFn({
525
+ $upload: $xeUpload,
526
+ option: item
527
+ })
528
+ : item[urlProp]
529
+ }
530
+
531
+ const handleDefaultFilePreview = (item: VxeUploadDefines.FileObjItem) => {
532
+ const { imageTypes, showDownloadButton } = props
533
+ const typeProp = computeTypeProp.value
534
+ const previewImageOpts = computePreviewImageOpts.value
535
+ const beforeDownloadFn = props.beforeDownloadMethod || getConfig().upload.beforeDownloadMethod
536
+ const { imagePreviewTypes } = internalData
537
+ // 如果是预览图片
538
+ if (imagePreviewTypes.concat(imageTypes || []).some(type => `${type}`.toLowerCase() === `${item[typeProp]}`.toLowerCase())) {
539
+ if (VxeUI.previewImage) {
540
+ VxeUI.previewImage({
541
+ ...previewImageOpts,
542
+ urlList: [getFileUrl(item)],
543
+ showDownloadButton,
544
+ beforeDownloadMethod: beforeDownloadFn
545
+ ? () => {
546
+ return beforeDownloadFn({
547
+ $upload: $xeUpload,
548
+ option: item
549
+ })
550
+ }
551
+ : undefined
552
+ })
553
+ }
554
+ }
555
+ }
556
+
557
+ const handlePreviewFileEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem) => {
558
+ const previewFn = props.previewMethod || getConfig().upload.previewMethod
559
+ if (props.showPreview) {
560
+ if (previewFn) {
561
+ previewFn({
562
+ $upload: $xeUpload,
563
+ option: item
564
+ })
565
+ } else {
566
+ handleDefaultFilePreview(item)
567
+ }
568
+ }
569
+ }
570
+
571
+ const handlePreviewImageEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem, index: number) => {
572
+ const { showDownloadButton } = props
573
+ const { fileList } = reactData
574
+ const previewImageOpts = computePreviewImageOpts.value
575
+ const previewFn = props.previewMethod || getConfig().upload.previewMethod
576
+ const beforeDownloadFn = props.beforeDownloadMethod || getConfig().upload.beforeDownloadMethod
577
+ if (props.showPreview) {
578
+ if (previewFn) {
579
+ previewFn({
580
+ $upload: $xeUpload,
581
+ option: item
582
+ })
583
+ } else if (VxeUI.previewImage) {
584
+ VxeUI.previewImage({
585
+ ...previewImageOpts,
586
+ urlList: fileList.map(item => getFileUrl(item)),
587
+ activeIndex: index,
588
+ showDownloadButton,
589
+ beforeDownloadMethod: beforeDownloadFn
590
+ ? ({ index }) => {
591
+ return beforeDownloadFn({
592
+ $upload: $xeUpload,
593
+ option: fileList[index]
594
+ })
595
+ }
596
+ : undefined
597
+ })
598
+ }
599
+ }
600
+ }
601
+
602
+ const handleUploadResult = (item: VxeUploadDefines.FileObjItem, file: File) => {
603
+ const { showErrorStatus } = props
604
+ const fileKey = getFieldKey(item)
605
+ const uploadFn = props.uploadMethod || getConfig().upload.uploadMethod
606
+ if (uploadFn) {
607
+ return Promise.resolve(
608
+ uploadFn({
609
+ $upload: $xeUpload,
610
+ file,
611
+ option: item,
612
+ updateProgress (percentNum) {
613
+ const { fileCacheMaps } = reactData
614
+ const cacheItem = fileCacheMaps[getFieldKey(item)]
615
+ if (cacheItem) {
616
+ cacheItem.percent = Math.max(0, Math.min(99, XEUtils.toNumber(percentNum)))
617
+ }
618
+ }
619
+ })
620
+ ).then(res => {
621
+ const { fileCacheMaps } = reactData
622
+ const cacheItem = fileCacheMaps[fileKey]
623
+ if (cacheItem) {
624
+ cacheItem.percent = 100
625
+ cacheItem.status = 'success'
626
+ }
627
+ Object.assign(item, res)
628
+ dispatchEvent('upload-success', { option: item, data: res }, null)
629
+ }).catch((res) => {
630
+ const { fileCacheMaps } = reactData
631
+ const cacheItem = fileCacheMaps[fileKey]
632
+ if (cacheItem) {
633
+ cacheItem.status = 'error'
634
+ }
635
+ if (showErrorStatus) {
636
+ Object.assign(item, res)
637
+ } else {
638
+ reactData.fileList = reactData.fileList.filter(obj => getFieldKey(obj) !== fileKey)
639
+ delete fileCacheMaps[fileKey]
640
+ }
641
+ dispatchEvent('upload-error', { option: item, data: res }, null)
642
+ }).finally(() => {
643
+ const { fileCacheMaps } = reactData
644
+ const cacheItem = fileCacheMaps[fileKey]
645
+ if (cacheItem) {
646
+ cacheItem.loading = false
647
+ }
648
+ })
649
+ } else {
650
+ const { fileCacheMaps } = reactData
651
+ const cacheItem = fileCacheMaps[fileKey]
652
+ if (cacheItem) {
653
+ cacheItem.loading = false
654
+ }
655
+ }
656
+ return Promise.resolve()
657
+ }
658
+
659
+ const handleReUpload = (item: VxeUploadDefines.FileObjItem) => {
660
+ const { uploadMethod, urlMode } = props
661
+ const { fileCacheMaps } = reactData
662
+ const fileKey = getFieldKey(item)
663
+ const cacheItem = fileCacheMaps[fileKey]
664
+ const uploadFn = uploadMethod || getConfig().upload.uploadMethod
665
+ if (uploadFn && cacheItem) {
666
+ const file = cacheItem.file
667
+ cacheItem.loading = true
668
+ cacheItem.status = 'pending'
669
+ cacheItem.percent = 0
670
+ handleUploadResult(item, file).then(() => {
671
+ if (urlMode) {
672
+ handleChange(reactData.fileList)
673
+ }
674
+ })
675
+ }
676
+ }
677
+ const handleUploadFile = (files: File[], evnt: Event | null) => {
678
+ const { multiple, urlMode, showLimitSize, limitSizeText, showLimitCount, limitCountText, autoSubmit } = props
679
+ const { fileList } = reactData
680
+ const beforeSelectFn = props.beforeSelectMethod || getConfig().upload.beforeSelectMethod
681
+ const uploadFn = props.uploadMethod || getConfig().upload.uploadMethod
682
+ const keyField = computeKeyField.value
683
+ const nameProp = computeNameProp.value
684
+ const typeProp = computeTypeProp.value
685
+ const urlProp = computeUrlProp.value
686
+ const sizeProp = computeSizeProp.value
687
+ const limitMaxSize = computeLimitMaxSize.value
688
+ const limitMaxCount = computeLimitMaxCount.value
689
+ const limitSizeUnit = computeLimitSizeUnit.value
690
+ let selectFiles = files
691
+
692
+ if (multiple && limitMaxCount) {
693
+ // 校验文件数量
694
+ if (showLimitCount && fileList.length >= limitMaxCount) {
695
+ if (VxeUI.modal) {
696
+ VxeUI.modal.notification({
697
+ title: getI18n('vxe.modal.errTitle'),
698
+ status: 'error',
699
+ content: limitCountText ? `${XEUtils.isFunction(limitCountText) ? limitCountText({ maxCount: limitMaxCount }) : limitCountText}` : getI18n('vxe.upload.overCountErr', [limitMaxCount])
700
+ })
701
+ }
702
+ return
703
+ }
704
+ const overNum = selectFiles.length - (limitMaxCount - fileList.length)
705
+ if (showLimitCount && overNum > 0) {
706
+ const overExtraList = selectFiles.slice(limitMaxCount - fileList.length)
707
+ if (limitCountText) {
708
+ VxeUI.modal.notification({
709
+ title: getI18n('vxe.modal.errTitle'),
710
+ status: 'error',
711
+ content: `${XEUtils.isFunction(limitCountText) ? limitCountText({ maxCount: limitMaxCount }) : limitCountText}`
712
+ })
713
+ } else if (VxeUI.modal) {
714
+ VxeUI.modal.notification({
715
+ title: getI18n('vxe.modal.errTitle'),
716
+ status: 'error',
717
+ width: null,
718
+ slots: {
719
+ default () {
720
+ return h('div', {
721
+ class: 'vxe-upload--file-message-over-error'
722
+ }, [
723
+ h('div', {}, getI18n('vxe.upload.overCountExtraErr', [limitMaxCount, overNum])),
724
+ h('div', {
725
+ class: 'vxe-upload--file-message-over-extra'
726
+ }, overExtraList.map((file, index) => {
727
+ return h('div', {
728
+ key: index,
729
+ class: 'vxe-upload--file-message-over-extra-item'
730
+ }, file.name)
731
+ }))
732
+ ])
733
+ }
734
+ }
735
+ })
736
+ }
737
+ }
738
+ selectFiles = selectFiles.slice(0, limitMaxCount - fileList.length)
739
+ }
740
+
741
+ // 校验文件大小
742
+ if (showLimitSize && limitMaxSize) {
743
+ for (let i = 0; i < files.length; i++) {
744
+ const file = files[0]
745
+ if (file.size > limitMaxSize) {
746
+ if (VxeUI.modal) {
747
+ VxeUI.modal.notification({
748
+ title: getI18n('vxe.modal.errTitle'),
749
+ status: 'error',
750
+ content: limitSizeText ? `${XEUtils.isFunction(limitSizeText) ? limitSizeText({ maxSize: limitMaxSize }) : limitSizeText}` : getI18n('vxe.upload.overSizeErr', [limitSizeUnit])
751
+ })
752
+ }
753
+ return
754
+ }
755
+ }
756
+ }
757
+
758
+ const cacheMaps = Object.assign({}, reactData.fileCacheMaps)
759
+ const newFileList = multiple ? fileList : []
760
+ const uploadPromiseRests: any[] = []
761
+ selectFiles.forEach(file => {
762
+ const { name } = file
763
+ const fileKey = getUniqueKey()
764
+ const fileObj: VxeUploadDefines.FileObjItem = {
765
+ [nameProp]: name,
766
+ [typeProp]: parseFileType(name),
767
+ [sizeProp]: file.size,
768
+ [urlProp]: URL.createObjectURL(file),
769
+ [keyField]: fileKey
770
+ }
771
+ if (uploadFn) {
772
+ cacheMaps[fileKey] = {
773
+ file: file,
774
+ loading: !!autoSubmit,
775
+ status: 'pending',
776
+ percent: 0
777
+ }
778
+ }
779
+ const item = reactive(fileObj)
780
+ if (!beforeSelectFn || beforeSelectFn({ $upload: $xeUpload, file })) {
781
+ if (uploadFn && autoSubmit) {
782
+ uploadPromiseRests.push(
783
+ handleUploadResult(item, file)
784
+ )
785
+ }
786
+ newFileList.push(item)
787
+ }
788
+ })
789
+ reactData.fileList = newFileList
790
+ reactData.fileCacheMaps = cacheMaps
791
+ newFileList.forEach(item => {
792
+ dispatchEvent('add', { option: item }, evnt)
793
+ })
794
+ Promise.all(urlMode ? uploadPromiseRests : []).then(() => {
795
+ const restFileList = reactData.fileList
796
+ handleChange(restFileList)
797
+ // 自动更新校验状态
798
+ if ($xeForm && formItemInfo) {
799
+ $xeForm.triggerItemEvent(evnt as any, formItemInfo.itemConfig.field, restFileList)
800
+ }
801
+ })
802
+ }
803
+
804
+ const handleChoose = (evnt: MouseEvent | null) => {
805
+ const { multiple, imageTypes, fileTypes } = props
806
+ const isDisabled = computeIsDisabled.value
807
+ const isImage = computeIsImage.value
808
+ if (isDisabled) {
809
+ return Promise.resolve({
810
+ status: false,
811
+ files: [],
812
+ file: null
813
+ })
814
+ }
815
+ return readLocalFile({
816
+ multiple,
817
+ types: isImage ? imageTypes : fileTypes
818
+ }).then((params) => {
819
+ handleUploadFile(params.files, evnt)
820
+ return params
821
+ })
822
+ }
823
+
824
+ const clickEvent = (evnt: MouseEvent) => {
825
+ handleChoose(evnt).catch(() => {
826
+ // 错误文件类型
827
+ })
828
+ }
829
+
830
+ const handleRemoveEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem, index: number) => {
831
+ const { fileList } = reactData
832
+ fileList.splice(index, 1)
833
+ handleChange(fileList)
834
+ // 自动更新校验状态
835
+ if ($xeForm && formItemInfo) {
836
+ $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, fileList)
837
+ }
838
+ dispatchEvent('remove', { option: item }, evnt)
839
+ }
840
+
841
+ const removeFileEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem, index: number) => {
842
+ const beforeRemoveFn = props.beforeRemoveMethod || getConfig().upload.beforeRemoveMethod
843
+ const removeFn = props.removeMethod || getConfig().upload.removeMethod
844
+ Promise.resolve(
845
+ beforeRemoveFn
846
+ ? beforeRemoveFn({
847
+ $upload: $xeUpload,
848
+ option: item
849
+ })
850
+ : true
851
+ ).then(status => {
852
+ if (status) {
853
+ if (removeFn) {
854
+ Promise.resolve(
855
+ removeFn({
856
+ $upload: $xeUpload,
857
+ option: item
858
+ })
859
+ ).then(() => {
860
+ handleRemoveEvent(evnt, item, index)
861
+ }).catch(e => e)
862
+ } else {
863
+ handleRemoveEvent(evnt, item, index)
864
+ }
865
+ } else {
866
+ dispatchEvent('remove-fail', { option: item }, evnt)
867
+ }
868
+ })
869
+ }
870
+
871
+ const handleDownloadEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem) => {
872
+ dispatchEvent('download', { option: item }, evnt)
873
+ }
874
+
875
+ const downloadFileEvent = (evnt: MouseEvent, item: VxeUploadDefines.FileObjItem) => {
876
+ const beforeDownloadFn = props.beforeDownloadMethod || getConfig().upload.beforeDownloadMethod
877
+ const downloadFn = props.downloadMethod || getConfig().upload.downloadMethod
878
+ Promise.resolve(
879
+ beforeDownloadFn
880
+ ? beforeDownloadFn({
881
+ $upload: $xeUpload,
882
+ option: item
883
+ })
884
+ : true
885
+ ).then(status => {
886
+ if (status) {
887
+ if (downloadFn) {
888
+ Promise.resolve(
889
+ downloadFn({
890
+ $upload: $xeUpload,
891
+ option: item
892
+ })
893
+ ).then(() => {
894
+ handleDownloadEvent(evnt, item)
895
+ }).catch(e => e)
896
+ } else {
897
+ handleDownloadEvent(evnt, item)
898
+ }
899
+ } else {
900
+ dispatchEvent('download-fail', { option: item }, evnt)
901
+ }
902
+ })
903
+ }
904
+
905
+ const handleUploadDragleaveEvent = (evnt: DragEvent) => {
906
+ const targetElem = evnt.currentTarget as HTMLDivElement
907
+ const { clientX, clientY } = evnt
908
+ if (targetElem) {
909
+ const { x: targetX, y: targetY, height: targetHeight, width: targetWidth } = targetElem.getBoundingClientRect()
910
+ if (clientX < targetX || clientX > targetX + targetWidth || clientY < targetY || clientY > targetY + targetHeight) {
911
+ reactData.isDragUploadStatus = false
912
+ }
913
+ }
914
+ }
915
+
916
+ const handleUploadDragoverEvent = (evnt: DragEvent) => {
917
+ const dataTransfer = evnt.dataTransfer
918
+ if (dataTransfer) {
919
+ const { items } = dataTransfer
920
+ if (items && items.length) {
921
+ evnt.preventDefault()
922
+ reactData.isDragUploadStatus = true
923
+ }
924
+ }
925
+ }
926
+
927
+ const uploadTransferFileEvent = (evnt: Event, files: File[]) => {
928
+ const { imageTypes, fileTypes } = props
929
+ const { imagePreviewTypes } = internalData
930
+ const isImage = computeIsImage.value
931
+ if (isImage) {
932
+ const pasteImgTypes = imagePreviewTypes.concat(imageTypes && imageTypes.length ? imageTypes : [])
933
+ files = files.filter(file => {
934
+ const fileType = `${file.type.split('/')[1] || ''}`.toLowerCase()
935
+ if (pasteImgTypes.some(type => `${type}`.toLowerCase() === fileType)) {
936
+ return true
937
+ }
938
+ return false
939
+ })
940
+ } else {
941
+ if (fileTypes && fileTypes.length) {
942
+ const errTypes: string[] = []
943
+ files.forEach(file => {
944
+ const fileType = parseFileType(file.name)
945
+ if (!fileTypes.some(type => `${type}`.toLowerCase() === fileType)) {
946
+ errTypes.push(fileType)
947
+ }
948
+ })
949
+ if (errTypes.length) {
950
+ if (VxeUI.modal) {
951
+ VxeUI.modal.message({
952
+ content: getI18n('vxe.error.notType', [errTypes.join(', ')]),
953
+ status: 'error'
954
+ })
955
+ }
956
+ return
957
+ }
958
+ }
959
+ }
960
+ // 如果全部不满足条件
961
+ if (!files.length) {
962
+ if (VxeUI.modal) {
963
+ VxeUI.modal.notification({
964
+ title: getI18n('vxe.modal.errTitle'),
965
+ status: 'error',
966
+ content: getI18n('vxe.upload.uploadTypeErr')
967
+ })
968
+ }
969
+ return
970
+ }
971
+ handleUploadFile(files, evnt)
972
+ }
973
+
974
+ const handleUploadDropEvent = (evnt: DragEvent) => {
975
+ const dataTransfer = evnt.dataTransfer
976
+ if (dataTransfer) {
977
+ const { items } = dataTransfer
978
+ if (items && items.length) {
979
+ evnt.preventDefault()
980
+ const files = handleTransferFiles(items)
981
+ if (files.length) {
982
+ uploadTransferFileEvent(evnt, files)
983
+ }
984
+ }
985
+ }
986
+ reactData.isDragUploadStatus = false
987
+ }
988
+
989
+ const handleTransferFiles = (items: DataTransferItemList) => {
990
+ const files: File[] = []
991
+ XEUtils.arrayEach(items, item => {
992
+ const file = item.getAsFile()
993
+ if (file) {
994
+ files.push(file)
995
+ }
996
+ })
997
+ return files
998
+ }
999
+
1000
+ const handleMoreEvent = (evntParams: VxeComponentEventParams) => {
1001
+ const formReadonly = computeFormReadonly.value
1002
+ const isImage = computeIsImage.value
1003
+
1004
+ const evnt = evntParams.$event
1005
+ if (VxeUI.modal) {
1006
+ VxeUI.modal.open({
1007
+ id: internalData.moreId,
1008
+ title: formReadonly ? getI18n('vxe.upload.morePopup.readTitle') : getI18n(`vxe.upload.morePopup.${isImage ? 'imageTitle' : 'fileTitle'}`),
1009
+ width: 660,
1010
+ height: 500,
1011
+ escClosable: true,
1012
+ showMaximize: true,
1013
+ resize: true,
1014
+ maskClosable: true,
1015
+ slots: {
1016
+ default () {
1017
+ const { showErrorStatus, dragToUpload, dragSort, dragPlaceholder } = props
1018
+ const { isActivated, isDragMove, isDragUploadStatus, dragIndex } = reactData
1019
+ const { fileList } = reactData
1020
+ const isDisabled = computeIsDisabled.value
1021
+ const moreContSlot = slots.moreContent || slots['more-content']
1022
+
1023
+ const ons: Record<string, any> = {}
1024
+ if (dragToUpload && dragIndex === -1) {
1025
+ ons.onDragover = handleUploadDragoverEvent
1026
+ ons.onDragleave = handleUploadDragleaveEvent
1027
+ ons.onDrop = handleUploadDropEvent
1028
+ }
1029
+
1030
+ return h('div', {
1031
+ ref: refPopupElem,
1032
+ class: ['vxe-upload--more-popup', {
1033
+ 'is--readonly': formReadonly,
1034
+ 'is--disabled': isDisabled,
1035
+ 'is--active': isActivated,
1036
+ 'show--error': showErrorStatus,
1037
+ 'is--drag': isDragUploadStatus
1038
+ }],
1039
+ ...ons
1040
+ }, moreContSlot
1041
+ ? getSlotVNs(moreContSlot({ options: fileList }))
1042
+ : [
1043
+ isImage
1044
+ ? (
1045
+ dragSort
1046
+ ? h(TransitionGroup, {
1047
+ name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
1048
+ tag: 'div',
1049
+ class: 'vxe-upload--image-more-list'
1050
+ }, {
1051
+ default: () => renderImageItemList(fileList, true).concat(renderImageAction(true))
1052
+ })
1053
+ : h('div', {
1054
+ class: 'vxe-upload--image-more-list'
1055
+ }, renderImageItemList(fileList, true).concat(renderImageAction(true)))
1056
+ )
1057
+ : h('div', {
1058
+ class: 'vxe-upload--file-more-list'
1059
+ }, [
1060
+ renderFileAction(true),
1061
+ dragSort
1062
+ ? h(TransitionGroup, {
1063
+ name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
1064
+ tag: 'div',
1065
+ class: 'vxe-upload--file-list'
1066
+ }, {
1067
+ default: () => renderFileItemList(fileList, false)
1068
+ })
1069
+ : h('div', {
1070
+ class: 'vxe-upload--file-list'
1071
+ }, renderFileItemList(fileList, true))
1072
+ ]),
1073
+ dragSort
1074
+ ? h('div', {
1075
+ ref: refModalDragLineElem,
1076
+ class: 'vxe-upload--drag-line'
1077
+ })
1078
+ : renderEmptyElement($xeUpload),
1079
+ isDragUploadStatus
1080
+ ? h('div', {
1081
+ class: 'vxe-upload--drag-placeholder'
1082
+ }, dragPlaceholder || getI18n('vxe.upload.dragPlaceholder'))
1083
+ : renderEmptyElement($xeUpload)
1084
+ ])
1085
+ }
1086
+ },
1087
+ onShow () {
1088
+ reactData.showMorePopup = true
1089
+ },
1090
+ onHide ({ $event }) {
1091
+ reactData.showMorePopup = false
1092
+ if ($event) {
1093
+ dispatchEvent('more-visible', { visible: false }, $event)
1094
+ }
1095
+ }
1096
+ })
1097
+ if (evnt) {
1098
+ dispatchEvent('more-visible', { visible: true }, evnt)
1099
+ }
1100
+ }
1101
+ }
1102
+
1103
+ const showDropTip = (evnt: DragEvent, dragEl: HTMLElement, dragPos: string) => {
1104
+ const { showMorePopup } = reactData
1105
+ const el = refElem.value
1106
+ const popupEl = refPopupElem.value
1107
+ const wrapperEl = showMorePopup ? popupEl : el
1108
+ if (!wrapperEl) {
1109
+ return
1110
+ }
1111
+ const wrapperRect = wrapperEl.getBoundingClientRect()
1112
+ const ddLineEl = refDragLineElem.value
1113
+ const mdLineEl = refModalDragLineElem.value
1114
+ const currDLineEl = showMorePopup ? mdLineEl : ddLineEl
1115
+ if (currDLineEl) {
1116
+ const dragRect = dragEl.getBoundingClientRect()
1117
+ currDLineEl.style.display = 'block'
1118
+ currDLineEl.style.top = `${Math.max(1, dragRect.y - wrapperRect.y)}px`
1119
+ currDLineEl.style.left = `${Math.max(1, dragRect.x - wrapperRect.x)}px`
1120
+ currDLineEl.style.height = `${dragRect.height}px`
1121
+ currDLineEl.style.width = `${dragRect.width - 1}px`
1122
+ currDLineEl.setAttribute('drag-pos', dragPos)
1123
+ }
1124
+ }
1125
+
1126
+ const hideDropTip = () => {
1127
+ const ddLineEl = refDragLineElem.value
1128
+ const mdLineEl = refModalDragLineElem.value
1129
+ if (ddLineEl) {
1130
+ ddLineEl.style.display = ''
1131
+ }
1132
+ if (mdLineEl) {
1133
+ mdLineEl.style.display = ''
1134
+ }
1135
+ }
1136
+
1137
+ // 拖拽
1138
+ const handleDragSortDragstartEvent = (evnt: DragEvent) => {
1139
+ evnt.stopPropagation()
1140
+ if (evnt.dataTransfer) {
1141
+ evnt.dataTransfer.setDragImage(getTpImg(), 0, 0)
1142
+ }
1143
+ const dragEl = evnt.currentTarget as HTMLElement
1144
+ const parentEl = dragEl.parentElement as HTMLDivElement
1145
+ const dragIndex = XEUtils.findIndexOf(Array.from(parentEl.children), item => dragEl === item)
1146
+ reactData.isDragMove = true
1147
+ reactData.dragIndex = dragIndex
1148
+ setTimeout(() => {
1149
+ reactData.isDragMove = false
1150
+ }, 500)
1151
+ }
1152
+
1153
+ const handleDragSortDragoverEvent = (evnt: DragEvent) => {
1154
+ evnt.stopPropagation()
1155
+ evnt.preventDefault()
1156
+ const { dragIndex } = reactData
1157
+ if (dragIndex === -1) {
1158
+ return
1159
+ }
1160
+ const isImage = computeIsImage.value
1161
+ const dragEl = evnt.currentTarget as HTMLElement
1162
+ const parentEl = dragEl.parentElement as HTMLDivElement
1163
+ const currIndex = XEUtils.findIndexOf(Array.from(parentEl.children), item => dragEl === item)
1164
+ let dragPos: 'top' | 'bottom' | 'left' | 'right' | '' = ''
1165
+ if (isImage) {
1166
+ const offsetX = evnt.clientX - dragEl.getBoundingClientRect().x
1167
+ dragPos = offsetX < dragEl.clientWidth / 2 ? 'left' : 'right'
1168
+ } else {
1169
+ const offsetY = evnt.clientY - dragEl.getBoundingClientRect().y
1170
+ dragPos = offsetY < dragEl.clientHeight / 2 ? 'top' : 'bottom'
1171
+ }
1172
+ if (dragIndex === currIndex) {
1173
+ showDropTip(evnt, dragEl, dragPos)
1174
+ return
1175
+ }
1176
+ showDropTip(evnt, dragEl, dragPos)
1177
+ internalData.prevDragIndex = currIndex
1178
+ internalData.prevDragPos = dragPos
1179
+ }
1180
+
1181
+ const handleDragSortDragendEvent = (evnt: DragEvent) => {
1182
+ const { fileList, dragIndex } = reactData
1183
+ const { prevDragIndex, prevDragPos } = internalData
1184
+ const oldIndex = dragIndex
1185
+ const targetIndex = prevDragIndex
1186
+ const dragOffsetIndex = prevDragPos === 'bottom' || prevDragPos === 'right' ? 1 : 0
1187
+ const oldItem = fileList[oldIndex]
1188
+ const newItem = fileList[targetIndex]
1189
+ if (oldItem && newItem) {
1190
+ fileList.splice(oldIndex, 1)
1191
+ const ptfIndex = XEUtils.findIndexOf(fileList, item => newItem === item)
1192
+ const nIndex = ptfIndex + dragOffsetIndex
1193
+ fileList.splice(nIndex, 0, oldItem)
1194
+ dispatchEvent('sort-dragend', {
1195
+ oldItem: oldItem,
1196
+ newItem: newItem,
1197
+ dragPos: prevDragPos as any,
1198
+ offsetIndex: dragOffsetIndex,
1199
+ _index: {
1200
+ newIndex: nIndex,
1201
+ oldIndex: oldIndex
1202
+ }
1203
+ }, evnt)
1204
+ }
1205
+ hideDropTip()
1206
+ reactData.dragIndex = -1
1207
+ }
1208
+
1209
+ const handleItemMousedownEvent = (evnt: MouseEvent) => {
1210
+ if ($xeTable) {
1211
+ evnt.stopPropagation()
1212
+ }
1213
+ reactData.isActivated = true
1214
+ }
1215
+
1216
+ const handleGlobalPasteEvent = (evnt: ClipboardEvent) => {
1217
+ const { pasteToUpload } = props
1218
+ const { isActivated } = reactData
1219
+ if (!isActivated || !pasteToUpload) {
1220
+ return
1221
+ }
1222
+ const clipboardData: DataTransfer = evnt.clipboardData || (evnt as any).originalEvent.clipboardData
1223
+ if (!clipboardData) {
1224
+ return
1225
+ }
1226
+ const { items } = clipboardData
1227
+ if (!items) {
1228
+ return
1229
+ }
1230
+ const files = handleTransferFiles(items)
1231
+ if (files.length) {
1232
+ evnt.preventDefault()
1233
+ uploadTransferFileEvent(evnt, files)
1234
+ }
1235
+ }
1236
+
1237
+ const handleGlobalClickEvent = (evnt: MouseEvent) => {
1238
+ const el = refElem.value
1239
+ const popupEl = refPopupElem.value
1240
+ let isActivated = getEventTargetNode(evnt, el).flag
1241
+ if (!isActivated && popupEl) {
1242
+ const parentEl = popupEl.parentElement || popupEl
1243
+ const modalEl = parentEl ? parentEl.parentElement : parentEl
1244
+ isActivated = getEventTargetNode(evnt, modalEl).flag
1245
+ }
1246
+ reactData.isActivated = isActivated
1247
+ }
1248
+
1249
+ const handleGlobalBlurEvent = () => {
1250
+ reactData.isActivated = false
1251
+ }
1252
+
1253
+ const uploadMethods: UploadMethods = {
1254
+ dispatchEvent,
1255
+ choose () {
1256
+ return handleChoose(null)
1257
+ },
1258
+ getPendingFiles () {
1259
+ const { fileList, fileCacheMaps } = reactData
1260
+ const pendingFiles: File[] = []
1261
+ fileList.forEach(item => {
1262
+ const fileKey = getFieldKey(item)
1263
+ const cacheItem = fileCacheMaps[fileKey]
1264
+ if (cacheItem && cacheItem.status === 'pending') {
1265
+ pendingFiles.push(cacheItem.file)
1266
+ }
1267
+ })
1268
+ return pendingFiles
1269
+ },
1270
+ submit (isFull) {
1271
+ const { maxSimultaneousUploads } = props
1272
+ const msNum = XEUtils.toNumber(maxSimultaneousUploads || 1) || 1
1273
+ const { fileList, fileCacheMaps } = reactData
1274
+ const allPendingList = fileList.filter(item => {
1275
+ const fileKey = getFieldKey(item)
1276
+ const cacheItem = fileCacheMaps[fileKey]
1277
+ return cacheItem && (cacheItem.status === 'pending' || (isFull && cacheItem.status === 'error'))
1278
+ })
1279
+
1280
+ const handleSubmit = (item: VxeUploadDefines.FileObjItem): Promise<void> => {
1281
+ const fileKey = getFieldKey(item)
1282
+ const cacheItem = fileCacheMaps[fileKey]
1283
+ if (cacheItem) {
1284
+ const file = cacheItem.file
1285
+ if (file && (cacheItem.status === 'pending' || (isFull && cacheItem.status === 'error'))) {
1286
+ cacheItem.loading = true
1287
+ cacheItem.percent = 0
1288
+ return handleUploadResult(item, file).then(handleNextSubmit)
1289
+ }
1290
+ }
1291
+ return handleNextSubmit()
1292
+ }
1293
+
1294
+ const handleNextSubmit = (): Promise<void> => {
1295
+ if (allPendingList.length) {
1296
+ const item = allPendingList[0]
1297
+ allPendingList.splice(0, 1)
1298
+ return handleSubmit(item).then(handleNextSubmit)
1299
+ }
1300
+ return Promise.resolve()
1301
+ }
1302
+
1303
+ return Promise.all(allPendingList.splice(0, msNum).map(handleSubmit)).then(() => {
1304
+ // 完成
1305
+ })
1306
+ },
1307
+ getMoreVisible () {
1308
+ return reactData.showMorePopup
1309
+ },
1310
+ openMore () {
1311
+ handleMoreEvent({ $event: new Event('click') })
1312
+ return nextTick()
1313
+ },
1314
+ openMoreByEvent (evnt) {
1315
+ handleMoreEvent({ $event: evnt })
1316
+ return nextTick()
1317
+ },
1318
+ closeMore () {
1319
+ if (VxeUI.modal) {
1320
+ VxeUI.modal.close(internalData.moreId)
1321
+ }
1322
+ return nextTick()
1323
+ }
1324
+ }
1325
+
1326
+ const uploadPrivateMethods: UploadPrivateMethods = {
1327
+ }
1328
+
1329
+ Object.assign($xeUpload, uploadMethods, uploadPrivateMethods)
1330
+
1331
+ const renderFileItemList = (currList: VxeUploadDefines.FileObjItem[], isMoreView: boolean) => {
1332
+ const { showRemoveButton, showDownloadButton, showProgress, progressText, showPreview, showErrorStatus, dragSort, autoSubmit, showSubmitButton } = props
1333
+ const { fileList, fileCacheMaps } = reactData
1334
+ const isDisabled = computeIsDisabled.value
1335
+ const formReadonly = computeFormReadonly.value
1336
+ const nameProp = computeNameProp.value
1337
+ const typeProp = computeTypeProp.value
1338
+ const optionSlot = slots.option
1339
+ const actionSlot = slots.action
1340
+ const cornerSlot = slots.corner
1341
+ const nameSlot = slots.name
1342
+
1343
+ const ons: Record<string, any> = {}
1344
+ if (dragSort && currList.length > 1) {
1345
+ ons.onDragstart = handleDragSortDragstartEvent
1346
+ ons.onDragover = handleDragSortDragoverEvent
1347
+ ons.onDragend = handleDragSortDragendEvent
1348
+ }
1349
+
1350
+ return currList.map((item, index) => {
1351
+ const fileKey = getFieldKey(item)
1352
+ const cacheItem = fileCacheMaps[fileKey]
1353
+ let isLoading = false
1354
+ let isError = false
1355
+ let isPending = false
1356
+ const fileName = `${item[nameProp] || ''}`
1357
+ if (cacheItem) {
1358
+ isLoading = cacheItem.loading
1359
+ isError = cacheItem.status === 'error'
1360
+ isPending = cacheItem.status === 'pending'
1361
+ }
1362
+ return h('div', {
1363
+ key: dragSort ? fileKey : index,
1364
+ class: ['vxe-upload--file-item', {
1365
+ 'is--preview': showPreview,
1366
+ 'is--loading': isLoading,
1367
+ 'is--pending': isPending,
1368
+ 'is--error': isError
1369
+ }],
1370
+ fileid: fileKey,
1371
+ draggable: dragSort ? true : null,
1372
+ ...ons
1373
+ }, optionSlot
1374
+ ? getSlotVNs(optionSlot({ option: item, isMoreView, options: fileList }))
1375
+ : [
1376
+ h('div', {
1377
+ class: 'vxe-upload--file-item-icon'
1378
+ }, [
1379
+ h('i', {
1380
+ class: getIcon()[`UPLOAD_FILE_TYPE_${`${item[typeProp]}`.toLocaleUpperCase() as 'DEFAULT'}`] || getIcon().UPLOAD_FILE_TYPE_DEFAULT
1381
+ })
1382
+ ]),
1383
+ h('div', {
1384
+ class: 'vxe-upload--file-item-name',
1385
+ title: fileName,
1386
+ onClick (evnt) {
1387
+ if (!isLoading && !isError) {
1388
+ handlePreviewFileEvent(evnt, item)
1389
+ }
1390
+ }
1391
+ }, nameSlot ? getSlotVNs(nameSlot({ option: item, isMoreView, options: fileList })) : fileName),
1392
+ isLoading
1393
+ ? h('div', {
1394
+ class: 'vxe-upload--file-item-loading-icon'
1395
+ }, [
1396
+ h('i', {
1397
+ class: getIcon().UPLOAD_LOADING
1398
+ })
1399
+ ])
1400
+ : renderEmptyElement($xeUpload),
1401
+ showProgress && isLoading && cacheItem
1402
+ ? h('div', {
1403
+ class: 'vxe-upload--file-item-loading-text'
1404
+ }, progressText ? XEUtils.toFormatString(`${XEUtils.isFunction(progressText) ? progressText({}) : progressText}`, { percent: cacheItem.percent }) : getI18n('vxe.upload.uploadProgress', [cacheItem.percent]))
1405
+ : renderEmptyElement($xeUpload),
1406
+ !isLoading && ((isError && showErrorStatus) || (isPending && showSubmitButton && !autoSubmit))
1407
+ ? h('div', {
1408
+ class: 'vxe-upload--file-item-rebtn'
1409
+ }, [
1410
+ h(VxeButtonComponent, {
1411
+ icon: isError ? getIcon().UPLOAD_IMAGE_RE_UPLOAD : getIcon().UPLOAD_IMAGE_UPLOAD,
1412
+ mode: 'text',
1413
+ status: 'primary',
1414
+ content: isError ? getI18n('vxe.upload.reUpload') : getI18n('vxe.upload.manualUpload'),
1415
+ onClick () {
1416
+ handleReUpload(item)
1417
+ }
1418
+ })
1419
+ ])
1420
+ : renderEmptyElement($xeUpload),
1421
+ h('div', {
1422
+ class: 'vxe-upload--file-item-btn-wrapper'
1423
+ }, actionSlot
1424
+ ? getSlotVNs(actionSlot({ option: item, isMoreView, options: fileList, readonly: formReadonly }))
1425
+ : [
1426
+ cornerSlot
1427
+ ? h('div', {
1428
+ class: 'vxe-upload--file-item-action'
1429
+ }, getSlotVNs(cornerSlot({ option: item, isMoreView, options: fileList, readonly: formReadonly })))
1430
+ : renderEmptyElement($xeUpload),
1431
+ showDownloadButton && !(isLoading || isPending)
1432
+ ? h('div', {
1433
+ class: 'vxe-upload--file-item-download-btn',
1434
+ onClick (evnt: MouseEvent) {
1435
+ downloadFileEvent(evnt, item)
1436
+ }
1437
+ }, [
1438
+ h('i', {
1439
+ class: getIcon().UPLOAD_FILE_DOWNLOAD
1440
+ })
1441
+ ])
1442
+ : renderEmptyElement($xeUpload),
1443
+ showRemoveButton && !formReadonly && !isDisabled && !isLoading
1444
+ ? h('div', {
1445
+ class: 'vxe-upload--file-item-remove-btn',
1446
+ onClick (evnt: MouseEvent) {
1447
+ removeFileEvent(evnt, item, index)
1448
+ }
1449
+ }, [
1450
+ h('i', {
1451
+ class: getIcon().UPLOAD_FILE_REMOVE
1452
+ })
1453
+ ])
1454
+ : renderEmptyElement($xeUpload)
1455
+ ])
1456
+ ])
1457
+ })
1458
+ }
1459
+
1460
+ const renderFileAction = (isMoreView: boolean) => {
1461
+ const { showUploadButton, buttonText, buttonIcon, showButtonText, showButtonIcon, autoHiddenButton } = props
1462
+ const { fileList } = reactData
1463
+ const isDisabled = computeIsDisabled.value
1464
+ const formReadonly = computeFormReadonly.value
1465
+ const showTipText = computedShowTipText.value
1466
+ const defTipText = computedDefTipText.value
1467
+ const overCount = computeOverCount.value
1468
+ const defaultSlot = slots.default
1469
+ const tipSlot = slots.tip || slots.hint
1470
+
1471
+ if (formReadonly || !showUploadButton) {
1472
+ return renderEmptyElement($xeUpload)
1473
+ }
1474
+ return h('div', {
1475
+ class: 'vxe-upload--file-action'
1476
+ }, [
1477
+ autoHiddenButton && overCount
1478
+ ? renderEmptyElement($xeUpload)
1479
+ : h('div', {
1480
+ class: 'vxe-upload--file-action-btn',
1481
+ onClick: clickEvent
1482
+ }, defaultSlot
1483
+ ? getSlotVNs(defaultSlot({ isMoreView, options: fileList, $upload: $xeUpload }))
1484
+ : [
1485
+ h(VxeButtonComponent, {
1486
+ class: 'vxe-upload--file-action-button',
1487
+ content: (isMoreView || showButtonText) ? (buttonText ? `${XEUtils.isFunction(buttonText) ? buttonText({}) : buttonText}` : getI18n('vxe.upload.fileBtnText')) : '',
1488
+ icon: showButtonIcon ? (buttonIcon || getIcon().UPLOAD_FILE_ADD) : '',
1489
+ disabled: isDisabled
1490
+ })
1491
+ ]),
1492
+ showTipText && (defTipText || tipSlot)
1493
+ ? h('div', {
1494
+ class: 'vxe-upload--file-action-tip'
1495
+ }, tipSlot ? getSlotVNs(tipSlot({ isMoreView, options: fileList, $upload: $xeUpload })) : `${defTipText}`)
1496
+ : renderEmptyElement($xeUpload)
1497
+ ])
1498
+ }
1499
+
1500
+ const rendeFileMode = () => {
1501
+ const { showList, moreConfig, dragSort } = props
1502
+ const { fileList, isDragMove } = reactData
1503
+ const moreOpts = computeMoreOpts.value
1504
+ const { maxCount, showMoreButton, layout, moreButtonText } = moreOpts
1505
+ const isHorizontal = layout === 'horizontal'
1506
+ const moreBtnSlot = slots.moreButton || slots['more-button']
1507
+
1508
+ let currList = fileList
1509
+ let overMaxNum = 0
1510
+ let isMoreMax = false
1511
+ let isMiniMore = false
1512
+ if (XEUtils.isNumber(maxCount) && fileList.length > maxCount) {
1513
+ isMoreMax = true
1514
+ isMiniMore = maxCount === 0
1515
+ overMaxNum = fileList.length - maxCount
1516
+ currList = fileList.slice(0, maxCount)
1517
+ }
1518
+
1519
+ return h('div', {
1520
+ key: 'all',
1521
+ class: 'vxe-upload--file-wrapper'
1522
+ }, showList
1523
+ ? [
1524
+ showMoreButton && moreConfig && isHorizontal
1525
+ ? renderEmptyElement($xeUpload)
1526
+ : renderFileAction(true),
1527
+ h('div', {
1528
+ class: ['vxe-upload--file-list-wrapper', {
1529
+ 'is--horizontal': isHorizontal
1530
+ }]
1531
+ }, [
1532
+ currList.length
1533
+ ? (
1534
+ dragSort
1535
+ ? h(TransitionGroup, {
1536
+ name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
1537
+ tag: 'div',
1538
+ class: 'vxe-upload--file-list'
1539
+ }, {
1540
+ default: () => renderFileItemList(currList, false)
1541
+ })
1542
+ : h('div', {
1543
+ class: 'vxe-upload--file-list'
1544
+ }, renderFileItemList(currList, false))
1545
+ )
1546
+ : renderEmptyElement($xeUpload),
1547
+ showMoreButton && overMaxNum
1548
+ ? h('div', {
1549
+ class: 'vxe-upload--file-over-more'
1550
+ }, moreBtnSlot
1551
+ ? getSlotVNs(moreBtnSlot({ options: fileList }))
1552
+ : [
1553
+ h(VxeButtonComponent, {
1554
+ mode: 'text',
1555
+ content: moreButtonText ? (XEUtils.isFunction(moreButtonText) ? moreButtonText({ $upload: $xeUpload, options: fileList }) : XEUtils.toFormatString(moreButtonText, [fileList.length])) : getI18n(isMoreMax && isMiniMore ? 'vxe.upload.moreFileBtnText' : 'vxe.upload.moreBtnText', [fileList.length]),
1556
+ status: 'primary',
1557
+ onClick: handleMoreEvent
1558
+ })
1559
+ ])
1560
+ : renderEmptyElement($xeUpload),
1561
+ showMoreButton && moreConfig && isHorizontal
1562
+ ? renderFileAction(false)
1563
+ : renderEmptyElement($xeUpload)
1564
+ ])
1565
+ ]
1566
+ : [
1567
+ renderFileAction(false)
1568
+ ])
1569
+ }
1570
+
1571
+ const renderImageItemList = (currList: VxeUploadDefines.FileObjItem[], isMoreView: boolean) => {
1572
+ const { showRemoveButton, showProgress, progressText, showPreview, showErrorStatus, dragSort, autoSubmit, showSubmitButton } = props
1573
+ const { fileList, fileCacheMaps } = reactData
1574
+ const isDisabled = computeIsDisabled.value
1575
+ const formReadonly = computeFormReadonly.value
1576
+ const imageOpts = computeImageOpts.value
1577
+ const imgStyle = computeImgStyle.value
1578
+ const optionSlot = slots.option
1579
+ const actionSlot = slots.action
1580
+ const cornerSlot = slots.corner
1581
+
1582
+ const ons: Record<string, any> = {
1583
+ onMousedown: handleItemMousedownEvent
1584
+ }
1585
+ if (dragSort && currList.length > 1) {
1586
+ ons.onDragstart = handleDragSortDragstartEvent
1587
+ ons.onDragover = handleDragSortDragoverEvent
1588
+ ons.onDragend = handleDragSortDragendEvent
1589
+ }
1590
+
1591
+ return currList.map((item, index) => {
1592
+ const fileKey = getFieldKey(item)
1593
+ const cacheItem = fileCacheMaps[fileKey]
1594
+ let isLoading = false
1595
+ let isError = false
1596
+ let isPending = false
1597
+ if (cacheItem) {
1598
+ isLoading = cacheItem.loading
1599
+ isError = cacheItem.status === 'error'
1600
+ isPending = cacheItem.status === 'pending'
1601
+ }
1602
+ return h('div', {
1603
+ key: dragSort ? fileKey : index,
1604
+ class: ['vxe-upload--image-item', {
1605
+ 'is--preview': showPreview,
1606
+ 'is--circle': imageOpts.circle,
1607
+ 'is--loading': isLoading,
1608
+ 'is--pending': isPending,
1609
+ 'is--error': isError
1610
+ }],
1611
+ fileid: fileKey,
1612
+ draggable: dragSort ? true : null,
1613
+ ...ons
1614
+ }, optionSlot
1615
+ ? getSlotVNs(optionSlot({ option: item, isMoreView, options: fileList }))
1616
+ : [
1617
+ h('div', {
1618
+ class: 'vxe-upload--image-item-box',
1619
+ style: isMoreView ? null : imgStyle,
1620
+ onClick (evnt) {
1621
+ if (!isLoading && !isError) {
1622
+ handlePreviewImageEvent(evnt, item, index)
1623
+ }
1624
+ }
1625
+ }, [
1626
+ isLoading && cacheItem
1627
+ ? h('div', {
1628
+ class: 'vxe-upload--image-item-loading'
1629
+ }, [
1630
+ h('div', {
1631
+ class: 'vxe-upload--image-item-loading-icon'
1632
+ }, [
1633
+ h('i', {
1634
+ class: getIcon().UPLOAD_LOADING
1635
+ })
1636
+ ]),
1637
+ showProgress
1638
+ ? h('div', {
1639
+ class: 'vxe-upload--image-item-loading-text'
1640
+ }, progressText ? XEUtils.toFormatString(`${XEUtils.isFunction(progressText) ? progressText({}) : progressText}`, { percent: cacheItem.percent }) : getI18n('vxe.upload.uploadProgress', [cacheItem.percent]))
1641
+ : renderEmptyElement($xeUpload)
1642
+ ])
1643
+ : renderEmptyElement($xeUpload),
1644
+ h('div', {
1645
+ class: 'vxe-upload--image-item-img-wrapper',
1646
+ title: getI18n('vxe.upload.viewItemTitle')
1647
+ }, [
1648
+ h('img', {
1649
+ class: 'vxe-upload--image-item-img',
1650
+ src: getThumbnailFileUrl(item)
1651
+ })
1652
+ ]),
1653
+ !isLoading && ((isError && showErrorStatus) || (isPending && showSubmitButton && !autoSubmit))
1654
+ ? h('div', {
1655
+ class: 'vxe-upload--image-item-rebtn'
1656
+ }, [
1657
+ h(VxeButtonComponent, {
1658
+ icon: isError ? getIcon().UPLOAD_IMAGE_RE_UPLOAD : getIcon().UPLOAD_IMAGE_UPLOAD,
1659
+ mode: 'text',
1660
+ status: 'primary',
1661
+ content: isError ? getI18n('vxe.upload.reUpload') : getI18n('vxe.upload.manualUpload'),
1662
+ onClick () {
1663
+ handleReUpload(item)
1664
+ }
1665
+ })
1666
+ ])
1667
+ : renderEmptyElement($xeUpload),
1668
+ h('div', {
1669
+ class: 'vxe-upload--image-item-btn-wrapper',
1670
+ onClick (evnt) {
1671
+ evnt.stopPropagation()
1672
+ }
1673
+ }, actionSlot
1674
+ ? getSlotVNs(actionSlot({ option: item, isMoreView, options: fileList, readonly: formReadonly }))
1675
+ : [
1676
+ cornerSlot
1677
+ ? h('div', {
1678
+ class: 'vxe-upload--file-item-action'
1679
+ }, getSlotVNs(cornerSlot({ option: item, isMoreView, options: fileList, readonly: formReadonly })))
1680
+ : renderEmptyElement($xeUpload),
1681
+ showRemoveButton && !formReadonly && !isDisabled && !isLoading
1682
+ ? h('div', {
1683
+ class: 'vxe-upload--image-item-remove-btn',
1684
+ onClick (evnt: MouseEvent) {
1685
+ evnt.stopPropagation()
1686
+ removeFileEvent(evnt, item, index)
1687
+ }
1688
+ }, [
1689
+ h('i', {
1690
+ class: getIcon().UPLOAD_IMAGE_REMOVE
1691
+ })
1692
+ ])
1693
+ : renderEmptyElement($xeUpload)
1694
+ ])
1695
+ ])
1696
+ ])
1697
+ })
1698
+ }
1699
+
1700
+ const renderImageAction = (isMoreView: boolean) => {
1701
+ const { showUploadButton, buttonText, buttonIcon, showButtonText, showButtonIcon, autoHiddenButton } = props
1702
+ const { fileList } = reactData
1703
+ const formReadonly = computeFormReadonly.value
1704
+ const showTipText = computedShowTipText.value
1705
+ const defTipText = computedDefTipText.value
1706
+ const overCount = computeOverCount.value
1707
+ const imgStyle = computeImgStyle.value
1708
+ const defaultSlot = slots.default
1709
+ const tipSlot = slots.tip || slots.hint
1710
+
1711
+ if (formReadonly || !showUploadButton || (autoHiddenButton && overCount)) {
1712
+ return renderEmptyElement($xeUpload)
1713
+ }
1714
+ return h('div', {
1715
+ key: 'action',
1716
+ class: 'vxe-upload--image-action'
1717
+ }, [
1718
+ h('div', {
1719
+ class: 'vxe-upload--image-action-btn',
1720
+ onClick: clickEvent
1721
+ }, defaultSlot
1722
+ ? defaultSlot({ isMoreView, options: fileList, $upload: $xeUpload })
1723
+ : [
1724
+ h('div', {
1725
+ class: 'vxe-upload--image-action-box',
1726
+ style: isMoreView ? null : imgStyle
1727
+ }, [
1728
+ showButtonIcon
1729
+ ? h('div', {
1730
+ class: 'vxe-upload--image-action-icon'
1731
+ }, [
1732
+ h('i', {
1733
+ class: buttonIcon || getIcon().UPLOAD_IMAGE_ADD
1734
+ })
1735
+ ])
1736
+ : renderEmptyElement($xeUpload),
1737
+ isMoreView || showButtonText
1738
+ ? h('div', {
1739
+ class: 'vxe-upload--image-action-content'
1740
+ }, buttonText ? `${XEUtils.isFunction(buttonText) ? buttonText({}) : buttonText}` : getI18n('vxe.upload.imgBtnText'))
1741
+ : renderEmptyElement($xeUpload),
1742
+ showTipText && (defTipText || tipSlot)
1743
+ ? h('div', {
1744
+ class: 'vxe-upload--image-action-hint'
1745
+ }, tipSlot ? getSlotVNs(tipSlot({ isMoreView, options: fileList, $upload: $xeUpload })) : `${defTipText}`)
1746
+ : renderEmptyElement($xeUpload)
1747
+ ])
1748
+ ])
1749
+ ])
1750
+ }
1751
+
1752
+ const renderImageMode = () => {
1753
+ const { showList, dragSort } = props
1754
+ const { fileList, isDragMove } = reactData
1755
+ const moreOpts = computeMoreOpts.value
1756
+ const moreBtnSlot = slots.moreButton || slots['more-button']
1757
+
1758
+ const { maxCount, showMoreButton, moreButtonText } = moreOpts
1759
+ let currList = fileList
1760
+ let overMaxNum = 0
1761
+ let isMoreMax = false
1762
+ let isMiniMore = false
1763
+ if (XEUtils.isNumber(maxCount) && fileList.length > maxCount) {
1764
+ isMoreMax = true
1765
+ isMiniMore = maxCount === 0
1766
+ overMaxNum = fileList.length - maxCount
1767
+ currList = fileList.slice(0, maxCount)
1768
+ }
1769
+
1770
+ return h('div', {
1771
+ key: 'image',
1772
+ class: 'vxe-upload--image-wrapper'
1773
+ }, showList
1774
+ ? [
1775
+ dragSort
1776
+ ? h(TransitionGroup, {
1777
+ name: `vxe-upload--drag-list${isDragMove ? '' : '-disabled'}`,
1778
+ tag: 'div',
1779
+ class: 'vxe-upload--image-list'
1780
+ }, {
1781
+ default: () => renderImageItemList(currList, false).concat([
1782
+ showMoreButton && overMaxNum
1783
+ ? h('div', {
1784
+ key: 'om',
1785
+ class: 'vxe-upload--image-over-more'
1786
+ }, moreBtnSlot
1787
+ ? getSlotVNs(moreBtnSlot({ options: fileList }))
1788
+ : [
1789
+ h(VxeButtonComponent, {
1790
+ mode: 'text',
1791
+ content: moreButtonText ? (XEUtils.isFunction(moreButtonText) ? moreButtonText({ $upload: $xeUpload, options: fileList }) : XEUtils.toFormatString(moreButtonText, [fileList.length])) : getI18n(isMoreMax && isMiniMore ? 'vxe.upload.moreImgBtnText' : 'vxe.upload.moreBtnText', [fileList.length]),
1792
+ status: 'primary',
1793
+ onClick: handleMoreEvent
1794
+ })
1795
+ ])
1796
+ : renderEmptyElement($xeUpload),
1797
+ renderImageAction(false)
1798
+ ])
1799
+ })
1800
+ : h('div', {
1801
+ class: 'vxe-upload--image-list'
1802
+ }, renderImageItemList(currList, false).concat([
1803
+ showMoreButton && overMaxNum
1804
+ ? h('div', {
1805
+ class: 'vxe-upload--image-over-more'
1806
+ }, moreBtnSlot
1807
+ ? getSlotVNs(moreBtnSlot({ options: fileList }))
1808
+ : [
1809
+ h(VxeButtonComponent, {
1810
+ mode: 'text',
1811
+ content: moreButtonText ? (XEUtils.isFunction(moreButtonText) ? moreButtonText({ $upload: $xeUpload, options: fileList }) : XEUtils.toFormatString(moreButtonText, [fileList.length])) : getI18n(isMoreMax && isMiniMore ? 'vxe.upload.moreImgBtnText' : 'vxe.upload.moreBtnText', [fileList.length]),
1812
+ status: 'primary',
1813
+ onClick: handleMoreEvent
1814
+ })
1815
+ ])
1816
+ : renderEmptyElement($xeUpload),
1817
+ renderImageAction(false)
1818
+ ]))
1819
+ ]
1820
+ : [
1821
+ h('div', {
1822
+ class: 'vxe-upload--image-list'
1823
+ }, [
1824
+ renderImageAction(false)
1825
+ ])
1826
+ ])
1827
+ }
1828
+
1829
+ const renderVN = () => {
1830
+ const { showErrorStatus, dragToUpload, pasteToUpload, dragSort, dragPlaceholder } = props
1831
+ const { isDragUploadStatus, showMorePopup, isActivated, dragIndex } = reactData
1832
+ const vSize = computeSize.value
1833
+ const isDisabled = computeIsDisabled.value
1834
+ const formReadonly = computeFormReadonly.value
1835
+ const isImage = computeIsImage.value
1836
+
1837
+ const ons: Record<string, any> = {
1838
+ onMousedown: handleItemMousedownEvent
1839
+ }
1840
+ if (dragToUpload && dragIndex === -1) {
1841
+ ons.onDragover = handleUploadDragoverEvent
1842
+ ons.onDragleave = handleUploadDragleaveEvent
1843
+ ons.onDrop = handleUploadDropEvent
1844
+ }
1845
+
1846
+ return h('div', {
1847
+ ref: refElem,
1848
+ class: ['vxe-upload', {
1849
+ [`size--${vSize}`]: vSize,
1850
+ 'is--active': isActivated,
1851
+ 'is--readonly': formReadonly,
1852
+ 'is--disabled': isDisabled,
1853
+ 'is--paste': pasteToUpload,
1854
+ 'show--error': showErrorStatus,
1855
+ 'is--drag': isDragUploadStatus
1856
+ }],
1857
+ ...ons
1858
+ }, [
1859
+ isImage ? renderImageMode() : rendeFileMode(),
1860
+ dragSort
1861
+ ? h('div', {
1862
+ ref: refDragLineElem,
1863
+ class: 'vxe-upload--drag-line'
1864
+ })
1865
+ : renderEmptyElement($xeUpload),
1866
+ isDragUploadStatus && !showMorePopup
1867
+ ? h('div', {
1868
+ class: 'vxe-upload--drag-placeholder'
1869
+ }, dragPlaceholder || getI18n('vxe.upload.dragPlaceholder'))
1870
+ : renderEmptyElement($xeUpload)
1871
+ ])
1872
+ }
1873
+
1874
+ const listFlag = ref(0)
1875
+ watch(() => props.modelValue ? props.modelValue.length : 0, () => {
1876
+ listFlag.value++
1877
+ })
1878
+ watch(() => props.modelValue, () => {
1879
+ listFlag.value++
1880
+ })
1881
+ watch(listFlag, () => {
1882
+ updateFileList()
1883
+ })
1884
+
1885
+ onMounted(() => {
1886
+ if (props.multiple && props.singleMode) {
1887
+ errLog('vxe.error.errConflicts', ['[upload] multiple', 'single-mode'])
1888
+ }
1889
+ if (props.imageStyle) {
1890
+ warnLog('vxe.error.delProp', ['[upload] image-style', 'image-config'])
1891
+ }
1892
+
1893
+ if (props.dragSort) {
1894
+ initTpImg()
1895
+ }
1896
+ globalEvents.on($xeUpload, 'paste', handleGlobalPasteEvent)
1897
+ globalEvents.on($xeUpload, 'click', handleGlobalClickEvent)
1898
+ globalEvents.on($xeUpload, 'blur', handleGlobalBlurEvent)
1899
+ })
1900
+
1901
+ onBeforeUnmount(() => {
1902
+ reactData.isDragUploadStatus = false
1903
+ globalEvents.off($xeUpload, 'paste')
1904
+ globalEvents.off($xeUpload, 'click')
1905
+ globalEvents.off($xeUpload, 'blur')
1906
+ XEUtils.assign(reactData, createReactData())
1907
+ XEUtils.assign(internalData, createInternalData())
1908
+ })
1909
+
1910
+ updateFileList()
1911
+
1912
+ $xeUpload.renderVN = renderVN
1913
+
1914
+ return $xeUpload
1915
+ },
1916
+ render () {
1917
+ return this.renderVN()
1918
+ }
1919
+ })