oxy-uni-ui 1.2.0 → 2.0.0

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 (306) hide show
  1. package/attributes.json +1 -1
  2. package/components/common/abstracts/variable.scss +396 -321
  3. package/components/common/path.ts +9 -0
  4. package/components/common/util.ts +200 -5
  5. package/components/composables/index.ts +1 -0
  6. package/components/composables/useGlobalLoading.ts +42 -0
  7. package/components/composables/useGlobalMessage.ts +48 -0
  8. package/components/composables/useGlobalToast.ts +84 -0
  9. package/components/composables/usePopover.ts +24 -20
  10. package/components/composables/useVirtualScroll.ts +13 -11
  11. package/components/composables/useWindowResize.ts +35 -0
  12. package/components/oxy-action-sheet/index.scss +24 -11
  13. package/components/oxy-action-sheet/oxy-action-sheet.vue +27 -19
  14. package/components/oxy-action-sheet/types.ts +7 -0
  15. package/components/oxy-backtop/index.scss +3 -3
  16. package/components/oxy-backtop/oxy-backtop.vue +9 -6
  17. package/components/oxy-backtop/types.ts +7 -7
  18. package/components/oxy-badge/index.scss +4 -4
  19. package/components/oxy-badge/oxy-badge.vue +3 -3
  20. package/components/oxy-badge/types.ts +2 -2
  21. package/components/oxy-button/index.scss +5 -5
  22. package/components/oxy-button/oxy-button.vue +5 -1
  23. package/components/oxy-calendar/index.scss +11 -11
  24. package/components/oxy-calendar/oxy-calendar.vue +1 -0
  25. package/components/oxy-calendar/types.ts +5 -0
  26. package/components/oxy-calendar-view/month/index.scss +4 -4
  27. package/components/oxy-calendar-view/month/types.ts +36 -0
  28. package/components/oxy-calendar-view/monthPanel/index.scss +7 -7
  29. package/components/oxy-calendar-view/monthPanel/month-panel.vue +14 -8
  30. package/components/oxy-calendar-view/year/index.scss +4 -4
  31. package/components/oxy-calendar-view/yearPanel/index.scss +4 -4
  32. package/components/oxy-calendar-view/yearPanel/year-panel.vue +21 -5
  33. package/components/oxy-card/index.scss +2 -2
  34. package/components/oxy-cell/index.scss +8 -8
  35. package/components/oxy-cell/oxy-cell.vue +15 -2
  36. package/components/oxy-cell/types.ts +4 -0
  37. package/components/oxy-checkbox/index.scss +8 -8
  38. package/components/oxy-checkbox/oxy-checkbox.vue +2 -2
  39. package/components/oxy-checkbox-group/index.scss +2 -2
  40. package/components/oxy-circle/oxy-circle.vue +10 -7
  41. package/components/oxy-circle/types.ts +5 -5
  42. package/components/oxy-col/oxy-col.vue +2 -2
  43. package/components/oxy-col-picker/index.scss +4 -4
  44. package/components/oxy-col-picker/oxy-col-picker.vue +9 -5
  45. package/components/oxy-col-picker/types.ts +12 -3
  46. package/components/oxy-collapse/index.scss +2 -2
  47. package/components/oxy-collapse-item/oxy-collapse-item.vue +3 -3
  48. package/components/oxy-corner/index.scss +32 -32
  49. package/components/oxy-corner/oxy-corner.vue +15 -3
  50. package/components/oxy-corner/types.ts +15 -1
  51. package/components/oxy-count-to/oxy-count-to.vue +3 -3
  52. package/components/oxy-curtain/index.scss +15 -15
  53. package/components/oxy-curtain/oxy-curtain.vue +4 -2
  54. package/components/oxy-curtain/types.ts +6 -1
  55. package/components/oxy-date-strip/index.scss +10 -0
  56. package/components/oxy-date-strip/oxy-date-strip.vue +198 -0
  57. package/components/oxy-date-strip/types.ts +98 -0
  58. package/components/oxy-date-strip/utils.ts +67 -0
  59. package/components/oxy-date-strip-item/index.scss +94 -0
  60. package/components/oxy-date-strip-item/oxy-date-strip-item.vue +102 -0
  61. package/components/oxy-date-strip-item/types.ts +53 -0
  62. package/components/oxy-datetime-picker/index.scss +11 -11
  63. package/components/oxy-datetime-picker/oxy-datetime-picker.vue +4 -1
  64. package/components/oxy-datetime-picker/types.ts +10 -1
  65. package/components/oxy-drop-menu/index.scss +3 -3
  66. package/components/oxy-drop-menu/oxy-drop-menu.vue +3 -3
  67. package/components/oxy-drop-menu-item/index.scss +1 -1
  68. package/components/oxy-drop-menu-item/oxy-drop-menu-item.vue +4 -3
  69. package/components/oxy-drop-menu-item/types.ts +5 -0
  70. package/components/oxy-echarts/index.scss +17 -0
  71. package/components/oxy-echarts/index.ts +1 -0
  72. package/components/oxy-echarts/oxy-echarts.vue +32 -0
  73. package/components/oxy-echarts/types.ts +18 -0
  74. package/components/oxy-fab/index.scss +8 -8
  75. package/components/oxy-fab/oxy-fab.vue +22 -3
  76. package/components/oxy-file-list/index.scss +42 -15
  77. package/components/oxy-file-list/oxy-file-list.vue +208 -34
  78. package/components/oxy-file-list/types.ts +58 -2
  79. package/components/oxy-floating-panel/oxy-floating-panel.vue +13 -9
  80. package/components/oxy-floating-panel/{type.ts → types.ts} +8 -8
  81. package/components/oxy-footer/index.scss +19 -0
  82. package/components/oxy-footer/oxy-footer.vue +78 -0
  83. package/components/oxy-footer/types.ts +17 -0
  84. package/components/oxy-form-item/types.ts +22 -1
  85. package/components/oxy-gap/oxy-gap.vue +2 -2
  86. package/components/oxy-gap/types.ts +2 -2
  87. package/components/oxy-global-loading/oxy-global-loading.vue +53 -0
  88. package/components/oxy-global-message/oxy-global-message.vue +64 -0
  89. package/components/oxy-global-toast/oxy-global-toast.vue +53 -0
  90. package/components/oxy-grid/oxy-grid.vue +1 -1
  91. package/components/oxy-grid/types.ts +1 -1
  92. package/components/oxy-grid-item/index.scss +1 -1
  93. package/components/oxy-grid-item/oxy-grid-item.vue +7 -5
  94. package/components/oxy-grid-item/types.ts +1 -1
  95. package/components/oxy-guidance/index.scss +75 -0
  96. package/components/oxy-guidance/oxy-guidance.vue +201 -0
  97. package/components/oxy-guidance/types.ts +33 -0
  98. package/components/oxy-icon/oxy-icon.vue +2 -2
  99. package/components/oxy-icon/types.ts +1 -1
  100. package/components/oxy-img/oxy-img.vue +4 -4
  101. package/components/oxy-img/types.ts +3 -3
  102. package/components/oxy-img-cropper/index.scss +12 -12
  103. package/components/oxy-img-cropper/oxy-img-cropper.vue +97 -52
  104. package/components/oxy-img-cropper/types.ts +2 -2
  105. package/components/oxy-img-lazy/index.scss +17 -0
  106. package/components/oxy-img-lazy/oxy-img-lazy.vue +332 -0
  107. package/components/oxy-img-lazy/types.ts +69 -0
  108. package/components/oxy-index-anchor/index.scss +2 -2
  109. package/components/oxy-index-anchor/oxy-index-anchor.vue +2 -2
  110. package/components/oxy-index-anchor/{type.ts → types.ts} +3 -0
  111. package/components/oxy-index-bar/index.scss +3 -3
  112. package/components/oxy-index-bar/oxy-index-bar.vue +3 -3
  113. package/components/oxy-index-bar/{type.ts → types.ts} +2 -2
  114. package/components/oxy-input/index.scss +1 -1
  115. package/components/oxy-input-number/index.scss +5 -5
  116. package/components/oxy-input-number/oxy-input-number.vue +2 -2
  117. package/components/oxy-input-number/types.ts +3 -2
  118. package/components/oxy-keyboard/index.scss +5 -5
  119. package/components/oxy-keyboard/key/index.scss +3 -3
  120. package/components/oxy-keyboard/key/index.vue +2 -2
  121. package/components/oxy-keyboard/key/types.ts +15 -0
  122. package/components/oxy-keyboard/oxy-keyboard.vue +1 -0
  123. package/components/oxy-keyboard/types.ts +5 -0
  124. package/components/oxy-link/index.scss +57 -0
  125. package/components/oxy-link/oxy-link.vue +130 -0
  126. package/components/oxy-link/types.ts +81 -0
  127. package/components/oxy-list/index.scss +7 -1
  128. package/components/oxy-list/oxy-list.vue +4 -3
  129. package/components/oxy-list/types.ts +1 -1
  130. package/components/oxy-loading/oxy-loading.vue +8 -4
  131. package/components/oxy-loading/types.ts +1 -1
  132. package/components/oxy-loadmore/index.scss +3 -3
  133. package/components/oxy-long-press-menu/index.scss +93 -0
  134. package/components/oxy-long-press-menu/oxy-long-press-menu.vue +338 -0
  135. package/components/oxy-long-press-menu/types.ts +34 -0
  136. package/components/oxy-message-box/index.scss +12 -11
  137. package/components/oxy-message-box/oxy-message-box.vue +11 -3
  138. package/components/oxy-message-box/types.ts +14 -0
  139. package/components/oxy-navbar/index.scss +2 -2
  140. package/components/oxy-navbar/oxy-navbar.vue +58 -13
  141. package/components/oxy-navbar/types.ts +8 -1
  142. package/components/oxy-navbar-capsule/types.ts +3 -0
  143. package/components/oxy-notice-bar/index.scss +3 -3
  144. package/components/oxy-notice-bar/oxy-notice-bar.vue +9 -5
  145. package/components/oxy-notice-bar/types.ts +3 -3
  146. package/components/oxy-notify/index.ts +1 -0
  147. package/components/oxy-notify/oxy-notify.vue +3 -2
  148. package/components/oxy-notify/types.ts +7 -0
  149. package/components/oxy-pagination/index.scss +1 -1
  150. package/components/oxy-password-input/oxy-password-input.vue +2 -2
  151. package/components/oxy-password-input/types.ts +1 -1
  152. package/components/oxy-picker/index.scss +45 -2
  153. package/components/oxy-picker/oxy-picker.vue +103 -14
  154. package/components/oxy-picker/types.ts +33 -1
  155. package/components/oxy-picker-view/index.scss +3 -3
  156. package/components/oxy-picker-view/oxy-picker-view.vue +4 -4
  157. package/components/oxy-popover/index.scss +9 -9
  158. package/components/oxy-popup/index.scss +2 -2
  159. package/components/oxy-popup/oxy-popup.vue +35 -2
  160. package/components/oxy-popup/types.ts +8 -1
  161. package/components/oxy-progress/index.scss +3 -3
  162. package/components/oxy-qrcode/draw.ts +398 -0
  163. package/components/oxy-qrcode/index.scss +2 -0
  164. package/components/oxy-qrcode/oxy-qrcode.vue +124 -0
  165. package/components/oxy-qrcode/qrcode.ts +936 -0
  166. package/components/oxy-qrcode/types.ts +42 -0
  167. package/components/oxy-radio/index.scss +13 -13
  168. package/components/oxy-radio/oxy-radio.vue +1 -1
  169. package/components/oxy-radio-group/index.scss +2 -2
  170. package/components/oxy-rate/types.ts +4 -4
  171. package/components/oxy-resize/index.scss +2 -2
  172. package/components/oxy-resize/oxy-resize.vue +4 -4
  173. package/components/oxy-resize/types.ts +3 -0
  174. package/components/oxy-rich-text/icon/emjio.svg +1 -0
  175. package/components/oxy-rich-text/icon/quote.svg +1 -0
  176. package/components/oxy-rich-text/icon/text.svg +1 -0
  177. package/components/oxy-rich-text/icon/title.svg +1 -0
  178. package/components/oxy-rich-text/index.scss +160 -0
  179. package/components/oxy-rich-text/mp-html/card/card.vue +122 -0
  180. package/components/oxy-rich-text/mp-html/card/index.js +7 -0
  181. package/components/oxy-rich-text/mp-html/editable/config.js +15 -0
  182. package/components/oxy-rich-text/mp-html/editable/index.js +553 -0
  183. package/components/oxy-rich-text/mp-html/emoji/index.js +203 -0
  184. package/components/oxy-rich-text/mp-html/highlight/config.js +5 -0
  185. package/components/oxy-rich-text/mp-html/highlight/index.js +96 -0
  186. package/components/oxy-rich-text/mp-html/highlight/prism.css +1 -0
  187. package/components/oxy-rich-text/mp-html/highlight/prism.min.js +7 -0
  188. package/components/oxy-rich-text/mp-html/img-cache/index.js +138 -0
  189. package/components/oxy-rich-text/mp-html/latex/index.js +80 -0
  190. package/components/oxy-rich-text/mp-html/latex/katex.css +1 -0
  191. package/components/oxy-rich-text/mp-html/latex/katex.min.js +1 -0
  192. package/components/oxy-rich-text/mp-html/markdown/index.js +50 -0
  193. package/components/oxy-rich-text/mp-html/markdown/marked.min.js +71 -0
  194. package/components/oxy-rich-text/mp-html/mp-html.d.ts +184 -0
  195. package/components/oxy-rich-text/mp-html/mp-html.vue +684 -0
  196. package/components/oxy-rich-text/mp-html/node/node.vue +1172 -0
  197. package/components/oxy-rich-text/mp-html/parser.js +1428 -0
  198. package/components/oxy-rich-text/mp-html/search/index.js +132 -0
  199. package/components/oxy-rich-text/mp-html/style/index.js +129 -0
  200. package/components/oxy-rich-text/mp-html/style/parser.js +175 -0
  201. package/components/oxy-rich-text/mp-html/template/index.js +67 -0
  202. package/components/oxy-rich-text/mp-html/txv-video/index.js +46 -0
  203. package/components/oxy-rich-text/oxy-rich-text.vue +642 -0
  204. package/components/oxy-rich-text/types.ts +76 -0
  205. package/components/oxy-row/oxy-row.vue +3 -3
  206. package/components/oxy-row/types.ts +1 -1
  207. package/components/oxy-search/index.scss +3 -3
  208. package/components/oxy-segmented/index.scss +16 -16
  209. package/components/oxy-segmented/oxy-segmented.vue +23 -3
  210. package/components/oxy-select/index.scss +331 -0
  211. package/components/oxy-select/oxy-select.vue +456 -0
  212. package/components/oxy-select/types.ts +83 -0
  213. package/components/oxy-select-picker/index.scss +7 -7
  214. package/components/oxy-select-picker/oxy-select-picker.vue +4 -0
  215. package/components/oxy-select-picker/types.ts +7 -1
  216. package/components/oxy-sidebar-item/index.scss +1 -1
  217. package/components/oxy-signature/oxy-signature.vue +18 -10
  218. package/components/oxy-signature/types.ts +106 -13
  219. package/components/oxy-skeleton/oxy-skeleton.vue +6 -6
  220. package/components/oxy-skeleton/types.ts +1 -1
  221. package/components/oxy-slider/index.scss +3 -3
  222. package/components/oxy-sort-button/index.scss +8 -8
  223. package/components/oxy-status-tip/index.scss +4 -4
  224. package/components/oxy-status-tip/oxy-status-tip.vue +5 -5
  225. package/components/oxy-status-tip/types.ts +3 -3
  226. package/components/oxy-step/index.scss +14 -14
  227. package/components/oxy-sticky/oxy-sticky.vue +6 -6
  228. package/components/oxy-stream-render/index.scss +6 -0
  229. package/components/oxy-stream-render/oxy-stream-render.vue +204 -0
  230. package/components/oxy-stream-render/types.ts +8 -0
  231. package/components/oxy-swipe-action/oxy-swipe-action.vue +27 -2
  232. package/components/oxy-swiper/oxy-swiper.vue +6 -6
  233. package/components/oxy-swiper/types.ts +5 -5
  234. package/components/oxy-switch/index.scss +8 -8
  235. package/components/oxy-switch/oxy-switch.vue +2 -2
  236. package/components/oxy-switch/types.ts +1 -1
  237. package/components/oxy-tab/index.scss +11 -1
  238. package/components/oxy-tabbar/index.scss +1 -1
  239. package/components/oxy-tabbar/oxy-tabbar.vue +39 -10
  240. package/components/oxy-table/index.scss +5 -5
  241. package/components/oxy-table/oxy-table.vue +8 -6
  242. package/components/oxy-table/types.ts +2 -2
  243. package/components/oxy-table-col/oxy-table-col.vue +3 -3
  244. package/components/oxy-table-col/types.ts +2 -2
  245. package/components/oxy-tabs/index.scss +43 -15
  246. package/components/oxy-tabs/oxy-tabs.vue +53 -19
  247. package/components/oxy-tabs/types.ts +15 -3
  248. package/components/oxy-tag/index.scss +15 -15
  249. package/components/oxy-text/index.scss +5 -1
  250. package/components/oxy-text/oxy-text.vue +76 -7
  251. package/components/oxy-text/types.ts +12 -0
  252. package/components/oxy-textarea/index.scss +6 -6
  253. package/components/oxy-toast/oxy-toast.vue +24 -8
  254. package/components/oxy-tooltip/index.scss +9 -9
  255. package/components/oxy-tree/index.scss +61 -9
  256. package/components/oxy-tree/oxy-tree.vue +102 -17
  257. package/components/oxy-tree/types.ts +23 -10
  258. package/components/oxy-upload/index.scss +21 -21
  259. package/components/oxy-upload/types.ts +2 -2
  260. package/components/oxy-verification-code/index.scss +6 -0
  261. package/components/oxy-verification-code/oxy-verification-code.vue +187 -0
  262. package/components/oxy-verification-code/types.ts +82 -0
  263. package/components/oxy-video-preview/index.scss +4 -4
  264. package/components/oxy-virtual-scroll/index.scss +4 -4
  265. package/components/oxy-virtual-scroll/oxy-virtual-scroll.vue +11 -7
  266. package/components/oxy-virtual-scroll/types.ts +14 -14
  267. package/components/oxy-voice-player/index.scss +908 -0
  268. package/components/oxy-voice-player/oxy-voice-player.vue +821 -0
  269. package/components/oxy-voice-player/types.ts +567 -0
  270. package/components/oxy-waterfall/index.scss +18 -0
  271. package/components/oxy-waterfall/oxy-waterfall.vue +218 -0
  272. package/components/oxy-waterfall/types.ts +90 -0
  273. package/components/oxy-waterfall-item/index.scss +8 -0
  274. package/components/oxy-waterfall-item/oxy-waterfall-item.vue +89 -0
  275. package/components/oxy-waterfall-item/types.ts +16 -0
  276. package/components/oxy-watermark/oxy-watermark.vue +35 -13
  277. package/components/oxy-watermark/types.ts +14 -14
  278. package/global.d.ts +9 -0
  279. package/index.ts +3 -0
  280. package/locale/lang/ar-SA.ts +3 -0
  281. package/locale/lang/en-US.ts +29 -0
  282. package/locale/lang/zh-CN.ts +29 -0
  283. package/package.json +97 -1
  284. package/tags.json +1 -1
  285. package/uni-echarts/changelog.md +2 -0
  286. package/uni-echarts/components/index.js +1 -0
  287. package/uni-echarts/components/uni-echarts/events.js +95 -0
  288. package/uni-echarts/components/uni-echarts/types.d.ts +183 -0
  289. package/uni-echarts/components/uni-echarts/types.js +1 -0
  290. package/uni-echarts/components/uni-echarts/uni-echarts.vue +530 -0
  291. package/uni-echarts/components/uni-echarts/uni-echarts.vue.d.ts +19 -0
  292. package/uni-echarts/global.d.ts +7 -0
  293. package/uni-echarts/index.d.ts +440 -0
  294. package/uni-echarts/index.js +2 -0
  295. package/uni-echarts/package.json +105 -0
  296. package/uni-echarts/shared-core.d.ts +269 -0
  297. package/uni-echarts/shared-core.js +900 -0
  298. package/web-types.json +1 -1
  299. package/components/oxy-number-keyboard/index.scss +0 -78
  300. package/components/oxy-number-keyboard/key/index.scss +0 -81
  301. package/components/oxy-number-keyboard/key/index.vue +0 -78
  302. package/components/oxy-number-keyboard/key/types.ts +0 -11
  303. package/components/oxy-number-keyboard/oxy-number-keyboard.vue +0 -151
  304. package/components/oxy-number-keyboard/types.ts +0 -83
  305. package/components/oxy-tree/components/tree-node-content.vue +0 -72
  306. package/components/oxy-tree/index.ts +0 -51
@@ -44,12 +44,13 @@ import OxyButton from '../oxy-button/oxy-button.vue'
44
44
  import OxyIcon from '../oxy-icon/oxy-icon.vue'
45
45
  import OxyTransition from '../oxy-transition/oxy-transition.vue'
46
46
  import { type CSSProperties, computed, ref, watch, inject, getCurrentInstance, onBeforeUnmount, onMounted, nextTick } from 'vue'
47
- import { getRect, isDef, isH5, objToStyle } from '../common/util'
47
+ import { getRect, isDef, isH5, objToStyle, unitConvert } from '../common/util'
48
48
  import { type Queue, queueKey } from '../composables/useQueue'
49
49
  import { closeOther, pushToQueue, removeFromQueue } from '../common/clickoutside'
50
50
  import { fabProps, type FabExpose } from './types'
51
51
  import { reactive } from 'vue'
52
52
  import { useRaf } from '../composables/useRaf'
53
+ import { useWindowResize } from '../composables/useWindowResize'
53
54
 
54
55
  const props = defineProps(fabProps)
55
56
  const emit = defineEmits(['update:active', 'click'])
@@ -121,6 +122,24 @@ async function getBounding() {
121
122
  bounding.maxTop = screen.height - fabSize.height - bottom
122
123
  }
123
124
 
125
+ function clampPosition() {
126
+ if (!inited.value) return
127
+ const { minLeft, minTop, maxLeft, maxTop } = bounding
128
+ left.value = Math.min(Math.max(left.value, minLeft), maxLeft)
129
+ top.value = Math.min(Math.max(top.value, minTop), maxTop)
130
+ }
131
+
132
+ const handleWindowResize = async () => {
133
+ await getBounding()
134
+ if (props.draggable) {
135
+ clampPosition()
136
+ return
137
+ }
138
+ initPosition()
139
+ }
140
+
141
+ useWindowResize(handleWindowResize)
142
+
124
143
  function initPosition() {
125
144
  const pos = props.position
126
145
  const { minLeft, minTop, maxLeft, maxTop } = bounding
@@ -210,8 +229,8 @@ function handleTouchEnd() {
210
229
 
211
230
  const rootStyle = computed(() => {
212
231
  const style: CSSProperties = {
213
- top: top.value + 'px',
214
- left: left.value + 'px',
232
+ top: unitConvert(top.value, 0, { output: 'px' }),
233
+ left: unitConvert(left.value, 0, { output: 'px' }),
215
234
  transition: attractTransition.value ? 'all ease 0.3s' : 'none'
216
235
  }
217
236
  if (isDef(props.zIndex)) {
@@ -5,12 +5,12 @@
5
5
  position: relative;
6
6
  display: flex;
7
7
  flex-wrap: wrap;
8
- margin: 0 -8px;
8
+ margin: 0 -16rpx;
9
9
  @include e(item) {
10
10
  position: relative;
11
- width: calc(33.33% - 16px);
11
+ width: calc(33.33% - 32rpx);
12
12
  height: $-file-list-height;
13
- margin: 0 8px 32px;
13
+ margin: 0 16rpx 64rpx;
14
14
  }
15
15
  @include e(content) {
16
16
  display: flex;
@@ -20,27 +20,28 @@
20
20
  width: 100%;
21
21
  height: 100%;
22
22
  border: 1px solid $-color-border;
23
- border-radius: 8px;
23
+ border-radius: 16rpx;
24
+ position: relative;
24
25
  }
25
26
  @include e(picture) {
26
27
  position: relative;
27
28
  display: block;
28
29
  width: 100%;
29
30
  height: 100%;
30
- border-radius: 8px;
31
+ border-radius: 16rpx;
31
32
  }
32
33
  @include e(icon) {
33
- width: 32px;
34
- height: 32px;
34
+ width: 64rpx;
35
+ height: 64rpx;
35
36
  }
36
37
  @include e(name) {
37
38
  display: block;
38
39
  width: 100%;
39
40
  font-size: $-upload-file-fs;
40
41
  color: $-upload-file-color;
41
- padding: 0 4px;
42
+ padding: 0 8rpx;
42
43
  text-align: center;
43
- margin-top: 8px;
44
+ margin-top: 16rpx;
44
45
  white-space: nowrap;
45
46
  overflow: hidden;
46
47
  text-overflow: ellipsis;
@@ -59,15 +60,15 @@
59
60
  .oxy-file-list__list--item {
60
61
  width: 100%;
61
62
  background: #f8f9ff;
62
- padding: 8px 12px;
63
- border-radius: 4px;
63
+ padding: 16rpx 24rpx;
64
+ border-radius: 8rpx;
64
65
  display: flex;
65
66
  flex-direction: row;
66
67
  align-items: center;
67
68
  .oxy-file-list__icon {
68
- width: 24px;
69
- height: 24px;
70
- margin-right: 8px;
69
+ width: 48rpx;
70
+ height: 48rpx;
71
+ margin-right: 16rpx;
71
72
  }
72
73
  .oxy-file-list__name {
73
74
  flex: 1;
@@ -75,9 +76,35 @@
75
76
  margin: 0;
76
77
  padding: 0;
77
78
  }
79
+ .oxy-file-list__download {
80
+ font-size: 36rpx;
81
+ color: $-cell-arrow-color;
82
+ }
83
+ .oxy-file-list__delete {
84
+ font-size: 36rpx;
85
+ color: $-cell-arrow-color;
86
+ margin-left: 24rpx;
87
+ }
78
88
  & + .oxy-file-list__list--item {
79
- margin-top: 8px;
89
+ margin-top: 16rpx;
80
90
  }
81
91
  }
82
92
  }
93
+
94
+ .oxy-file-list__download-btn {
95
+ position: absolute;
96
+ top: 12rpx;
97
+ right: 12rpx;
98
+ background: rgba(0, 0, 0, 0.45);
99
+ border-radius: 12rpx;
100
+ padding: 8rpx 10rpx;
101
+ display: flex;
102
+ }
103
+ .oxy-file-list__download {
104
+ color: $-color-white;
105
+ }
106
+ .oxy-file-list__delete {
107
+ color: $-color-white;
108
+ margin-left: 12rpx;
109
+ }
83
110
  }
@@ -1,16 +1,34 @@
1
1
  <template>
2
2
  <view :class="['oxy-file-list', { 'oxy-file-list__list': props.type === 'list' }, customClass]">
3
3
  <block v-if="props.type === 'list'">
4
- <view v-for="(file, index) in props.data" :key="index" class="oxy-file-list__list--item" @click="onPreview(file)">
4
+ <view v-for="(file, index) in props.data" :key="index" class="oxy-file-list__list--item" @click="handleClick(file, index)">
5
5
  <image :src="getUploadImage(file)" mode="aspectFill" class="oxy-file-list__icon" />
6
6
  <text class="oxy-file-list__name">{{ file.name }}</text>
7
+ <oxy-loading v-if="props.enableDownload && isDownloading(file)" size="36rpx" custom-class="oxy-file-list__download" />
8
+ <view @tap.stop="onDownload(file)" v-if="props.enableDownload && !isDownloading(file)">
9
+ <oxy-icon name="download" custom-class="oxy-file-list__download" />
10
+ </view>
11
+ <view v-if="props.enableDelete && !isDownloading(file)" @tap.stop="onDelete(file, index)">
12
+ <oxy-icon name="delete" custom-class="oxy-file-list__delete" />
13
+ </view>
7
14
  </view>
8
15
  </block>
9
16
  <block v-else>
10
17
  <view v-for="(file, index) in props.data" :key="index" class="oxy-file-list__item">
11
18
  <view class="oxy-file-list__content">
12
- <image v-if="isImage(file)" :src="file.url" mode="aspectFill" class="oxy-file-list__picture" @click="onPreview(file)" />
13
- <image v-else :src="getUploadImage(file)" mode="aspectFill" class="oxy-file-list__icon" @click="onPreview(file)" />
19
+ <image v-if="isImage(file)" :src="file.url" mode="aspectFill" class="oxy-file-list__picture" @click="handleClick(file, index)" />
20
+ <image v-else :src="getUploadImage(file)" mode="aspectFill" class="oxy-file-list__icon" @click="handleClick(file, index)" />
21
+ <view v-if="props.enableDownload || props.enableDelete" class="oxy-file-list__download-btn">
22
+ <template v-if="props.enableDownload">
23
+ <oxy-loading v-if="isDownloading(file)" size="36rpx" color="#ffffff" custom-class="oxy-file-list__download" />
24
+ <view @tap.stop="onDownload(file)">
25
+ <oxy-icon name="download" custom-class="oxy-file-list__download" />
26
+ </view>
27
+ </template>
28
+ <view v-if="props.enableDelete && !isDownloading(file)" @tap.stop="onDelete(file, index)">
29
+ <oxy-icon name="delete" custom-class="oxy-file-list__delete" />
30
+ </view>
31
+ </view>
14
32
  </view>
15
33
  <oxy-tooltip placement="top" :content="file.name">
16
34
  <text class="oxy-file-list__name">{{ file.name }}</text>
@@ -18,6 +36,8 @@
18
36
  </view>
19
37
  </block>
20
38
  </view>
39
+ <oxy-toast selector="oxy-file-list" />
40
+ <oxy-message-box selector="oxy-file-list" />
21
41
  <oxy-video-preview ref="videoPreview"></oxy-video-preview>
22
42
  </template>
23
43
 
@@ -39,7 +59,13 @@ import ImgVideo from '../oxy-upload/images/video.png'
39
59
  import ImgPic from '../oxy-upload/images/pic.png'
40
60
  import ImgOther from '../oxy-upload/images/other.png'
41
61
  import OxyVideoPreview from '../oxy-video-preview/oxy-video-preview.vue'
42
- import { ref } from 'vue'
62
+ import OxyIcon from '../oxy-icon/oxy-icon.vue'
63
+ import OxyLoading from '../oxy-loading/oxy-loading.vue'
64
+ import OxyToast from '../oxy-toast/oxy-toast.vue'
65
+ import OxyMessageBox from '../oxy-message-box/oxy-message-box.vue'
66
+ import { useToast } from '../oxy-toast'
67
+ import { useMessage } from '../oxy-message-box'
68
+ import { ref, nextTick } from 'vue'
43
69
  import { isImageUrl, isVideoUrl, isAudioUrl, isPdfUrl, isDocUrl } from '../common/util'
44
70
  import { type FileListItem, fileListProps } from './types'
45
71
  import type { VideoPreviewInstance } from '../oxy-video-preview/types'
@@ -54,25 +80,41 @@ const imgs: AnyObject = {
54
80
  }
55
81
 
56
82
  const props = defineProps(fileListProps)
83
+ const emit = defineEmits(['delete', 'click'])
57
84
 
58
85
  const videoPreview = ref<VideoPreviewInstance>()
86
+ const toast = useToast('oxy-file-list')
87
+ const message = useMessage('oxy-file-list')
88
+ const downloading = ref<Record<string, boolean>>({})
89
+
90
+ function isDownloading(file: FileListItem) {
91
+ return !!downloading.value[file.url]
92
+ }
59
93
  /**
60
94
  * 预览图片
61
95
  * @param file
62
96
  */
63
97
  function handlePreviewImage(file: FileListItem) {
64
98
  const { onPreviewFail } = props
99
+ toast.loading({ msg: '正在打开预览...', direction: 'vertical', position: 'middle' })
65
100
  uni.previewImage({
66
101
  urls: [file.url],
67
102
  current: 0,
103
+ success() {
104
+ toast.close()
105
+ },
68
106
  fail() {
69
107
  if (onPreviewFail) {
70
108
  onPreviewFail({
71
109
  file
72
110
  })
73
111
  } else {
74
- uni.showToast({ title: '预览图片失败', icon: 'none' })
112
+ toast.error({ msg: '预览图片失败', direction: 'vertical', position: 'middle' })
75
113
  }
114
+ toast.close()
115
+ },
116
+ complete() {
117
+ toast.close()
76
118
  }
77
119
  })
78
120
  }
@@ -81,8 +123,9 @@ function handlePreviewImage(file: FileListItem) {
81
123
  * 预览视频
82
124
  * @param file
83
125
  */
84
- function handlePreviewVieo(file: FileListItem) {
126
+ function handlePreviewVideo(file: FileListItem) {
85
127
  const { onPreviewFail } = props
128
+ toast.loading({ msg: '正在打开预览...', direction: 'vertical', position: 'middle' })
86
129
  // #ifdef MP-WEIXIN
87
130
  uni.previewMedia({
88
131
  current: 0,
@@ -93,19 +136,29 @@ function handlePreviewVieo(file: FileListItem) {
93
136
  poster: file.thumb
94
137
  }
95
138
  ],
139
+ success() {
140
+ toast.close()
141
+ },
96
142
  fail() {
97
143
  if (onPreviewFail) {
98
144
  onPreviewFail({
99
145
  file
100
146
  })
101
147
  } else {
102
- uni.showToast({ title: '预览视频失败', icon: 'none' })
148
+ toast.error({ msg: '预览视频失败', direction: 'vertical', position: 'middle' })
103
149
  }
150
+ toast.close()
151
+ },
152
+ complete() {
153
+ toast.close()
104
154
  }
105
155
  })
106
156
  // #endif
107
157
  // #ifndef MP-WEIXIN
108
158
  videoPreview.value?.open({ url: file.url, poster: file.thumb, title: file.name })
159
+ nextTick(() => {
160
+ toast.close()
161
+ })
109
162
  // #endif
110
163
  }
111
164
 
@@ -114,62 +167,183 @@ function handlePreviewVieo(file: FileListItem) {
114
167
  * @param file
115
168
  */
116
169
  function handlePreviewFile(file: FileListItem) {
170
+ const { onPreviewFail } = props
171
+ toast.loading({ msg: '正在打开预览...', direction: 'vertical', position: 'middle' })
117
172
  uni.openDocument({
118
173
  filePath: file.url,
119
- showMenu: true
174
+ showMenu: true,
175
+ success() {
176
+ toast.close()
177
+ },
178
+ fail() {
179
+ if (onPreviewFail) {
180
+ onPreviewFail({
181
+ file
182
+ })
183
+ } else {
184
+ toast.error({ msg: '预览文件失败', direction: 'vertical', position: 'middle' })
185
+ }
186
+ toast.close()
187
+ },
188
+ complete() {
189
+ toast.close()
190
+ }
120
191
  })
121
192
  }
122
193
 
123
- function onPreviewImage(file: FileListItem) {
194
+ function handleClick(file: FileListItem, index: number) {
195
+ emit('click', { file, index })
196
+ if (!props.enablePreview) return
197
+ const execPreview = () => {
198
+ if (isImage(file)) {
199
+ handlePreviewImage(file)
200
+ } else if (isVideo(file)) {
201
+ handlePreviewVideo(file)
202
+ } else {
203
+ handlePreviewFile(file)
204
+ }
205
+ }
206
+
124
207
  const { beforePreview } = props
125
208
  if (beforePreview) {
126
209
  beforePreview({
127
210
  file,
128
211
  resolve: (isPass: boolean) => {
129
- isPass && handlePreviewImage(file)
212
+ isPass && execPreview()
130
213
  }
131
214
  })
132
215
  } else {
133
- handlePreviewImage(file)
216
+ execPreview()
134
217
  }
135
218
  }
136
219
 
137
- function onPreviewVideo(file: FileListItem) {
138
- const { beforePreview } = props
139
- if (beforePreview) {
140
- beforePreview({
141
- file,
142
- resolve: (isPass: boolean) => {
143
- isPass && handlePreviewVieo(file)
220
+ function onDownload(file: FileListItem) {
221
+ const { beforeDownload, onDownloadSuccess, onDownloadFail } = props
222
+
223
+ const execDownload = () => {
224
+ const filename = file.name || file.url
225
+ downloading.value[file.url] = true
226
+ // #ifdef MP-WEIXIN
227
+ uni.downloadFile({
228
+ url: file.url,
229
+ success(res) {
230
+ const tempFilePath = res.tempFilePath
231
+ uni.saveFile({
232
+ tempFilePath,
233
+ success() {
234
+ if (onDownloadSuccess) {
235
+ onDownloadSuccess({ file, tempFilePath })
236
+ } else {
237
+ toast.success({ msg: `下载成功:${filename}`, direction: 'vertical', position: 'middle' })
238
+ }
239
+ downloading.value[file.url] = false
240
+ },
241
+ fail() {
242
+ if (onDownloadFail) {
243
+ onDownloadFail({ file })
244
+ } else {
245
+ toast.error({ msg: `下载失败:${filename}`, direction: 'vertical', position: 'middle' })
246
+ }
247
+ downloading.value[file.url] = false
248
+ }
249
+ })
250
+ },
251
+ fail() {
252
+ if (onDownloadFail) {
253
+ onDownloadFail({ file })
254
+ } else {
255
+ toast.error({ msg: `下载失败:${filename}`, direction: 'vertical', position: 'middle' })
256
+ }
257
+ downloading.value[file.url] = false
144
258
  }
145
259
  })
146
- } else {
147
- handlePreviewVieo(file)
260
+ // #endif
261
+ // #ifdef H5
262
+ try {
263
+ const a = document.createElement('a')
264
+ a.href = file.url
265
+ a.download = file.name || ''
266
+ a.target = '_blank'
267
+ document.body.appendChild(a)
268
+ a.click()
269
+ document.body.removeChild(a)
270
+ if (onDownloadSuccess) {
271
+ onDownloadSuccess({ file })
272
+ } else {
273
+ toast.success({ msg: `下载成功:${filename}`, direction: 'vertical', position: 'middle' })
274
+ }
275
+ downloading.value[file.url] = false
276
+ } catch (e) {
277
+ if (onDownloadFail) {
278
+ onDownloadFail({ file })
279
+ } else {
280
+ toast.error({ msg: `下载失败:${filename}`, direction: 'vertical', position: 'middle' })
281
+ }
282
+ downloading.value[file.url] = false
283
+ }
284
+ // #endif
285
+ // #ifdef APP-PLUS
286
+ uni.downloadFile({
287
+ url: file.url,
288
+ success(res) {
289
+ const tempFilePath = res.tempFilePath
290
+ uni.saveFile({
291
+ tempFilePath,
292
+ success() {
293
+ if (onDownloadSuccess) {
294
+ onDownloadSuccess({ file, tempFilePath })
295
+ } else {
296
+ toast.success({ msg: `下载成功:${filename}`, direction: 'vertical', position: 'middle' })
297
+ }
298
+ downloading.value[file.url] = false
299
+ },
300
+ fail() {
301
+ if (onDownloadFail) {
302
+ onDownloadFail({ file })
303
+ } else {
304
+ toast.error({ msg: `下载失败:${filename}`, direction: 'vertical', position: 'middle' })
305
+ }
306
+ downloading.value[file.url] = false
307
+ }
308
+ })
309
+ },
310
+ fail() {
311
+ if (onDownloadFail) {
312
+ onDownloadFail({ file })
313
+ } else {
314
+ toast.error({ msg: `下载失败:${filename}`, direction: 'vertical', position: 'middle' })
315
+ }
316
+ downloading.value[file.url] = false
317
+ }
318
+ })
319
+ // #endif
148
320
  }
149
- }
150
321
 
151
- function onPreviewFile(file: FileListItem) {
152
- const { beforePreview } = props
153
- if (beforePreview) {
154
- beforePreview({
322
+ if (beforeDownload) {
323
+ beforeDownload({
155
324
  file,
156
325
  resolve: (isPass: boolean) => {
157
- isPass && handlePreviewFile(file)
326
+ isPass && execDownload()
158
327
  }
159
328
  })
160
329
  } else {
161
- handlePreviewFile(file)
330
+ execDownload()
162
331
  }
163
332
  }
164
333
 
165
- function onPreview(file: FileListItem) {
166
- if (isImage(file)) {
167
- onPreviewImage(file)
168
- } else if (isVideo(file)) {
169
- onPreviewVideo(file)
170
- } else {
171
- onPreviewFile(file)
334
+ function onDelete(file: FileListItem, index: number) {
335
+ const execDelete = () => {
336
+ const title = '确认删除文件'
337
+ const msg = file.name || '确认删除该文件?'
338
+ message
339
+ .confirm({ title, msg, confirmButtonText: '删除', cancelButtonText: '取消' })
340
+ .then(() => {
341
+ emit('delete', { file, index })
342
+ })
343
+ .catch(() => {})
172
344
  }
345
+
346
+ execDelete()
173
347
  }
174
348
 
175
349
  function isVideo(file: FileListItem) {
@@ -1,5 +1,5 @@
1
1
  import type { ExtractPropTypes, PropType } from 'vue'
2
- import { baseProps, makeArrayProp, makeStringProp } from '../common/props'
2
+ import { baseProps, makeArrayProp, makeStringProp, makeBooleanProp } from '../common/props'
3
3
 
4
4
  export type FileListItem = {
5
5
  [key: string]: any
@@ -22,6 +22,29 @@ export type FileListOnPreviewFailOption = {
22
22
  }
23
23
  export type FileListOnPreviewFail = (option: FileListOnPreviewFailOption) => void
24
24
 
25
+ export type FileListBeforeDownloadOption = {
26
+ file: FileListItem
27
+ resolve: (isPass: boolean) => void
28
+ }
29
+ export type FileListBeforeDownload = (option: FileListBeforeDownloadOption) => void
30
+
31
+ export type FileListOnDownloadSuccessOption = {
32
+ file: FileListItem
33
+ tempFilePath?: string
34
+ }
35
+ export type FileListOnDownloadSuccess = (option: FileListOnDownloadSuccessOption) => void
36
+
37
+ export type FileListOnDownloadFailOption = {
38
+ file: FileListItem
39
+ }
40
+ export type FileListOnDownloadFail = (option: FileListOnDownloadFailOption) => void
41
+
42
+ export type FileListBeforeDeleteOption = {
43
+ file: FileListItem
44
+ resolve: (isPass: boolean) => void
45
+ }
46
+ export type FileListBeforeDelete = (option: FileListBeforeDeleteOption) => void
47
+
25
48
  export const fileListProps = {
26
49
  ...baseProps,
27
50
 
@@ -37,6 +60,24 @@ export const fileListProps = {
37
60
  * 默认值:'card'
38
61
  */
39
62
  type: makeStringProp<FileListType>('list'),
63
+ /**
64
+ * 是否启用文件预览
65
+ * 类型:boolean
66
+ * 默认值:true
67
+ */
68
+ enablePreview: makeBooleanProp(true),
69
+ /**
70
+ * 是否启用文件下载
71
+ * 类型:boolean
72
+ * 默认值:true
73
+ */
74
+ enableDownload: makeBooleanProp(true),
75
+ /**
76
+ * 是否启用删除按钮
77
+ * 类型:boolean
78
+ * 默认值:true
79
+ */
80
+ enableDelete: makeBooleanProp(true),
40
81
  /**
41
82
  * 文件预览前的钩子,参数为预览的文件,若返回false或者返回Promise且被reject,则停止预览。
42
83
  * 类型:function({file,resolve})
@@ -48,7 +89,22 @@ export const fileListProps = {
48
89
  * 类型:function({file})
49
90
  * 默认值:-
50
91
  */
51
- onPreviewFail: Function as PropType<FileListOnPreviewFail>
92
+ onPreviewFail: Function as PropType<FileListOnPreviewFail>,
93
+ /**
94
+ * 文件下载前钩子
95
+ * 类型:function({file,resolve})
96
+ */
97
+ beforeDownload: Function as PropType<FileListBeforeDownload>,
98
+ /**
99
+ * 文件下载成功回调
100
+ * 类型:function({file,tempFilePath})
101
+ */
102
+ onDownloadSuccess: Function as PropType<FileListOnDownloadSuccess>,
103
+ /**
104
+ * 文件下载失败回调
105
+ * 类型:function({file})
106
+ */
107
+ onDownloadFail: Function as PropType<FileListOnDownloadFail>
52
108
  }
53
109
 
54
110
  export type CornerProps = ExtractPropTypes<typeof fileListProps>
@@ -35,10 +35,11 @@ export default {
35
35
  </script>
36
36
 
37
37
  <script lang="ts" setup>
38
- import { computed, onBeforeMount, ref, watch, type CSSProperties } from 'vue'
39
- import { floatingPanelProps } from './type'
40
- import { addUnit, closest, objToStyle } from '../common/util'
38
+ import { computed, ref, watch, type CSSProperties } from 'vue'
39
+ import { floatingPanelProps } from './types'
40
+ import { closest, objToStyle, unitConvert } from '../common/util'
41
41
  import { useTouch } from '../composables/useTouch'
42
+ import { useWindowResize, type WindowResizeResult } from '../composables/useWindowResize'
42
43
 
43
44
  const touch = useTouch()
44
45
 
@@ -61,8 +62,8 @@ const anchors = computed(() => (props.anchors.length >= 2 ? props.anchors : [bou
61
62
 
62
63
  const rootStyle = computed(() => {
63
64
  const style: CSSProperties = {
64
- height: addUnit(boundary.value.max),
65
- transform: `translateY(calc(100% + ${addUnit(-heightValue.value)}))`,
65
+ height: unitConvert(boundary.value.max, 0, { output: 'px' }),
66
+ transform: `translateY(calc(100% + ${unitConvert(-heightValue.value, 0, { output: 'px' })}))`,
66
67
  transition: !dragging.value ? `transform ${props.duration}ms cubic-bezier(0.18, 0.89, 0.32, 1.28)` : 'none'
67
68
  }
68
69
 
@@ -129,10 +130,13 @@ watch(
129
130
  { immediate: true }
130
131
  )
131
132
 
132
- onBeforeMount(() => {
133
- const { windowHeight: _windowHeight } = uni.getSystemInfoSync()
134
- windowHeight.value = _windowHeight
135
- })
133
+ const syncWindowHeight = (res?: WindowResizeResult) => {
134
+ const resizeHeight = Number(res?.size?.windowHeight ?? res?.windowHeight)
135
+ const systemHeight = uni.getSystemInfoSync().windowHeight
136
+ windowHeight.value = Number.isFinite(resizeHeight) && resizeHeight > 0 ? resizeHeight : systemHeight
137
+ }
138
+
139
+ useWindowResize(syncWindowHeight, { immediate: true })
136
140
  </script>
137
141
 
138
142
  <style lang="scss" scoped>
@@ -1,30 +1,30 @@
1
1
  import type { ExtractPropTypes } from 'vue'
2
- import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, makeNumericProp, truthProp } from '../common/props'
2
+ import { baseProps, makeArrayProp, makeBooleanProp, makeNumberProp, truthProp } from '../common/props'
3
3
 
4
4
  export const floatingPanelProps = {
5
5
  ...baseProps,
6
6
  /**
7
- * 面板的显示高度
7
+ * 面板当前高度
8
8
  */
9
9
  height: makeNumberProp(0),
10
10
  /**
11
- * 设置自定义锚点,默认值 [100, windowHeight * 0.6]
11
+ * 拖拽吸附锚点列表
12
12
  */
13
13
  anchors: makeArrayProp<number>(),
14
14
  /**
15
- * 弹出面板是否设置底部安全距离(iphone X 类型的机型)
15
+ * 是否预留底部安全区
16
16
  */
17
17
  safeAreaInsetBottom: makeBooleanProp(false),
18
18
  /**
19
- * 是否显示滚动条,默认值为 true
19
+ * 内容区是否显示滚动条
20
20
  */
21
21
  showScrollbar: truthProp,
22
22
  /**
23
- * 动画时长,单位毫秒,默认值为 300ms
23
+ * 高度变化动画时长,单位毫秒
24
24
  */
25
- duration: makeNumericProp(300),
25
+ duration: makeNumberProp(300),
26
26
  /**
27
- * 是否允许内容区容器拖拽,默认值为 true
27
+ * 内容区是否允许拖拽
28
28
  */
29
29
  contentDraggable: truthProp
30
30
  }