vxe-pc-ui 4.14.6 → 4.14.7

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 (611) 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/checkbox/src/button.js +26 -5
  7. package/es/checkbox/src/checkbox.js +26 -5
  8. package/es/checkbox/src/group.js +23 -3
  9. package/es/checkbox/style.css +6 -3
  10. package/es/checkbox/style.min.css +1 -1
  11. package/es/language/ar-EG.js +4 -0
  12. package/es/language/de-DE.js +4 -0
  13. package/es/language/en-US.js +4 -0
  14. package/es/language/es-ES.js +4 -0
  15. package/es/language/fr-FR.js +4 -0
  16. package/es/language/hu-HU.js +4 -0
  17. package/es/language/hy-AM.js +4 -0
  18. package/es/language/id-ID.js +4 -0
  19. package/es/language/it-IT.js +4 -0
  20. package/es/language/ja-JP.js +4 -0
  21. package/es/language/ko-KR.js +4 -0
  22. package/es/language/ms-MY.js +4 -0
  23. package/es/language/nb-NO.js +4 -0
  24. package/es/language/pt-BR.js +4 -0
  25. package/es/language/ru-RU.js +4 -0
  26. package/es/language/th-TH.js +4 -0
  27. package/es/language/ug-CN.js +4 -0
  28. package/es/language/uk-UA.js +4 -0
  29. package/es/language/uz-UZ.js +4 -0
  30. package/es/language/vi-VN.js +4 -0
  31. package/es/language/zh-CHT.js +4 -0
  32. package/es/language/zh-CN.js +4 -0
  33. package/es/radio/src/button.js +27 -5
  34. package/es/radio/src/group.js +17 -2
  35. package/es/radio/src/radio.js +27 -5
  36. package/es/radio/style.css +5 -3
  37. package/es/radio/style.min.css +1 -1
  38. package/es/style.css +1 -1
  39. package/es/style.min.css +1 -1
  40. package/es/switch/src/switch.js +19 -11
  41. package/es/tree/style.css +11 -6
  42. package/es/tree/style.min.css +1 -1
  43. package/es/ui/index.js +1 -1
  44. package/es/ui/src/log.js +1 -1
  45. package/es/vxe-checkbox/style.css +6 -3
  46. package/es/vxe-checkbox/style.min.css +1 -1
  47. package/es/vxe-radio/style.css +5 -3
  48. package/es/vxe-radio/style.min.css +1 -1
  49. package/es/vxe-tree/style.css +11 -6
  50. package/es/vxe-tree/style.min.css +1 -1
  51. package/lib/checkbox/src/button.js +26 -3
  52. package/lib/checkbox/src/button.min.js +1 -1
  53. package/lib/checkbox/src/checkbox.js +26 -3
  54. package/lib/checkbox/src/checkbox.min.js +1 -1
  55. package/lib/checkbox/src/group.js +25 -3
  56. package/lib/checkbox/src/group.min.js +1 -1
  57. package/lib/checkbox/style/style.css +6 -3
  58. package/lib/checkbox/style/style.min.css +1 -1
  59. package/lib/index.umd.js +2446 -2376
  60. package/lib/index.umd.min.js +1 -1
  61. package/lib/language/ar-EG.js +4 -0
  62. package/lib/language/ar-EG.min.js +1 -1
  63. package/lib/language/ar-EG.umd.js +4 -0
  64. package/lib/language/de-DE.js +4 -0
  65. package/lib/language/de-DE.min.js +1 -1
  66. package/lib/language/de-DE.umd.js +4 -0
  67. package/lib/language/en-US.js +4 -0
  68. package/lib/language/en-US.min.js +1 -1
  69. package/lib/language/en-US.umd.js +4 -0
  70. package/lib/language/es-ES.js +4 -0
  71. package/lib/language/es-ES.min.js +1 -1
  72. package/lib/language/es-ES.umd.js +4 -0
  73. package/lib/language/fr-FR.js +4 -0
  74. package/lib/language/fr-FR.min.js +1 -1
  75. package/lib/language/fr-FR.umd.js +4 -0
  76. package/lib/language/hu-HU.js +4 -0
  77. package/lib/language/hu-HU.min.js +1 -1
  78. package/lib/language/hu-HU.umd.js +4 -0
  79. package/lib/language/hy-AM.js +4 -0
  80. package/lib/language/hy-AM.min.js +1 -1
  81. package/lib/language/hy-AM.umd.js +4 -0
  82. package/lib/language/id-ID.js +4 -0
  83. package/lib/language/id-ID.min.js +1 -1
  84. package/lib/language/id-ID.umd.js +4 -0
  85. package/lib/language/it-IT.js +4 -0
  86. package/lib/language/it-IT.min.js +1 -1
  87. package/lib/language/it-IT.umd.js +4 -0
  88. package/lib/language/ja-JP.js +4 -0
  89. package/lib/language/ja-JP.min.js +1 -1
  90. package/lib/language/ja-JP.umd.js +4 -0
  91. package/lib/language/ko-KR.js +4 -0
  92. package/lib/language/ko-KR.min.js +1 -1
  93. package/lib/language/ko-KR.umd.js +4 -0
  94. package/lib/language/ms-MY.js +4 -0
  95. package/lib/language/ms-MY.min.js +1 -1
  96. package/lib/language/ms-MY.umd.js +4 -0
  97. package/lib/language/nb-NO.js +4 -0
  98. package/lib/language/nb-NO.min.js +1 -1
  99. package/lib/language/nb-NO.umd.js +4 -0
  100. package/lib/language/pt-BR.js +4 -0
  101. package/lib/language/pt-BR.min.js +1 -1
  102. package/lib/language/pt-BR.umd.js +4 -0
  103. package/lib/language/ru-RU.js +4 -0
  104. package/lib/language/ru-RU.min.js +1 -1
  105. package/lib/language/ru-RU.umd.js +4 -0
  106. package/lib/language/th-TH.js +4 -0
  107. package/lib/language/th-TH.min.js +1 -1
  108. package/lib/language/th-TH.umd.js +4 -0
  109. package/lib/language/ug-CN.js +4 -0
  110. package/lib/language/ug-CN.min.js +1 -1
  111. package/lib/language/ug-CN.umd.js +4 -0
  112. package/lib/language/uk-UA.js +4 -0
  113. package/lib/language/uk-UA.min.js +1 -1
  114. package/lib/language/uk-UA.umd.js +4 -0
  115. package/lib/language/uz-UZ.js +4 -0
  116. package/lib/language/uz-UZ.min.js +1 -1
  117. package/lib/language/uz-UZ.umd.js +4 -0
  118. package/lib/language/vi-VN.js +4 -0
  119. package/lib/language/vi-VN.min.js +1 -1
  120. package/lib/language/vi-VN.umd.js +4 -0
  121. package/lib/language/zh-CHT.js +4 -0
  122. package/lib/language/zh-CHT.min.js +1 -1
  123. package/lib/language/zh-CHT.umd.js +4 -0
  124. package/lib/language/zh-CN.js +4 -0
  125. package/lib/language/zh-CN.min.js +1 -1
  126. package/lib/language/zh-CN.umd.js +4 -0
  127. package/lib/radio/src/button.js +27 -3
  128. package/lib/radio/src/button.min.js +1 -1
  129. package/lib/radio/src/group.js +19 -2
  130. package/lib/radio/src/group.min.js +1 -1
  131. package/lib/radio/src/radio.js +27 -3
  132. package/lib/radio/src/radio.min.js +1 -1
  133. package/lib/radio/style/style.css +5 -3
  134. package/lib/radio/style/style.min.css +1 -1
  135. package/lib/style.css +1 -1
  136. package/lib/style.min.css +1 -1
  137. package/lib/switch/src/switch.js +18 -10
  138. package/lib/switch/src/switch.min.js +1 -1
  139. package/lib/tree/style/style.css +11 -6
  140. package/lib/tree/style/style.min.css +1 -1
  141. package/lib/ui/index.js +1 -1
  142. package/lib/ui/index.min.js +1 -1
  143. package/lib/ui/src/log.js +1 -1
  144. package/lib/ui/src/log.min.js +1 -1
  145. package/lib/vxe-checkbox/style/style.css +6 -3
  146. package/lib/vxe-checkbox/style/style.min.css +1 -1
  147. package/lib/vxe-radio/style/style.css +5 -3
  148. package/lib/vxe-radio/style/style.min.css +1 -1
  149. package/lib/vxe-tree/style/style.css +11 -6
  150. package/lib/vxe-tree/style/style.min.css +1 -1
  151. package/package.json +88 -88
  152. package/packages/alert/index.ts +16 -16
  153. package/packages/alert/src/alert.ts +124 -124
  154. package/packages/anchor/index.ts +16 -16
  155. package/packages/anchor/src/anchor-link.ts +121 -121
  156. package/packages/anchor/src/anchor.ts +237 -237
  157. package/packages/anchor/src/util.ts +23 -23
  158. package/packages/anchor-link/index.ts +16 -16
  159. package/packages/avatar/index.ts +16 -16
  160. package/packages/avatar/src/avatar.ts +149 -149
  161. package/packages/backtop/index.ts +16 -16
  162. package/packages/backtop/src/backtop.ts +314 -314
  163. package/packages/badge/index.ts +16 -16
  164. package/packages/badge/src/badge.ts +100 -100
  165. package/packages/breadcrumb/index.ts +16 -16
  166. package/packages/breadcrumb/src/breadcrumb-item.ts +106 -106
  167. package/packages/breadcrumb/src/breadcrumb.ts +92 -92
  168. package/packages/breadcrumb-item/index.ts +16 -16
  169. package/packages/button/index.ts +16 -16
  170. package/packages/button/src/button-group.ts +110 -110
  171. package/packages/button/src/button.ts +841 -841
  172. package/packages/button-group/index.ts +16 -16
  173. package/packages/calendar/index.ts +16 -16
  174. package/packages/calendar/src/calendar.ts +1351 -1351
  175. package/packages/card/index.ts +16 -16
  176. package/packages/card/src/card.ts +175 -175
  177. package/packages/carousel/index.ts +16 -16
  178. package/packages/carousel/src/carousel-item.ts +102 -102
  179. package/packages/carousel/src/carousel.ts +414 -414
  180. package/packages/carousel/src/util.ts +21 -21
  181. package/packages/carousel-item/index.ts +16 -16
  182. package/packages/cascader/index.ts +16 -16
  183. package/packages/cascader/src/cascader.ts +741 -741
  184. package/packages/checkbox/index.ts +16 -16
  185. package/packages/checkbox/src/button.ts +165 -144
  186. package/packages/checkbox/src/checkbox.ts +176 -154
  187. package/packages/checkbox/src/group.ts +243 -222
  188. package/packages/checkbox-button/index.ts +16 -16
  189. package/packages/checkbox-group/index.ts +16 -16
  190. package/packages/col/index.ts +16 -16
  191. package/packages/collapse/index.ts +16 -16
  192. package/packages/collapse/src/collapse-pane.ts +114 -114
  193. package/packages/collapse/src/collapse.ts +284 -284
  194. package/packages/collapse/src/util.ts +21 -21
  195. package/packages/collapse-pane/index.ts +16 -16
  196. package/packages/color-picker/index.ts +16 -16
  197. package/packages/color-picker/src/color-picker.ts +1109 -1109
  198. package/packages/color-picker/src/util.ts +198 -198
  199. package/packages/components.ts +307 -307
  200. package/packages/context-menu/index.ts +54 -54
  201. package/packages/context-menu/src/context-menu.ts +681 -681
  202. package/packages/countdown/index.ts +16 -16
  203. package/packages/countdown/src/countdown.ts +262 -262
  204. package/packages/date-panel/index.ts +16 -16
  205. package/packages/date-panel/src/date-panel.ts +1809 -1809
  206. package/packages/date-panel/src/util.ts +244 -244
  207. package/packages/date-picker/index.ts +16 -16
  208. package/packages/date-picker/src/date-picker.ts +1071 -1071
  209. package/packages/date-range-picker/index.ts +16 -16
  210. package/packages/date-range-picker/src/date-range-picker.ts +1280 -1280
  211. package/packages/drawer/index.ts +77 -77
  212. package/packages/drawer/src/drawer.ts +657 -657
  213. package/packages/dynamics/index.ts +89 -89
  214. package/packages/empty/index.ts +16 -16
  215. package/packages/empty/src/empty.ts +100 -100
  216. package/packages/form/index.ts +16 -16
  217. package/packages/form/render/index.ts +598 -598
  218. package/packages/form/src/form-config-item.ts +72 -72
  219. package/packages/form/src/form-group.ts +86 -86
  220. package/packages/form/src/form-item.ts +174 -174
  221. package/packages/form/src/form.ts +987 -987
  222. package/packages/form/src/itemInfo.ts +80 -80
  223. package/packages/form/src/render.ts +387 -387
  224. package/packages/form/src/util.ts +93 -93
  225. package/packages/form-gather/index.ts +26 -26
  226. package/packages/form-group/index.ts +16 -16
  227. package/packages/form-item/index.ts +16 -16
  228. package/packages/icon/index.ts +16 -16
  229. package/packages/icon/src/icon.ts +75 -75
  230. package/packages/icon-picker/index.ts +16 -16
  231. package/packages/icon-picker/src/icon-picker.ts +626 -626
  232. package/packages/image/index.ts +16 -16
  233. package/packages/image/src/group.ts +153 -153
  234. package/packages/image/src/image.ts +298 -298
  235. package/packages/image/src/preview.ts +672 -672
  236. package/packages/image/src/util.ts +59 -59
  237. package/packages/image-group/index.ts +16 -16
  238. package/packages/image-preview/index.ts +19 -19
  239. package/packages/index.ts +4 -4
  240. package/packages/input/index.ts +16 -16
  241. package/packages/input/src/input.ts +2788 -2788
  242. package/packages/language/ar-EG.ts +844 -840
  243. package/packages/language/de-DE.ts +844 -840
  244. package/packages/language/en-US.ts +844 -840
  245. package/packages/language/es-ES.ts +844 -840
  246. package/packages/language/fr-FR.ts +844 -840
  247. package/packages/language/hu-HU.ts +844 -840
  248. package/packages/language/hy-AM.ts +844 -840
  249. package/packages/language/id-ID.ts +844 -840
  250. package/packages/language/it-IT.ts +844 -840
  251. package/packages/language/ja-JP.ts +844 -840
  252. package/packages/language/ko-KR.ts +844 -840
  253. package/packages/language/ms-MY.ts +844 -840
  254. package/packages/language/nb-NO.ts +844 -840
  255. package/packages/language/pt-BR.ts +844 -840
  256. package/packages/language/ru-RU.ts +844 -840
  257. package/packages/language/th-TH.ts +844 -840
  258. package/packages/language/ug-CN.ts +844 -840
  259. package/packages/language/uk-UA.ts +844 -840
  260. package/packages/language/uz-UZ.ts +844 -840
  261. package/packages/language/vi-VN.ts +844 -840
  262. package/packages/language/zh-CHT.ts +844 -840
  263. package/packages/language/zh-CN.ts +844 -840
  264. package/packages/language/zh-HK.ts +3 -3
  265. package/packages/language/zh-MO.ts +3 -3
  266. package/packages/language/zh-TC.ts +3 -3
  267. package/packages/language/zh-TW.ts +3 -3
  268. package/packages/layout-aside/index.ts +16 -16
  269. package/packages/layout-aside/src/layout-aside.ts +123 -123
  270. package/packages/layout-body/index.ts +16 -16
  271. package/packages/layout-body/src/layout-body.ts +142 -142
  272. package/packages/layout-container/index.ts +16 -16
  273. package/packages/layout-container/src/layout-container.ts +82 -82
  274. package/packages/layout-footer/index.ts +16 -16
  275. package/packages/layout-footer/src/layout-footer.ts +74 -74
  276. package/packages/layout-header/index.ts +16 -16
  277. package/packages/layout-header/src/layout-header.ts +73 -73
  278. package/packages/link/index.ts +16 -16
  279. package/packages/link/src/link.ts +161 -161
  280. package/packages/list/index.ts +16 -16
  281. package/packages/list/src/list.ts +442 -442
  282. package/packages/loading/index.ts +34 -34
  283. package/packages/loading/src/loading.ts +152 -152
  284. package/packages/mention/index.ts +16 -16
  285. package/packages/mention/src/mention.ts +71 -71
  286. package/packages/menu/index.ts +16 -16
  287. package/packages/menu/src/menu.ts +581 -581
  288. package/packages/modal/index.ts +136 -136
  289. package/packages/modal/src/modal.ts +1494 -1494
  290. package/packages/notice-bar/index.ts +16 -16
  291. package/packages/notice-bar/src/notice-bar.ts +181 -181
  292. package/packages/number-input/index.ts +16 -16
  293. package/packages/number-input/src/number-input.ts +1096 -1096
  294. package/packages/number-input/src/util.ts +12 -12
  295. package/packages/optgroup/index.ts +16 -16
  296. package/packages/option/index.ts +16 -16
  297. package/packages/pager/index.ts +16 -16
  298. package/packages/pager/src/pager.ts +769 -769
  299. package/packages/password-input/index.ts +16 -16
  300. package/packages/password-input/src/password-input.ts +378 -378
  301. package/packages/print/index.ts +18 -18
  302. package/packages/print/src/page-break.ts +92 -92
  303. package/packages/print/src/print.ts +272 -272
  304. package/packages/print/src/util.ts +284 -284
  305. package/packages/print-page-break/index.ts +16 -16
  306. package/packages/pulldown/index.ts +16 -16
  307. package/packages/pulldown/src/pulldown.ts +457 -457
  308. package/packages/radio/index.ts +16 -16
  309. package/packages/radio/src/button.ts +195 -173
  310. package/packages/radio/src/group.ts +229 -213
  311. package/packages/radio/src/radio.ts +203 -180
  312. package/packages/radio-button/index.ts +16 -16
  313. package/packages/radio-group/index.ts +16 -16
  314. package/packages/rate/index.ts +16 -16
  315. package/packages/rate/src/rate.ts +192 -192
  316. package/packages/result/index.ts +16 -16
  317. package/packages/result/src/result.ts +112 -112
  318. package/packages/row/index.ts +16 -16
  319. package/packages/row/src/col.ts +136 -136
  320. package/packages/row/src/row.ts +119 -119
  321. package/packages/segmented/index.ts +16 -16
  322. package/packages/segmented/src/segmented.ts +264 -264
  323. package/packages/select/index.ts +16 -16
  324. package/packages/select/src/optgroup.ts +49 -49
  325. package/packages/select/src/option-info.ts +20 -20
  326. package/packages/select/src/option.ts +47 -47
  327. package/packages/select/src/select.ts +1699 -1699
  328. package/packages/select/src/util.ts +47 -47
  329. package/packages/slider/index.ts +16 -16
  330. package/packages/slider/src/slider.ts +304 -304
  331. package/packages/split/index.ts +16 -16
  332. package/packages/split-pane/index.ts +17 -17
  333. package/packages/splitter/index.ts +16 -16
  334. package/packages/splitter/src/splitter-panel.ts +145 -145
  335. package/packages/splitter/src/splitter.ts +1009 -1009
  336. package/packages/splitter/src/util.ts +21 -21
  337. package/packages/splitter-panel/index.ts +16 -16
  338. package/packages/steps/index.ts +16 -16
  339. package/packages/steps/src/steps.ts +68 -68
  340. package/packages/switch/index.ts +16 -16
  341. package/packages/switch/src/switch.ts +245 -237
  342. package/packages/tab-pane/index.ts +16 -16
  343. package/packages/table-select/index.ts +16 -16
  344. package/packages/table-select/src/table-select.ts +800 -800
  345. package/packages/tabs/index.ts +16 -16
  346. package/packages/tabs/src/tab-pane.ts +117 -117
  347. package/packages/tabs/src/tabs.ts +940 -940
  348. package/packages/tabs/src/util.ts +21 -21
  349. package/packages/tag/index.ts +16 -16
  350. package/packages/tag/src/tag.ts +187 -187
  351. package/packages/text/index.ts +16 -16
  352. package/packages/text/src/text.ts +260 -260
  353. package/packages/text-ellipsis/index.ts +16 -16
  354. package/packages/text-ellipsis/src/text-ellipsis.ts +282 -282
  355. package/packages/textarea/index.ts +16 -16
  356. package/packages/textarea/src/textarea.ts +373 -373
  357. package/packages/timeline/index.ts +16 -16
  358. package/packages/timeline/src/timeline-item.ts +67 -67
  359. package/packages/timeline/src/timeline.ts +71 -71
  360. package/packages/timeline-item/index.ts +16 -16
  361. package/packages/tip/index.ts +19 -19
  362. package/packages/tip/src/tip.ts +129 -129
  363. package/packages/tooltip/index.ts +16 -16
  364. package/packages/tooltip/src/tooltip.ts +589 -589
  365. package/packages/tour/index.ts +16 -16
  366. package/packages/tour/src/tour.ts +71 -71
  367. package/packages/tree/index.ts +16 -16
  368. package/packages/tree/src/store.ts +14 -14
  369. package/packages/tree/src/tree.ts +2825 -2825
  370. package/packages/tree/src/util.ts +45 -45
  371. package/packages/tree-select/index.ts +16 -16
  372. package/packages/tree-select/src/tree-select.ts +979 -979
  373. package/packages/ui/index.ts +697 -697
  374. package/packages/ui/src/anime.ts +52 -52
  375. package/packages/ui/src/comp.ts +3 -3
  376. package/packages/ui/src/dom.ts +279 -279
  377. package/packages/ui/src/log.ts +6 -6
  378. package/packages/ui/src/utils.ts +49 -49
  379. package/packages/ui/src/vn.ts +39 -39
  380. package/packages/upload/index.ts +20 -20
  381. package/packages/upload/src/upload.ts +1919 -1919
  382. package/packages/upload/src/util.ts +109 -109
  383. package/packages/watermark/index.ts +31 -31
  384. package/packages/watermark/src/util.ts +176 -176
  385. package/packages/watermark/src/watermark.ts +168 -168
  386. package/styles/all.scss +90 -90
  387. package/styles/base.scss +16 -16
  388. package/styles/components/alert.scss +101 -101
  389. package/styles/components/anchor.scss +44 -44
  390. package/styles/components/avatar.scss +115 -115
  391. package/styles/components/backtop.scss +82 -82
  392. package/styles/components/badge.scss +45 -45
  393. package/styles/components/breadcrumb.scss +29 -29
  394. package/styles/components/button-group.scss +30 -30
  395. package/styles/components/button.scss +415 -415
  396. package/styles/components/calendar.scss +471 -471
  397. package/styles/components/card.scss +121 -121
  398. package/styles/components/carousel.scss +184 -184
  399. package/styles/components/cascader.scss +140 -140
  400. package/styles/components/checkbox-button.scss +57 -57
  401. package/styles/components/checkbox.scss +81 -81
  402. package/styles/components/collapse.scss +56 -56
  403. package/styles/components/color-picker.scss +409 -409
  404. package/styles/components/context-menu.scss +102 -102
  405. package/styles/components/countdown.scss +35 -35
  406. package/styles/components/date-panel.scss +505 -505
  407. package/styles/components/date-picker.scss +247 -247
  408. package/styles/components/date-range-picker.scss +252 -252
  409. package/styles/components/drawer.scss +298 -298
  410. package/styles/components/empty.scss +79 -79
  411. package/styles/components/form.scss +668 -668
  412. package/styles/components/icon-picker.scss +211 -211
  413. package/styles/components/icon.scss +1048 -1048
  414. package/styles/components/image-group.scss +2 -2
  415. package/styles/components/image-preview.scss +215 -215
  416. package/styles/components/image.scss +16 -16
  417. package/styles/components/input.scss +846 -846
  418. package/styles/components/layout-aside.scss +22 -22
  419. package/styles/components/layout-body.scss +14 -14
  420. package/styles/components/layout-container.scss +13 -13
  421. package/styles/components/layout-footer.scss +14 -14
  422. package/styles/components/layout-header.scss +11 -11
  423. package/styles/components/link.scss +115 -115
  424. package/styles/components/list.scss +40 -40
  425. package/styles/components/loading.scss +137 -137
  426. package/styles/components/menu.scss +150 -150
  427. package/styles/components/modal.scss +480 -480
  428. package/styles/components/notice-bar.scss +91 -91
  429. package/styles/components/number-input.scss +283 -283
  430. package/styles/components/old-icon.scss +4 -4
  431. package/styles/components/pager.scss +282 -282
  432. package/styles/components/password-input.scss +374 -374
  433. package/styles/components/print.scss +3 -3
  434. package/styles/components/pulldown.scss +75 -75
  435. package/styles/components/radio-button.scss +57 -57
  436. package/styles/components/radio.scss +79 -79
  437. package/styles/components/rate.scss +76 -76
  438. package/styles/components/result.scss +91 -91
  439. package/styles/components/row.scss +69 -69
  440. package/styles/components/segmented.scss +215 -215
  441. package/styles/components/select.scss +244 -244
  442. package/styles/components/slider.scss +139 -139
  443. package/styles/components/split.scss +1 -1
  444. package/styles/components/splitter.scss +318 -318
  445. package/styles/components/switch.scss +128 -128
  446. package/styles/components/table-select.scss +105 -105
  447. package/styles/components/tabs.scss +745 -745
  448. package/styles/components/tag.scss +184 -184
  449. package/styles/components/text-ellipsis.scss +130 -130
  450. package/styles/components/text.scss +123 -123
  451. package/styles/components/textarea.scss +106 -106
  452. package/styles/components/tip.scss +97 -97
  453. package/styles/components/tooltip.scss +141 -141
  454. package/styles/components/tree-select.scss +166 -166
  455. package/styles/components/tree.scss +294 -294
  456. package/styles/components/upload.scss +497 -497
  457. package/styles/components/watermark.scss +26 -26
  458. package/styles/helpers/baseMixin.scss +104 -95
  459. package/styles/helpers/baseVar.scss +3 -3
  460. package/styles/helpers/placement.scss +38 -38
  461. package/styles/theme/base.scss +214 -214
  462. package/styles/theme/dark.scss +119 -119
  463. package/styles/theme/light.scss +118 -118
  464. package/styles/variable.scss +111 -111
  465. package/types/all.d.ts +327 -327
  466. package/types/components/alert.d.ts +87 -87
  467. package/types/components/anchor-link.d.ts +91 -91
  468. package/types/components/anchor.d.ts +104 -104
  469. package/types/components/avatar.d.ts +88 -88
  470. package/types/components/backtop.d.ts +122 -122
  471. package/types/components/badge.d.ts +76 -76
  472. package/types/components/breadcrumb-item.d.ts +80 -80
  473. package/types/components/breadcrumb.d.ts +87 -87
  474. package/types/components/button-group.d.ts +120 -120
  475. package/types/components/button.d.ts +323 -323
  476. package/types/components/calendar.d.ts +264 -264
  477. package/types/components/card.d.ts +93 -93
  478. package/types/components/carousel-item.d.ts +75 -75
  479. package/types/components/carousel.d.ts +134 -134
  480. package/types/components/cascader.d.ts +263 -263
  481. package/types/components/checkbox-button.d.ts +103 -103
  482. package/types/components/checkbox-group.d.ts +146 -143
  483. package/types/components/checkbox.d.ts +123 -123
  484. package/types/components/col.d.ts +80 -80
  485. package/types/components/colgroup.d.ts +137 -137
  486. package/types/components/collapse-pane.d.ts +89 -89
  487. package/types/components/collapse.d.ts +121 -121
  488. package/types/components/color-picker.d.ts +176 -176
  489. package/types/components/column.d.ts +841 -841
  490. package/types/components/context-menu.d.ts +289 -289
  491. package/types/components/countdown.d.ts +112 -112
  492. package/types/components/date-panel.d.ts +280 -280
  493. package/types/components/date-picker.d.ts +332 -332
  494. package/types/components/date-range-picker.d.ts +352 -352
  495. package/types/components/drawer.d.ts +299 -299
  496. package/types/components/empty.d.ts +78 -78
  497. package/types/components/flow-design.d.ts +85 -85
  498. package/types/components/flow-view.d.ts +85 -85
  499. package/types/components/form-design.d.ts +376 -376
  500. package/types/components/form-gather.d.ts +124 -124
  501. package/types/components/form-group.d.ts +77 -77
  502. package/types/components/form-item.d.ts +411 -411
  503. package/types/components/form-view.d.ts +183 -183
  504. package/types/components/form.d.ts +468 -468
  505. package/types/components/gantt-module/gantt-view.d.ts +177 -177
  506. package/types/components/gantt-module/index.d.ts +1 -1
  507. package/types/components/gantt-plugins/extend-gantt-chart.d.ts +131 -131
  508. package/types/components/gantt-plugins/index.d.ts +1 -1
  509. package/types/components/gantt.d.ts +1194 -1194
  510. package/types/components/grid.d.ts +1040 -1040
  511. package/types/components/icon-picker.d.ts +196 -196
  512. package/types/components/icon.d.ts +87 -87
  513. package/types/components/image-group.d.ts +127 -127
  514. package/types/components/image-preview.d.ts +167 -167
  515. package/types/components/image.d.ts +173 -173
  516. package/types/components/input.d.ts +435 -435
  517. package/types/components/layout-aside.d.ts +80 -80
  518. package/types/components/layout-body.d.ts +91 -91
  519. package/types/components/layout-container.d.ts +73 -73
  520. package/types/components/layout-footer.d.ts +73 -73
  521. package/types/components/layout-header.d.ts +69 -69
  522. package/types/components/link.d.ts +111 -111
  523. package/types/components/list-design.d.ts +190 -190
  524. package/types/components/list-view.d.ts +199 -199
  525. package/types/components/list.d.ts +204 -204
  526. package/types/components/loading.d.ts +103 -103
  527. package/types/components/mention.d.ts +77 -77
  528. package/types/components/menu.d.ts +211 -211
  529. package/types/components/modal.d.ts +542 -542
  530. package/types/components/notice-bar.d.ts +102 -102
  531. package/types/components/number-input.d.ts +309 -309
  532. package/types/components/optgroup.d.ts +88 -88
  533. package/types/components/option.d.ts +103 -103
  534. package/types/components/pager.d.ts +335 -335
  535. package/types/components/password-input.d.ts +142 -142
  536. package/types/components/print-page-break.d.ts +69 -69
  537. package/types/components/print.d.ts +206 -206
  538. package/types/components/pulldown.d.ts +231 -231
  539. package/types/components/radio-button.d.ts +114 -114
  540. package/types/components/radio-group.d.ts +147 -144
  541. package/types/components/radio.d.ts +129 -129
  542. package/types/components/rate.d.ts +88 -88
  543. package/types/components/result.d.ts +84 -84
  544. package/types/components/row.d.ts +79 -79
  545. package/types/components/segmented.d.ts +123 -123
  546. package/types/components/select.d.ts +527 -527
  547. package/types/components/slider.d.ts +126 -126
  548. package/types/components/split-pane.d.ts +133 -133
  549. package/types/components/split.d.ts +312 -312
  550. package/types/components/splitter-panel.d.ts +105 -105
  551. package/types/components/splitter.d.ts +288 -288
  552. package/types/components/steps.d.ts +68 -68
  553. package/types/components/switch.d.ts +133 -133
  554. package/types/components/tab-pane.d.ts +114 -114
  555. package/types/components/table-module/custom.d.ts +123 -123
  556. package/types/components/table-module/edit.d.ts +243 -243
  557. package/types/components/table-module/export.d.ts +96 -96
  558. package/types/components/table-module/filter.d.ts +140 -140
  559. package/types/components/table-module/index.d.ts +7 -7
  560. package/types/components/table-module/keyboard.d.ts +26 -26
  561. package/types/components/table-module/menu.d.ts +28 -28
  562. package/types/components/table-module/validator.d.ts +53 -53
  563. package/types/components/table-plugins/extend-cell-area.d.ts +770 -770
  564. package/types/components/table-plugins/extend-pivot-table.d.ts +58 -58
  565. package/types/components/table-plugins/filters-combination.d.ts +15 -15
  566. package/types/components/table-plugins/filters-complex-input.d.ts +9 -9
  567. package/types/components/table-plugins/index.d.ts +4 -4
  568. package/types/components/table-select.d.ts +219 -219
  569. package/types/components/table.d.ts +7465 -7465
  570. package/types/components/tabs.d.ts +332 -332
  571. package/types/components/tag.d.ts +114 -114
  572. package/types/components/text-ellipsis.d.ts +112 -112
  573. package/types/components/text.d.ts +122 -122
  574. package/types/components/textarea.d.ts +247 -247
  575. package/types/components/timeline-item.d.ts +75 -75
  576. package/types/components/timeline.d.ts +77 -77
  577. package/types/components/tip.d.ts +83 -83
  578. package/types/components/toolbar.d.ts +336 -336
  579. package/types/components/tooltip.d.ts +180 -180
  580. package/types/components/tour.d.ts +77 -77
  581. package/types/components/tree-select.d.ts +310 -310
  582. package/types/components/tree.d.ts +843 -843
  583. package/types/components/upload.d.ts +437 -437
  584. package/types/components/watermark.d.ts +120 -120
  585. package/types/handles/form-design.d.ts +50 -50
  586. package/types/handles/index.d.ts +3 -3
  587. package/types/handles/list-design.d.ts +2 -2
  588. package/types/handles/table.d.ts +15 -15
  589. package/types/index.d.ts +8 -8
  590. package/types/ui/commands.d.ts +57 -57
  591. package/types/ui/formats.d.ts +62 -62
  592. package/types/ui/global-config.d.ts +254 -254
  593. package/types/ui/global-icon.d.ts +292 -292
  594. package/types/ui/hooks.d.ts +13 -13
  595. package/types/ui/index.d.ts +96 -96
  596. package/types/ui/interceptor.d.ts +52 -52
  597. package/types/ui/menus.d.ts +77 -77
  598. package/types/ui/renderer.d.ts +1041 -1041
  599. package/types/ui/validators.d.ts +38 -38
  600. /package/es/icon/{iconfont.1778317220469.ttf → iconfont.1778465063324.ttf} +0 -0
  601. /package/es/icon/{iconfont.1778317220469.woff → iconfont.1778465063324.woff} +0 -0
  602. /package/es/icon/{iconfont.1778317220469.woff2 → iconfont.1778465063324.woff2} +0 -0
  603. /package/es/{iconfont.1778317220469.ttf → iconfont.1778465063324.ttf} +0 -0
  604. /package/es/{iconfont.1778317220469.woff → iconfont.1778465063324.woff} +0 -0
  605. /package/es/{iconfont.1778317220469.woff2 → iconfont.1778465063324.woff2} +0 -0
  606. /package/lib/icon/style/{iconfont.1778317220469.ttf → iconfont.1778465063324.ttf} +0 -0
  607. /package/lib/icon/style/{iconfont.1778317220469.woff → iconfont.1778465063324.woff} +0 -0
  608. /package/lib/icon/style/{iconfont.1778317220469.woff2 → iconfont.1778465063324.woff2} +0 -0
  609. /package/lib/{iconfont.1778317220469.ttf → iconfont.1778465063324.ttf} +0 -0
  610. /package/lib/{iconfont.1778317220469.woff → iconfont.1778465063324.woff} +0 -0
  611. /package/lib/{iconfont.1778317220469.woff2 → iconfont.1778465063324.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
+ })