|
|
@@ -0,0 +1,286 @@
|
|
|
+<template>
|
|
|
+ <div class="component-upload-image">
|
|
|
+ <el-upload
|
|
|
+ action="#"
|
|
|
+ list-type="picture-card"
|
|
|
+ drag
|
|
|
+ :on-success="handleSuccess"
|
|
|
+ :on-change="handleChange"
|
|
|
+ ref="uploadInner"
|
|
|
+ :auto-upload="false"
|
|
|
+ :file-list="fileList"
|
|
|
+ >
|
|
|
+ <el-icon><Plus /></el-icon>
|
|
|
+ <template #file="{ file }">
|
|
|
+ <div style="display: flex; flex-direction: column; position: relative">
|
|
|
+ <div style="width: 146px; height: 146px">
|
|
|
+ <img
|
|
|
+ class="el-upload-list__item-thumbnail"
|
|
|
+ :src="getImageUrl(file)"
|
|
|
+ alt=""
|
|
|
+ />
|
|
|
+ <span class="el-upload-list__item-actions">
|
|
|
+ <span
|
|
|
+ class="el-upload-list__item-preview"
|
|
|
+ @click="handlePictureCardPreview(file)"
|
|
|
+ >
|
|
|
+ <el-icon><zoom-in /></el-icon>
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ class="el-upload-list__item-delete"
|
|
|
+ @click="handleDownload(file)"
|
|
|
+ >
|
|
|
+ <el-icon><Download /></el-icon>
|
|
|
+ </span>
|
|
|
+ <span
|
|
|
+ class="el-upload-list__item-delete"
|
|
|
+ @click="handleRemove(file)"
|
|
|
+ >
|
|
|
+ <el-icon><Delete /></el-icon>
|
|
|
+ </span>
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <span
|
|
|
+ style="
|
|
|
+ position: absolute;
|
|
|
+ bottom: 0;
|
|
|
+ width: 146px;
|
|
|
+ font-size: 11px;
|
|
|
+ line-height: 14px;
|
|
|
+ "
|
|
|
+ >{{ file.name }}</span
|
|
|
+ >
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+ </el-upload>
|
|
|
+ <el-dialog v-model="dialogVisible">
|
|
|
+ <img :src="dialogImageUrl" alt="Preview Image" style="width: 100%;"/>
|
|
|
+ </el-dialog>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script setup>
|
|
|
+import { Delete, Download, Plus, ZoomIn } from "@element-plus/icons-vue";
|
|
|
+import dayjs from "dayjs";
|
|
|
+import OSS from "ali-oss";
|
|
|
+import { ElLoading } from "element-plus";
|
|
|
+import { ref, watch } from "vue";
|
|
|
+import { handleBatchDownload } from "../../utils/downFile";
|
|
|
+const props = defineProps({
|
|
|
+ modelValue: [String, Object, Array],
|
|
|
+ // 图片数量限制
|
|
|
+ limit: {
|
|
|
+ type: Number,
|
|
|
+ default: 5,
|
|
|
+ },
|
|
|
+});
|
|
|
+
|
|
|
+const emit = defineEmits();
|
|
|
+const uploadList = ref([]);
|
|
|
+const baseUrl = "https://dfdiyfile.oss-cn-fuzhou.aliyuncs.com/";
|
|
|
+const fileList = ref([]);
|
|
|
+const dialogImageUrl = ref("");
|
|
|
+const dialogVisible = ref(false);
|
|
|
+const disabled = ref(false);
|
|
|
+
|
|
|
+watch(
|
|
|
+ () => props.modelValue,
|
|
|
+ (val) => {
|
|
|
+ if (val) {
|
|
|
+ // 首先将值转为数组
|
|
|
+ const list = Array.isArray(val) ? val : props.modelValue.split(",");
|
|
|
+ // 然后将数组转为对象数组
|
|
|
+ fileList.value = list.map((item) => {
|
|
|
+ if (typeof item === "string") {
|
|
|
+ if (item.indexOf(baseUrl) === -1 && !item.startsWith("http")) {
|
|
|
+ item = { name: item, url: baseUrl + item };
|
|
|
+ } else {
|
|
|
+ item = { name: item, url: item };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return item;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ fileList.value = [];
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+ },
|
|
|
+ { deep: true, immediate: true }
|
|
|
+);
|
|
|
+
|
|
|
+let fileTypes = [
|
|
|
+ {
|
|
|
+ logo: require("../../assets/iso.png"),
|
|
|
+ types: "iso,gho",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/mv.png"),
|
|
|
+ types: "rm,wav,mpg,rmvb,mov,mp4",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/txt.png"),
|
|
|
+ types: "txt,conf",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/excel.png"),
|
|
|
+ types: "xls,xlsx",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/exe.png"),
|
|
|
+ types: "exe,sh",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/html.png"),
|
|
|
+ types: "html,htm",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/image.png"),
|
|
|
+ types: "png,jpg,jpeg,bpm",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/music.png"),
|
|
|
+ types: "mp3,m4a",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/pdf.png"),
|
|
|
+ types: "pdf",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/psd.png"),
|
|
|
+ types: "psd",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/sql.png"),
|
|
|
+ types: "sql",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/word.png"),
|
|
|
+ types: "doc,docx",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/ppt.png"),
|
|
|
+ types: "ppt,pptx",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/zip.png"),
|
|
|
+ types: "zip,7z,gz",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ logo: require("../../assets/apk.png"),
|
|
|
+ types: "apk",
|
|
|
+ },
|
|
|
+];
|
|
|
+
|
|
|
+function getImageUrl(file) {
|
|
|
+ let suffix = file.name.split(".").pop();
|
|
|
+ if ("png,jpg,jpeg".indexOf(suffix) != -1) {
|
|
|
+ return file.url;
|
|
|
+ }
|
|
|
+ for (let ft of fileTypes) {
|
|
|
+ if (ft.types.indexOf(suffix) != -1) {
|
|
|
+ return ft.logo;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return "../../assets/other.png";
|
|
|
+}
|
|
|
+let loading = null;
|
|
|
+const handlePictureCardPreview = (file) => {
|
|
|
+ dialogImageUrl.value = file.url;
|
|
|
+ dialogVisible.value = true;
|
|
|
+};
|
|
|
+function handleRemove(file) {
|
|
|
+ const findex = fileList.value.map((f) => f.name).indexOf(file.name);
|
|
|
+ fileList.value.splice(findex, 1);
|
|
|
+ emit("update:modelValue", listToString(fileList.value));
|
|
|
+ return false;
|
|
|
+}
|
|
|
+function handleDownload(file) {
|
|
|
+ handleBatchDownload([file.url]);
|
|
|
+}
|
|
|
+
|
|
|
+function handleSuccess(res, file) {
|
|
|
+ uploadList.value.push({ name: res.name, url: res.url });
|
|
|
+ uploadedSuccessfully();
|
|
|
+}
|
|
|
+
|
|
|
+// 上传结束处理
|
|
|
+function uploadedSuccessfully() {
|
|
|
+ fileList.value = fileList.value
|
|
|
+ .filter((f) => f.url !== undefined)
|
|
|
+ .concat(uploadList.value);
|
|
|
+
|
|
|
+ uploadList.value = [];
|
|
|
+ emit("update:modelValue", listToString(fileList.value));
|
|
|
+ loading && loading.close();
|
|
|
+}
|
|
|
+
|
|
|
+function guid() {
|
|
|
+ return "xxxxxxxx-xxxx-4xxx-yxxx".replace(/[xy]/g, function (c) {
|
|
|
+ var r = (Math.random() * 16) | 0,
|
|
|
+ v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
|
+ return v.toString(16);
|
|
|
+ });
|
|
|
+}
|
|
|
+const progress = (p, _checkpoint) => {
|
|
|
+ // Object的上传进度。
|
|
|
+ console.log(p);
|
|
|
+ // 分片上传的断点信息。
|
|
|
+ console.log(_checkpoint);
|
|
|
+};
|
|
|
+
|
|
|
+function getSuff(name) {
|
|
|
+ return name.substring(name.lastIndexOf("."));
|
|
|
+}
|
|
|
+function handleChange(file, fileList) {
|
|
|
+ loading = ElLoading.service({
|
|
|
+ lock: true,
|
|
|
+ text: "Loading",
|
|
|
+ background: "rgba(0, 0, 0, 0.7)",
|
|
|
+ });
|
|
|
+ let fileDir = dayjs().format("YYYYMMDD");
|
|
|
+ const client = new OSS({
|
|
|
+ // yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
|
|
|
+ region: "oss-cn-fuzhou",
|
|
|
+ // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
|
|
|
+ accessKeyId: process.env.VUE_APP_OSS_ACCESS_KEY_ID,
|
|
|
+ accessKeySecret: process.env.VUE_APP_OSS_ACCESS_KEY_SECRET,
|
|
|
+ // 填写存储空间名称。
|
|
|
+ bucket: "dfdiyfile",
|
|
|
+ endpoint: "https://oss-cn-fuzhou.aliyuncs.com",
|
|
|
+ });
|
|
|
+ let name = "desgn/" + fileDir + "/" + guid() + getSuff(file.name);
|
|
|
+ // storeAs表示上传的object name , file表示上传的文件
|
|
|
+ client
|
|
|
+ .multipartUpload(name, file.raw, {
|
|
|
+ progress,
|
|
|
+ })
|
|
|
+ .then((result) => {
|
|
|
+ console.log(result);
|
|
|
+ let url = `https://dfdiyfile.oss-cn-fuzhou.aliyuncs.com/${result.name}`;
|
|
|
+ /**
|
|
|
+ * 设置本地上传成功的回调
|
|
|
+ */
|
|
|
+ // this.imageUrl = result.res.requestUrl;
|
|
|
+ handleSuccess({ url, name: result.name }, file);
|
|
|
+ })
|
|
|
+ .catch(function (err) {
|
|
|
+ console.log(err);
|
|
|
+ /**
|
|
|
+ * 设置本地上传失败的回调
|
|
|
+ */
|
|
|
+ });
|
|
|
+}
|
|
|
+// 对象转成指定字符串分隔
|
|
|
+function listToString(list, separator) {
|
|
|
+ let strs = "";
|
|
|
+ separator = separator || ",";
|
|
|
+ for (let i in list) {
|
|
|
+ if (undefined !== list[i].url && list[i].url.indexOf("blob:") !== 0) {
|
|
|
+ strs += list[i].url.replace(baseUrl, "") + separator;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return strs != "" ? strs.substr(0, strs.length - 1) : "";
|
|
|
+}
|
|
|
+</script>
|
|
|
+
|
|
|
+<style scoped lang="scss"></style>
|