| | |
| | | files: { type: Array, default: () => [] }, |
| | | gradesFiles: { type: Array, default: () => [] }, |
| | | readonly: { type: Boolean, default: false }, |
| | | position: { type: Object, default: () => ({ right: "30rpx", bottom: "200rpx" }) }, |
| | | position: { |
| | | type: Object, |
| | | default: () => ({ right: "30rpx", bottom: "200rpx" }) |
| | | }, |
| | | bgColor: { type: String, default: "#67AFAB" }, |
| | | maxCount: { type: Number, default: 9 }, |
| | | showGradeSlip: { type: Boolean, default: false }, |
| | | isGradeRequired: { type: Boolean, default: false } |
| | | }, |
| | | emits: ["update:files", "update:gradesFiles", "upload", "preview", "upload-grade", "upload-base"], |
| | | emits: [ |
| | | "update:files", |
| | | "update:gradesFiles", |
| | | "upload", |
| | | "preview", |
| | | "upload-grade", |
| | | "upload-base" |
| | | ], |
| | | setup(__props, { expose: __expose, emit: __emit }) { |
| | | const userStore = stores_user.useUserStore(); |
| | | const props = __props; |
| | |
| | | const gradeFiles = common_vendor.ref([]); |
| | | const showButton = common_vendor.ref(true); |
| | | const mainColor = common_vendor.ref("#67AFAB"); |
| | | const baseUrlHt = userStore.baseUrlHt; |
| | | const currentTab = common_vendor.ref("base"); |
| | | const blobUrls = common_vendor.ref([]); |
| | | const getBaseUrlHt = () => { |
| | | return userStore.baseUrlHt; |
| | | }; |
| | | const baseUrlHt = getBaseUrlHt(); |
| | | const currentFileList = common_vendor.computed(() => { |
| | | if (!props.showGradeSlip) |
| | | return baseFiles.value; |
| | | return currentTab.value === "base" ? baseFiles.value : gradeFiles.value; |
| | | }); |
| | | const totalFileCount = common_vendor.computed(() => baseFiles.value.length + gradeFiles.value.length); |
| | | common_vendor.watch(() => props.files, (newFiles) => { |
| | | const totalFileCount = common_vendor.computed( |
| | | () => baseFiles.value.length + gradeFiles.value.length |
| | | ); |
| | | common_vendor.watch( |
| | | () => props.files, |
| | | (newFiles) => { |
| | | baseFiles.value = [...newFiles]; |
| | | }, { immediate: true }); |
| | | common_vendor.watch(() => props.gradesFiles, (newFiles) => { |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | common_vendor.watch( |
| | | () => props.gradesFiles, |
| | | (newFiles) => { |
| | | gradeFiles.value = [...newFiles]; |
| | | }, { immediate: true }); |
| | | }, |
| | | { immediate: true } |
| | | ); |
| | | const getFullUrl = (path) => { |
| | | if (!path) |
| | | return ""; |
| | | if (path.startsWith("http://") || path.startsWith("https://")) { |
| | | try { |
| | | const url = new URL(path); |
| | | return `${baseUrlHt}${url.pathname}${url.search}${url.hash}`; |
| | | } catch { |
| | | if (path.startsWith("blob:") || path.startsWith("file://")) { |
| | | return path; |
| | | } |
| | | if (path.startsWith("http://") || path.startsWith("https://")) { |
| | | const protocolEnd = path.indexOf("://") + 3; |
| | | const pathStart = path.indexOf("/", protocolEnd); |
| | | if (pathStart !== -1) { |
| | | return `${baseUrlHt}${path.substring(pathStart)}`; |
| | | } |
| | | return baseUrlHt; |
| | | } |
| | | return `${baseUrlHt}${path.startsWith("/") ? "" : "/"}${path}`; |
| | | }; |
| | | const supportedImageTypes = ["image/jpeg", "image/png", "image/gif", "image/webp", "image/bmp", "image/svg+xml"]; |
| | | const supportedImageTypes = [ |
| | | "image/jpeg", |
| | | "image/png", |
| | | "image/gif", |
| | | "image/webp", |
| | | "image/bmp", |
| | | "image/svg+xml" |
| | | ]; |
| | | const onPopupChange = (e) => { |
| | | showButton.value = !e.show; |
| | | }; |
| | |
| | | const isGradeTab = props.showGradeSlip && currentTab.value === "grade"; |
| | | const targetFiles = isGradeTab ? gradeFiles.value : baseFiles.value; |
| | | if (targetFiles.length + newFiles.length > props.maxCount) { |
| | | common_vendor.index.showToast({ title: `最多只能上传${props.maxCount}个文件`, icon: "none" }); |
| | | common_vendor.index.showToast({ |
| | | title: `最多只能上传${props.maxCount}个文件`, |
| | | icon: "none" |
| | | }); |
| | | newFiles.forEach((f) => { |
| | | if (f.url && f.url.startsWith("blob:")) |
| | | URL.revokeObjectURL(f.url); |
| | |
| | | success: (res) => { |
| | | const remain = props.maxCount - currentFileList.value.length; |
| | | if (remain <= 0) { |
| | | common_vendor.index.showToast({ title: `最多上传${props.maxCount}个文件`, icon: "none" }); |
| | | common_vendor.index.showToast({ |
| | | title: `最多上传${props.maxCount}个文件`, |
| | | icon: "none" |
| | | }); |
| | | return; |
| | | } |
| | | if (res.tapIndex === 0) { |
| | |
| | | path: file.path, |
| | | url: file.path, |
| | | uploadPath: file.path, |
| | | // 小程序临时文件路径 |
| | | type: file.type || "image/jpeg", |
| | | size: file.size, |
| | | raw: file, |
| | |
| | | } |
| | | if (file.type && supportedImageTypes.includes(file.type)) { |
| | | const allFiles = [...baseFiles.value, ...gradeFiles.value]; |
| | | const imageUrls = allFiles.filter((f) => f.type && supportedImageTypes.includes(f.type)).map((f) => f.url.startsWith("blob:") || f.url.startsWith("file://") || f.url.startsWith("/") ? f.url : getFullUrl(f.url)); |
| | | const imageUrls = allFiles.filter((f) => f.type && supportedImageTypes.includes(f.type)).map( |
| | | (f) => f.url.startsWith("blob:") || f.url.startsWith("file://") || f.url.startsWith("/") ? f.url : getFullUrl(f.url) |
| | | ); |
| | | common_vendor.index.previewImage({ urls: imageUrls, current: previewUrl }); |
| | | } else if (file.type && file.type.includes("pdf")) { |
| | | common_vendor.index.downloadFile({ |
| | |
| | | const uploadFile = (file, type) => { |
| | | return new Promise((resolve, reject) => { |
| | | const token = common_vendor.index.getStorageSync("token"); |
| | | let filePath = file.uploadPath || file.url || file.path; |
| | | const filePath = file.uploadPath || file.url || file.path; |
| | | if (!filePath || typeof filePath !== "string") { |
| | | reject(new Error("无效的文件路径")); |
| | | return; |
| | | } |
| | | let uploadUrl = "/api/common/upload"; |
| | | uploadUrl = "https://opo.qduh.cn/common/upload"; |
| | | const uploadUrl = `${userStore.baseUrlHt}/common/upload`; |
| | | common_vendor.index.uploadFile({ |
| | | url: uploadUrl, |
| | | filePath, |
| | | name: "file", |
| | | header: { "Authorization": `Bearer ${token}` }, |
| | | header: { |
| | | Authorization: `Bearer ${token}` |
| | | }, |
| | | success: (res) => { |
| | | if (res.statusCode === 200) { |
| | | try { |
| | | const data = JSON.parse(res.data); |
| | | if (data.code === 200) |
| | | if (data.code === 200) { |
| | | resolve({ ...data, fileName: data.fileName }); |
| | | else |
| | | } else { |
| | | reject(new Error(data.msg || "上传失败")); |
| | | } catch { |
| | | reject(new Error("解析响应失败")); |
| | | } |
| | | } else |
| | | } catch { |
| | | reject(new Error("响应解析失败")); |
| | | } |
| | | } else { |
| | | reject(new Error(`上传失败,状态码: ${res.statusCode}`)); |
| | | } |
| | | }, |
| | | fail: reject |
| | | }); |
| | |
| | | currentTab.value = "grade"; |
| | | return; |
| | | } |
| | | const totalPending = [...baseFiles.value, ...gradeFiles.value].filter((f) => !f.url || f.status === "pending").length; |
| | | const totalPending = [...baseFiles.value, ...gradeFiles.value].filter( |
| | | (f) => !f.url || f.status === "pending" |
| | | ).length; |
| | | if (totalPending === 0) { |
| | | common_vendor.index.showToast({ title: "没有待上传的文件", icon: "none" }); |
| | | return; |
| | | } |
| | | common_vendor.index.showLoading({ title: "上传中", mask: true }); |
| | | try { |
| | | const pendingBase = baseFiles.value.filter((f) => !f.url || f.status === "pending"); |
| | | const pendingGrade = gradeFiles.value.filter((f) => !f.url || f.status === "pending"); |
| | | const pendingBase = baseFiles.value.filter( |
| | | (f) => !f.url || f.status === "pending" |
| | | ); |
| | | const pendingGrade = gradeFiles.value.filter( |
| | | (f) => !f.url || f.status === "pending" |
| | | ); |
| | | for (const file of pendingBase) { |
| | | try { |
| | | file.status = "uploading"; |
| | |
| | | common_vendor.index.showToast({ title: "上传完成", icon: "success" }); |
| | | closePopup(); |
| | | } catch (error) { |
| | | common_vendor.index.__f__("error", "at components/attachment/index.vue:398", "上传出错:", error); |
| | | common_vendor.index.__f__("error", "at components/attachment/index.vue:609", "上传出错:", error); |
| | | common_vendor.index.showToast({ title: "上传出错", icon: "none" }); |
| | | } finally { |
| | | common_vendor.index.hideLoading(); |