@ecolovo/uniapp-components 1.0.4 → 1.0.5
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/components/aspect/aspect.vue +1 -1
- package/components/button/button.vue +1 -1
- package/components/checkbox/checkbox.vue +11 -10
- package/components/checkbox-group/checkbox-group.vue +18 -12
- package/components/checkbox-group2/checkbox-group2.vue +16 -10
- package/components/checkbox-group2/checkbox.vue +15 -9
- package/components/uploader/media-uploader.vue +53 -12
- package/components/uploader/mixin.js +113 -48
- package/package.json +15 -14
- package/utils/fileSize.js +39 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<view :class="componentClassNames">
|
|
3
3
|
<view :class="$style['Aspect--content-wrapper']" :style="{ paddingTop: 100 / ratio + '%' }">
|
|
4
|
-
<view :class="$style['Aspect--content']">
|
|
4
|
+
<view :class="$style['Aspect--content']" @click="$emit('click')">
|
|
5
5
|
<slot></slot>
|
|
6
6
|
</view>
|
|
7
7
|
</view>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
]"
|
|
22
22
|
:hover-class="disabled ? 'none' : $style['Button--active']"
|
|
23
23
|
:style="buttonTheme"
|
|
24
|
-
@click
|
|
24
|
+
@click="onClick"
|
|
25
25
|
@getphonenumber="onOpenType('getphonenumber', $event)"
|
|
26
26
|
@agreeprivacyauthorization="onOpenType('agreeprivacyauthorization', $event)"
|
|
27
27
|
>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<view :class="componentClassNames" @click="toggle()">
|
|
3
3
|
<icon-cpn
|
|
4
|
+
v-if="checkboxGroupProps.icon"
|
|
4
5
|
:icon="usingIcon || ''"
|
|
5
6
|
tap-size="50rpx"
|
|
6
7
|
:class="[$style['Checkbox--icon'], { [$style['Checkbox--checked']]: isChecked }]"
|
|
@@ -42,7 +43,7 @@ export default {
|
|
|
42
43
|
},
|
|
43
44
|
},
|
|
44
45
|
props: {
|
|
45
|
-
/**
|
|
46
|
+
/** 当在 checkbox-group 中时,这个值用于选项值;否则用于 v-model ,只能是 boolean 类型 */
|
|
46
47
|
value: {
|
|
47
48
|
type: [Number, String, Boolean, null],
|
|
48
49
|
default: null,
|
|
@@ -114,16 +115,16 @@ export default {
|
|
|
114
115
|
}
|
|
115
116
|
return this.value === null ? this.innerChecked : this.value;
|
|
116
117
|
},
|
|
117
|
-
set(
|
|
118
|
-
this.$emit('input',
|
|
119
|
-
this.innerChecked =
|
|
120
|
-
this.$emit('change',
|
|
118
|
+
set(val) {
|
|
119
|
+
this.$emit('input', val);
|
|
120
|
+
this.innerChecked = val;
|
|
121
|
+
this.$emit('change', val);
|
|
121
122
|
},
|
|
122
123
|
},
|
|
123
124
|
},
|
|
124
125
|
methods: {
|
|
125
126
|
/** 切换选择 */
|
|
126
|
-
toggle(
|
|
127
|
+
toggle(checked) {
|
|
127
128
|
if (this.isReadonly) return;
|
|
128
129
|
|
|
129
130
|
if (this.isInGroup) {
|
|
@@ -131,13 +132,13 @@ export default {
|
|
|
131
132
|
return;
|
|
132
133
|
}
|
|
133
134
|
|
|
134
|
-
if (
|
|
135
|
+
if (checked === undefined || checked === null) {
|
|
135
136
|
this.isChecked = !this.isChecked;
|
|
136
137
|
return;
|
|
137
138
|
}
|
|
138
139
|
|
|
139
|
-
if (this.isChecked !== !!
|
|
140
|
-
this.isChecked = !!
|
|
140
|
+
if (this.isChecked !== !!checked) {
|
|
141
|
+
this.isChecked = !!checked;
|
|
141
142
|
}
|
|
142
143
|
},
|
|
143
144
|
},
|
|
@@ -167,6 +168,7 @@ $component-vars: $checkbox;
|
|
|
167
168
|
}
|
|
168
169
|
.Checkbox--icon {
|
|
169
170
|
flex: none;
|
|
171
|
+
margin-right: 12rpx;
|
|
170
172
|
color: UTILS__LOCAL_VAR(unchecked-color);
|
|
171
173
|
}
|
|
172
174
|
.Checkbox--checked {
|
|
@@ -177,7 +179,6 @@ $component-vars: $checkbox;
|
|
|
177
179
|
}
|
|
178
180
|
.Checkbox--text {
|
|
179
181
|
flex: 0 1 auto;
|
|
180
|
-
margin-left: 12rpx;
|
|
181
182
|
}
|
|
182
183
|
}
|
|
183
184
|
</style>
|
|
@@ -32,6 +32,11 @@ export default {
|
|
|
32
32
|
type: Boolean,
|
|
33
33
|
default: false,
|
|
34
34
|
},
|
|
35
|
+
/** 是否显示勾选图标 */
|
|
36
|
+
icon: {
|
|
37
|
+
type: Boolean,
|
|
38
|
+
default: true,
|
|
39
|
+
},
|
|
35
40
|
/** 选中时的图标 */
|
|
36
41
|
checkedIcon: {
|
|
37
42
|
type: String,
|
|
@@ -53,37 +58,38 @@ export default {
|
|
|
53
58
|
get: function () {
|
|
54
59
|
return this.value === null ? this.checkedValue : this.value;
|
|
55
60
|
},
|
|
56
|
-
set: function (
|
|
57
|
-
this.$emit('input',
|
|
58
|
-
this.checkedValue =
|
|
59
|
-
this.$emit('change',
|
|
61
|
+
set: function (val) {
|
|
62
|
+
this.$emit('input', val);
|
|
63
|
+
this.checkedValue = val;
|
|
64
|
+
this.$emit('change', val);
|
|
60
65
|
},
|
|
61
66
|
},
|
|
62
67
|
},
|
|
63
68
|
watch: {
|
|
64
69
|
value: {
|
|
65
|
-
handler: function (
|
|
66
|
-
this.checkedValue =
|
|
70
|
+
handler: function (val) {
|
|
71
|
+
this.checkedValue = val;
|
|
67
72
|
},
|
|
68
73
|
immediate: true,
|
|
74
|
+
deep: true,
|
|
69
75
|
},
|
|
70
76
|
},
|
|
71
77
|
methods: {
|
|
72
|
-
check(
|
|
78
|
+
check(val) {
|
|
73
79
|
if (this.radio) {
|
|
74
|
-
this.currentValue =
|
|
80
|
+
this.currentValue = val;
|
|
75
81
|
return;
|
|
76
82
|
}
|
|
77
83
|
|
|
78
84
|
if (!Array.isArray(this.currentValue)) {
|
|
79
|
-
this.currentValue = [
|
|
85
|
+
this.currentValue = [val];
|
|
80
86
|
return;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
|
-
if (this.currentValue.includes(
|
|
84
|
-
this.currentValue = this.currentValue.filter((item) => item !==
|
|
89
|
+
if (this.currentValue.includes(val)) {
|
|
90
|
+
this.currentValue = this.currentValue.filter((item) => item !== val);
|
|
85
91
|
} else {
|
|
86
|
-
this.currentValue.push(
|
|
92
|
+
this.currentValue.push(val);
|
|
87
93
|
}
|
|
88
94
|
},
|
|
89
95
|
},
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
v-for="(item, index) in options"
|
|
5
5
|
:key="index"
|
|
6
6
|
:value="radio ? item.value === currentValue : currentValue && currentValue.includes(item.value)"
|
|
7
|
+
:icon="icon"
|
|
7
8
|
:checked-icon="checkedIcon || (radio ? 'radio-checked' : 'checkbox-checked')"
|
|
8
9
|
:unchecked-icon="uncheckedIcon || (radio ? 'radio-unchecked' : 'checkbox-unchecked')"
|
|
9
10
|
:class="$style['CheckboxGroup2--item']"
|
|
@@ -42,6 +43,11 @@ export default {
|
|
|
42
43
|
type: Boolean,
|
|
43
44
|
default: true,
|
|
44
45
|
},
|
|
46
|
+
/** 是否显示勾选图标 */
|
|
47
|
+
icon: {
|
|
48
|
+
type: Boolean,
|
|
49
|
+
default: true,
|
|
50
|
+
},
|
|
45
51
|
/** 选中时的图标 */
|
|
46
52
|
checkedIcon: {
|
|
47
53
|
type: String,
|
|
@@ -63,10 +69,10 @@ export default {
|
|
|
63
69
|
get() {
|
|
64
70
|
return this.value === null ? this.checkedValue : this.value;
|
|
65
71
|
},
|
|
66
|
-
set(
|
|
67
|
-
this.$emit('input',
|
|
68
|
-
this.checkedValue =
|
|
69
|
-
this.$emit('change',
|
|
72
|
+
set(val) {
|
|
73
|
+
this.$emit('input', val);
|
|
74
|
+
this.checkedValue = val;
|
|
75
|
+
this.$emit('change', val);
|
|
70
76
|
},
|
|
71
77
|
},
|
|
72
78
|
optionsValue() {
|
|
@@ -74,21 +80,21 @@ export default {
|
|
|
74
80
|
},
|
|
75
81
|
},
|
|
76
82
|
methods: {
|
|
77
|
-
check(
|
|
83
|
+
check(val) {
|
|
78
84
|
if (this.radio) {
|
|
79
|
-
this.currentValue =
|
|
85
|
+
this.currentValue = val;
|
|
80
86
|
return;
|
|
81
87
|
}
|
|
82
88
|
|
|
83
89
|
if (!Array.isArray(this.currentValue)) {
|
|
84
|
-
this.currentValue = [
|
|
90
|
+
this.currentValue = [val];
|
|
85
91
|
return;
|
|
86
92
|
}
|
|
87
93
|
|
|
88
|
-
if (this.currentValue.includes(
|
|
89
|
-
this.currentValue = this.currentValue.filter((item) => item !==
|
|
94
|
+
if (this.currentValue.includes(val)) {
|
|
95
|
+
this.currentValue = this.currentValue.filter((item) => item !== val);
|
|
90
96
|
} else {
|
|
91
|
-
this.currentValue.push(
|
|
97
|
+
this.currentValue.push(val);
|
|
92
98
|
}
|
|
93
99
|
},
|
|
94
100
|
/** 切换全选
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<view :class="componentClassNames" @click="toggle()">
|
|
3
3
|
<icon-cpn
|
|
4
|
+
v-if="icon"
|
|
4
5
|
:icon="currentValue ? checkedIcon || 'checkbox-checked' : uncheckedIcon || 'checkbox-unchecked'"
|
|
5
6
|
tap-size="50rpx"
|
|
6
7
|
:class="[$style['Checkbox2--icon'], { [$style['Checkbox2--checked']]: currentValue }]"
|
|
@@ -29,6 +30,11 @@ export default {
|
|
|
29
30
|
type: [Boolean, null],
|
|
30
31
|
default: null,
|
|
31
32
|
},
|
|
33
|
+
/** 是否显示勾选图标 */
|
|
34
|
+
icon: {
|
|
35
|
+
type: Boolean,
|
|
36
|
+
default: true,
|
|
37
|
+
},
|
|
32
38
|
/** 选中时的图标 */
|
|
33
39
|
checkedIcon: {
|
|
34
40
|
type: String,
|
|
@@ -50,23 +56,23 @@ export default {
|
|
|
50
56
|
get: function () {
|
|
51
57
|
return this.value === null ? this.innerValue : this.value;
|
|
52
58
|
},
|
|
53
|
-
set: function (
|
|
54
|
-
this.$emit('input',
|
|
55
|
-
this.innerValue =
|
|
56
|
-
this.$emit('change',
|
|
59
|
+
set: function (val) {
|
|
60
|
+
this.$emit('input', val);
|
|
61
|
+
this.innerValue = val;
|
|
62
|
+
this.$emit('change', val);
|
|
57
63
|
},
|
|
58
64
|
},
|
|
59
65
|
},
|
|
60
66
|
methods: {
|
|
61
67
|
/** 切换选择 */
|
|
62
|
-
toggle(
|
|
63
|
-
if (
|
|
68
|
+
toggle(checked) {
|
|
69
|
+
if (checked === undefined || checked === null) {
|
|
64
70
|
this.currentValue = !this.currentValue;
|
|
65
71
|
return;
|
|
66
72
|
}
|
|
67
73
|
|
|
68
|
-
if (this.currentValue !== !!
|
|
69
|
-
this.currentValue = !!
|
|
74
|
+
if (this.currentValue !== !!checked) {
|
|
75
|
+
this.currentValue = !!checked;
|
|
70
76
|
}
|
|
71
77
|
},
|
|
72
78
|
},
|
|
@@ -90,6 +96,7 @@ $component-vars: $checkbox;
|
|
|
90
96
|
|
|
91
97
|
.Checkbox2--icon {
|
|
92
98
|
flex: none;
|
|
99
|
+
margin-right: 12rpx;
|
|
93
100
|
color: UTILS__LOCAL_VAR(unchecked-color);
|
|
94
101
|
}
|
|
95
102
|
.Checkbox2--checked {
|
|
@@ -97,7 +104,6 @@ $component-vars: $checkbox;
|
|
|
97
104
|
}
|
|
98
105
|
.Checkbox2--text {
|
|
99
106
|
flex: 0 1 auto;
|
|
100
|
-
margin-left: 12rpx;
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
</style>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<view :class="componentClassNames" :style="{ '--columns': columns }">
|
|
3
3
|
<!-- 已上传文件列表 -->
|
|
4
|
-
<aspect-cpn v-for="(item, idx) in
|
|
4
|
+
<aspect-cpn v-for="(item, idx) in fileList" :key="idx" :class="$style['Uploader--item']" :style="styleWidth">
|
|
5
5
|
<!-- TODO: 视频文件支持 -->
|
|
6
6
|
<!-- <video
|
|
7
7
|
v-if="item.fileType === 'video'"
|
|
@@ -24,21 +24,30 @@
|
|
|
24
24
|
:style="styleSize"
|
|
25
25
|
mode="aspectFill"
|
|
26
26
|
/>
|
|
27
|
+
<loading-cpn
|
|
28
|
+
v-if="!isReadonly && item.uploadStatus === 'uploading'"
|
|
29
|
+
:class="$style['Uploader--upload-loading']"
|
|
30
|
+
/>
|
|
31
|
+
<view v-if="!isReadonly && item.uploadStatus === 'error'" :class="$style['Uploader--upload-error']">
|
|
32
|
+
上传失败
|
|
33
|
+
</view>
|
|
27
34
|
<view
|
|
28
|
-
v-if="item.uploadStatus !== 'uploading'"
|
|
35
|
+
v-if="!isReadonly && item.uploadStatus !== 'uploading'"
|
|
29
36
|
:class="$style['Uploader--icon-delete']"
|
|
30
37
|
@click.stop="deleteFile(idx)"
|
|
31
38
|
>
|
|
32
39
|
</view>
|
|
33
40
|
</aspect-cpn>
|
|
34
41
|
<!-- 上传按钮 -->
|
|
35
|
-
<aspect-cpn :class="$style['Uploader--item']" :style="styleWidth">
|
|
36
|
-
<
|
|
37
|
-
<
|
|
38
|
-
<view
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
+
<aspect-cpn v-if="!isReadonly" :class="$style['Uploader--item']" :style="styleWidth" @click="selectFile">
|
|
43
|
+
<slot>
|
|
44
|
+
<button-cpn plain :class="$style['Uploader--button']">
|
|
45
|
+
<view style="line-height: 1.3em">
|
|
46
|
+
<view>上传</view>
|
|
47
|
+
<view>图片</view>
|
|
48
|
+
</view>
|
|
49
|
+
</button-cpn>
|
|
50
|
+
</slot>
|
|
42
51
|
</aspect-cpn>
|
|
43
52
|
</view>
|
|
44
53
|
</template>
|
|
@@ -48,6 +57,7 @@ import componentName from '../../mixins/componentName';
|
|
|
48
57
|
import AspectCpn from '../aspect/aspect.vue';
|
|
49
58
|
import ButtonCpn from '../button/button.vue';
|
|
50
59
|
import ImageCpn from '../image/image.vue';
|
|
60
|
+
import LoadingCpn from '../loading/animations/loading-animation4.vue';
|
|
51
61
|
import UploadMixin from './mixin';
|
|
52
62
|
|
|
53
63
|
export default {
|
|
@@ -56,7 +66,7 @@ export default {
|
|
|
56
66
|
virtualHost: true,
|
|
57
67
|
styleIsolation: 'shared',
|
|
58
68
|
},
|
|
59
|
-
components: { AspectCpn, ButtonCpn, ImageCpn },
|
|
69
|
+
components: { AspectCpn, ButtonCpn, ImageCpn, LoadingCpn },
|
|
60
70
|
mixins: [componentName, UploadMixin],
|
|
61
71
|
props: {
|
|
62
72
|
/** 显示宽度 */
|
|
@@ -78,7 +88,7 @@ export default {
|
|
|
78
88
|
},
|
|
79
89
|
/** 预览列表 */
|
|
80
90
|
previewList() {
|
|
81
|
-
return this.
|
|
91
|
+
return this.fileList.map((item) => item.tempFilePath || item.url);
|
|
82
92
|
},
|
|
83
93
|
},
|
|
84
94
|
methods: {
|
|
@@ -88,7 +98,10 @@ export default {
|
|
|
88
98
|
mediaType: ['image', 'video'],
|
|
89
99
|
sourceType: ['album', 'camera'],
|
|
90
100
|
success: (res) => {
|
|
91
|
-
this.validateFiles(res.tempFiles);
|
|
101
|
+
const files = this.validateFiles(res.tempFiles);
|
|
102
|
+
if (this.autoUpload && files) {
|
|
103
|
+
this.upload();
|
|
104
|
+
}
|
|
92
105
|
},
|
|
93
106
|
});
|
|
94
107
|
},
|
|
@@ -105,11 +118,39 @@ export default {
|
|
|
105
118
|
}
|
|
106
119
|
|
|
107
120
|
.Uploader--item {
|
|
121
|
+
position: relative;
|
|
108
122
|
width: calc(100% / var(--columns) - 12rpx * (var(--columns) - 1) / var(--columns));
|
|
109
123
|
}
|
|
110
124
|
.Uploader--image {
|
|
111
125
|
border-radius: 16rpx;
|
|
112
126
|
}
|
|
127
|
+
.Uploader--upload-loading {
|
|
128
|
+
pointer-events: none;
|
|
129
|
+
position: absolute;
|
|
130
|
+
top: 50%;
|
|
131
|
+
left: 50%;
|
|
132
|
+
font-size: 2em;
|
|
133
|
+
color: #fff;
|
|
134
|
+
transform: translate(-50%, -50%);
|
|
135
|
+
}
|
|
136
|
+
.Uploader--upload-error {
|
|
137
|
+
pointer-events: none;
|
|
138
|
+
position: absolute;
|
|
139
|
+
top: 50%;
|
|
140
|
+
left: 50%;
|
|
141
|
+
width: 2em;
|
|
142
|
+
height: 2em;
|
|
143
|
+
box-sizing: content-box;
|
|
144
|
+
transform: translate(-50%, -50%);
|
|
145
|
+
padding: 1.25em;
|
|
146
|
+
border-radius: 50%;
|
|
147
|
+
background-color: #00000080;
|
|
148
|
+
color: #fff;
|
|
149
|
+
font-size: 22rpx;
|
|
150
|
+
display: flex;
|
|
151
|
+
justify-content: center;
|
|
152
|
+
align-items: center;
|
|
153
|
+
}
|
|
113
154
|
.Uploader--button {
|
|
114
155
|
height: 100%;
|
|
115
156
|
border-color: #ccc;
|
|
@@ -1,18 +1,40 @@
|
|
|
1
|
+
import { fileSize } from '../../utils/fileSize';
|
|
2
|
+
import { isFormReadonly } from '../form/mixin';
|
|
3
|
+
|
|
1
4
|
export default {
|
|
5
|
+
mixins: [isFormReadonly],
|
|
2
6
|
props: {
|
|
3
|
-
/**
|
|
7
|
+
/** 绑定值,文件列表 */
|
|
4
8
|
value: {
|
|
5
9
|
type: Array,
|
|
6
10
|
default: () => [],
|
|
7
11
|
},
|
|
12
|
+
/** 是否只读 */
|
|
13
|
+
readonly: {
|
|
14
|
+
type: Boolean,
|
|
15
|
+
default: false,
|
|
16
|
+
},
|
|
17
|
+
/** 最大上传文件数 */
|
|
8
18
|
max: {
|
|
9
19
|
type: Number,
|
|
10
20
|
default: 9,
|
|
11
21
|
},
|
|
22
|
+
/** 最大上传文件大小 */
|
|
12
23
|
maxSize: {
|
|
13
24
|
type: Number,
|
|
14
25
|
default: 1024 * 1024 * 10, // 10MB
|
|
15
26
|
},
|
|
27
|
+
/** 自动上传文件 */
|
|
28
|
+
autoUpload: {
|
|
29
|
+
type: Boolean,
|
|
30
|
+
default: true,
|
|
31
|
+
},
|
|
32
|
+
/** 上传文件方法
|
|
33
|
+
*
|
|
34
|
+
* 函数签名:
|
|
35
|
+
* @param {UniApp.MediaFile} file - 待上传文件
|
|
36
|
+
* @return {Promise<{url: string}>} - 上传后的文件信息
|
|
37
|
+
*/
|
|
16
38
|
uploadHandler: {
|
|
17
39
|
type: Function,
|
|
18
40
|
default: null,
|
|
@@ -20,79 +42,122 @@ export default {
|
|
|
20
42
|
},
|
|
21
43
|
data() {
|
|
22
44
|
return {
|
|
23
|
-
innerValue:
|
|
45
|
+
innerValue: this.value,
|
|
24
46
|
};
|
|
25
47
|
},
|
|
26
48
|
computed: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return this.value === null ? this.innerValue : this.value;
|
|
30
|
-
},
|
|
31
|
-
set: function (value) {
|
|
32
|
-
this.$emit('input', value);
|
|
33
|
-
this.innerValue = value;
|
|
34
|
-
this.$emit('change', value);
|
|
35
|
-
},
|
|
49
|
+
isReadonly() {
|
|
50
|
+
return this.readonly || this.isFormReadonly;
|
|
36
51
|
},
|
|
52
|
+
/** 剩余可上传文件数 */
|
|
37
53
|
restCount() {
|
|
38
54
|
if (this.max <= 0) return 9;
|
|
39
55
|
return this.max - this.currentValue.length;
|
|
40
56
|
},
|
|
41
|
-
|
|
57
|
+
currentValue: {
|
|
58
|
+
get: function () {
|
|
59
|
+
return this.innerValue;
|
|
60
|
+
},
|
|
61
|
+
set: function (val) {
|
|
62
|
+
this.innerValue = val;
|
|
63
|
+
this.$emit('input', val);
|
|
64
|
+
this.$emit('change', val);
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
fileList() {
|
|
42
68
|
return this.currentValue.map((item) =>
|
|
43
69
|
typeof item === 'string' ? { url: item, uploadStatus: 'success' } : { uploadStatus: 'success', ...item }
|
|
44
70
|
);
|
|
45
71
|
},
|
|
72
|
+
/** 当前是否有文件还在上传 */
|
|
73
|
+
isUploading() {
|
|
74
|
+
return this.currentValue.some((item) => item.uploadStatus === 'uploading');
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
watch: {
|
|
78
|
+
value: {
|
|
79
|
+
handler(val) {
|
|
80
|
+
this.innerValue = val || [];
|
|
81
|
+
},
|
|
82
|
+
immediate: true,
|
|
83
|
+
deep: true,
|
|
84
|
+
},
|
|
46
85
|
},
|
|
47
86
|
methods: {
|
|
48
87
|
/** 校验待上传文件 */
|
|
49
|
-
|
|
88
|
+
validateFiles(files) {
|
|
50
89
|
if (files.length === 0) return;
|
|
51
90
|
|
|
52
91
|
// 过滤大文件
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
uni.showToast({
|
|
92
|
+
const selectedFiles = files.filter((file) => file.size <= this.maxSize);
|
|
93
|
+
if (selectedFiles.length < files.length) {
|
|
94
|
+
uni.showToast({
|
|
95
|
+
icon: 'none',
|
|
96
|
+
title: `文件大小不能超过${fileSize(this.maxSize).formattedSize}`,
|
|
97
|
+
duration: 2000,
|
|
98
|
+
});
|
|
56
99
|
}
|
|
57
|
-
if (
|
|
100
|
+
if (selectedFiles.length === 0) return;
|
|
58
101
|
|
|
59
102
|
// 校验数量
|
|
60
|
-
if (
|
|
103
|
+
if (selectedFiles.length > this.restCount) {
|
|
61
104
|
uni.showToast({ icon: 'none', title: `最多只能上传${this.max}个文件`, duration: 2000 });
|
|
62
105
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
106
|
+
|
|
107
|
+
const validFiles = selectedFiles
|
|
108
|
+
.slice(0, this.restCount)
|
|
109
|
+
.map((file) => ({ ...file, uploadStatus: 'ready' }));
|
|
110
|
+
this.currentValue = this.fileList.concat(validFiles);
|
|
111
|
+
|
|
112
|
+
return validFiles;
|
|
66
113
|
},
|
|
67
114
|
/** 上传文件 */
|
|
68
|
-
upload(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
115
|
+
upload() {
|
|
116
|
+
return Promise.all(
|
|
117
|
+
this.currentValue.map(async (file) => {
|
|
118
|
+
if (file.uploadStatus !== 'ready') return file;
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
file.uploadStatus = 'uploading';
|
|
122
|
+
const res = await this.uploadHandler(file);
|
|
123
|
+
|
|
124
|
+
const index = this.currentValue.findIndex((item) => item.tempFilePath === file.tempFilePath);
|
|
125
|
+
if (index < 0) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const currentValue = [...this.currentValue];
|
|
130
|
+
currentValue.splice(
|
|
131
|
+
index,
|
|
132
|
+
1,
|
|
133
|
+
res && res.url
|
|
134
|
+
? {
|
|
135
|
+
...file,
|
|
136
|
+
name: res.name,
|
|
137
|
+
url: res.url,
|
|
138
|
+
type: file.type,
|
|
139
|
+
uploadStatus: 'success',
|
|
140
|
+
}
|
|
141
|
+
: {
|
|
142
|
+
...file,
|
|
143
|
+
uploadStatus: 'error',
|
|
144
|
+
}
|
|
145
|
+
);
|
|
146
|
+
this.currentValue = currentValue;
|
|
147
|
+
return this.currentValue[index];
|
|
148
|
+
} catch {
|
|
149
|
+
const index = this.currentValue.findIndex((item) => item.tempFilePath === file.tempFilePath);
|
|
150
|
+
if (index < 0) {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const currentValue = [...this.currentValue];
|
|
155
|
+
currentValue.splice(index, 1, { ...file, uploadStatus: 'error' });
|
|
156
|
+
this.currentValue = currentValue;
|
|
157
|
+
return this.currentValue[index];
|
|
90
158
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
this.currentValue = currentValue;
|
|
94
|
-
}
|
|
95
|
-
});
|
|
159
|
+
})
|
|
160
|
+
);
|
|
96
161
|
},
|
|
97
162
|
/** 删除文件 */
|
|
98
163
|
deleteFile(index) {
|
package/package.json
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
2
|
+
"name": "@ecolovo/uniapp-components",
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Ecolovo UniApp 组件库",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"uniapp",
|
|
7
|
+
"components"
|
|
8
|
+
],
|
|
9
|
+
"author": "Yang",
|
|
10
|
+
"license": "ISC",
|
|
11
|
+
"packageManager": "pnpm@10.10.0",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"case-anything": "3.1.2",
|
|
14
|
+
"lodash-es": "4.17.21"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { floor } from './floor';
|
|
2
|
+
|
|
3
|
+
const ONE_KB = 1024;
|
|
4
|
+
const ONE_MB = ONE_KB * 1024;
|
|
5
|
+
const ONE_GB = ONE_MB * 1024;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* 格式化文件尺寸
|
|
9
|
+
* @param {number} size 文件大小 B
|
|
10
|
+
* @returns {{
|
|
11
|
+
* size: number;
|
|
12
|
+
* unit: 'B' | 'KB' | 'MB' | 'GB';
|
|
13
|
+
* formattedSize: string;
|
|
14
|
+
* }} 格式化后的大小
|
|
15
|
+
*/
|
|
16
|
+
export function fileSize(size) {
|
|
17
|
+
if (size < 0) {
|
|
18
|
+
return { size: -1, unit: 'B', formattedSize: '' };
|
|
19
|
+
}
|
|
20
|
+
const rtnObj = {};
|
|
21
|
+
if (size < 100) {
|
|
22
|
+
rtnObj.size = size;
|
|
23
|
+
rtnObj.unit = 'B';
|
|
24
|
+
} else if (size < ONE_KB) {
|
|
25
|
+
rtnObj.size = floor(size / ONE_KB, 2);
|
|
26
|
+
rtnObj.unit = 'KB';
|
|
27
|
+
} else if (size < ONE_MB) {
|
|
28
|
+
rtnObj.size = floor(size / ONE_KB, 0);
|
|
29
|
+
rtnObj.unit = 'KB';
|
|
30
|
+
} else if (size < ONE_GB) {
|
|
31
|
+
rtnObj.size = floor(size / ONE_MB, 1);
|
|
32
|
+
rtnObj.unit = 'MB';
|
|
33
|
+
} else {
|
|
34
|
+
rtnObj.size = floor(size / ONE_GB, 1);
|
|
35
|
+
rtnObj.unit = 'GB';
|
|
36
|
+
}
|
|
37
|
+
rtnObj.formattedSize = `${rtnObj.size} ${rtnObj.unit}`;
|
|
38
|
+
return rtnObj;
|
|
39
|
+
}
|