papayaui 0.2.13 → 0.2.15

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.
package/.DS_Store CHANGED
Binary file
@@ -151,9 +151,13 @@ const scrollToMonth = async () => {
151
151
  scrollTop.value = 0
152
152
  await nextTick()
153
153
  }
154
- const start = Array.isArray(defaultDate.value) ? defaultDate.value[0] : defaultDate.value
154
+ const first = Array.isArray(defaultDate.value) ? defaultDate.value[0] : defaultDate.value
155
+ let firstDate = dayjs(first)
156
+ if (!firstDate.isValid()) {
157
+ firstDate = months.value[0].date
158
+ }
155
159
  months.value.forEach((item, index) => {
156
- if (item.date.diff(dayjs(start).startOf('month')) === 0) {
160
+ if (item.date.diff(firstDate.startOf('month')) === 0) {
157
161
  monthCurrent.value = index
158
162
  scrollTop.value = monthTops.value[index]
159
163
  }
@@ -47,7 +47,7 @@
47
47
  <view v-if="loading" :class="ns.e('loading')">
48
48
  <loadmore :status="LoadStatusEnum.LOADING" />
49
49
  </view>
50
- <view v-if="!currentData.length && !loading" :class="ns.e('empty')">无数据</view>
50
+ <view v-if="!currentData.length && !loading" :class="ns.e('empty')">{{ emptyText }}</view>
51
51
  <SafeBottom v-if="safeAreaInsetBottom && !localState.hasConfirm" />
52
52
  </scroll-view>
53
53
  <SearchView
@@ -56,6 +56,7 @@
56
56
  :options="treeData"
57
57
  :field-names="_fieldNames"
58
58
  :search-text="searchText"
59
+ :empty-text="emptyText"
59
60
  :lazy-search="lazySearch"
60
61
  :is-selected="isSelected"
61
62
  :safe-area-inset-bottom="safeAreaInsetBottom && !localState.hasConfirm"
@@ -81,6 +81,13 @@ export const cascaderProps = {
81
81
  type: String,
82
82
  default: '重置',
83
83
  },
84
+ /**
85
+ * 数据为空时的提示文案
86
+ */
87
+ emptyText: {
88
+ type: String,
89
+ default: '无数据',
90
+ },
84
91
  /**
85
92
  * 确定后是否重置数据
86
93
  */
@@ -130,6 +137,10 @@ export const cascaderSearchViewProps = {
130
137
  type: String,
131
138
  required: true,
132
139
  },
140
+ emptyText: {
141
+ type: String,
142
+ required: true,
143
+ },
133
144
  lazySearch: Function as PropType<
134
145
  (searchText: string) => CascaderOption[] | Promise<CascaderOption[]>
135
146
  >,
@@ -10,7 +10,7 @@
10
10
  <view v-if="loading" :class="ns.e('loading')">
11
11
  <loadmore :status="LoadStatusEnum.LOADING" />
12
12
  </view>
13
- <view v-if="!searchData.length && !loading" :class="ns.e('empty')">无数据</view>
13
+ <view v-if="!searchData.length && !loading" :class="ns.e('empty')">{{ emptyText }}</view>
14
14
  <SafeBottom v-if="safeAreaInsetBottom" />
15
15
  </scroll-view>
16
16
  </template>
@@ -44,7 +44,7 @@
44
44
  <LoadMore
45
45
  v-if="!filterOptions.length || !!pagination"
46
46
  :status="loadStatus"
47
- :config="{ nomore: isEmpty ? '无数据' : '没有更多了' }"
47
+ :config="{ nomore: isEmpty ? emptyText : '没有更多了' }"
48
48
  :full-page="isEmpty"
49
49
  :show-text="!onlyOnePage"
50
50
  @next="onScrollNext"
@@ -88,6 +88,13 @@ export const pickerPopupProps = {
88
88
  type: String,
89
89
  default: '确定',
90
90
  },
91
+ /**
92
+ * 数据为空时的提示文案
93
+ */
94
+ emptyText: {
95
+ type: String,
96
+ default: '无数据',
97
+ },
91
98
  /**
92
99
  * 确定后是否重置数据
93
100
  */
@@ -10,7 +10,7 @@
10
10
  :show="visible"
11
11
  :duration="duration"
12
12
  :mode="animateMode"
13
- :custom-class="`${ns.b()} ${customClass}`"
13
+ :custom-class="`${ns.b()} ${customClass ?? ''}`"
14
14
  :custom-style="transitionStyle"
15
15
  @click="onContentClick"
16
16
  @before-enter="onBeforeEnter"
@@ -113,7 +113,128 @@ export default defineComponent({
113
113
  },
114
114
  })
115
115
  </script>
116
- <script module="wxs" lang="wxs" src="./transition.wxs"></script>
116
+ <script module="wxs" lang="wxs">
117
+ function getClassNames(name) {
118
+ return {
119
+ enter: name + '-enter ' + name + '-enter-active',
120
+ 'enter-to': name + '-enter-to ' + name + '-enter-active',
121
+ leave: name + '-leave ' + name + '-leave-active',
122
+ 'leave-to': name + '-leave-to ' + name + '-leave-active',
123
+ }
124
+ }
125
+
126
+ function onOptionsChange(newValue, _oldValue, _ownInstance, instance) {
127
+ if (typeof newValue === 'undefined') return
128
+ var state = instance.getState()
129
+ state.mainClass = newValue.mainClass
130
+ state.prefix = newValue.prefix
131
+ state.mode = newValue.mode
132
+ state.duration = newValue.duration
133
+ }
134
+
135
+ function onShowChange(newValue, _oldValue, ownInstance, instance) {
136
+ if (typeof newValue === 'undefined') return
137
+ var state = instance.getState()
138
+ var classNames = getClassNames(state.prefix + '-' + state.mode)
139
+ classNames.hide = state.mainClass + '-hide'
140
+
141
+ if (newValue) {
142
+ enter(ownInstance, instance, classNames)
143
+ } else {
144
+ leave(ownInstance, instance, classNames)
145
+ }
146
+ }
147
+
148
+ function compatible(instance) {
149
+ // #ifdef H5
150
+ instance.setStyle = function (style) {
151
+ Object.keys(style).forEach((key) => {
152
+ this.$el.style[key] = style[key]
153
+ })
154
+ }
155
+ instance.addClass = function (className) {
156
+ this.$el.classList.add(...className.split(' '))
157
+ }
158
+ instance.removeClass = function (className) {
159
+ this.$el.classList.remove(...className.split(' '))
160
+ }
161
+ // #endif
162
+ }
163
+
164
+ function enter(ownInstance, instance, classNames) {
165
+ compatible(instance)
166
+ var state = instance.getState()
167
+ var clearClassNames = [classNames.hide, classNames.leave, classNames['leave-to']]
168
+ clearClassNames.forEach(function (className) {
169
+ instance.removeClass(className)
170
+ })
171
+ // 进入前
172
+ state._status = 'enter'
173
+ ownInstance.callMethod('beforeEnter')
174
+ instance.setStyle({
175
+ 'transition-duration': '0ms',
176
+ })
177
+ // 进入动画
178
+ ownInstance.callMethod('enter')
179
+ instance.addClass(classNames.enter)
180
+
181
+ instance.requestAnimationFrame(function () {
182
+ instance.removeClass(classNames.enter)
183
+ instance.setStyle({
184
+ 'transition-duration': state.duration + 'ms',
185
+ })
186
+ // 进入动画中
187
+ instance.addClass(classNames['enter-to'])
188
+ state.transitionEnded = false
189
+
190
+ instance.setTimeout(function () {
191
+ if (state._status !== 'enter') return
192
+ // 进入动画完成
193
+ instance.removeClass(classNames['enter-to'])
194
+ ownInstance.callMethod('afterEnter')
195
+ }, state.duration)
196
+ })
197
+ }
198
+
199
+ function leave(ownInstance, instance, classNames) {
200
+ var state = instance.getState()
201
+ var clearClassNames = [classNames.enter, classNames['enter-to']]
202
+ clearClassNames.forEach(function (className) {
203
+ instance.removeClass(className)
204
+ })
205
+ // 离开前
206
+ state._status = 'leave'
207
+ ownInstance.callMethod('beforeLeave')
208
+
209
+ instance.requestAnimationFrame(function () {
210
+ // 离开动画
211
+ ownInstance.callMethod('leave')
212
+ instance.addClass(classNames.leave)
213
+
214
+ instance.requestAnimationFrame(function () {
215
+ instance.removeClass(classNames.leave)
216
+ // 离开动画中
217
+ instance.addClass(classNames['leave-to'])
218
+ state.transitionEnded = false
219
+
220
+ instance.setTimeout(function () {
221
+ if (state._status !== 'leave') return
222
+ if (state.transitionEnded) return
223
+ state.transitionEnded = true
224
+ // 离开动画完成
225
+ instance.removeClass(classNames['leave-to'])
226
+ instance.addClass(classNames.hide)
227
+ ownInstance.callMethod('afterLeave')
228
+ }, state.duration)
229
+ })
230
+ })
231
+ }
232
+
233
+ module.exports = {
234
+ onOptionsChange: onOptionsChange,
235
+ onShowChange: onShowChange,
236
+ }
237
+ </script>
117
238
 
118
239
  <style lang="scss">
119
240
  @import './transition.scss';
@@ -27,6 +27,10 @@
27
27
  <Demo7 />
28
28
  </DocDemoBlock>
29
29
 
30
+ <DocDemoBlock title="其他文件类型" card>
31
+ <Demo8 />
32
+ </DocDemoBlock>
33
+
30
34
  <pa-safe-bottom />
31
35
  </template>
32
36
 
@@ -38,6 +42,7 @@ import Demo4 from '../../demos/uploader/demo-4.vue'
38
42
  import Demo5 from '../../demos/uploader/demo-5.vue'
39
43
  import Demo6 from '../../demos/uploader/demo-6.vue'
40
44
  import Demo7 from '../../demos/uploader/demo-7.vue'
45
+ import Demo8 from '../../demos/uploader/demo-8.vue'
41
46
  import DocDemoBlock from '../../doc/doc-demo-block.vue'
42
47
  </script>
43
48
 
@@ -1,10 +1,12 @@
1
1
  import type { ExtractPropTypes, PropType } from 'vue'
2
2
  import { isArray, isNumber, isObject } from '../../utils'
3
3
 
4
+ export type FileMediaType = 'image' | 'video'
5
+ export type FileOtherType = 'word' | 'excel' | 'ppt' | 'pdf' | 'markdown' | 'zip' | 'file'
4
6
  export type FileItem = {
5
7
  name?: string
6
8
  url: string
7
- type?: 'image' | 'video'
9
+ type?: FileMediaType | FileOtherType
8
10
  status?: 'ready' | 'uploading' | 'success' | 'error'
9
11
  deletable?: boolean
10
12
  thumbUrl?: string
@@ -24,6 +24,43 @@
24
24
  overflow: hidden;
25
25
  }
26
26
 
27
+ &-type-word,
28
+ &-type-excel,
29
+ &-type-ppt,
30
+ &-type-pdf,
31
+ &-type-markdown,
32
+ &-type-zip,
33
+ &-type-file {
34
+ display: flex;
35
+ flex-direction: column;
36
+ align-items: center;
37
+ justify-content: center;
38
+ background-color: #f7f8fa;
39
+ font-size: _var(uploader-preview-file-size, 36px);
40
+ color: _var(uploader-preview-file-color, _var(color-black-3));
41
+ text {
42
+ font-size: _var(uploader-preview-file-text-size, 14px);
43
+ }
44
+ }
45
+ &-type-word {
46
+ color: #285898;
47
+ }
48
+ &-type-excel {
49
+ color: #15723b;
50
+ }
51
+ &-type-ppt {
52
+ color: #cd3f2b;
53
+ }
54
+ &-type-pdf {
55
+ color: #b40009;
56
+ }
57
+ &-type-markdown {
58
+ color: #6188bd;
59
+ }
60
+ &-type-zip {
61
+ color: #f2bb3c;
62
+ }
63
+
27
64
  &-delete {
28
65
  position: absolute;
29
66
  top: 0;
@@ -4,14 +4,22 @@
4
4
  <slot v-if="$slots.default" />
5
5
  <template v-else>
6
6
  <view v-for="(file, index) in fileList" :key="index" :class="ns.e('preview')">
7
- <view :class="ns.e('preview-image')" :style="sizeStyle">
7
+ <view
8
+ :class="[ns.e('preview-image'), ns.e(`preview-type-${file.type ?? 'image'}`)]"
9
+ :style="sizeStyle"
10
+ >
8
11
  <ImageComponent
12
+ v-if="!file.type || file.type === 'image' || file.type === 'video'"
9
13
  :src="file.thumbUrl ?? file.url"
10
14
  width="100%"
11
15
  height="100%"
12
16
  mode="aspectFill"
13
17
  @click="onPreview(file, index)"
14
18
  />
19
+ <template v-else>
20
+ <IconComponent :name="(file.type !== 'file' ? `file-` : '') + file.type" />
21
+ <text>{{ file.type }}</text>
22
+ </template>
15
23
  </view>
16
24
  <view
17
25
  v-if="deletable && file.deletable !== false"
@@ -42,7 +50,7 @@ import useNamespace from '../../core/useNamespace'
42
50
  import { getUnitValue } from '../../utils'
43
51
  import IconComponent from '../icon/icon.vue'
44
52
  import ImageComponent from '../image/image.vue'
45
- import type { FileItem } from './props'
53
+ import type { FileItem, FileMediaType } from './props'
46
54
  import { uploaderProps, uploaderEmits } from './props'
47
55
 
48
56
  const ns = useNamespace('uploader')
@@ -129,26 +137,27 @@ const afterRead = (fileList: FileItem[]) => {
129
137
  }
130
138
 
131
139
  const onPreview = (file: FileItem, index: number) => {
132
- if (!props.previewFullImage) return
133
- // #ifdef MP
134
- uni.previewMedia({
135
- sources: props.fileList,
136
- current: index,
137
- fail: () => {
138
- // 前面的API可能存在兼容问题,失败时使用降级方法
139
- uni.previewImage({
140
- urls: props.fileList.map((file) => file.url),
141
- current: index,
142
- })
143
- },
144
- })
145
- // #endif
146
- // #ifndef MP
147
- uni.previewImage({
148
- urls: props.fileList.map((file) => file.url),
149
- current: index,
150
- })
151
- // #endif
140
+ if (props.previewFullImage && ['image', 'video'].includes(file.type ?? 'image')) {
141
+ // #ifdef MP
142
+ uni.previewMedia({
143
+ sources: props.fileList.map((file) => ({ url: file.url, type: file.type as FileMediaType })),
144
+ current: index,
145
+ fail: () => {
146
+ // 前面的API可能存在兼容问题,失败时使用降级方法
147
+ uni.previewImage({
148
+ urls: props.fileList.map((file) => file.url),
149
+ current: index,
150
+ })
151
+ },
152
+ })
153
+ // #endif
154
+ // #ifndef MP
155
+ uni.previewImage({
156
+ urls: props.fileList.map((file) => file.url),
157
+ current: index,
158
+ })
159
+ // #endif
160
+ }
152
161
  emit('click-preview', file, index)
153
162
  }
154
163
 
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <pa-uploader v-model:file-list="fileList" />
3
+ </template>
4
+
5
+ <script setup lang="ts">
6
+ import { ref } from 'vue'
7
+ import type { FileItem } from '../..'
8
+
9
+ const fileList = ref<FileItem[]>([
10
+ {
11
+ url: '',
12
+ type: 'word',
13
+ },
14
+ {
15
+ url: '',
16
+ type: 'excel',
17
+ },
18
+ {
19
+ url: '',
20
+ type: 'ppt',
21
+ },
22
+ {
23
+ url: '',
24
+ type: 'pdf',
25
+ },
26
+ {
27
+ url: '',
28
+ type: 'markdown',
29
+ },
30
+ {
31
+ url: '',
32
+ type: 'zip',
33
+ },
34
+ {
35
+ url: '',
36
+ type: 'file',
37
+ },
38
+ ])
39
+ </script>
package/fonts/.DS_Store CHANGED
Binary file
@@ -1,8 +1,8 @@
1
1
  @font-face {
2
2
  font-family: "pa-icon"; /* Project id 3668565 */
3
- src: url('iconfont.woff2?t=1692684761658') format('woff2'),
4
- url('iconfont.woff?t=1692684761658') format('woff'),
5
- url('iconfont.ttf?t=1692684761658') format('truetype');
3
+ src: url('iconfont.woff2?t=1715567017689') format('woff2'),
4
+ url('iconfont.woff?t=1715567017689') format('woff'),
5
+ url('iconfont.ttf?t=1715567017689') format('truetype');
6
6
  }
7
7
 
8
8
  .pa-icon {
@@ -13,6 +13,38 @@
13
13
  -moz-osx-font-smoothing: grayscale;
14
14
  }
15
15
 
16
+ .pa-icon-refresh:before {
17
+ content: "\e6a4";
18
+ }
19
+
20
+ .pa-icon-file-excel:before {
21
+ content: "\e7b8";
22
+ }
23
+
24
+ .pa-icon-file-pdf:before {
25
+ content: "\e7ba";
26
+ }
27
+
28
+ .pa-icon-file-markdown:before {
29
+ content: "\e7bb";
30
+ }
31
+
32
+ .pa-icon-file-ppt:before {
33
+ content: "\e7bc";
34
+ }
35
+
36
+ .pa-icon-file-word:before {
37
+ content: "\e7bd";
38
+ }
39
+
40
+ .pa-icon-file:before {
41
+ content: "\e7be";
42
+ }
43
+
44
+ .pa-icon-file-zip:before {
45
+ content: "\e7bf";
46
+ }
47
+
16
48
  .pa-icon-order:before {
17
49
  content: "\e66d";
18
50
  }