优化组件/更新

This commit is contained in:
gyq
2025-12-03 10:13:55 +08:00
parent 92f9776a35
commit 09b6e36a52
261 changed files with 22080 additions and 7238 deletions

View File

@@ -7,10 +7,32 @@ function chooseImage(opts) {
const {
count,
sizeType = ['original', 'compressed'],
sourceType = ['album', 'camera'],
sourceType,
extension
} = opts
return new Promise((resolve, reject) => {
// 微信由于旧接口不再维护针对微信小程序平台改用chooseMedia接口
// #ifdef MP-WEIXIN
uni.chooseMedia({
count,
sizeType,
sourceType,
mediaType: ['image'],
extension,
success(res) {
res.tempFiles.forEach(item => {
item.path = item.tempFilePath;
})
resolve(normalizeChooseAndUploadFileRes(res, 'image'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseImage:fail', ERR_MSG_FAIL),
});
},
})
// #endif
// #ifndef MP-WEIXIN
uni.chooseImage({
count,
sizeType,
@@ -25,18 +47,60 @@ function chooseImage(opts) {
});
},
});
// #endif
});
}
function chooseVideo(opts) {
const {
count,
camera,
compressed,
maxDuration,
sourceType = ['album', 'camera'],
sourceType,
extension
} = opts;
return new Promise((resolve, reject) => {
// 微信由于旧接口不再维护针对微信小程序平台改用chooseMedia接口
// #ifdef MP-WEIXIN
uni.chooseMedia({
count,
compressed,
maxDuration,
sourceType,
extension,
mediaType: ['video'],
success(res) {
const {
tempFiles,
} = res;
resolve(normalizeChooseAndUploadFileRes({
errMsg: 'chooseVideo:ok',
tempFiles: tempFiles.map(item => {
return {
name: item.name || '',
path: item.tempFilePath,
thumbTempFilePath: item.thumbTempFilePath,
size:item.size,
type: (res.tempFile && res.tempFile.type) || '',
width:item.width,
height:item.height,
duration:item.duration,
fileType: 'video',
cloudPath: '',
}
}),
}, 'video'));
},
fail(res) {
reject({
errMsg: res.errMsg.replace('chooseVideo:fail', ERR_MSG_FAIL),
});
},
})
// #endif
// #ifndef MP-WEIXIN
uni.chooseVideo({
camera,
compressed,
@@ -54,8 +118,7 @@ function chooseVideo(opts) {
resolve(normalizeChooseAndUploadFileRes({
errMsg: 'chooseVideo:ok',
tempFilePaths: [tempFilePath],
tempFiles: [
{
tempFiles: [{
name: (res.tempFile && res.tempFile.name) || '',
path: tempFilePath,
size,
@@ -74,6 +137,7 @@ function chooseVideo(opts) {
});
},
});
// #endif
});
}
@@ -211,8 +275,7 @@ function chooseAndUploadFile(opts = {
}) {
if (opts.type === 'image') {
return uploadFiles(chooseImage(opts), opts);
}
else if (opts.type === 'video') {
} else if (opts.type === 'video') {
return uploadFiles(chooseVideo(opts), opts);
}
return uploadFiles(chooseAll(opts), opts);

View File

@@ -4,19 +4,13 @@
<text class="file-title">{{ title }}</text>
<text class="file-count">{{ filesList.length }}/{{ limitLength }}</text>
</view>
<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly"
:image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview"
:delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
<upload-image v-if="fileMediatype === 'image' && showType === 'grid'" :readonly="readonly" :image-styles="imageStyles" :files-list="filesList" :limit="limitLength" :disablePreview="disablePreview" :delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
<slot>
<view class="is-add">
<view class="icon-add"></view>
<view class="icon-add rotate"></view>
</view>
<view class="icon-add"></view>
<view class="icon-add rotate"></view>
</slot>
</upload-image>
<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly"
:list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon"
@uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
<upload-file v-if="fileMediatype !== 'image' || showType !== 'grid'" :readonly="readonly" :list-styles="listStyles" :files-list="filesList" :showType="showType" :delIcon="delIcon" @uploadFiles="uploadFiles" @choose="choose" @delFile="delFile">
<slot><button type="primary" size="mini">选择文件</button></slot>
</upload-file>
</view>
@@ -89,24 +83,18 @@
},
emits: ['select', 'success', 'fail', 'progress', 'delete', 'update:modelValue', 'input'],
props: {
// #ifdef VUE3
modelValue: {
type: [Array, Object],
default () {
return []
}
},
// #endif
// #ifndef VUE3
value: {
type: [Array, Object],
default () {
return []
}
},
// #endif
disabled: {
type: Boolean,
default: false
@@ -185,31 +173,48 @@
default () {
return ['original', 'compressed']
}
},
sourceType: {
type: Array,
default () {
return ['album', 'camera']
}
},
provider: {
type: String,
default: '' // 默认上传到 unicloud 内置存储 extStorage 扩展存储
},
dir: {
type: String,
default: '/'
}
},
data() {
return {
files: [],
localValue: []
localValue: [],
dirPath: '/'
}
},
watch: {
// #ifndef VUE3
value: {
handler(newVal, oldVal) {
this.setValue(newVal, oldVal)
},
immediate: true
},
// #endif
// #ifdef VUE3
modelValue: {
handler(newVal, oldVal) {
this.setValue(newVal, oldVal)
},
immediate: true
},
// #endif
dir: {
handler(newVal) {
this.dirPath = newVal
},
immediate: true
},
},
computed: {
filesList() {
@@ -284,19 +289,19 @@
return this.uploadFiles(files)
},
async setValue(newVal, oldVal) {
const newData = async (v) => {
const newData = async (v) => {
const reg = /cloud:\/\/([\w.]+\/?)\S*/
let url = ''
if(v.fileID){
if (v.fileID) {
url = v.fileID
}else{
} else {
url = v.url
}
if (reg.test(url)) {
v.fileID = url
v.url = await this.getTempFileURL(url)
}
if(v.url) v.path = v.url
if (v.url) v.path = v.url
return v
}
if (this.returnType === 'object') {
@@ -307,13 +312,13 @@
}
} else {
if (!newVal) newVal = []
for(let i =0 ;i < newVal.length ;i++){
for (let i = 0; i < newVal.length; i++) {
let v = newVal[i]
await newData(v)
}
}
this.localValue = newVal
if (this.form && this.formItem &&!this.is_reset) {
if (this.form && this.formItem && !this.is_reset) {
this.is_reset = false
this.formItem.setValue(this.localValue)
}
@@ -325,7 +330,6 @@
* 选择文件
*/
choose() {
if (this.disabled) return
if (this.files.length >= Number(this.limitLength) && this.showType !== 'grid' && this.returnType ===
'array') {
@@ -349,6 +353,7 @@
type: this.fileMediatype,
compressed: false,
sizeType: this.sizeType,
sourceType: this.sourceType,
// TODO 如果为空video 有问题
extension: _extname.length > 0 ? _extname : undefined,
count: this.limitLength - this.files.length, //默认9
@@ -370,7 +375,9 @@
* @param {Object} res
*/
async chooseFileCallback(res) {
const _extname = get_extname(this.fileExtname)
const is_one = (Number(this.limitLength) === 1 &&
this.disablePreview &&
!this.disabled) ||
@@ -396,11 +403,13 @@
let filedata = await get_file_data(files[i], this.fileMediatype)
filedata.progress = 0
filedata.status = 'ready'
this.files.push(filedata)
currentData.push({
// fix by mehaotian ,统一返回删除也包含file对象
let fileTempData = {
...filedata,
file: files[i]
})
}
this.files.push(fileTempData)
currentData.push(fileTempData)
}
this.$emit('select', {
tempFiles: currentData,
@@ -411,6 +420,24 @@
if (!this.autoUpload || this.noSpace) {
res.tempFiles = []
}
res.tempFiles.map((fileItem, index) => {
this.provider && (fileItem.provider = this.provider);
const fileNameSplit = fileItem.name.split('.')
const ext = fileNameSplit.pop()
const fileName = fileNameSplit.join('.').replace(/[\s\/\?<>\\:\*\|":]/g, '_')
// 选择文件目录上传
let dir = this.dirPath || ''; // 防止用户传入的 dir 不正常
// 检查最后一个字符是否为 '/'(同时处理空字符串情况)
if (dir && dir[dir.length - 1] !== '/') {
dir += '/';
}
fileItem.cloudPath = dir + fileName + '_' + Date.now() + '_' + index + '.' + ext
fileItem.cloudPathAsRealPath = true
return fileItem
})
return res
},
/**
@@ -457,7 +484,7 @@
const reg = /cloud:\/\/([\w.]+\/?)\S*/
if (reg.test(item.url)) {
this.files[index].url = await this.getTempFileURL(item.url)
}else{
} else {
this.files[index].url = item.url
}
@@ -516,6 +543,7 @@
*/
delFile(index) {
this.$emit('delete', {
index,
tempFile: this.files[index],
tempFilePath: this.files[index].url
})
@@ -545,7 +573,7 @@
let data = []
if (this.returnType === 'object') {
data = this.backObject(this.files)[0]
this.localValue = data?data:null
this.localValue = data ? data : null
} else {
data = this.backObject(this.files)
if (!this.localValue) {
@@ -575,8 +603,12 @@
name: v.name,
path: v.path,
size: v.size,
fileID:v.fileID,
url: v.url
fileID: v.fileID,
url: v.url,
// 修改删除一个文件后不能再上传的bug, #694
uuid: v.uuid,
status: v.status,
cloudPath: v.cloudPath
})
})
return newFilesData
@@ -634,14 +666,6 @@
color: #999;
}
.is-add {
/* #ifndef APP-NVUE */
display: flex;
/* #endif */
align-items: center;
justify-content: center;
}
.icon-add {
width: 50px;
height: 5px;

View File

@@ -8,8 +8,7 @@
<!-- ,'is-list-card':showType === 'list-card' -->
<view class="uni-file-picker__lists-box" v-for="(item ,index) in list" :key="index" :class="{
'files-border':index !== 0 && styles.dividline}"
:style="index !== 0 && styles.dividline &&borderLineStyle">
'files-border':index !== 0 && styles.dividline}" :style="index !== 0 && styles.dividline &&borderLineStyle">
<view class="uni-file-picker__item">
<!-- :class="{'is-text-image':showType === 'list'}" -->
<!-- <view class="files__image is-text-image">
@@ -22,8 +21,7 @@
</view>
</view>
<view v-if="(item.progress && item.progress !== 100) ||item.progress===0 " class="file-picker__progress">
<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4"
:backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
<progress class="file-picker__progress-item" :percent="item.progress === -1?0:item.progress" stroke-width="4" :backgroundColor="item.errMsg?'#ff5a5f':'#EBEBEB'" />
</view>
<view v-if="item.status === 'error'" class="file-picker__mask" @click.stop="uploadFiles(item,index)">
点击重试
@@ -37,7 +35,7 @@
<script>
export default {
name: "uploadFile",
emits:['uploadFiles','choose','delFile'],
emits: ['uploadFiles', 'choose', 'delFile'],
props: {
filesList: {
type: Array,
@@ -70,9 +68,9 @@
}
}
},
readonly:{
type:Boolean,
default:false
readonly: {
type: Boolean,
default: false
}
},
computed: {
@@ -322,4 +320,4 @@
}
/* #endif */
</style>
</style>

View File

@@ -16,12 +16,9 @@
</view>
</view>
</view>
<view v-if="filesList.length < limit && !readonly" class="file-picker__box" :style="boxStyle">
<view v-if="filesList.length < limit" class="file-picker__box" :style="boxStyle">
<view class="file-picker__box-content is-add" :style="borderStyle" @click="choose">
<slot>
<view class="icon-add"></view>
<view class="icon-add rotate"></view>
</slot>
<slot></slot>
</view>
</view>
</view>
@@ -145,12 +142,15 @@
this.$emit("uploadFiles", item)
},
choose() {
if(this.readonly) return
this.$emit("choose")
},
delFile(index) {
if(this.readonly) return
this.$emit('delFile', index)
},
prviewImage(img, index) {
if(this.readonly) return
let urls = []
if(Number(this.limit) === 1&&this.disablePreview&&!this.disabled){
this.$emit("choose")
@@ -254,13 +254,6 @@
justify-content: center;
}
.icon-add {
width: 50px;
height: 5px;
background-color: #f1f1f1;
border-radius: 2px;
}
.rotate {
position: absolute;
transform: rotate(90deg);

View File

@@ -90,6 +90,7 @@ export const get_file_data = async (files, type = 'image') => {
extname: extname || '',
cloudPath: files.cloudPath,
fileType: files.fileType,
thumbTempFilePath: files.thumbTempFilePath,
url: files.path || files.path,
size: files.size, //单位是字节
image: {},