zhao_js
2023-11-21 19d5fa154937406af1dc8dc017a68c04e55e00ca
no message
已添加6个文件
已修改5个文件
1676 ■■■■■ 文件已修改
H5/manifest.json 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/pages.json 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/pages/ad_page/sms_examine.vue 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/pages/ad_page/wx_pyqset.vue 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/uni_modules/cl-upload/changelog.md 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/uni_modules/cl-upload/components/cl-image/cl-image.vue 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/uni_modules/cl-upload/components/cl-upload/cl-upload.vue 1031 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/uni_modules/cl-upload/package.json 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/uni_modules/cl-upload/readme.md 253 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
H5/utils/ComUtils.js 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api/.vs/FxProject/v16/.suo 补丁 | 查看 | 原始文档 | blame | 历史
H5/manifest.json
@@ -86,7 +86,13 @@
                    "target" : "http://124.70.216.149:8083", //测试环境
                    "changeOrigin" : true, //是否跨域
                    "secure" : true // æ˜¯å¦æ”¯æŒ https åè®®çš„代理
                }
                },
                "/api/" : {
                    //映射域名
                    "target" : "http://localhost:24147", //测试环境
                    "changeOrigin" : true, //是否跨域
                    "secure" : true // æ˜¯å¦æ”¯æŒ https åè®®çš„代理
                }
            }
        }
    }
H5/pages.json
@@ -74,6 +74,14 @@
            }
        },
        {
            "path": "pages/ad_page/wx_pyqset",
            "style": {
                "navigationBarTitleText": "朋友圈设置",
                "navigationBarTextStyle": "black",
                "navigationBarBackgroundColor": "#ffffff"
            }
        },
        {
            "path": "pages/ad_page/trans",
            "style": {
                "navigationStyle": "custom",
H5/pages/ad_page/sms_examine.vue
@@ -1,5 +1,10 @@
<template>
    <view class="container" style="height: auto;">
        <view style="margin: 0.5rem;">
            <button class="mini-btn" style="background-color: cornflowerblue; margin-right: 10px;" type="primary" size="mini">短信审核</button>
            <button @click="toPyq()" class="mini-btn" type="default" size="mini">微信朋友圈</button>
        </view>
        <v-tabs v-model="currentTab" :tabs="tabList" :pills="true" line-height="0" activeColor="#fff"
            @change="changeTab" pillsColor="#FF928F" :fixed="true"></v-tabs>
        <cc-pullScroolView class="pullScrollView" ref="pullScroll" :enablePullDown="false" :back-top="false">
@@ -97,12 +102,11 @@
                curPageNum: 1,
                pageCount: 10,
                totalNum: 0,
                checkType: '',
                whiteid: "ocUrg6nVVPhn-m6yNPg7igYnB64g,ocUrg6ud9UqAdLpqnA2sSf24EFd4,ocUrg6klrlpbPTnzMDr6R8WDmOXU,ocUrg6qawIzxqqzOHYy2a9YSfx_0"
                checkType: ''
            }
        },
        onLoad(option) {
            this.checkId();
            //this.checkId();
        },
        // ä¸Šæ‹‰åŠ è½½
@@ -115,16 +119,23 @@
            }
        },
        methods: {
            toPyq()
            {
                uni.navigateTo({
                    url:'/pages/ad_page/wx_pyqset'
                })
            },
            //检查白名单
            checkId() {
                 var openId = uni.getStorageSync('smsopenid');
                if (openId == "" || this.whiteid.indexOf(openId) < 0) {
                var openId = uni.getStorageSync('smsopenid');
                 var whiteid=comUtils.getSmsStatus(status);
                if (openId == "" || whiteid.indexOf(openId) < 0) {
                    uni.reLaunch({
                        url: '/pages/emptypage/nopermissions'
                    })
                } else {
                    this.getTemplateData();
                }
                }
            },
            copy(taskid) {
                uni.setClipboardData({
H5/pages/ad_page/wx_pyqset.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,126 @@
<template>
    <view class="container" style="height: auto;">
        <view style="margin: 0.5rem;">
            <button class="mini-btn" style="margin-right: 10px;" type="default" size="mini">短信审核</button>
            <button class="mini-btn" style="background-color: cornflowerblue;" type="primary" size="mini">微信朋友圈</button>
        </view>
        <view style="display: flex;justify-content: center; flex-direction: column; /">
            <view>
                <textarea maxlength="492" v-model="content" class="smstxt" placeholder="请输入朋友圈文案"
                    placeholder-class="text-color-assist font-size-base"></textarea>
            </view>
            <view>
                <textarea maxlength="492" v-model="commnet" class="smstxt" placeholder="请输入评论(非必填)"
                    placeholder-class="text-color-assist font-size-base"></textarea>
            </view>
            <view>
                <cl-upload action="/api/automanage/uploadpublicfile" @onSuccess="onSuccess" v-model="list" :listStyle="{
                        columns: 2,
                        columnGap: '20rpx',
                        rowGap:'20rpx',
                        padding:'10rpx',
                        height:'300rpx',
                        radius:'20rpx'
                    }">
                    <template v-slot:addImg>
                        <view class="newAddImg">
                            <view>+</view>
                            <text>添加</text>
                        </view>
                    </template>
                </cl-upload>
            </view>
        </view>
        <view style="text-align: center;margin-top: 3rem;">
            <button @click="addSet()"
                style="width: 10rem;height: 3rem; line-height: 3rem; font-size: 20px; color: #fff; background: green;"
                class="mini-btn" type="default" size="mini">提交</button>
        </view>
    </view>
</template>
<script>
    import comUtils from '@/utils/ComUtils.js'
    export default {
        data() {
            return {
                content: '',
                list: [],
                commnet: ''
            }
        },
        onLoad(option) {
            //this.checkId();
        },
        methods: {
            //检查白名单
            checkId() {
                var openId = uni.getStorageSync('smsopenid');
                var whiteid = comUtils.getSmsStatus(status);
                if (openId == "" || whiteid.indexOf(openId) < 0) {
                    uni.reLaunch({
                        url: '/pages/emptypage/nopermissions'
                    })
                } else {
                    this.getTemplateData();
                }
            },
            onSuccess(reslut) {
                // æŠŠæœåŠ¡ç«¯è¿”å›žçš„å›¾ç‰‡åœ°å€æ·»åŠ åˆ°list中与组件数据同步
                this.list.push(reslut.result)
            },
            addSet() {
                var param = {
                    Content: this.content,
                    PicList: this.list,
                    Commnet: this.commnet
                }
                var that=this;
                that.$http.post('/api/AutoManage/AddPyq', param).then(e => {
                    uni.hideLoading();
                    if (e.result) {
                        uni.showToast({
                            title: '操作成功!',
                            icon: 'none'
                        });
                        that.content='';
                        that.list=[];
                        that.commnet='';
                    } else {
                        uni.showToast({
                            title: '操作失败!',
                            icon: 'none'
                        });
                    }
                }).catch(function(err) {
                    uni.hideLoading()
                    console.log(err);
                })
            }
        }
    }
</script>
<style lang="scss" scoped>
    page {
        background: #fff;
        height: 100%;
    }
    .smstxt {
        width: 90%;
        margin-top: 2rem;
        border: 1px solid;
    }
    .newAddImg {
        width: 8rem;
        border: 1px solid;
        height: 8rem;
        display: flex;
        justify-content: center;
        flex-direction: column;
        text-align: center;
    }
</style>
H5/uni_modules/cl-upload/changelog.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,77 @@
## 1.4.0(2023-07-04)
新增unicloud启用目录选项
## 1.3.9(2023-06-28)
修复属性选择器警告提示
## 1.3.8(2023-06-02)
手动上传没有可上传文件时返回空数组; æé«˜ä»£ç è´¨é‡å’Œå¯é˜…读性;
## 1.3.7(2023-05-22)
新增自定义视频封面配置; æ–°å¢žæ·»åŠ æŒ‰é’®æ’æ§½
## 1.3.6(2023-05-22)
添加自定义图片资源配置
## 1.3.5(2023-05-04)
修复小程序cloudType为other的时候获取不到视频删除按钮焦点问题
## 1.3.4(2023-04-27)
修复小程序unicloud自动上传不自动同步数据问题
## 1.3.3(2023-04-27)
修复删除按钮层级问题
## 1.3.2(2023-04-24)
修复安卓APP配置cloudType:other æ— æ³•显示http封面问题
## 1.3.1(2023-04-19)
修改版本信息
## 1.3.0(2023-04-19)
修复手动上传已知问题; æ–°å¢žåˆ é™¤å‰ï¼Œä¸Šä¼ å‰é’©å­å‡½æ•°
## 1.2.9(2023-03-22)
修复已知问题
## 1.2.8(2023-03-22)
修复已知问题
## 1.2.7(2023-03-21)
修复部分视频封面白屏问题
## 1.2.6(2023-03-21)
修复部分视频封面白屏问题
## 1.2.5(2023-03-08)
兼容vue3中v-model数据绑定
## 1.2.4(2023-03-06)
1.修复低版本微信小程序video图层兼容问题;
2.修复unicloud上传v-model不同步问题;
## 1.2.3(2023-02-02)
添加限制图片视频大小功能
## 1.2.2(2023-02-01)
兼容支付宝小程序手动上传视频
## 1.2.1(2023-01-31)
更新图片资源地址
## 1.2.0(2022-12-12)
兼容uniCloud上传
## 1.1.9(2022-12-12)
1. æ·»åŠ æœ€å¤§è§†é¢‘é™åˆ¶
2. ä¼˜åŒ–部分功能
## 1.1.8(2022-12-09)
修复部分设备上传视频第一帧黑屏问题
## 1.1.7(2022-12-01)
修复h5上传开启压缩后一直显示“正在压缩中”问题
## 1.1.6(2022-11-24)
兼容支付宝小程序手动上传
## 1.1.5(2022-11-07)
添加加载配置
## 1.1.4(2022-11-07)
修复图片限制数量后可以多次选择最大数量图片问题
## 1.1.3(2022-10-28)
添加提示弹窗配置
## 1.1.1(2022-10-28)
修复已知问题
## 1.1.0(2022-08-25)
修复base64压缩问题
## 1.0.9(2022-08-25)
修复服务器返回数据格式问题
## 1.0.8(2022-08-01)
优化代码格式、逻辑
## 1.0.6(2022-07-30)
修改已知问题
## 1.0.5(2022-07-30)
1. aspect-ratio兼容问题,添加height属性保底
2. æ·»åŠ ç›‘å¬ä¸Šä¼ è¿›åº¦å˜åŒ–äº‹ä»¶
## 1.0.3(2022-07-30)
添加按钮控制,事件说明
## 1.0.2(2022-07-30)
优化服务器接口返回数据上传
## 1.0.1(2022-07-29)
初始化组件
H5/uni_modules/cl-upload/components/cl-image/cl-image.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,60 @@
<template>
    <image class="image" :src="imgSrc" mode="aspectFill" :disabled="false" :controls='false' @error="imgerror"></image>
</template>
<script>
    export default {
        props: {
            src: {
                type: String,
                default: ''
            },
            cloudType: {
                type: String,
                default: 'oss'
            },
        },
        data() {
            return {
                imgSrc: ''
            };
        },
        mounted() {
            this.setCloudFunction()
        },
        methods: {
            imgerror(even) {
                this.imgSrc =  `https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/887c60f0-27f8-46d1-8769-2c45be0f3d7d.png`
            },
            setCloudFunction() {
                const fileType = this.src.split('.').pop();
                const IMAGE_REGEXP = /(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg|image)/i
                if (IMAGE_REGEXP.test(fileType)) {
                    return this.imgSrc = this.src;
                }
                switch (this.cloudType){
                    case 'oss':
                        this.imgSrc = this.src + '?x-oss-process=video/snapshot,t_0,f_jpg'
                        break;
                    case 'process':
                        this.imgSrc = this.src + '?ci-process=snapshot&time=0.01'
                        break;
                    case 'vframe':
                        this.imgSrc = this.src + '?vframe/jpg/offset/0'
                        break;
                    default:
                        this.imgSrc = this.src
                        break;
                }
            }
        }
    }
</script>
<style lang="scss" scoped>
    .image {
        width: 100%;
        height: 100%;
    }
</style>
H5/uni_modules/cl-upload/components/cl-upload/cl-upload.vue
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,1031 @@
<template>
    <view class="cl-updata">
        <view class="file-list" :style="[listRowStyle]">
            <view v-for="(item, index) in previewList" @tap="clickSelectedFile(item, index)" class="file-list-row"
                :style="[rowStyle]" :key="index">
                <image
                    class="_image"
                    v-if="fileUrlType(item) === 'image'"
                    :src="item.path"
                    :style="[imgStyle]"
                    mode="aspectFill">
                </image>
                <view v-else class="_video" :style="[imgStyle]">
                    <!-- #ifdef MP-WEIXIN || MP-ALIPAY -->
                    <video
                        v-if="!autoUpload || cloudType === 'other'"
                        class="_video"
                        :style="[imgStyle]"
                        :src="item.path"
                        :show-center-play-btn="false"
                        :show-fullscreen-btn="false"
                        :show-play-btn="false"
                        :show-loading="false"
                        :enable-progress-gesture="false"
                        :controls="false">
                        <view @tap="previewVideo(item, index)" class="play">
                            <image style="width: 100%;" :src="playImg" mode="widthFix"></image>
                        </view>
                    </video>
                    <!-- #endif -->
                    <!-- #ifdef APP-PLUS -->
                    <video
                        v-if="cloudType === 'other'"
                        class="_video"
                        :style="[imgStyle]"
                        :src="item.path"
                        :poster="item.path"
                        :controls="false"
                        :show-center-play-btn="false"
                        :show-fullscreen-btn="false"
                        :show-play-btn="false"
                        :show-loading="false"
                        :enable-progress-gesture="false">
                        <cover-image class="app_play" :src="playImg" @tap="previewVideo(item, index)"></cover-image>
                        <cover-view class="remove" v-if="remove" @tap="deleteSelectedFile(item, index)">
                            <cover-image class="image" :src="deleteImg" mode="widthFix" @tap="deleteSelectedFile(item, index)"></cover-image>
                        </cover-view>
                    </video>
                    <!-- #endif -->
                    <!-- #ifndef MP-WEIXIN || MP-ALIPAY || APP-PLUS -->
                    <video
                        v-if="cloudType === 'other'"
                        class="_video"
                        :autoplay="false"
                        :style="[imgStyle]"
                        :src="item.path"
                        :controls="false"
                        :show-center-play-btn="false"
                        :show-fullscreen-btn="false"
                        :show-play-btn="false"
                        :show-loading="false"
                        :enable-progress-gesture="false" >
                        <cover-view  @tap="previewVideo(item, index)" class="play">
                            <cover-image style="width: 100%;" :src="playImg" mode="widthFix"></cover-image>
                        </cover-view>
                    </video>
                    <!-- #endif -->
                    <template v-else>
                        <cl-image class="pay" :style="[imgStyle]" :cloudType="cloudType"
                            :src="(item.poster || item.path)"></cl-image>
                        <view class="play" @tap="previewVideo(item, index)">
                            <image class="play-img" :src="playImg" mode="widthFix"></image>
                        </view>
                    </template>
                </view>
                <view class="remove" v-if="remove" @tap.stop="deleteSelectedFile(item, index)">
                    <image class="image" :src="deleteImg" mode="widthFix"></image>
                </view>
            </view>
            <view v-if="add && FileList.length < max" @tap="selectFileTypeOnAdd" :style="[rowStyle]" class="file-list-row">
                <slot name="addImg">
                    <div class="add-image">
                        <image class="_image" :src="addImg" mode="widthFix"></image>
                    </div>
                </slot>
            </view>
        </view>
        <view v-if="tempVideoUrl" class="mask">
            <image @tap="tempVideoUrl = ''" class="_root" :src="closeImg" mode="widthFix"></image>
            <view class="block" @tap.stop>
                <video class="block_video" autoplay :src="tempVideoUrl"></video>
            </view>
        </view>
    </view>
</template>
<script>
import ClImage from '../cl-image/cl-image.vue'
export default {
    name: "cl-upload",
    components: { ClImage },
    props: {
        //受控图片列表
        // #ifdef VUE2
        value: {
            type: Array,
            default: () => [],
        },
        // #endif
        // #ifdef VUE3
        modelValue: {
            type: Array,
            default: () => [],
        },
        // #endif
        // å­˜å‚¨äº‘类型 oss阿里云  vframe七牛云   process腾讯云  other其他
        cloudType: {
            type: String,
            default: 'oss'
        },
        // æ ‡è¯†ç¬¦,即后端接口参数名
        fileName: {
            type: String,
            default: 'file'
        },
        // æ–‡ä»¶ç±»åž‹ 'image', 'video', 'all'
        fileType: {
            type: String,
            default: 'all'
        },
        // ä¸Šä¼ å›¾ç‰‡å‚æ•°
        imageFormData: {
            type: Object | null,
            default: () => { }
        },
        // ä¸Šä¼ è§†é¢‘参数
        videoFromData: {
            type: Object,
            default: () => { }
        },
        // å¿…选参数,上传的地址
        action: {
            type: String,
            default: ''
        },
        // å¯ç”¨ç›®å½•, ä»…unicloud阿里云支持
        // https://uniapp.dcloud.net.cn/uniCloud/storage.html#storage-dir
        cloudPathAsRealPath: {
            type: Boolean,
            default: false
        },
        // è®¾ç½®ä¸Šä¼ çš„请求头部
        headers: {
            type: Object,
            default: () => { }
        },
        // ä¸Šä¼ æ—¶é™„带的额外参数
        data: {
            type: Object,
            default: () => { }
        },
        // æ˜¯å¦å¼€å¯é¢„览图片
        isPreviewImage: {
            type: Boolean,
            default: true
        },
        // å›¾ç‰‡æŒ‡ç¤ºå™¨æ ·å¼ï¼Œå¯å–值:"default" - åº•部圆点指示器; "number" - é¡¶éƒ¨æ•°å­—指示器; "none" - ä¸æ˜¾ç¤ºæŒ‡ç¤ºå™¨ã€‚
        indicator: {
            type: String,
            default: 'none'
        },
        // æ˜¯å¦åœ¨é€‰å–文件后立即进行上传
        autoUpload: {
            type: Boolean,
            default: true
        },
        // æ˜¯å¦æ˜¾ç¤ºåˆ é™¤æŒ‰é’®
        remove: {
            type: Boolean,
            default: true
        },
        // æ˜¯å¦æ·»åŠ æŒ‰é’®
        add: {
            type: Boolean,
            default: true
        },
        // æœ€å¤šæ˜¾ç¤ºæ•°é‡
        max: {
            type: Number,
            default: 9
        },
        // è§†é¢‘最大上传数量
        maxVideo: {
            type: Number,
            default: 0
        },
        // åˆ—表样式
        listStyle: {
            type: Object,
            default: () => { }
        },
        // åˆ é™¤æç¤ºå¼¹çª—标题
        deleteTitle: {
            type: String,
            default: '提示'
        },
        // åˆ é™¤æç¤ºå¼¹çª—文案
        deleteText: {
            type: String,
            default: '您确认要删除吗?'
        },
        // åŠ è½½æ–‡æ¡ˆ
        loadingText: {
            type: String,
            default: '正在上传中...'
        },
        // æ˜¯å¦å¼€å¯åˆ é™¤å‰é’©å­
        useBeforeDelete: {
            type: Boolean,
            default: false
        },
        // æ˜¯å¦å¼€å¯ä¸Šä¼ å‰é’©å­
        useBeforeUpload: {
            type: Boolean,
            default: false
        },
        // æ·»åŠ æŒ‰é’®å›¾ç‰‡
        addImg: {
            type: String,
            default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/bb1550b3-e0a8-4a90-a86f-00f8c6afa9fb.png'
        },
        // æ’­æ”¾æŒ‰é’®å›¾ç‰‡
        playImg: {
            type: String,
            default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/ae40402f-aa53-4344-b553-2322799bebd6.png'
        },
        // åˆ é™¤æŒ‰é’®å›¾ç‰‡
        deleteImg: {
            type: String,
            default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/d20177a5-417e-4c5d-a266-1988361c543d.png'
        },
        // å…³é—­è§†é¢‘按钮图片
        closeImg: {
            type: String,
            default: 'https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/cde4362d-7ec7-4cac-a692-12e1f576be1e.png'
        },
    },
    data() {
        return {
            // æ¸²æŸ“列表
            FileList: [],
            // é¢„览视频地址
            tempVideoUrl: '',
            // ä¸´æ—¶æ–‡ä»¶åˆ—表
            tempFile_paths: [],
        };
    },
    watch: {
        // #ifdef VUE2
        'value': {
            handler: function (newVal, oldVal) {
                this.FileList = newVal;
            },
            deep: true,
            immediate: true
        },
        // #endif
        // #ifdef VUE3
        'modelValue': {
            handler: function (newVal, oldVal) {
                this.FileList = newVal;
            },
            deep: true,
            immediate: true
        },
        // #endif
    },
    computed: {
        previewList() {
            return this.FileList.map(item => {
                return {
                    path: item.path || item,
                    poster: item.poster || ''
                }
            })
        },
        listRowStyle() {
            const style = {
                'grid-template-columns': `repeat(${this.listStyle?.columns || 4}, 1fr)`, // æ¯è¡Œæ•°é‡
                'grid-column-gap': this.listStyle?.columnGap || '40rpx', // è¡Œé—´è·
                'grid-row-gap': this.listStyle?.rowGap || '40rpx', // åˆ—间距
                'padding': this.listStyle?.padding || '0rpx' // åˆ—表内边距
            }
            return style;
        },
        rowStyle() {
            const { height = '140rpx', ratio } = this.listStyle || {};
            const style = {
                'aspect-ratio': height ? '' : ratio || '1/1', // å›¾ç‰‡æ¯”例
                'height': height,
            };
            return style;
        },
        imgStyle() {
            const style = {
                'border-radius': this.listStyle?.radius || '6rpx', // å›¾ç‰‡åœ†è§’
            }
            return style;
        }
    },
    methods: {
        /**
         * åˆ é™¤å·²é€‰æ‹©æ–‡ä»¶
         * @param {object} item æ–‡ä»¶ä¿¡æ¯
         * @param {number} selectedFileIndex æ–‡ä»¶ç´¢å¼•
         * */
        deleteSelectedFile(item, selectedFileIndex) {
            const fileToDelete = this.FileList[selectedFileIndex];
            // åˆ é™¤å‰é’©å­
            if (this.useBeforeDelete) {
                this.$emit('beforeDelete', fileToDelete, selectedFileIndex, () => {
                    return deleteFileFromList()
                })
            }
            if (!this.useBeforeDelete) {
                uni.showModal({
                    title: this.deleteTitle,
                    content: this.deleteText,
                    success: (res) => {
                        if (res.confirm) {
                            deleteFileFromList()
                        }
                    }
                });
            }
            const deleteFileFromList = () => {
                const tempFileIndex = this.tempFile_paths.indexOf(item || item.path);
                if (tempFileIndex > -1) {
                    this.tempFile_paths.splice(tempFileIndex, 1)
                }
                this.FileList.splice(selectedFileIndex, 1)
                // #ifdef VUE2
                this.$emit('input', this.FileList)
                // #endif
                // #ifdef VUE3
                this.$emit("update:modelValue", this.FileList);
                // #endif
            }
        },
        /**
         * ç‚¹å‡»å·²é€‰æ‹©æ–‡ä»¶
         * @param {object} item æ–‡ä»¶ä¿¡æ¯
         * @param {number} index æ–‡ä»¶ç´¢å¼•
         * */
        clickSelectedFile(item, index) {
            this.previewImage(item?.path ?? item, index);
            this.$emit('onImage', {
                item,
                index
            })
        },
        /**
         * ç‚¹å‡»é€‰æ‹©å›¾ç‰‡æŒ‰é’®
         * */
        selectFileTypeOnAdd() {
            switch (this.fileType) {
                case 'image':
                    this.handleFileSelection(1);
                    break;
                case 'video':
                    this.handleFileSelection(2);
                    break;
                case 'all':
                    uni.showActionSheet({
                        itemList: ['相册', '视频'],
                        success: (res) => {
                            const tapIndex = res.tapIndex;
                            if (tapIndex === 0) {
                                this.handleFileSelection(1);
                            } else {
                                this.handleFileSelection(2);
                            }
                        },
                        fail: (res) => {
                            console.error(res.errMsg);
                        }
                    });
                    break;
                default:
                    this.handleFileSelection(1);
                    break;
            }
        },
        /**
         * ä»Žæœ¬åœ°é€‰æ‹©æ–‡ä»¶ã€‚
         * @param { number } updataType é€‰æ‹©ç±»åž‹ 1:图片 2视频
         * */
        async handleFileSelection(updataType) {
            const that = this;
            if (updataType === 1) {
                const data = Object.assign({}, {
                    // æœ€å¤šå¯ä»¥é€‰æ‹©çš„图片张数,默认9
                    count: 9,
                    // ä»…对 mediaType ä¸º image æ—¶æœ‰æ•ˆï¼Œæ˜¯å¦åŽ‹ç¼©æ‰€é€‰æ–‡ä»¶
                    // #ifndef MP-TOUTIAO
                    sizeType: ['original', 'compressed'],
                    // #endif
                    // album ä»Žç›¸å†Œé€‰å›¾ï¼Œcamera ä½¿ç”¨ç›¸æœºï¼Œé»˜è®¤äºŒè€…都有。
                    sourceType: ['camera', 'album'],
                    compress: false
                }, this.imageFormData)
                data['count'] = this.max - this.FileList.length
                uni.chooseImage({
                    ...data,
                    success: async (res) => {
                        let tempFiles = res.tempFiles
                        const compress = that.imageFormData?.compress || false;
                        // é™åˆ¶å›¾ç‰‡ä¸Šä¼ å°ºå¯¸
                        if (that.imageFormData?.size ?? false) {
                            const maxSize = that.imageFormData.size * 1024 * 1024
                            tempFiles.map((imgInfo, index) => {
                                if (imgInfo.size > maxSize) {
                                    tempFiles.splice(index, 1)
                                    that.$emit('onImageSize', imgInfo)
                                    return uni.showToast({
                                        title: `图片最大上传${that.imageFormData.size}MB`,
                                        duration: 2000,
                                        icon: 'none'
                                    });
                                }
                            })
                        }
                        // å¼€å¯åŽ‹ç¼©å›¾ç‰‡
                        if (compress) {
                            const compressedImagePathList = tempFiles.map(imageItem => {
                                return that.compressImage(imageItem.path)
                            })
                            Promise.all(compressedImagePathList).then(result => {
                                upload(result);
                            })
                        } else {
                            upload(tempFiles);
                        }
                        function upload(tempImages) {
                            if (that.autoUpload) {
                                tempImages.map(item => {
                                    that.onBeforeUploadFile(item, 'image')
                                })
                            } else {
                                that.FileList = [...that.FileList, ...tempImages]
                                tempImages.map(item => {
                                    that.tempFile_paths.push(item)
                                })
                            }
                        }
                    },
                    fail(err) {
                        console.error('选择图片失败', err)
                        that.$emit('onError', err)
                    }
                })
            }
            if (updataType === 2) {
                // é™åˆ¶è§†é¢‘最大上传数量
                const VIDEO_REGEXP = /\.(mp4|flv|avi)/i
                const videoList = await that.FileList.filter(item => {
                    const fileUrl = item?.url ?? item
                    return VIDEO_REGEXP.test(fileUrl)
                })
                if (that.maxVideo > 0 && videoList.length >= that.maxVideo) {
                    that.$emit('onVideoMax', that.maxVideo, videoList.length)
                    return uni.showToast({
                        title: '视频数量已超出',
                        duration: 2000,
                        icon: 'none'
                    });
                }
                const data = Object.assign({}, {
                    //     æ‹æ‘„视频最长拍摄时间,单位秒。最长支持 60 ç§’。
                    maxDuration: 60,
                    // #ifndef MP-TOUTIAO
                    // 'front'、'back',默认'back'
                    camera: "back",
                    // #endif
                    // album ä»Žç›¸å†Œé€‰è§†é¢‘,camera ä½¿ç”¨ç›¸æœºæ‹æ‘„,默认二者都有。
                    sourceType: ['camera', 'album'],
                    // æ˜¯å¦åŽ‹ç¼©æ‰€é€‰çš„è§†é¢‘æºæ–‡ä»¶ï¼Œé»˜è®¤å€¼ä¸º true,需要压缩。
                    compressed: true,
                    // 'front'、'back',默认'back'
                }, this.videoFromData)
                uni.chooseVideo({
                    ...data,
                    success: (res) => {
                        let tempFilePath = { ...res }
                        tempFilePath['path'] = res.tempFilePath
                        // é™åˆ¶è§†é¢‘上传尺寸
                        if (that.videoFromData?.size ?? false) {
                            const maxSize = that.videoFromData.size * 1024 * 1024
                            if (tempFilePath.size > maxSize) {
                                uni.showToast({
                                    title: `视频最大上传${that.videoFromData.size}MB`,
                                    duration: 2000,
                                    icon: 'none'
                                });
                                return false;
                            }
                        }
                        if (that.autoUpload) {
                            that.onBeforeUploadFile(tempFilePath, 'video')
                        } else {
                            that.FileList.push(tempFilePath)
                            that.tempFile_paths.push(tempFilePath)
                        }
                    },
                    fail(err) {
                        console.error('选择视频失败', err)
                    }
                })
            }
        },
        /**
         * ä¸Šä¼ å‰é’©å­
         * @param { tempFile } ä¸´æ—¶æ–‡ä»¶
         * @return { Promise }
         * */
        onBeforeUploadFile(tempFile) {
            if (this.useBeforeUpload) {
                return this.$emit('beforeUpload', tempFile, () => {
                    return this.updataFile(tempFile);
                })
            }
            return this.updataFile(tempFile);
        },
        /**
         * ä¸Šä¼ æ–‡ä»¶åˆ°æœåС噍
         * @param { tempFile } ä¸´æ—¶æ–‡ä»¶
         * @return { Promise }
         * */
        updataFile(tempFile) {
            const that = this;
            const filePath = tempFile.path || tempFile;
            const fileType = this.fileUrlType(filePath) == 'image' ? '.png' : '.mp4';
            const fileName = tempFile.name || Date.now() + fileType;
            uni.showLoading({
                title: this.loadingText,
                icon: 'loading'
            })
            return new Promise((resolve, reject) => {
                // uniCloud上传
                if (that.action === 'uniCloud') {
                    uniCloud.uploadFile({
                        cloudPath: String(fileName),
                        filePath: filePath,
                        // #ifdef MP-ALIPAY
                        fileType: fileType,
                        // #endif
                        cloudPathAsRealPath: this.cloudPathAsRealPath,
                        onUploadProgress: (progressEvent) => {
                            const percentCompleted = Math.round(
                                (progressEvent.loaded * 100) / progressEvent.total
                            );
                            that.$emit('onProgress', percentCompleted)
                        },
                        success(result) {
                            if (that.autoUpload) {
                                that.FileList.push(result.fileID)
                            } else {
                                that.FileList.map((item, index) => {
                                    if (item === filePath || item.path === filePath) {
                                        that.FileList.splice(index, 1, result.fileID)
                                    }
                                })
                            }
                            // #ifdef VUE2
                            that.$emit('input', that.FileList)
                            // #endif
                            // #ifdef VUE3
                            that.$emit("update:modelValue", that.FileList);
                            // #endif
                            resolve(result.fileID)
                            uni.hideLoading();
                            that.$emit('onProgress', {
                                ...result
                            })
                        },
                        fail: (error) => {
                            uni.hideLoading();
                            console.error('error', error);
                            that.$emit('onError', error)
                            reject(error)
                        }
                    })
                    return false;
                }
                // æŽ¥å£æœåŠ¡ä¸Šä¼ 
                const uploadTask = uni.uploadFile({
                    url: that.action,
                    filePath: filePath,
                    name: that.fileName,
                    formData: that.data,
                    header: that.headers,
                    // #ifdef MP-ALIPAY
                    fileType: filetype,
                    // #endif
                    success: (uploadFileRes) => {
                        const data = JSON.parse(uploadFileRes.data)
                        uni.hideLoading();
                        that.success(data)
                        if (!this.autoUpload) {
                            that.FileList.map((item, index) => {
                                if (item === filePath || item.path === filePath) {
                                    that.FileList.splice(index, 1)
                                }
                            })
                        }
                        resolve(data)
                    },
                    fail: (error) => {
                        uni.hideLoading();
                        console.error('error', error);
                        that.$emit('onError', error)
                        reject(error)
                    }
                });
                uploadTask.onProgressUpdate((res) => {
                    that.$emit('onProgress', {
                        ...res,
                        ...tempFile
                    })
                });
            })
        },
        /**
         * æ‰‹åŠ¨ä¸Šä¼ 
         * */
        submit() {
            return new Promise((resolve, reject) => {
                if (this.tempFile_paths.length <= 0) {
                    resolve([])
                }
                const uploadedFilePaths = this.tempFile_paths.map(item => {
                    return this.onBeforeUploadFile(item || item.path)
                })
                Promise.all(uploadedFilePaths).then(res => {
                    this.tempFile_paths = []
                    resolve(res)
                }).catch(err => {
                    reject(err)
                })
            })
        },
        /**
         * è¿”回数据
         * @param {array} data ä¸Šä¼ æˆåŠŸåŽçš„æ•°æ®
         * @return {array} è¿”回数据
         * */
        success(data) {
            this.$emit('onSuccess', data);
            // è‡ªå®šä¹‰æ•°æ®ç»“æž„-选择性开启
            // const list = data.map(item=> {
            //     return JSON.parse(item).data.link;
            // })
            // this.$emit('input', [...this.FileList, ...list]);
        },
        /**
         * åŽ‹ç¼©å›¾ç‰‡
         * @param {array} tempFilePaths ä¸´æ—¶è·¯å¾„数组
         * @return {array} è¢«åŽ‹ç¼©è¿‡çš„è·¯å¾„æ•°ç»„
         * */
        async compressImage(tempFilePaths) {
            const that = this;
            return new Promise((resolve, reject) => {
                if (typeof tempFilePaths !== 'string') {
                    console.error('压缩路径错误')
                    reject([])
                }
                uni.showLoading({
                    title: '压缩中...',
                    icon: 'loading',
                })
                // #ifdef H5
                this.canvasDataURL(tempFilePaths, {
                    quality: that.imageFormData.quality / 100
                }, (base64Codes) => {
                    resolve(base64Codes);
                    uni.hideLoading();
                })
                // #endif
                // #ifndef H5
                uni.compressImage({
                    src: tempFilePaths,
                    quality: that.imageFormData.quality || 80,
                    success: res => {
                        resolve(res.tempFilePath);
                        uni.hideLoading();
                    },
                    fail(err) {
                        reject(err);
                        uni.hideLoading();
                    }
                })
                // #endif
            })
        },
        /**
         * H5压缩图片质量
         * @param {string} path å›¾ç‰‡è·¯å¾„
         * @param {object} obj åŽ‹ç¼©é…ç½®
         * @param {function} callback å›žè°ƒå‡½æ•°
         * @return {string} base64
         * */
        canvasDataURL(path, obj, callback) {
            var img = new Image();
            img.src = path;
            img.onload = function () {
                var that = this;
                // é»˜è®¤æŒ‰æ¯”例压缩
                var w = that.width,
                    h = that.height,
                    scale = w / h;
                w = obj.width || w;
                h = obj.height || (w / scale);
                var quality = 0.8; // é»˜è®¤å›¾ç‰‡è´¨é‡ä¸º0.8
                //生成canvas
                var canvas = document.createElement('canvas');
                var ctx = canvas.getContext('2d');
                // åˆ›å»ºå±žæ€§èŠ‚ç‚¹
                var anw = document.createAttribute("width");
                anw.nodeValue = w;
                var anh = document.createAttribute("height");
                anh.nodeValue = h;
                canvas.setAttributeNode(anw);
                canvas.setAttributeNode(anh);
                ctx.drawImage(that, 0, 0, w, h);
                // å›¾åƒè´¨é‡
                if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
                    quality = obj.quality;
                }
                // quality值越小,所绘制出的图像越模糊
                var base64 = canvas.toDataURL('image/jpeg', quality);
                // å›žè°ƒå‡½æ•°è¿”回base64的值
                callback(base64);
            }
        },
        /**
         * é¢„览图片
         * @param {string, object} item æ–‡ä»¶ä¿¡æ¯
         * */
        previewImage(item) {
            if (this.fileUrlType(item) === 'video') return false;
            if (!this.isPreviewImage) return false;
            const imgs = this.FileList.filter(item => {
                return this.fileUrlType(item) !== 'video'
            }).map(item => item?.path ?? item)
            const current = imgs.indexOf(item || item.path);
            uni.previewImage({
                current: current,
                urls: imgs,
                success() {
                },
                fail(err) {
                    console.log(err);
                }
            })
        },
        /**
         * é¢„览视频
         * @param {string, object} item æ–‡ä»¶ä¿¡æ¯
         * @param {number} index ç´¢å¼•
         * */
        previewVideo(item, index) {
            this.$emit('onVideo', {
                item,
                index
            })
            this.tempVideoUrl = item.path;
        },
        /**
         * æ˜¯å¦img类型
         * @param {string, object} item æ–‡ä»¶ä¿¡æ¯
         * @return {boolean} æ˜¯å¦img类型
         * */
        fileUrlType(file) {
            const filePath = file.path || file;
            if (this.isBase64(filePath)) return 'image'
            const fileType = filePath.split('.').pop();
            const IMAGE_REGEXP = /(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg|image)/i
            if (IMAGE_REGEXP.test(fileType)) {
                return 'image';
            } else {
                return 'video';
            }
        },
        // åˆ¤æ–­æ˜¯å¦æ˜¯base64
        isBase64(str) {
            if (str === '' || typeof str !== 'string') return console.error('文件路径错误, base64', str);
            return str.includes('blob:') || str.includes('data:image');
        }
    }
}
</script>
<style lang="scss" scoped>
.cl-updata {
    .file-list {
        display: grid;
        &-row {
            display: inline-flex;
            align-items: center;
            position: relative;
            .play-img {
                width: 100%;
            }
            ._image {
                height: 100%;
                width: 100%;
            }
            ._video {
                position: relative;
                width: 100%;
                height: 100%;
                overflow: hidden;
            }
            .video-fixed {
                position: absolute;
                top: 0;
                left: 0;
                bottom: 0;
                width: 100%;
                height: 100%;
                border-radius: 10rpx;
                z-index: 96;
            }
            .play {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: 30%;
                z-index: 95;
            }
            .app_play {
                position: absolute;
                top: 50%;
                left: 50%;
                transform: translate(-50%, -50%);
                width: 50rpx;
                height: 50rpx;
            }
            .remove {
                position: absolute;
                top: 0;
                right: 0;
                background-color: #373737;
                height: 50rpx;
                width: 50rpx;
                border-bottom-left-radius: 200rpx;
                z-index: 97;
                .image {
                    width: 20rpx;
                    height: 20rpx;
                    position: absolute;
                    right: 12rpx;
                    top: 12rpx;
                }
            }
        }
        .add-image {
            display: flex;
            align-items: center;
            justify-content: center;
            border: 2rpx dashed #ccc;
            width: 100%;
            height: 100%;
            border-radius: 5rpx;
            &:active {
                opacity: 0.8;
            }
            ._image {
                width: 40%;
            }
        }
    }
    .mask {
        background-color: #000;
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        z-index: 99;
        .block {
            padding: 0 30rpx;
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 100%;
            .block_video {
                width: 100%;
                height: 78vh;
            }
        }
        ._root {
            width: 60rpx;
            height: 60rpx;
            position: absolute;
            left: 40rpx;
            top: 5vh
        }
    }
}
</style>
H5/uni_modules/cl-upload/package.json
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,82 @@
{
  "id": "cl-upload",
  "displayName": "上传图片、视频 åŒ…括预览、压缩、手动上传、uniCloud上传 ç­‰åŠŸèƒ½",
  "version": "1.4.0",
  "description": "上传图片视频,支持手动自动上传,自定义样式,uniCloud上传、预览,删除等功能",
  "keywords": [
    "上传图片,上传视频,预览,删除,",
    "uniCloud上传"
],
  "repository": "",
  "engines": {
    "HBuilderX": "^3.5.3"
  },
  "dcloudext": {
    "type": "component-vue",
    "sale": {
      "regular": {
        "price": "0.00"
      },
      "sourcecode": {
        "price": "0.00"
      }
    },
    "contact": {
      "qq": ""
    },
    "declaration": {
      "ads": "无",
      "data": "无",
      "permissions": "无"
    },
    "npmurl": ""
  },
  "uni_modules": {
    "dependencies": [],
    "encrypt": [],
    "platforms": {
      "cloud": {
        "tcb": "y",
        "aliyun": "y"
      },
      "client": {
        "Vue": {
          "vue2": "y",
          "vue3": "y"
        },
        "App": {
          "app-vue": "u",
          "app-nvue": "u"
        },
        "H5-mobile": {
          "Safari": "y",
          "Android Browser": "y",
          "微信浏览器(Android)": "y",
          "QQ浏览器(Android)": "y"
        },
        "H5-pc": {
          "Chrome": "y",
          "IE": "y",
          "Edge": "y",
          "Firefox": "y",
          "Safari": "y"
        },
        "小程序": {
          "微信": "y",
          "阿里": "y",
          "百度": "u",
          "字节跳动": "y",
          "QQ": "u",
          "钉钉": "u",
          "快手": "u",
          "飞书": "u",
          "京东": "u"
        },
        "快应用": {
          "华为": "u",
          "联盟": "u"
        }
      }
    }
  }
}
H5/uni_modules/cl-upload/readme.md
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,253 @@
### cl-upload ä¸Šä¼ ç»„ä»¶
> æ”¯æŒæ‰‹åŠ¨è‡ªåŠ¨ä¸Šä¼ ï¼Œæ ·å¼è°ƒæ•´ï¼Œå‚æ•°é…ç½®ï¼Œé¢„è§ˆï¼Œåˆ é™¤ç­‰åŠŸèƒ½
> `注意:每次上传都需要回调函数接收参数并且添加到与组件绑定的数组中以保持数据一致,这样做是因为组件不知道服务端返回的数据格式,也可以在组件中修改promise格式 ä¸€åŠ³æ°¸é€¸`
### æ³¨æ„äº‹é¡¹
1. ratio å›¾ç‰‡æ¯”例属性部分手机不支持,可选用height属性代替
2. è‡ªå®šä¹‰æ’­æ”¾æŒ‰é’®éƒ¨åˆ†å¹³å°æœ‰å…¼å®¹æ€§é—®é¢˜ï¼Œå¯é€‰æ‹©æ€§å…³é—­
3. å¼€å¯åŽ‹ç¼©å›¾ç‰‡è¿”å›žçš„ä¸´æ—¶è·¯å¾„æ²¡æœ‰å°¾ç¼€ï¼Œå®˜æ–¹api的问题。真机上没问题,也可以在上传的时候手动添加尾缀
4. **视频地址必须`https`, http可能导致无法显示封面图**
5. å¦‚果没条件用`https`那就配置`cloudType: other`
### H5体验地址
![image](https://mp-61599c79-d7ee-4a75-a24b-e5a288da6dd3.cdn.bspapp.com/cloudstorage/eff364bc-65f7-47e0-ae4b-7d5f19b9f094.png)
#### list数据格式
1. æ•°ç»„格式
```
['地址1','地址2']
```
2. JSON格式
```
[
    {
        path: '地址1.png',
        // å…¶ä»–信息
    },
    {
        path: '地址2.mp4',
        poster: '自定义封面.png'
        // å…¶ä»–信息
    },
    {
        path: '地址3.mp4',
        poster: require('../../static/c1.png'), // å°é¢ä¹Ÿå¯ä»¥æ˜¯æœ¬åœ°å›¾ç‰‡
        // å…¶ä»–信息
    },
]
```
#### åŸºç¡€ä½¿ç”¨
```
<cl-upload v-model="list" action="请求地址" @onSuccess="onSuccess"></cl-upload>
methods: {
    /**
     * è‡ªåŠ¨ä¸Šä¼ è¿”å›žçš„æ˜¯ä¸€å¼ å›¾ç‰‡ä¿¡æ¯
     * æ‰‹åŠ¨ä¸Šä¼ è¿”å›žçš„æ˜¯å·²é€‰ä¸­æ‰€æœ‰å›¾ç‰‡æˆ–è€…è§†é¢‘ä¿¡æ¯
     * */
    onSuccess(reslut) {
        // æŠŠæœåŠ¡ç«¯è¿”å›žçš„å›¾ç‰‡åœ°å€æ·»åŠ åˆ°list中与组件数据同步
        this.list.push(reslut.url)
    },
}
```
### uniCloud上传
> ä¸€å¥ä»£ç å®žçŽ°ä¸Šä¼ ,就是这么简单
```
<cl-upload v-model="list" action="uniCloud"></cl-upload>
```
### è‡ªå®šä¹‰æ ·å¼
> é€šè¿‡ listStyle æŽ§åˆ¶æ¯è¡Œæ•°é‡ã€æ¯”例、行间距、列间距等常用样式
```
<cl-upload v-model="list" :listStyle="{
    columns: 2,
    columnGap: '20rpx',
    rowGap:'20rpx',
    padding:'10rpx',
    height:'300rpx',
    radius:'20rpx'
}">
    <template v-slot:addImg>
        <view class="newAddImg">
            <view>+</view>
            <text >添加</text>
        </view>
    </template>
</cl-upload>
```
### é¢„览模式
> å…³é—­æ˜¾ç¤ºæ·»åŠ æŒ‰é’®å’Œåˆ é™¤æŒ‰é’®
```
<cl-upload v-model="list" :add="false" :remove="false"></cl-upload>
```
### æ‰‹åŠ¨ä¸Šä¼ 
> é€šè¿‡ autoUpload å…³é—­æŽ‰è‡ªåŠ¨ä¸Šä¼ ï¼Œæäº¤çš„æ—¶å€™é€šè¿‡ refs ä¸»åŠ¨è°ƒç”¨ç»„ä»¶ä¸Šä¼ æ–¹æ³•ï¼Œè¿”å›žæœ¬æ¬¡æäº¤æˆåŠŸæœåŠ¡å™¨è¿”å›žæ•°æ®
```
<cl-upload
    ref="upload2"
    v-model="list2"
    :autoUpload="false"></cl-upload>
<button @tap="submit">手动提交</button>
methods: {
    submit() {
        /**
         * ä¸»åŠ¨è°ƒç”¨ç»„ä»¶ä¸Šä¼ æ–¹æ³•
         * */
        this.$refs.upload2.submit().then(reslut=>{
            console.log(reslut); // æœ¬æ¬¡æäº¤æˆåŠŸæœåŠ¡å™¨è¿”å›žæ•°æ®
            // ä¸Šä¼ ç¬¬ä¸‰æ–¹æœåŠ¡å™¨éœ€è¦æ‰‹åŠ¨åŒæ­¥æ•°æ®
            // ä¸Šä¼ uniCloud则不需要
            const imgUrls = reslut.list.map(imgInfo=> imgInfo.url);
            this.list2 = [...this.list2, ...imgUrls]
        })
    },
}
```
### é…ç½®åˆ é™¤å‰å’Œä¸Šä¼ å‰é’©å­
```
/ **
* å¼€å¯åˆ é™¤å‰é’©å­ useBeforeDelete
* å¼€å¯ä¸Šä¼ å‰é’©å­ useBeforeUpload
*/
<cl-upload v-model="list"
    useBeforeDelete
    useBeforeUpload
    @beforeDelete="beforeDelete"
    @beforeUpload="beforeUpload"></cl-upload>
methods: {
    /**
     * åˆ é™¤å‰é’©å­
     * @param {Object} item å½“前删除的图片或者视频信息
     * @param {Number} index å½“前删除的图片或视频索引
     * @param {Function} next è°ƒç”¨æ­¤å‡½æ•°ç»§ç»­æ‰§è¡Œç»„件删除逻辑
     * */
    beforeDelete(item, index, next) {
        uni.showModal({
            title: '提示信息',
            content: '确定要删除这个文件嘛?',
            success: res => {
                if (res.confirm) {
                    // æ¨¡æ‹ŸæœåŠ¡å™¨æŽ¥å£
                    setTimeout(() => {
                        next();
                    }, 1000);
                }
            }
        });
    },
    /**
     * ä¸Šä¼ å‰é’©å­
     * @param {Object} tempFile å½“前上传文件信息
     * @param {Function} next è°ƒç”¨æ­¤å‡½æ•°ç»§ç»­æ‰§è¡Œç»„件上传逻辑
     * */
    beforeUpload(tempFile, next) {
        // è‡ªå·±çš„上传逻辑
        // å¦‚果不需要走组件的上传逻辑就不用调用next(), ä½†æ˜¯ä¸Šä¼ å®Œè¦åŒæ­¥åˆ°list
    }
}
```
## API
| å‚æ•° | è¯´æ˜Ž | ç±»åž‹ | é»˜è®¤å€¼ | å¯é€‰å€¼ |
| --- | --- | --- | --- | --- |
| action | ä¸Šä¼ åœ°å€ | String |-| uniCloud |
| cloudPathAsRealPath | å¯ç”¨ç›®å½•, ä»…unicloud阿里云支持`1.4.0` `HBuilderX 3.8.5` | Boolean |false| true |
| cloudType | å­˜å‚¨äº‘类型(各个云服务截取封面方式不同。 other选项是video保底手段,部分平台有兼容性问题) | String |oss| é˜¿é‡Œäº‘:oss  ä¸ƒç‰›äº‘:vframe   è…¾è®¯äº‘:process  å…¶ä»–:other |
| headers | è®¾ç½®ä¸Šä¼ çš„请求头部 | Object | - |-  |
| data | ä¸Šä¼ æ—¶é™„带的额外参数 | Object | - | - |
| fileName| æ ‡è¯†ç¬¦,即后端接口参数名 | String | file | - |
| fileType | æ–‡ä»¶ç±»åž‹ | String | all | 'image', 'video', 'all' |
| imageFormData | ä¸Šä¼ å›¾ç‰‡å‚æ•° | Object | - | - |
| videoFromData | ä¸Šä¼ è§†é¢‘参数 | Object  | - | - |
| listStyle | åˆ—表样式 |Object  | - | - |
| isPreviewImage | æ˜¯å¦å¼€å¯é¢„览图片 | Boolean | true |false  |
| remove | æ˜¯å¦æ˜¾ç¤ºåˆ é™¤æŒ‰é’® | Boolean | true |false  |
| add | æ˜¯å¦æ·»åŠ æŒ‰é’® | Boolean | true |false  |
| max | æœ€å¤šæ˜¾ç¤ºæ•°é‡ | Number | 9 | -  |
| maxVideo | è§†é¢‘最大上传数量 | Number | ä¸é™åˆ¶ |  - |
| deleteTitle| åˆ é™¤æç¤ºå¼¹çª—标题 | String | æç¤º |  - |
| deleteText| åˆ é™¤æç¤ºå¼¹çª—文案 | String | æ‚¨ç¡®è®¤è¦åˆ é™¤å—? | - |
| loadingText| åŠ è½½æ–‡æ¡ˆ | String | æ­£åœ¨ä¸Šä¼ ä¸­... | - |
| useBeforeDelete| æ˜¯å¦å¼€å¯åˆ é™¤å‰é’©å­  | Boolean | false  | true |
| useBeforeUpload | æ˜¯å¦å¼€å¯ä¸Šä¼ å‰é’©å­ | Boolean | false  | true |
| addImg| æ·»åŠ æŒ‰é’®å›¾ç‰‡ | String | - |  - |
| playImg| æ’­æ”¾æŒ‰é’®å›¾ç‰‡ | String | - |  - |
| deleteImg| åˆ é™¤æŒ‰é’®å›¾ç‰‡ | String | - |  - |
| closeImg| å…³é—­è§†é¢‘按钮图片 | String | - |  - |
#### imageFormData
| å‚æ•° | è¯´æ˜Ž | ç±»åž‹ | é»˜è®¤å€¼ | å¯é€‰å€¼ |
| --- | --- | --- | --- | --- |
| count | æœ€å¤šå¯ä»¥é€‰æ‹©çš„图片张数 | number |9| - |
| sizeType | original åŽŸå›¾ï¼Œcompressed åŽ‹ç¼©å›¾ | array | é»˜è®¤äºŒè€…都有 |-  |
| sourceType | ç›¸å†Œæˆ–者相机 | array |  ['camera ', 'album'] | ['camera ', 'album']  |
| compress | æ˜¯å¦å¼€å¯å›¾ç‰‡åŽ‹ç¼© | Boolean | false | true  |
| quality | åŽ‹ç¼©è´¨é‡ | number | 80 | -  |
| size | å›¾ç‰‡å¤§å° | number | - | å•位MB |
#### videoFromData
| å‚æ•° | è¯´æ˜Ž | ç±»åž‹ | é»˜è®¤å€¼ | å¯é€‰å€¼ |
| --- | --- | --- | --- | --- |
| maxDuration | æ‹æ‘„视频最长拍摄时间 | number |60| æœ€å¤š60秒 |
| camera | å‰æ‘„像头后摄像头 | array | - |-  |
| compressed | æ˜¯å¦åŽ‹ç¼©æ‰€é€‰çš„è§†é¢‘æºæ–‡ä»¶ã€‚ | Boolean | true |-  |
| sourceType | ç›¸å†Œæˆ–者相机 | array |  ['camera ', 'album'] | ['camera ', 'album']  |
| size | è§†é¢‘大小 | number | - | å•位MB |
#### listStyle
| å‚æ•° | è¯´æ˜Ž | ç±»åž‹ | é»˜è®¤å€¼ | å¯é€‰å€¼ |
| --- | --- | --- | --- | --- |
| columns | æ¯è¡Œæ•°é‡ | number |4| - |
| columnGap | è¡Œé—´è· | string | '40rpx' |-  |
| rowGap | åˆ—间距 | string | '40rpx' |-  |
| padding | åˆ—表内边距 | string | '0 0rpx' |-  |
| ratio | å›¾ç‰‡æ¯”例 | string | '1/1' | ä½Žç‰ˆæœ¬æ‰‹æœºä¸æ”¯æŒ,可以选择height属性  |
| height | å›¾ç‰‡é«˜åº¦ | string | '140rpx' |-  |
| radius | å›¾ç‰‡åœ†è§’ | string | '6rpx' |-  |
#### Events
| äº‹ä»¶å | è¯´æ˜Ž | å›žè°ƒå‚æ•° |
| --- | --- | --- |
| onSuccess | ä¸Šä¼ æˆåŠŸ | data: æœåŠ¡å™¨è¿”å›žæ•°æ® |
| onError | ä¸Šä¼ å¤±è´¥ | error:错误信息 |
| onImage | ç‚¹å‡»å›¾ç‰‡ | item: å›¾ç‰‡ä¿¡æ¯ index: åˆ—表索引 |
| onVideo | ç‚¹å‡»è§†é¢‘ | item: è§†é¢‘信息 index: åˆ—表索引 |
| onProgress | ä¸Šä¼ è¿›ç¨‹ | onProgress参数说明|
| onVideoMax | è§¦å‘视频最大数量限制 | maxVideo, fileLength|
| onImageSize | è§¦å‘图片最大尺寸限制 | å›¾ç‰‡ä¿¡æ¯ |
| beforeDelete | åˆ é™¤å‰é’©å­ | item: æ–‡ä»¶ä¿¡æ¯ index:文件索引 next:继续执行删除逻辑 |
| beforeUpload | ä¸Šä¼ å‰é’©å­ | tempFile: æ–‡ä»¶ä¿¡æ¯ next:继续执行删除逻辑 |
#### onProgress参数说明
| äº‹ä»¶å | è¯´æ˜Ž |
| --- | --- |
| progress | ä¸Šä¼ è¿›åº¦ç™¾åˆ†æ¯” |
| totalBytesSent | å·²ç»ä¸Šä¼ çš„æ•°æ®é•¿åº¦ |
| totalBytesExpectedToSend | é¢„期需要上传的数据总长度 |
### [遇到问题或者讨论 uniapp åŠ å…¥QQ群  553291781](https://jq.qq.com/?_wv=1027&k=5UkMN1QX)
H5/utils/ComUtils.js
@@ -29,6 +29,11 @@
    return fmt;
}
function getAllowdId()
{
    return "ocUrg6nVVPhn-m6yNPg7igYnB64g,ocUrg6ud9UqAdLpqnA2sSf24EFd4,ocUrg6klrlpbPTnzMDr6R8WDmOXU,ocUrg6qawIzxqqzOHYy2a9YSfx_0";
}
function getSmsStatus(status) {
    switch (status) {
        case 0:
@@ -80,5 +85,6 @@
    getUrlPar,
    formatDate,
    getSmsStatus,
    getBackSmsStatus
    getBackSmsStatus,
    getAllowdId
}
api/.vs/FxProject/v16/.suo
Binary files differ