xt-element-ui 2.2.3 → 2.2.4

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 (116) hide show
  1. package/README.md +140 -192
  2. package/docs/README.md +162 -88
  3. package/docs/components/base/theme.md +248 -0
  4. package/docs/components/base/xt-list.md +1 -1
  5. package/docs/components/base/xt-scroll-arrow.md +87 -1
  6. package/docs/components/base/xt-scroll.md +237 -0
  7. package/docs/components/utils/config.md +18 -4
  8. package/docs/components/utils/theme.md +280 -183
  9. package/lib/index.common.1.js +4 -26
  10. package/lib/index.common.2.js +1 -1
  11. package/lib/index.common.js +1871 -671
  12. package/lib/index.css +1 -1
  13. package/lib/index.umd.1.js +4 -26
  14. package/lib/index.umd.2.js +1 -1
  15. package/lib/index.umd.js +1871 -671
  16. package/lib/index.umd.min.1.js +1 -1
  17. package/lib/index.umd.min.js +1 -1
  18. package/lib/theme/element-overrides.css +607 -0
  19. package/lib/theme/element-vars.css +280 -0
  20. package/lib/xt-badge/xt-badge.common.js +1 -1
  21. package/lib/xt-badge/xt-badge.umd.js +1 -1
  22. package/lib/xt-button/xt-button.common.js +1 -1
  23. package/lib/xt-button/xt-button.umd.js +1 -1
  24. package/lib/xt-card/xt-card.common.js +1 -1
  25. package/lib/xt-card/xt-card.umd.js +1 -1
  26. package/lib/xt-card-item/xt-card-item.common.js +1 -1
  27. package/lib/xt-card-item/xt-card-item.umd.js +1 -1
  28. package/lib/xt-chart/xt-chart.common.js +5 -5
  29. package/lib/xt-chart/xt-chart.umd.js +5 -5
  30. package/lib/xt-config-provider/xt-config-provider.css +1 -1
  31. package/lib/xt-date-picker/xt-date-picker.common.1.js +4 -26
  32. package/lib/xt-date-picker/xt-date-picker.common.2.js +1 -1
  33. package/lib/xt-date-picker/xt-date-picker.common.js +1 -47
  34. package/lib/xt-date-picker/xt-date-picker.css +1 -1
  35. package/lib/xt-date-picker/xt-date-picker.umd.1.js +4 -26
  36. package/lib/xt-date-picker/xt-date-picker.umd.2.js +1 -1
  37. package/lib/xt-date-picker/xt-date-picker.umd.js +1 -47
  38. package/lib/xt-date-picker/xt-date-picker.umd.min.1.js +1 -1
  39. package/lib/xt-date-picker/xt-date-picker.umd.min.js +1 -1
  40. package/lib/xt-flex-box/xt-flex-box.common.js +1 -1
  41. package/lib/xt-flex-box/xt-flex-box.umd.js +1 -1
  42. package/lib/xt-flow/xt-flow.common.js +1 -1
  43. package/lib/xt-flow/xt-flow.umd.js +1 -1
  44. package/lib/xt-form-schema/xt-form-schema.common.js +1 -1
  45. package/lib/xt-form-schema/xt-form-schema.umd.js +1 -1
  46. package/lib/xt-grid-box/xt-grid-box.common.js +1 -1
  47. package/lib/xt-grid-box/xt-grid-box.umd.js +1 -1
  48. package/lib/xt-grid-item/xt-grid-item.common.js +1 -1
  49. package/lib/xt-grid-item/xt-grid-item.umd.js +1 -1
  50. package/lib/xt-icon/xt-icon.common.js +1 -1
  51. package/lib/xt-icon/xt-icon.umd.js +1 -1
  52. package/lib/xt-input/xt-input.common.js +1 -1
  53. package/lib/xt-input/xt-input.umd.js +1 -1
  54. package/lib/xt-list/xt-list.common.js +457 -118
  55. package/lib/xt-list/xt-list.css +1 -1
  56. package/lib/xt-list/xt-list.umd.js +457 -118
  57. package/lib/xt-list/xt-list.umd.min.js +1 -1
  58. package/lib/xt-map/xt-map.common.js +1 -1
  59. package/lib/xt-map/xt-map.umd.js +1 -1
  60. package/lib/xt-map-provider/xt-map-provider.common.js +1 -1
  61. package/lib/xt-map-provider/xt-map-provider.umd.js +1 -1
  62. package/lib/xt-page/xt-page.common.js +1 -1
  63. package/lib/xt-page/xt-page.umd.js +1 -1
  64. package/lib/xt-progress/xt-progress.common.js +1 -1
  65. package/lib/xt-progress/xt-progress.umd.js +1 -1
  66. package/lib/xt-scroll/demo.html +10 -0
  67. package/lib/xt-scroll/index.js +1 -0
  68. package/lib/xt-scroll/xt-scroll.common.js +551 -0
  69. package/lib/xt-scroll/xt-scroll.css +1 -0
  70. package/lib/xt-scroll/xt-scroll.umd.js +561 -0
  71. package/lib/xt-scroll/xt-scroll.umd.min.js +1 -0
  72. package/lib/xt-scroll-arrow/xt-scroll-arrow.common.js +591 -170
  73. package/lib/xt-scroll-arrow/xt-scroll-arrow.css +1 -1
  74. package/lib/xt-scroll-arrow/xt-scroll-arrow.umd.js +591 -170
  75. package/lib/xt-scroll-arrow/xt-scroll-arrow.umd.min.js +1 -1
  76. package/lib/xt-select-tree/xt-select-tree.common.js +1 -1
  77. package/lib/xt-select-tree/xt-select-tree.umd.js +1 -1
  78. package/lib/xt-step-price/xt-step-price.common.js +2 -2
  79. package/lib/xt-step-price/xt-step-price.umd.js +2 -2
  80. package/lib/xt-step-price-item/xt-step-price-item.common.js +1 -1
  81. package/lib/xt-step-price-item/xt-step-price-item.umd.js +1 -1
  82. package/lib/xt-tab-pane/xt-tab-pane.common.js +1 -1
  83. package/lib/xt-tab-pane/xt-tab-pane.umd.js +1 -1
  84. package/lib/xt-table/xt-table.common.js +2 -2
  85. package/lib/xt-table/xt-table.umd.js +2 -2
  86. package/lib/xt-tabs/xt-tabs.common.js +1 -1
  87. package/lib/xt-tabs/xt-tabs.umd.js +1 -1
  88. package/lib/xt-text/xt-text.common.js +1 -1
  89. package/lib/xt-text/xt-text.umd.js +1 -1
  90. package/lib/xt-time/xt-time.common.js +1 -1
  91. package/lib/xt-time/xt-time.umd.js +1 -1
  92. package/lib/xt-transfer-tree/xt-transfer-tree.common.js +1 -1
  93. package/lib/xt-transfer-tree/xt-transfer-tree.umd.js +1 -1
  94. package/lib/xt-upload/xt-upload.common.js +2 -2
  95. package/lib/xt-upload/xt-upload.umd.js +2 -2
  96. package/package.json +5 -3
  97. package/src/components/index.scss +3 -0
  98. package/src/components/theme/element-overrides.css +607 -0
  99. package/src/components/theme/element-vars.css +280 -0
  100. package/src/components/theme/iframe-injector.js +502 -0
  101. package/src/components/theme/index.js +64 -0
  102. package/src/components/xt-config-provider/style/index.scss +0 -11
  103. package/src/components/xt-date-picker/component/RangeDate.vue +1 -29
  104. package/src/components/xt-date-picker/style/index.scss +80 -53
  105. package/src/components/xt-list/index.vue +23 -12
  106. package/src/components/xt-scroll/index.js +9 -0
  107. package/src/components/xt-scroll/index.vue +363 -0
  108. package/src/components/xt-scroll/style/index.scss +107 -0
  109. package/src/components/xt-scroll-arrow/index.vue +200 -83
  110. package/src/components/xt-scroll-arrow/style/index.scss +16 -5
  111. package/src/index.js +9 -2
  112. package/src/utils/color.js +105 -0
  113. package/src/utils/index.js +456 -468
  114. package/src/utils/theme-vars.js +134 -0
  115. package/lib/css/1.87a493be.css +0 -1
  116. package/lib/xt-date-picker/css/1.87a493be.css +0 -1
@@ -94,6 +94,13 @@ module.exports =
94
94
 
95
95
  /***/ }),
96
96
 
97
+ /***/ "f699":
98
+ /***/ (function(module, exports, __webpack_require__) {
99
+
100
+ // extracted by mini-css-extract-plugin
101
+
102
+ /***/ }),
103
+
97
104
  /***/ "fb15":
98
105
  /***/ (function(module, __webpack_exports__, __webpack_require__) {
99
106
 
@@ -123,32 +130,465 @@ if (typeof window !== 'undefined') {
123
130
  // EXTERNAL MODULE: ./src/components/xt-scroll-arrow/style/index.scss
124
131
  var style = __webpack_require__("4e56");
125
132
 
126
- // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"d8e97dbc-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??ref--5!./node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/xt-scroll-arrow/index.vue?vue&type=template&id=3d6a271c
127
- var render = function render(){var _vm=this,_c=_vm._self._c;return _c('div',{staticClass:"xt-scroll-arrow",class:[`xt-scroll-arrow--${_vm.direction}`],style:(_vm.containerStyle)},[(_vm.showLeftArrow)?_c('div',{staticClass:"xt-scroll-arrow__btn xt-scroll-arrow__btn--left",on:{"click":_vm.scrollLeft}},[_c('i',{staticClass:"el-icon-arrow-left"})]):_vm._e(),_c('div',{ref:"scrollContainer",staticClass:"xt-scroll-arrow__content",on:{"scroll":_vm.handleScroll,"click":_vm.handleClick}},[_vm._t("default")],2),(_vm.showRightArrow)?_c('div',{staticClass:"xt-scroll-arrow__btn xt-scroll-arrow__btn--right",on:{"click":_vm.scrollRight}},[_c('i',{staticClass:"el-icon-arrow-right"})]):_vm._e(),(_vm.showTopArrow && _vm.direction === 'vertical')?_c('div',{staticClass:"xt-scroll-arrow__btn xt-scroll-arrow__btn--top",on:{"click":_vm.scrollTop}},[_c('i',{staticClass:"el-icon-arrow-up"})]):_vm._e(),(_vm.showBottomArrow && _vm.direction === 'vertical')?_c('div',{staticClass:"xt-scroll-arrow__btn xt-scroll-arrow__btn--bottom",on:{"click":_vm.scrollBottom}},[_c('i',{staticClass:"el-icon-arrow-down"})]):_vm._e()])
133
+ // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"1d9e3ae5-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??ref--5!./node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/xt-scroll-arrow/index.vue?vue&type=template&id=6d59f4e4
134
+ var render = function render(){var _vm=this,_c=_vm._self._c;return _c('div',{staticClass:"xt-scroll-arrow",class:[`xt-scroll-arrow--${_vm.direction}`],style:(_vm.containerStyle)},[(_vm.showLeftArrow)?_c('div',{staticClass:"xt-scroll-arrow__btn xt-scroll-arrow__btn--left",on:{"click":_vm.scrollLeft}},[_c('i',{staticClass:"el-icon-arrow-left"})]):_vm._e(),(_vm.showTopArrow && _vm.direction === 'vertical')?_c('div',{staticClass:"xt-scroll-arrow__btn xt-scroll-arrow__btn--top",on:{"click":_vm.scrollTop}},[_c('i',{staticClass:"el-icon-arrow-up"})]):_vm._e(),_c('xt-scroll',{ref:"scrollRef",class:['xt-scroll-arrow__content', _vm.scrollClass],attrs:{"v-scroll":_vm.vScroll,"data":_vm.vScrollData,"item-size":_vm.itemSize,"key-field":_vm.keyField,"buffer-size":_vm.bufferSize,"scroll-direction":_vm.direction,"loading":_vm.vScrollLoading,"load-more":_vm.loadMore,"load-more-text":_vm.loadMoreText,"load-more-loading":_vm.loadMoreLoading},on:{"scroll":_vm.onScroll,"load-more":function($event){return _vm.$emit('load-more')}},scopedSlots:_vm._u([(_vm.vScroll)?{key:"item",fn:function({ item, index }){return [_vm._t("vitem",function(){return [_c('div',{staticClass:"xt-scroll-arrow__vitem"},[_vm._v(_vm._s(item))])]},{"item":item,"index":index})]}}:{key:"default",fn:function(undefined){return _vm._t("default")}}],null,true)}),(_vm.showRightArrow)?_c('div',{staticClass:"xt-scroll-arrow__btn xt-scroll-arrow__btn--right",on:{"click":_vm.scrollRight}},[_c('i',{staticClass:"el-icon-arrow-right"})]):_vm._e(),(_vm.showBottomArrow && _vm.direction === 'vertical')?_c('div',{staticClass:"xt-scroll-arrow__btn xt-scroll-arrow__btn--bottom",on:{"click":_vm.scrollBottom}},[_c('i',{staticClass:"el-icon-arrow-down"})]):_vm._e()],1)
128
135
  }
129
136
  var staticRenderFns = []
130
137
 
131
138
 
132
- // CONCATENATED MODULE: ./src/components/xt-scroll-arrow/index.vue?vue&type=template&id=3d6a271c
139
+ // CONCATENATED MODULE: ./src/components/xt-scroll-arrow/index.vue?vue&type=template&id=6d59f4e4
140
+
141
+ // EXTERNAL MODULE: ./src/components/xt-scroll/style/index.scss
142
+ var xt_scroll_style = __webpack_require__("f699");
143
+
144
+ // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js?{"cacheDirectory":"node_modules/.cache/vue-loader","cacheIdentifier":"1d9e3ae5-vue-loader-template"}!./node_modules/vue-loader/lib/loaders/templateLoader.js??ref--5!./node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/xt-scroll/index.vue?vue&type=template&id=74170e40
145
+ var xt_scrollvue_type_template_id_74170e40_render = function render(){var _vm=this,_c=_vm._self._c;return _c('div',{staticClass:"xt-scroll",class:[`xt-scroll--${_vm.scrollDirection}`],style:(_vm.containerStyle)},[_c('div',{ref:"scrollWrap",staticClass:"xt-scroll__wrap",class:[`xt-scroll__wrap--${_vm.scrollDirection}`],on:{"scroll":_vm.onScroll}},[(_vm.vScroll)?_c('div',{staticClass:"xt-scroll__virtual",style:(_vm.virtualWrapperStyle)},[(_vm.scrollDirection === 'vertical')?_c('div',{staticClass:"xt-scroll__phantom",style:({ height: _vm.totalSize + 'px' })},[_c('div',{style:({ transform: `translateY(${_vm.offsetStart}px)` })},[_vm._l((_vm.visibleData),function(item,index){return [_c('div',{key:_vm.getItemKey(item, index),staticClass:"xt-scroll__item",class:_vm.itemClassName,style:(_vm.itemStyle)},[_vm._t("item",function(){return [_vm._v(" "+_vm._s(item)+" ")]},{"item":item,"index":_vm.getOriginalIndex(index)})],2)]})],2)]):(_vm.scrollDirection === 'horizontal')?_c('div',{staticClass:"xt-scroll__phantom",style:({ width: _vm.totalSize + 'px' })},[_c('div',{style:({ transform: `translateX(${_vm.offsetStart}px)` })},[_vm._l((_vm.visibleData),function(item,index){return [_c('div',{key:_vm.getItemKey(item, index),staticClass:"xt-scroll__item",class:_vm.itemClassName,style:(_vm.itemStyle)},[_vm._t("item",function(){return [_vm._v(" "+_vm._s(item)+" ")]},{"item":item,"index":_vm.getOriginalIndex(index)})],2)]})],2)]):_vm._e()]):_vm._e(),(_vm.vScroll && (!_vm.data || !_vm.data.length) && !_vm.loading)?_c('div',{staticClass:"xt-scroll__empty"},[_vm._t("empty",function(){return [_c('span',[_vm._v(_vm._s(_vm.emptyText))])]})],2):_vm._e(),(_vm.loading)?_c('div',{staticClass:"xt-scroll__loading"},[_vm._t("loading",function(){return [_c('i',{staticClass:"el-icon-loading"}),_c('span',[_vm._v("加载中...")])]})],2):_vm._e(),(!_vm.vScroll)?_c('div',{staticClass:"xt-scroll__default"},[_vm._t("default")],2):_vm._e(),(_vm.vScroll && _vm.showLoadMore && !_vm.loading)?_c('div',{staticClass:"xt-scroll__loadmore",on:{"click":_vm.onLoadMore}},[_c('el-button',{attrs:{"type":"text","loading":_vm.loadMoreLoading}},[_vm._v(" "+_vm._s(_vm.loadMoreText)+" ")])],1):_vm._e()])])
146
+ }
147
+ var xt_scrollvue_type_template_id_74170e40_staticRenderFns = []
148
+
149
+
150
+ // CONCATENATED MODULE: ./src/components/xt-scroll/index.vue?vue&type=template&id=74170e40
151
+
152
+ // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/xt-scroll/index.vue?vue&type=script&lang=js
153
+
154
+ /* harmony default export */ var xt_scrollvue_type_script_lang_js = ({
155
+ name: 'XtScroll',
156
+
157
+ props: {
158
+ // ========== 虚拟滚动配置 ==========
159
+ /** 是否启用虚拟滚动 */
160
+ vScroll: { type: Boolean, default: false },
161
+ /** 数据源 */
162
+ data: { type: Array, default: () => [] },
163
+ /** 每个 item 的固定尺寸(px),纵向为高度,横向为宽度 */
164
+ itemSize: { type: Number, default: 50 },
165
+ /** item 的唯一键字段名 */
166
+ keyField: { type: String, default: 'id' },
167
+ /** 预渲染缓冲区大小(item 数量) */
168
+ bufferSize: { type: Number, default: 5 },
169
+ /** 虚拟滚动方向 */
170
+ scrollDirection: {
171
+ type: String,
172
+ default: 'vertical',
173
+ validator: (v) => ['vertical', 'horizontal'].includes(v)
174
+ },
175
+ /** item 的自定义 CSS 类名 */
176
+ itemClassName: { type: String, default: '' },
177
+
178
+ // ========== 容器尺寸 ==========
179
+ height: { type: [Number, String], default: '' },
180
+ maxHeight: { type: [Number, String], default: '' },
181
+ width: { type: [Number, String], default: '' },
182
+ maxWidth: { type: [Number, String], default: '' },
183
+
184
+ // ========== 状态 ==========
185
+ loading: { type: Boolean, default: false },
186
+ emptyText: { type: String, default: '暂无数据' },
187
+
188
+ // ========== 加载更多 ==========
189
+ loadMore: { type: Boolean, default: false },
190
+ loadMoreText: { type: String, default: '加载更多' },
191
+ loadMoreLoading: { type: Boolean, default: false }
192
+ },
193
+
194
+ data() {
195
+ return {
196
+ scrollPos: 0,
197
+ containerSize: 0,
198
+ resizeObserver: null,
199
+ rafId: null
200
+ }
201
+ },
202
+
203
+ computed: {
204
+ containerStyle() {
205
+ const style = {}
206
+ if (this.height) {
207
+ style.height = typeof this.height === 'number' ? this.height + 'px' : this.height
208
+ }
209
+ if (this.maxHeight) {
210
+ style.maxHeight = typeof this.maxHeight === 'number' ? this.maxHeight + 'px' : this.maxHeight
211
+ }
212
+ if (this.width) {
213
+ style.width = typeof this.width === 'number' ? this.width + 'px' : this.width
214
+ }
215
+ if (this.maxWidth) {
216
+ style.maxWidth = typeof this.maxWidth === 'number' ? this.maxWidth + 'px' : this.maxWidth
217
+ }
218
+ return style
219
+ },
220
+
221
+ virtualWrapperStyle() {
222
+ const style = {}
223
+ if (this.scrollDirection === 'horizontal') {
224
+ style.height = '100%'
225
+ }
226
+ return style
227
+ },
228
+
229
+ itemStyle() {
230
+ return this.scrollDirection === 'vertical'
231
+ ? { height: this.itemSize + 'px' }
232
+ : { width: this.itemSize + 'px', display: 'inline-block' }
233
+ },
234
+
235
+ /** 数据总条数 */
236
+ dataCount() {
237
+ return (this.data && this.data.length) || 0
238
+ },
239
+
240
+ /** 总滚动尺寸 */
241
+ totalSize() {
242
+ return this.dataCount * this.itemSize
243
+ },
244
+
245
+ /** 虚拟滚动:可见范围起始索引 */
246
+ visibleStartIndex() {
247
+ if (!this.vScroll) return 0
248
+ const start = Math.floor(this.scrollPos / this.itemSize)
249
+ return Math.max(0, start - this.bufferSize)
250
+ },
251
+
252
+ /** 虚拟滚动:可见范围结束索引 */
253
+ visibleEndIndex() {
254
+ if (!this.vScroll) return this.dataCount
255
+ const visibleCount = Math.ceil(this.containerSize / this.itemSize)
256
+ const end = Math.ceil(this.scrollPos / this.itemSize) + visibleCount
257
+ return Math.min(this.dataCount, end + this.bufferSize)
258
+ },
259
+
260
+ /** 可见数据 */
261
+ visibleData() {
262
+ if (!this.vScroll || !this.data) return this.data || []
263
+ return this.data.slice(this.visibleStartIndex, this.visibleEndIndex)
264
+ },
265
+
266
+ /** 偏移量(px) */
267
+ offsetStart() {
268
+ return this.visibleStartIndex * this.itemSize
269
+ },
270
+
271
+ /** 是否显示加载更多 */
272
+ showLoadMore() {
273
+ if (!this.loadMore || !this.dataCount) return false
274
+ if (this.scrollDirection === 'vertical') {
275
+ return this.scrollPos + this.containerSize >= this.totalSize - this.itemSize * 2
276
+ }
277
+ return false
278
+ }
279
+ },
280
+
281
+ watch: {
282
+ data: {
283
+ handler() {
284
+ this.$nextTick(() => {
285
+ this.updateContainerSize()
286
+ })
287
+ }
288
+ },
289
+ vScroll(val) {
290
+ if (val) {
291
+ this.$nextTick(() => {
292
+ this.updateContainerSize()
293
+ this.bindResizeObserver()
294
+ })
295
+ }
296
+ }
297
+ },
298
+
299
+ mounted() {
300
+ this.$nextTick(() => {
301
+ this.updateContainerSize()
302
+ if (this.vScroll) {
303
+ this.bindResizeObserver()
304
+ }
305
+ })
306
+ },
307
+
308
+ beforeDestroy() {
309
+ this.unbindResizeObserver()
310
+ if (this.rafId && typeof cancelAnimationFrame !== 'undefined') {
311
+ cancelAnimationFrame(this.rafId)
312
+ this.rafId = null
313
+ }
314
+ },
315
+
316
+ methods: {
317
+ // ========== 虚拟滚动 ==========
318
+ onScroll() {
319
+ const wrap = this.$refs.scrollWrap
320
+ if (!wrap) return
321
+
322
+ const pos = this.scrollDirection === 'vertical' ? wrap.scrollTop : wrap.scrollLeft
323
+ this.scrollPos = pos
324
+
325
+ // 对外 emit scroll 事件,传递 scrollTop/scrollLeft 方便父组件使用
326
+ this.$emit('scroll', {
327
+ scrollTop: wrap.scrollTop,
328
+ scrollLeft: wrap.scrollLeft
329
+ })
330
+
331
+ if (this.rafId) return
332
+ if (typeof requestAnimationFrame === 'undefined') return
333
+ this.rafId = requestAnimationFrame(() => {
334
+ this.$forceUpdate()
335
+ this.rafId = null
336
+ })
337
+ },
338
+
339
+ getItemKey(item, index) {
340
+ if (item && typeof item === 'object' && this.keyField && item[this.keyField] != null) {
341
+ return item[this.keyField]
342
+ }
343
+ return `vitem_${this.visibleStartIndex + index}`
344
+ },
345
+
346
+ getOriginalIndex(index) {
347
+ return this.visibleStartIndex + index
348
+ },
349
+
350
+ // ========== 容器尺寸 ==========
351
+ updateContainerSize() {
352
+ const wrap = this.$refs.scrollWrap
353
+ if (!wrap) return
354
+
355
+ this.containerSize = this.scrollDirection === 'vertical'
356
+ ? wrap.clientHeight
357
+ : wrap.clientWidth
358
+ },
359
+
360
+ bindResizeObserver() {
361
+ if (typeof ResizeObserver === 'undefined') return
362
+ this.unbindResizeObserver()
363
+
364
+ const wrap = this.$refs.scrollWrap
365
+ if (!wrap) return
366
+
367
+ this.resizeObserver = new ResizeObserver(() => {
368
+ this.updateContainerSize()
369
+ })
370
+ this.resizeObserver.observe(wrap)
371
+ },
372
+
373
+ unbindResizeObserver() {
374
+ if (this.resizeObserver) {
375
+ this.resizeObserver.disconnect()
376
+ this.resizeObserver = null
377
+ }
378
+ },
379
+
380
+ // ========== 加载更多 ==========
381
+ onLoadMore() {
382
+ this.$emit('load-more')
383
+ },
384
+
385
+ // ========== 对外暴露方法 ==========
386
+ /** 获取原生滚动容器 DOM 元素 */
387
+ getScrollContainer() {
388
+ return this.$refs.scrollWrap
389
+ },
390
+
391
+ /** 滚动到指定位置 */
392
+ scrollTo(pos, behavior) {
393
+ const wrap = this.$refs.scrollWrap
394
+ if (!wrap) return
395
+
396
+ const opts = behavior && typeof behavior === 'string'
397
+ ? { behavior }
398
+ : { behavior: 'smooth' }
399
+
400
+ if (this.scrollDirection === 'vertical') {
401
+ wrap.scrollTo({ top: pos, ...opts })
402
+ } else {
403
+ wrap.scrollTo({ left: pos, ...opts })
404
+ }
405
+ },
406
+
407
+ /** 滚动到指定索引的 item */
408
+ scrollToItem(index) {
409
+ const pos = index * this.itemSize
410
+ this.scrollTo(pos)
411
+ },
412
+
413
+ /** 滚动到顶部/左侧 */
414
+ scrollToStart() {
415
+ this.scrollTo(0)
416
+ },
417
+
418
+ /** 滚动到底部/右侧 */
419
+ scrollToEnd() {
420
+ this.scrollTo(this.totalSize)
421
+ },
422
+
423
+ /** 获取当前滚动位置 */
424
+ getScrollPos() {
425
+ return this.scrollPos
426
+ }
427
+ }
428
+ });
429
+
430
+ // CONCATENATED MODULE: ./src/components/xt-scroll/index.vue?vue&type=script&lang=js
431
+ /* harmony default export */ var components_xt_scrollvue_type_script_lang_js = (xt_scrollvue_type_script_lang_js);
432
+ // CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js
433
+ /* globals __VUE_SSR_CONTEXT__ */
434
+
435
+ // IMPORTANT: Do NOT use ES2015 features in this file (except for modules).
436
+ // This module is a runtime utility for cleaner component module output and will
437
+ // be included in the final webpack user bundle.
438
+
439
+ function normalizeComponent(
440
+ scriptExports,
441
+ render,
442
+ staticRenderFns,
443
+ functionalTemplate,
444
+ injectStyles,
445
+ scopeId,
446
+ moduleIdentifier /* server only */,
447
+ shadowMode /* vue-cli only */
448
+ ) {
449
+ // Vue.extend constructor export interop
450
+ var options =
451
+ typeof scriptExports === 'function' ? scriptExports.options : scriptExports
452
+
453
+ // render functions
454
+ if (render) {
455
+ options.render = render
456
+ options.staticRenderFns = staticRenderFns
457
+ options._compiled = true
458
+ }
459
+
460
+ // functional template
461
+ if (functionalTemplate) {
462
+ options.functional = true
463
+ }
464
+
465
+ // scopedId
466
+ if (scopeId) {
467
+ options._scopeId = 'data-v-' + scopeId
468
+ }
469
+
470
+ var hook
471
+ if (moduleIdentifier) {
472
+ // server build
473
+ hook = function (context) {
474
+ // 2.3 injection
475
+ context =
476
+ context || // cached call
477
+ (this.$vnode && this.$vnode.ssrContext) || // stateful
478
+ (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
479
+ // 2.2 with runInNewContext: true
480
+ if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
481
+ context = __VUE_SSR_CONTEXT__
482
+ }
483
+ // inject component styles
484
+ if (injectStyles) {
485
+ injectStyles.call(this, context)
486
+ }
487
+ // register component module identifier for async chunk inferrence
488
+ if (context && context._registeredComponents) {
489
+ context._registeredComponents.add(moduleIdentifier)
490
+ }
491
+ }
492
+ // used by ssr in case component is cached and beforeCreate
493
+ // never gets called
494
+ options._ssrRegister = hook
495
+ } else if (injectStyles) {
496
+ hook = shadowMode
497
+ ? function () {
498
+ injectStyles.call(
499
+ this,
500
+ (options.functional ? this.parent : this).$root.$options.shadowRoot
501
+ )
502
+ }
503
+ : injectStyles
504
+ }
505
+
506
+ if (hook) {
507
+ if (options.functional) {
508
+ // for template-only hot-reload because in that case the render fn doesn't
509
+ // go through the normalizer
510
+ options._injectStyles = hook
511
+ // register for functional component in vue file
512
+ var originalRender = options.render
513
+ options.render = function renderWithStyleInjection(h, context) {
514
+ hook.call(context)
515
+ return originalRender(h, context)
516
+ }
517
+ } else {
518
+ // inject component registration as beforeCreate hook
519
+ var existing = options.beforeCreate
520
+ options.beforeCreate = existing ? [].concat(existing, hook) : [hook]
521
+ }
522
+ }
523
+
524
+ return {
525
+ exports: scriptExports,
526
+ options: options
527
+ }
528
+ }
529
+
530
+ // CONCATENATED MODULE: ./src/components/xt-scroll/index.vue
531
+
532
+
533
+
534
+
535
+
536
+ /* normalize component */
537
+
538
+ var component = normalizeComponent(
539
+ components_xt_scrollvue_type_script_lang_js,
540
+ xt_scrollvue_type_template_id_74170e40_render,
541
+ xt_scrollvue_type_template_id_74170e40_staticRenderFns,
542
+ false,
543
+ null,
544
+ null,
545
+ null
546
+
547
+ )
548
+
549
+ /* harmony default export */ var xt_scroll = (component.exports);
550
+ // CONCATENATED MODULE: ./src/components/xt-scroll/index.js
551
+
552
+
553
+
554
+ xt_scroll.install = function (Vue) {
555
+ Vue.component(xt_scroll.name, xt_scroll)
556
+ }
557
+
558
+ /* harmony default export */ var components_xt_scroll = (xt_scroll);
133
559
 
134
560
  // CONCATENATED MODULE: ./node_modules/cache-loader/dist/cjs.js??ref--1-0!./node_modules/vue-loader/lib??vue-loader-options!./src/components/xt-scroll-arrow/index.vue?vue&type=script&lang=js
135
561
 
562
+
563
+
136
564
  /* harmony default export */ var xt_scroll_arrowvue_type_script_lang_js = ({
137
565
  name: 'XtScrollArrow',
566
+
567
+ components: {
568
+ XtScroll: components_xt_scroll
569
+ },
570
+
138
571
  props: {
572
+ // ========== 滚动方向 ==========
139
573
  direction: {
140
574
  type: String,
141
575
  default: 'horizontal',
142
576
  validator: (val) => ['horizontal', 'vertical'].includes(val)
143
577
  },
578
+
579
+ // ========== 滚动步长 ==========
144
580
  scrollStep: {
145
581
  type: Number,
146
582
  default: 100
147
583
  },
584
+
585
+ // ========== 箭头显示 ==========
148
586
  autoHide: {
149
587
  type: Boolean,
150
588
  default: true
151
589
  },
590
+
591
+ // ========== 容器尺寸 ==========
152
592
  height: {
153
593
  type: [String, Number],
154
594
  default: ''
@@ -157,6 +597,8 @@ var staticRenderFns = []
157
597
  type: [String, Number],
158
598
  default: ''
159
599
  },
600
+
601
+ // ========== 模式 ==========
160
602
  appendMode: {
161
603
  type: Boolean,
162
604
  default: false
@@ -164,16 +606,65 @@ var staticRenderFns = []
164
606
  clickMode: {
165
607
  type: Boolean,
166
608
  default: false
609
+ },
610
+
611
+ // ========== 虚拟滚动配置 ==========
612
+ /** 是否启用虚拟滚动 */
613
+ vScroll: {
614
+ type: Boolean,
615
+ default: false
616
+ },
617
+ /** 虚拟滚动数据源 */
618
+ vScrollData: {
619
+ type: Array,
620
+ default: () => []
621
+ },
622
+ /** 每个 item 的固定尺寸(px) */
623
+ itemSize: {
624
+ type: Number,
625
+ default: 50
626
+ },
627
+ /** item 的唯一键字段名 */
628
+ keyField: {
629
+ type: String,
630
+ default: 'id'
631
+ },
632
+ /** 预渲染缓冲区大小 */
633
+ bufferSize: {
634
+ type: Number,
635
+ default: 5
636
+ },
637
+ /** 虚拟滚动加载状态 */
638
+ vScrollLoading: {
639
+ type: Boolean,
640
+ default: false
641
+ },
642
+
643
+ // ========== 加载更多 ==========
644
+ loadMore: {
645
+ type: Boolean,
646
+ default: false
647
+ },
648
+ loadMoreText: {
649
+ type: String,
650
+ default: '加载更多'
651
+ },
652
+ loadMoreLoading: {
653
+ type: Boolean,
654
+ default: false
167
655
  }
168
656
  },
657
+
169
658
  data() {
170
659
  return {
171
660
  showLeftArrow: false,
172
661
  showRightArrow: false,
173
662
  showTopArrow: false,
174
- showBottomArrow: false
663
+ showBottomArrow: false,
664
+ mutationObserver: null
175
665
  }
176
666
  },
667
+
177
668
  computed: {
178
669
  containerStyle() {
179
670
  const style = {}
@@ -184,27 +675,44 @@ var staticRenderFns = []
184
675
  style.width = typeof this.width === 'number' ? `${this.width}px` : this.width
185
676
  }
186
677
  return style
678
+ },
679
+ scrollClass() {
680
+ return this.vScroll ? 'xt-scroll-arrow__content--virtual' : ''
187
681
  }
188
682
  },
683
+
189
684
  watch: {
190
685
  direction() {
191
686
  this.$nextTick(() => {
192
687
  this.checkScroll()
193
688
  })
689
+ },
690
+ vScrollData: {
691
+ handler() {
692
+ this.$nextTick(() => {
693
+ this.checkScroll()
694
+ })
695
+ }
194
696
  }
195
697
  },
698
+
196
699
  mounted() {
197
700
  this.$nextTick(() => {
198
701
  this.checkScroll()
199
702
  })
200
703
  this.addResizeObserver()
201
- this.addMutationObserver()
704
+ if (!this.vScroll) {
705
+ this.addMutationObserver()
706
+ }
202
707
  },
708
+
203
709
  beforeDestroy() {
204
710
  this.removeResizeObserver()
205
711
  this.removeMutationObserver()
206
712
  },
713
+
207
714
  methods: {
715
+ // ========== 尺寸监听 ==========
208
716
  addResizeObserver() {
209
717
  if (typeof ResizeObserver !== 'undefined') {
210
718
  this.resizeObserver = new ResizeObserver(() => {
@@ -212,17 +720,19 @@ var staticRenderFns = []
212
720
  this.checkScroll()
213
721
  })
214
722
  })
215
- const container = this.$refs.scrollContainer
723
+ const container = this.$el
216
724
  if (container) {
217
725
  this.resizeObserver.observe(container)
218
726
  }
219
727
  }
220
728
  },
729
+
221
730
  removeResizeObserver() {
222
731
  if (this.resizeObserver) {
223
732
  this.resizeObserver.disconnect()
224
733
  }
225
734
  },
735
+
226
736
  addMutationObserver() {
227
737
  if (typeof MutationObserver !== 'undefined') {
228
738
  this.mutationObserver = new MutationObserver(() => {
@@ -233,28 +743,37 @@ var staticRenderFns = []
233
743
  }
234
744
  })
235
745
  })
236
- const container = this.$refs.scrollContainer
746
+ const container = this.$refs.scrollRef
237
747
  if (container) {
238
- this.mutationObserver.observe(container, {
239
- childList: true,
240
- subtree: true
241
- })
748
+ const wrap = container.getScrollContainer && container.getScrollContainer()
749
+ if (wrap) {
750
+ this.mutationObserver.observe(wrap, {
751
+ childList: true,
752
+ subtree: true
753
+ })
754
+ }
242
755
  }
243
756
  }
244
757
  },
758
+
245
759
  removeMutationObserver() {
246
760
  if (this.mutationObserver) {
247
761
  this.mutationObserver.disconnect()
248
762
  }
249
763
  },
764
+
765
+ // ========== 滚动检测 ==========
250
766
  checkScroll() {
251
- const container = this.$refs.scrollContainer
252
- if (!container) return
767
+ const scrollRef = this.$refs.scrollRef
768
+ if (!scrollRef) return
769
+
770
+ const wrap = scrollRef.getScrollContainer && scrollRef.getScrollContainer()
771
+ if (!wrap) return
253
772
 
254
773
  if (this.direction === 'horizontal') {
255
- const scrollLeft = container.scrollLeft
256
- const scrollWidth = container.scrollWidth
257
- const clientWidth = container.clientWidth
774
+ const scrollLeft = wrap.scrollLeft
775
+ const scrollWidth = wrap.scrollWidth
776
+ const clientWidth = wrap.clientWidth
258
777
  const maxScroll = scrollWidth - clientWidth
259
778
 
260
779
  this.showTopArrow = false
@@ -262,15 +781,15 @@ var staticRenderFns = []
262
781
 
263
782
  if (this.autoHide) {
264
783
  this.showLeftArrow = scrollLeft > 0
265
- this.showRightArrow = maxScroll > 0 && scrollLeft < maxScroll
784
+ this.showRightArrow = maxScroll > 0 && scrollLeft < maxScroll - 1
266
785
  } else {
267
786
  this.showLeftArrow = maxScroll > 0
268
787
  this.showRightArrow = maxScroll > 0
269
788
  }
270
789
  } else {
271
- const scrollTop = container.scrollTop
272
- const scrollHeight = container.scrollHeight
273
- const clientHeight = container.clientHeight
790
+ const scrollTop = wrap.scrollTop
791
+ const scrollHeight = wrap.scrollHeight
792
+ const clientHeight = wrap.clientHeight
274
793
  const maxScroll = scrollHeight - clientHeight
275
794
 
276
795
  this.showLeftArrow = false
@@ -278,181 +797,83 @@ var staticRenderFns = []
278
797
 
279
798
  if (this.autoHide) {
280
799
  this.showTopArrow = scrollTop > 0
281
- this.showBottomArrow = maxScroll > 0 && scrollTop < maxScroll
800
+ this.showBottomArrow = maxScroll > 0 && scrollTop < maxScroll - 1
282
801
  } else {
283
802
  this.showTopArrow = maxScroll > 0
284
803
  this.showBottomArrow = maxScroll > 0
285
804
  }
286
805
  }
287
806
  },
288
- handleScroll() {
807
+
808
+ onScroll() {
289
809
  this.checkScroll()
290
- this.$emit('scroll', this.$refs.scrollContainer)
291
- },
292
- handleClick(e) {
293
- if (!this.clickMode) return
294
- const container = this.$refs.scrollContainer
295
- if (!container) return
296
-
297
- const target = e.target
298
- if (!target || target === container) return
299
-
300
- const containerRect = container.getBoundingClientRect()
301
- const targetRect = target.getBoundingClientRect()
302
-
303
- const isVisible = (
304
- targetRect.left >= containerRect.left &&
305
- targetRect.right <= containerRect.right &&
306
- targetRect.top >= containerRect.top &&
307
- targetRect.bottom <= containerRect.bottom
308
- )
309
-
310
- if (!isVisible) {
311
- if (this.direction === 'horizontal') {
312
- const scrollLeft = target.offsetLeft - (container.clientWidth - targetRect.width) / 2
313
- container.scrollTo({ left: scrollLeft, behavior: 'smooth' })
314
- } else {
315
- const scrollTop = target.offsetTop - (container.clientHeight - targetRect.height) / 2
316
- container.scrollTo({ top: scrollTop, behavior: 'smooth' })
317
- }
318
- }
810
+ this.$emit('scroll', this.$refs.scrollRef)
319
811
  },
812
+
813
+ // ========== 滚动操作 ==========
320
814
  scrollLeft() {
321
- const container = this.$refs.scrollContainer
322
- if (container) {
323
- container.scrollBy({ left: -this.scrollStep, behavior: 'smooth' })
324
- }
815
+ this._scrollBy(-this.scrollStep)
325
816
  },
817
+
326
818
  scrollRight() {
327
- const container = this.$refs.scrollContainer
328
- if (container) {
329
- container.scrollBy({ left: this.scrollStep, behavior: 'smooth' })
330
- }
819
+ this._scrollBy(this.scrollStep)
331
820
  },
821
+
332
822
  scrollTop() {
333
- const container = this.$refs.scrollContainer
334
- if (container) {
335
- container.scrollBy({ top: -this.scrollStep, behavior: 'smooth' })
336
- }
823
+ this._scrollBy(-this.scrollStep, 'vertical')
337
824
  },
825
+
338
826
  scrollBottom() {
339
- const container = this.$refs.scrollContainer
340
- if (container) {
341
- container.scrollBy({ top: this.scrollStep, behavior: 'smooth' })
827
+ this._scrollBy(this.scrollStep, 'vertical')
828
+ },
829
+
830
+ _scrollBy(delta, dir) {
831
+ const direction = dir || this.direction
832
+ const scrollRef = this.$refs.scrollRef
833
+ if (!scrollRef) return
834
+
835
+ const wrap = scrollRef.getScrollContainer && scrollRef.getScrollContainer()
836
+ if (!wrap) return
837
+
838
+ if (direction === 'horizontal') {
839
+ wrap.scrollBy({ left: delta, behavior: 'smooth' })
840
+ } else {
841
+ wrap.scrollBy({ top: delta, behavior: 'smooth' })
342
842
  }
343
843
  },
844
+
344
845
  scrollToEnd() {
345
- const container = this.$refs.scrollContainer
346
- if (!container) return
846
+ const scrollRef = this.$refs.scrollRef
847
+ if (!scrollRef) return
848
+ const wrap = scrollRef.getScrollContainer && scrollRef.getScrollContainer()
849
+ if (!wrap) return
850
+
347
851
  if (this.direction === 'horizontal') {
348
- container.scrollTo({ left: container.scrollWidth, behavior: 'smooth' })
852
+ wrap.scrollTo({ left: wrap.scrollWidth, behavior: 'smooth' })
349
853
  } else {
350
- container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' })
854
+ wrap.scrollTo({ top: wrap.scrollHeight, behavior: 'smooth' })
351
855
  }
856
+ },
857
+
858
+ // ========== 对外暴露方法 ==========
859
+ /** 获取滚动位置 */
860
+ getScrollPos() {
861
+ const scrollRef = this.$refs.scrollRef
862
+ if (!scrollRef) return 0
863
+ const wrap = scrollRef.getScrollContainer && scrollRef.getScrollContainer()
864
+ if (!wrap) return 0
865
+ return this.direction === 'horizontal' ? wrap.scrollLeft : wrap.scrollTop
866
+ },
867
+
868
+ /** 获取 xt-scroll 组件实例 */
869
+ getScrollInstance() {
870
+ return this.$refs.scrollRef
352
871
  }
353
872
  }
354
873
  });
355
874
 
356
875
  // CONCATENATED MODULE: ./src/components/xt-scroll-arrow/index.vue?vue&type=script&lang=js
357
876
  /* harmony default export */ var components_xt_scroll_arrowvue_type_script_lang_js = (xt_scroll_arrowvue_type_script_lang_js);
358
- // CONCATENATED MODULE: ./node_modules/vue-loader/lib/runtime/componentNormalizer.js
359
- /* globals __VUE_SSR_CONTEXT__ */
360
-
361
- // IMPORTANT: Do NOT use ES2015 features in this file (except for modules).
362
- // This module is a runtime utility for cleaner component module output and will
363
- // be included in the final webpack user bundle.
364
-
365
- function normalizeComponent(
366
- scriptExports,
367
- render,
368
- staticRenderFns,
369
- functionalTemplate,
370
- injectStyles,
371
- scopeId,
372
- moduleIdentifier /* server only */,
373
- shadowMode /* vue-cli only */
374
- ) {
375
- // Vue.extend constructor export interop
376
- var options =
377
- typeof scriptExports === 'function' ? scriptExports.options : scriptExports
378
-
379
- // render functions
380
- if (render) {
381
- options.render = render
382
- options.staticRenderFns = staticRenderFns
383
- options._compiled = true
384
- }
385
-
386
- // functional template
387
- if (functionalTemplate) {
388
- options.functional = true
389
- }
390
-
391
- // scopedId
392
- if (scopeId) {
393
- options._scopeId = 'data-v-' + scopeId
394
- }
395
-
396
- var hook
397
- if (moduleIdentifier) {
398
- // server build
399
- hook = function (context) {
400
- // 2.3 injection
401
- context =
402
- context || // cached call
403
- (this.$vnode && this.$vnode.ssrContext) || // stateful
404
- (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional
405
- // 2.2 with runInNewContext: true
406
- if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
407
- context = __VUE_SSR_CONTEXT__
408
- }
409
- // inject component styles
410
- if (injectStyles) {
411
- injectStyles.call(this, context)
412
- }
413
- // register component module identifier for async chunk inferrence
414
- if (context && context._registeredComponents) {
415
- context._registeredComponents.add(moduleIdentifier)
416
- }
417
- }
418
- // used by ssr in case component is cached and beforeCreate
419
- // never gets called
420
- options._ssrRegister = hook
421
- } else if (injectStyles) {
422
- hook = shadowMode
423
- ? function () {
424
- injectStyles.call(
425
- this,
426
- (options.functional ? this.parent : this).$root.$options.shadowRoot
427
- )
428
- }
429
- : injectStyles
430
- }
431
-
432
- if (hook) {
433
- if (options.functional) {
434
- // for template-only hot-reload because in that case the render fn doesn't
435
- // go through the normalizer
436
- options._injectStyles = hook
437
- // register for functional component in vue file
438
- var originalRender = options.render
439
- options.render = function renderWithStyleInjection(h, context) {
440
- hook.call(context)
441
- return originalRender(h, context)
442
- }
443
- } else {
444
- // inject component registration as beforeCreate hook
445
- var existing = options.beforeCreate
446
- options.beforeCreate = existing ? [].concat(existing, hook) : [hook]
447
- }
448
- }
449
-
450
- return {
451
- exports: scriptExports,
452
- options: options
453
- }
454
- }
455
-
456
877
  // CONCATENATED MODULE: ./src/components/xt-scroll-arrow/index.vue
457
878
 
458
879
 
@@ -461,7 +882,7 @@ function normalizeComponent(
461
882
 
462
883
  /* normalize component */
463
884
 
464
- var component = normalizeComponent(
885
+ var xt_scroll_arrow_component = normalizeComponent(
465
886
  components_xt_scroll_arrowvue_type_script_lang_js,
466
887
  render,
467
888
  staticRenderFns,
@@ -472,7 +893,7 @@ var component = normalizeComponent(
472
893
 
473
894
  )
474
895
 
475
- /* harmony default export */ var xt_scroll_arrow = (component.exports);
896
+ /* harmony default export */ var xt_scroll_arrow = (xt_scroll_arrow_component.exports);
476
897
  // CONCATENATED MODULE: ./src/components/xt-scroll-arrow/index.js
477
898
 
478
899