|  | @@ -0,0 +1,298 @@
 | 
	
		
			
				|  |  | +<template>
 | 
	
		
			
				|  |  | +    <up-upload :fileList="fileList" @after-read="afterRead" @delete="deletePic" :max-count="maxCount" :accept="accept"
 | 
	
		
			
				|  |  | +        multiple />
 | 
	
		
			
				|  |  | +</template>
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +<script setup>
 | 
	
		
			
				|  |  | +import { ref, reactive, defineProps, defineEmits, getCurrentInstance, onUnmounted } from 'vue'
 | 
	
		
			
				|  |  | +// 4. 删除文件 临时附件直接删除 绑定过的放到待删除列表中,保存时清空
 | 
	
		
			
				|  |  | +// 5. 上传和清空附件返回列表,和单个附件 用于表单校验
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +const emit = defineEmits(['uploadCallback'])
 | 
	
		
			
				|  |  | +const props = defineProps({
 | 
	
		
			
				|  |  | +    accept: {
 | 
	
		
			
				|  |  | +        type: String,
 | 
	
		
			
				|  |  | +        default: "image"
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    maxCount: {
 | 
	
		
			
				|  |  | +        type: [String, Number],
 | 
	
		
			
				|  |  | +        default: 99
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    uploadCallback: {
 | 
	
		
			
				|  |  | +        type: Function
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    fileList: {
 | 
	
		
			
				|  |  | +        type: Array,
 | 
	
		
			
				|  |  | +        default: reactive([])
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    usetype: {
 | 
	
		
			
				|  |  | +        type: String,
 | 
	
		
			
				|  |  | +        default: 'default'
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    ownertable: {
 | 
	
		
			
				|  |  | +        type: String,
 | 
	
		
			
				|  |  | +        default: 'temporary'
 | 
	
		
			
				|  |  | +    },
 | 
	
		
			
				|  |  | +    ownerid: {
 | 
	
		
			
				|  |  | +        type: [String, Number],
 | 
	
		
			
				|  |  | +        default: 1
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +const { $Http } = getCurrentInstance().proxy;
 | 
	
		
			
				|  |  | +const deleteList = reactive([]); // 用于存储待删除的文件列表
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 文件读取后处理
 | 
	
		
			
				|  |  | +const afterRead = ({ file }) => {
 | 
	
		
			
				|  |  | +    file.forEach(v => {
 | 
	
		
			
				|  |  | +        // #ifdef H5
 | 
	
		
			
				|  |  | +        getArrayBuffer(v).then(data => {
 | 
	
		
			
				|  |  | +            data.data.url = v.url;
 | 
	
		
			
				|  |  | +            handleUploadFile(requestType(v), data.data)
 | 
	
		
			
				|  |  | +            props.fileList.push({
 | 
	
		
			
				|  |  | +                ...v,
 | 
	
		
			
				|  |  | +                status: 'uploading',
 | 
	
		
			
				|  |  | +                message: '上传中',
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        // #endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        // #ifndef H5
 | 
	
		
			
				|  |  | +        uni.getFileSystemManager().readFile({
 | 
	
		
			
				|  |  | +            filePath: v.url,
 | 
	
		
			
				|  |  | +            success: data => {
 | 
	
		
			
				|  |  | +                data.data.url = v.url;
 | 
	
		
			
				|  |  | +                handleUploadFile(requestType(v), data.data)
 | 
	
		
			
				|  |  | +                props.fileList.push({
 | 
	
		
			
				|  |  | +                    ...v,
 | 
	
		
			
				|  |  | +                    status: 'uploading',
 | 
	
		
			
				|  |  | +                    message: '上传中',
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +            },
 | 
	
		
			
				|  |  | +            fail: console.error
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +        // #endif
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 获取文件类型信息
 | 
	
		
			
				|  |  | +const requestType = (file) => {
 | 
	
		
			
				|  |  | +    let ext = ''
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // #ifdef H5
 | 
	
		
			
				|  |  | +    ext = file.name.substring(file.name.lastIndexOf(".") + 1)
 | 
	
		
			
				|  |  | +    // #endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // #ifndef H5
 | 
	
		
			
				|  |  | +    ext = file.type?.split("/")[1] ||
 | 
	
		
			
				|  |  | +        file.url.substring(file.url.lastIndexOf(".") + 1) ||
 | 
	
		
			
				|  |  | +        file.name.substring(file.name.lastIndexOf(".") + 1)
 | 
	
		
			
				|  |  | +    // #endif
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return {
 | 
	
		
			
				|  |  | +        "classname": "system.attachment.huawei.OBS",
 | 
	
		
			
				|  |  | +        "method": "getFileName",
 | 
	
		
			
				|  |  | +        "content": {
 | 
	
		
			
				|  |  | +            "filename": `${Date.now() + file.size}.${ext}`,
 | 
	
		
			
				|  |  | +            "filetype": ext,
 | 
	
		
			
				|  |  | +            "parentid": uni.getStorageSync('siteP').appfolderid
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 处理文件上传
 | 
	
		
			
				|  |  | +const handleUploadFile = (file, data) => {
 | 
	
		
			
				|  |  | +    $Http.basic(file).then(res => {
 | 
	
		
			
				|  |  | +        console.log("上传文件成功", res)
 | 
	
		
			
				|  |  | +        if (res.msg == "成功") {
 | 
	
		
			
				|  |  | +            uploadFile(res.data, data)
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            uni.showToast({
 | 
	
		
			
				|  |  | +                title: `${file.content.filename}上传失败`,
 | 
	
		
			
				|  |  | +                icon: "none"
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 获取ArrayBuffer (H5专用)
 | 
	
		
			
				|  |  | +const getArrayBuffer = (file) => {
 | 
	
		
			
				|  |  | +    return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | +        const xhr = new XMLHttpRequest()
 | 
	
		
			
				|  |  | +        xhr.open('GET', file.url, true)
 | 
	
		
			
				|  |  | +        xhr.responseType = 'blob'
 | 
	
		
			
				|  |  | +        xhr.onload = function () {
 | 
	
		
			
				|  |  | +            if (this.status === 200) {
 | 
	
		
			
				|  |  | +                const myBlob = this.response
 | 
	
		
			
				|  |  | +                const files = new File(
 | 
	
		
			
				|  |  | +                    [myBlob],
 | 
	
		
			
				|  |  | +                    file.name,
 | 
	
		
			
				|  |  | +                    { type: file.type }
 | 
	
		
			
				|  |  | +                )
 | 
	
		
			
				|  |  | +                const reader = new FileReader()
 | 
	
		
			
				|  |  | +                reader.readAsArrayBuffer(files)
 | 
	
		
			
				|  |  | +                reader.onload = () => resolve(reader.result)
 | 
	
		
			
				|  |  | +                reader.onerror = error => reject(error)
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                reject(`文件加载失败: ${this.status}`)
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        xhr.onerror = () => reject('网络请求失败')
 | 
	
		
			
				|  |  | +        xhr.send()
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 上传文件到服务器
 | 
	
		
			
				|  |  | +const uploadFile = (res, data) => {
 | 
	
		
			
				|  |  | +    uni.request({
 | 
	
		
			
				|  |  | +        url: res.uploadurl,
 | 
	
		
			
				|  |  | +        method: "PUT",
 | 
	
		
			
				|  |  | +        data,
 | 
	
		
			
				|  |  | +        header: { 'Content-Type': 'application/octet-stream' },
 | 
	
		
			
				|  |  | +        success: () => {
 | 
	
		
			
				|  |  | +            $Http.basic({
 | 
	
		
			
				|  |  | +                "classname": "system.attachment.huawei.OBS",
 | 
	
		
			
				|  |  | +                "method": "uploadSuccess",
 | 
	
		
			
				|  |  | +                "content": { "serialfilename": res.serialfilename }
 | 
	
		
			
				|  |  | +            }).then(s => {
 | 
	
		
			
				|  |  | +                console.log("文件上传反馈", s)
 | 
	
		
			
				|  |  | +                handleFileLink([{
 | 
	
		
			
				|  |  | +                    attachmentid: s.data.attachmentids[0],
 | 
	
		
			
				|  |  | +                    url: data.url
 | 
	
		
			
				|  |  | +                }], "temporary", 1, props.usetype)
 | 
	
		
			
				|  |  | +            }).catch(console.error)
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        fail: console.error
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function handleFileLink(list, ownertable = "temporary", ownerid = 1, usetype = 'default') {
 | 
	
		
			
				|  |  | +    return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | +        if (list.length == 0) return resolve(true);
 | 
	
		
			
				|  |  | +        let content = {
 | 
	
		
			
				|  |  | +            ownertable,
 | 
	
		
			
				|  |  | +            ownerid,
 | 
	
		
			
				|  |  | +            usetype,
 | 
	
		
			
				|  |  | +            attachmentids: list.map(v => v.attachmentid),
 | 
	
		
			
				|  |  | +            siteid: uni.getStorageSync("userMsg").siteid
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +        $Http.basic({
 | 
	
		
			
				|  |  | +            "classname": "system.attachment.Attachment",
 | 
	
		
			
				|  |  | +            "method": "createFileLink",
 | 
	
		
			
				|  |  | +            content
 | 
	
		
			
				|  |  | +        }).then(res => {
 | 
	
		
			
				|  |  | +            console.log('跟进记录绑定附件', res)
 | 
	
		
			
				|  |  | +            resolve(res.code == '1')
 | 
	
		
			
				|  |  | +            if (res.code != '1') return uni.showToast({
 | 
	
		
			
				|  |  | +                title: res.msg,
 | 
	
		
			
				|  |  | +                icon: "none"
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +            list.forEach(v => {
 | 
	
		
			
				|  |  | +                let index = props.fileList.findIndex(s => v.url == s.url)
 | 
	
		
			
				|  |  | +                props.fileList[index] = res.data.find(s => s.attachmentid == v.attachmentid)
 | 
	
		
			
				|  |  | +                console.log("props.fileList[index]", props.fileList[index])
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +            emit('uploadCallback', { fileList: props.fileList, attachmentids: content.attachmentids })
 | 
	
		
			
				|  |  | +        })
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 保存所有的附件绑定到表上,有在上传的文件不能保存
 | 
	
		
			
				|  |  | +const isUploading = (showToast = true) => {
 | 
	
		
			
				|  |  | +    let res = props.fileList.some(file => file.status === 'uploading');
 | 
	
		
			
				|  |  | +    if (res && showToast) uni.showToast({
 | 
	
		
			
				|  |  | +        title: '文件正在上传中,请稍后再试',
 | 
	
		
			
				|  |  | +        icon: 'none'
 | 
	
		
			
				|  |  | +    });
 | 
	
		
			
				|  |  | +    return res
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 保存接口 接受数据调用handleFileLink
 | 
	
		
			
				|  |  | +const saveFileLinks = (ownertable, ownerid, usetype = 'default') => {
 | 
	
		
			
				|  |  | +    return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | +        if (isUploading(false)) return resolve(false);
 | 
	
		
			
				|  |  | +        const list = props.fileList;
 | 
	
		
			
				|  |  | +        if (list.length) {
 | 
	
		
			
				|  |  | +            return handleFileLink(list, ownertable, ownerid, usetype);
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            resolve(true)
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +function deletePic({ file, index, name }) {
 | 
	
		
			
				|  |  | +    console.log("index", index)
 | 
	
		
			
				|  |  | +    uni.showModal({
 | 
	
		
			
				|  |  | +        cancelText: '取消',
 | 
	
		
			
				|  |  | +        confirmText: '删除',
 | 
	
		
			
				|  |  | +        content: '是否确定删除该文件?',
 | 
	
		
			
				|  |  | +        title: '提示',
 | 
	
		
			
				|  |  | +        success: ({ confirm }) => {
 | 
	
		
			
				|  |  | +            if (confirm) {
 | 
	
		
			
				|  |  | +                console.log("删除文件", file);
 | 
	
		
			
				|  |  | +                if (file.ownertable == 'temporary') {
 | 
	
		
			
				|  |  | +                    // 临时文件直接删除
 | 
	
		
			
				|  |  | +                    deleteFile([file]).then(res => {
 | 
	
		
			
				|  |  | +                        if (res) {
 | 
	
		
			
				|  |  | +                            props.fileList.splice(index, 1);
 | 
	
		
			
				|  |  | +                            emit('uploadCallback', { fileList: props.fileList });
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    })
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    deleteList.push(file)
 | 
	
		
			
				|  |  | +                    props.fileList.splice(index, 1);
 | 
	
		
			
				|  |  | +                    emit('uploadCallback', { fileList: props.fileList })
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 直接删除文件
 | 
	
		
			
				|  |  | +const deleteFile = (arr) => {
 | 
	
		
			
				|  |  | +    return new Promise((resolve, reject) => {
 | 
	
		
			
				|  |  | +        let list = arr.filter(file => file.linksid);
 | 
	
		
			
				|  |  | +        if (list.length) {
 | 
	
		
			
				|  |  | +            $Http.basic({
 | 
	
		
			
				|  |  | +                "classname": "system.attachment.Attachment",
 | 
	
		
			
				|  |  | +                "method": "deleteFileLink",
 | 
	
		
			
				|  |  | +                "content": {
 | 
	
		
			
				|  |  | +                    linksids: list.map(v => v.linksid),
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }).then(res => {
 | 
	
		
			
				|  |  | +                console.log("删除文件", res);
 | 
	
		
			
				|  |  | +                resolve(res.code == 1)
 | 
	
		
			
				|  |  | +                if (res.code != 1) uni.showToast({
 | 
	
		
			
				|  |  | +                    title: res.msg,
 | 
	
		
			
				|  |  | +                    icon: "none"
 | 
	
		
			
				|  |  | +                })
 | 
	
		
			
				|  |  | +            })
 | 
	
		
			
				|  |  | +        } else {
 | 
	
		
			
				|  |  | +            resolve(true)
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 清空临时文件 ownertable == 'temporary'
 | 
	
		
			
				|  |  | +const clearTemporaryFiles = (arr = props.fileList) => {
 | 
	
		
			
				|  |  | +    let list = arr.filter(file => file.ownertable == 'temporary' && file.linksid);
 | 
	
		
			
				|  |  | +    if (list.length) $Http.basic({
 | 
	
		
			
				|  |  | +        "classname": "system.attachment.Attachment",
 | 
	
		
			
				|  |  | +        "method": "deleteFileLink",
 | 
	
		
			
				|  |  | +        "content": {
 | 
	
		
			
				|  |  | +            linksids: list.map(v => v.linksid),
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +    }).then(res => {
 | 
	
		
			
				|  |  | +        console.log("清空临时文件", res);
 | 
	
		
			
				|  |  | +    })
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +// 在页面销毁的时候 自动清空所有的临时文件
 | 
	
		
			
				|  |  | +onUnmounted(() => {
 | 
	
		
			
				|  |  | +    console.log("组件销毁,清空临时文件");
 | 
	
		
			
				|  |  | +    clearTemporaryFiles();
 | 
	
		
			
				|  |  | +})
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +defineExpose({ isUploading, saveFileLinks, clearTemporaryFiles, handleFileLink })
 | 
	
		
			
				|  |  | +</script>
 |