From c80bc467a41daa6cbae4e5515a300a8ca98cfeaa Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期二, 21 七月 2026 15:44:01 +0800
Subject: [PATCH] 维护
---
components/attachment/index.vue | 683 ++++++++++++++++++++++++++++----------------------------
1 files changed, 345 insertions(+), 338 deletions(-)
diff --git a/components/attachment/index.vue b/components/attachment/index.vue
index 42276f6..cebfc08 100644
--- a/components/attachment/index.vue
+++ b/components/attachment/index.vue
@@ -23,7 +23,6 @@
@change="onPopupChange"
>
<view class="attachment-popup">
- <!-- 寮瑰眰鏍囬 -->
<view class="popup-header">
<text class="title">闄勪欢绠$悊</text>
<uni-icons
@@ -36,18 +35,18 @@
<uni-icons type="close" size="24" color="#999" @click="closePopup" />
</view>
- <!-- 鏍囩椤靛垏鎹� -->
+ <!-- 鏍囩椤� -->
<view v-if="showGradeSlip" class="attachment-tabs">
- <view
- class="tab-item"
- :class="{ active: currentTab === 'base' }"
+ <view
+ class="tab-item"
+ :class="{ active: currentTab === 'base' }"
@click="currentTab = 'base'"
>
<text>鍩虹闄勪欢</text>
</view>
- <view
- class="tab-item"
- :class="{ active: currentTab === 'grade' }"
+ <view
+ class="tab-item"
+ :class="{ active: currentTab === 'grade' }"
@click="currentTab = 'grade'"
>
<text>鎴愮哗鍗曢檮浠�</text>
@@ -57,7 +56,6 @@
<!-- 闄勪欢鍒楄〃 -->
<scroll-view scroll-y class="file-list">
- <!-- 鍩虹闄勪欢鍒楄〃 -->
<template v-if="currentTab === 'base' || !showGradeSlip">
<view
class="file-item"
@@ -72,10 +70,18 @@
/>
</view>
<view class="file-info" @click="previewFile(file)">
- <text class="file-name">{{ file.originalFilename || file.name }}</text>
+ <text class="file-name">{{
+ file.originalFilename || file.name
+ }}</text>
<text class="file-size">{{ formatFileSize(file.size) }}</text>
- <text class="file-status" v-if="file.status === 'uploading'">涓婁紶涓�...</text>
- <text class="file-status error" v-else-if="file.status === 'error'">涓婁紶澶辫触</text>
+ <text class="file-status" v-if="file.status === 'uploading'"
+ >涓婁紶涓�...</text
+ >
+ <text
+ class="file-status error"
+ v-else-if="file.status === 'error'"
+ >涓婁紶澶辫触</text
+ >
</view>
<uni-icons
v-if="!readonly"
@@ -87,7 +93,6 @@
</view>
</template>
- <!-- 鎴愮哗鍗曢檮浠跺垪琛� -->
<template v-if="currentTab === 'grade' && showGradeSlip">
<view
class="file-item"
@@ -102,10 +107,18 @@
/>
</view>
<view class="file-info" @click="previewFile(file)">
- <text class="file-name">{{ file.originalFilename || file.name }}</text>
+ <text class="file-name">{{
+ file.originalFilename || file.name
+ }}</text>
<text class="file-size">{{ formatFileSize(file.size) }}</text>
- <text class="file-status" v-if="file.status === 'uploading'">涓婁紶涓�...</text>
- <text class="file-status error" v-else-if="file.status === 'error'">涓婁紶澶辫触</text>
+ <text class="file-status" v-if="file.status === 'uploading'"
+ >涓婁紶涓�...</text
+ >
+ <text
+ class="file-status error"
+ v-else-if="file.status === 'error'"
+ >涓婁紶澶辫触</text
+ >
</view>
<uni-icons
v-if="!readonly"
@@ -117,138 +130,154 @@
</view>
</template>
- <!-- 绌虹姸鎬� -->
<view class="empty" v-if="currentFileList.length === 0">
<uni-icons type="info" size="24" color="#999" />
- <text v-if="currentTab === 'base' || !showGradeSlip">鏆傛棤鍩虹闄勪欢</text>
+ <text v-if="currentTab === 'base' || !showGradeSlip">鏆傛棤闄勪欢</text>
<text v-else-if="currentTab === 'grade'">鏆傛棤鎴愮哗鍗曢檮浠�</text>
</view>
</scroll-view>
- <!-- 鎿嶄綔鎸夐挳 -->
<view class="popup-footer" v-if="!readonly">
- <button class="btn" @click="chooseFile">娣诲姞{{ currentTab === 'grade' ? '鎴愮哗鍗�' : '鍩虹' }}闄勪欢</button>
+ <button class="btn" @click="chooseFile">娣诲姞</button>
<button class="btn primary" @click="confirmUpload">纭涓婁紶</button>
</view>
</view>
</uni-popup>
-
- <!-- 鏂囦欢閫夋嫨鍣� -->
- <uni-file-picker
- ref="filePicker"
- v-if="!readonly"
- :auto-upload="false"
- file-mediatype="all"
- :limit="maxCount - currentFileList.length"
- :image-styles="imageStyles"
- @select="onFileSelect"
- @delete="onFileDelete"
- style="display: none"
- />
</view>
</template>
<script setup>
-import { ref, computed, watch, onMounted } from "vue";
+import { ref, computed, watch, onBeforeUnmount } from "vue";
import { useUserStore } from "@/stores/user";
const userStore = useUserStore();
const props = defineProps({
- files: {
- type: Array,
- default: () => [],
- },
- gradesFiles: { // 鏂板灞炴�э細鎴愮哗鍗曢檮浠跺垪琛�
- type: Array,
- default: () => [],
- },
- readonly: {
- type: Boolean,
- default: false,
- },
+ files: { type: Array, default: () => [] },
+ gradesFiles: { type: Array, default: () => [] },
+ readonly: { type: Boolean, default: false },
position: {
type: Object,
- default: () => ({
- right: "30rpx",
- bottom: "200rpx",
- }),
+ 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
- }
+ bgColor: { type: String, default: "#67AFAB" },
+ maxCount: { type: Number, default: 9 },
+ showGradeSlip: { type: Boolean, default: false },
+ isGradeRequired: { type: Boolean, default: false },
});
const emit = defineEmits([
- "update:files",
- "update:gradesFiles", // 鏂板浜嬩欢锛氭洿鏂版垚缁╁崟闄勪欢
- "upload",
+ "update:files",
+ "update:gradesFiles",
+ "upload",
"preview",
- "upload-grade", // 鏂板浜嬩欢锛氫笂浼犳垚缁╁崟闄勪欢
- "upload-base" // 鏂板浜嬩欢锛氫笂浼犲熀纭�闄勪欢
+ "upload-grade",
+ "upload-base",
]);
const popup = ref(null);
-const filePicker = ref(null);
const baseFiles = ref([]);
const gradeFiles = ref([]);
const showButton = ref(true);
const mainColor = ref("#67AFAB");
-const baseUrlHt = userStore.baseUrlHt;
-const currentTab = ref('base');
+const currentTab = ref("base");
+const blobUrls = ref([]);
-// 璁$畻褰撳墠鏄剧ず鐨勬枃浠跺垪琛�
-const currentFileList = computed(() => {
- if (!props.showGradeSlip) {
- return baseFiles.value;
+const getBaseUrlHt = () => {
+ // #ifdef H5
+ try {
+ const href = window.location.href;
+
+ // 瑙勫垯 1锛�192.168.120.27:8091 鈫� 120.27 + :9095
+ if (href.startsWith("http://192.168.120.27:8091")) {
+ return "http://192.168.120.27:9095";
+ }
+
+ // 瑙勫垯 2锛�192.168.76.25:8091 鈫� 76.25 + :9095
+ if (href.startsWith("http://192.168.76.25:8091")) {
+ return "http://192.168.76.25:9095";
+ }
+
+ // 瑙勫垯 3锛氬叾浣欏叏閮ㄨ蛋鐢熶骇
+ return "https://opo.qduh.cn";
+ } catch {
+ return "https://opo.qduh.cn";
}
- return currentTab.value === 'base' ? baseFiles.value : gradeFiles.value;
+ // #endif
+
+ // #ifdef MP-WEIXIN
+ return userStore.baseUrlHt;
+ // #endif
+};
+
+
+const baseUrlHt = getBaseUrlHt();
+
+const currentFileList = computed(() => {
+ if (!props.showGradeSlip) return baseFiles.value;
+ return currentTab.value === "base" ? baseFiles.value : gradeFiles.value;
});
+const totalFileCount = computed(
+ () => baseFiles.value.length + gradeFiles.value.length,
+);
-// 璁$畻鏂囦欢鎬绘暟
-const totalFileCount = computed(() => {
- return baseFiles.value.length + gradeFiles.value.length;
-});
+watch(
+ () => props.files,
+ (newFiles) => {
+ baseFiles.value = [...newFiles];
+ },
+ { immediate: true },
+);
+watch(
+ () => props.gradesFiles,
+ (newFiles) => {
+ gradeFiles.value = [...newFiles];
+ },
+ { immediate: true },
+);
-// 鐩戝惉澶栭儴浼犲叆鐨刦iles锛屽垵濮嬪寲鏂囦欢鍒楄〃
-watch(() => props.files, (newFiles) => {
- baseFiles.value = [...newFiles];
-}, { immediate: true });
-
-// 鐩戝惉澶栭儴浼犲叆鐨刧radesFiles锛屽垵濮嬪寲鎴愮哗鍗曢檮浠跺垪琛�
-watch(() => props.gradesFiles, (newFiles) => {
- gradeFiles.value = [...newFiles];
-}, { immediate: true });
-
-// 鑾峰彇瀹屾暣URL
+// 鑾峰彇瀹屾暣URL - 骞冲彴宸紓鍖栧鐞�
const getFullUrl = (path) => {
- if (!path) return '';
- if (path.startsWith('http://') || path.startsWith('https://')) {
+ if (!path) return "";
+
+ // 濡傛灉鏄� blob 鎴� file 鍗忚鐨勬湰鍦拌矾寰勶紝鐩存帴杩斿洖
+ if (path.startsWith("blob:") || path.startsWith("file://")) {
return path;
}
- return `${baseUrlHt}${path.startsWith('/') ? '' : '/'}${path}`;
+
+ // 濡傛灉鏄畬鏁寸殑 http/https 閾炬帴
+ if (path.startsWith("http://") || path.startsWith("https://")) {
+ // #ifdef H5
+ // H5 鐜锛氫娇鐢� new URL 瑙f瀽
+ try {
+ const url = new URL(path);
+ return `${baseUrlHt}${url.pathname}${url.search}${url.hash}`;
+ } catch (error) {
+ console.error("URL瑙f瀽澶辫触:", error);
+ // 闄嶇骇澶勭悊锛氭墜鍔ㄦ埅鍙栬矾寰�
+ const pathIndex = path.indexOf("/", 8); // 璺宠繃 http:// 鎴� https://
+ if (pathIndex !== -1) {
+ return `${baseUrlHt}${path.substring(pathIndex)}`;
+ }
+ return path;
+ }
+ // #endif
+
+ // #ifdef MP-WEIXIN
+ // 灏忕▼搴忕幆澧冿細涓嶄娇鐢� new URL锛屾墜鍔ㄥ鐞�
+ const protocolEnd = path.indexOf("://") + 3;
+ const pathStart = path.indexOf("/", protocolEnd);
+ if (pathStart !== -1) {
+ // 鎻愬彇璺緞閮ㄥ垎锛堝寘鎷矾寰勩�佹煡璇㈠弬鏁板拰hash锛�
+ return `${baseUrlHt}${path.substring(pathStart)}`;
+ }
+ return baseUrlHt;
+ // #endif
+ }
+
+ // 鐩稿璺緞澶勭悊
+ return `${baseUrlHt}${path.startsWith("/") ? "" : "/"}${path}`;
};
-// 鏂囦欢閫夋嫨鍣ㄦ牱寮�
-const imageStyles = {
- width: 120,
- height: 120,
- border: false,
-};
-
-// 鏀寔鐨勫浘鐗囨牸寮�
const supportedImageTypes = [
"image/jpeg",
"image/png",
@@ -258,12 +287,9 @@
"image/svg+xml",
];
-// 寮瑰眰鐘舵�佸彉鍖�
const onPopupChange = (e) => {
showButton.value = !e.show;
};
-
-// 鑾峰彇鏂囦欢鍥炬爣
const getFileIcon = (type) => {
if (type && supportedImageTypes.includes(type)) return "image";
if (type && type.includes("pdf")) return "paperclip";
@@ -272,8 +298,6 @@
if (type && type.includes("powerpoint")) return "file-ppt";
return "file";
};
-
-// 鑾峰彇鏂囦欢棰滆壊
const getFileColor = (type) => {
if (type && supportedImageTypes.includes(type)) return mainColor.value;
if (type && type.includes("pdf")) return "#ff4d4f";
@@ -282,85 +306,32 @@
if (type && type.includes("powerpoint")) return "#b7472a";
return "#666";
};
-
-// 鏍煎紡鍖栨枃浠跺ぇ灏�
const formatFileSize = (size) => {
if (!size) return "";
if (size < 1024) return `${size}B`;
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)}KB`;
return `${(size / (1024 * 1024)).toFixed(1)}MB`;
};
-
-// 鍒囨崲寮瑰眰鏄剧ず
const togglePopup = () => {
- if (popup.value) {
- popup.value.open();
- }
+ popup.value?.open();
};
-
-// 鍏抽棴寮瑰眰
const closePopup = () => {
- if (popup.value) {
- popup.value.close();
- }
+ popup.value?.close();
};
-// 閫夋嫨鏂囦欢
-const chooseFile = () => {
- filePicker.value?.choose();
-};
-
-// 浠庢枃浠跺悕鑾峰彇绫诲瀷
-const getFileTypeFromName = (filename) => {
- if (!filename) return "application/octet-stream";
- const ext = filename.split(".").pop().toLowerCase();
- const typeMap = {
- jpg: "image/jpeg",
- jpeg: "image/jpeg",
- png: "image/png",
- gif: "image/gif",
- webp: "image/webp",
- bmp: "image/bmp",
- SVG: "image/svg+xml",
- pdf: "application/pdf",
- };
- return typeMap[ext] || "application/octet-stream";
-};
-
-// 鏂囦欢閫変腑鍥炶皟
-const onFileSelect = (e) => {
- // 鏄庣‘纭畾褰撳墠鏄熀纭�闄勪欢杩樻槸鎴愮哗鍗曢檮浠�
- const isGradeTab = props.showGradeSlip && currentTab.value === 'grade';
+const addFilesToCurrentTab = (newFiles) => {
+ const isGradeTab = props.showGradeSlip && currentTab.value === "grade";
const targetFiles = isGradeTab ? gradeFiles.value : baseFiles.value;
-
- const newFiles = e.tempFiles
- .filter((file) => {
- const fileExt = file.name ? file.name.split(".").pop().toLowerCase() : "";
- const isImage = supportedImageTypes.includes(file.type) ||
- ["jpg", "jpeg", "png", "gif", "webp", "bmp", "svg"].includes(fileExt);
- const isPDF = (file.type && file.type.includes("pdf")) || fileExt === "pdf";
- return isImage || isPDF;
- })
- .map((file) => ({
- name: file.name,
- url: file.path || file.url,
- type: file.type || getFileTypeFromName(file.name),
- size: file.size,
- file: file,
- status: 'pending',
- // 鏄庣‘鏍囪闄勪欢绫诲瀷
- attachmentType: isGradeTab ? 'grade' : 'base'
- }));
-
if (targetFiles.length + newFiles.length > props.maxCount) {
uni.showToast({
title: `鏈�澶氬彧鑳戒笂浼�${props.maxCount}涓枃浠禶,
icon: "none",
});
+ newFiles.forEach((f) => {
+ if (f.url && f.url.startsWith("blob:")) URL.revokeObjectURL(f.url);
+ });
return;
}
-
- // 涓ユ牸鍖哄垎瀛樺偍浣嶇疆
if (isGradeTab) {
gradeFiles.value = [...gradeFiles.value, ...newFiles];
emit("update:gradesFiles", gradeFiles.value);
@@ -370,18 +341,115 @@
}
};
-// 鑾峰彇鎵�鏈夋枃浠�
-const getAllFiles = () => {
- return [...baseFiles.value, ...gradeFiles.value];
+// 閫夋嫨鏂囦欢锛堝钩鍙板樊寮傦級
+const chooseFile = () => {
+ // #ifdef H5
+ const input = document.createElement("input");
+ input.type = "file";
+ input.accept = "image/*,application/pdf";
+ input.multiple = true;
+ input.onchange = (e) => {
+ const files = Array.from(e.target.files);
+ if (files.length === 0) return;
+ const newFiles = files
+ .map((file) => {
+ const ext = file.name.split(".").pop().toLowerCase();
+ const isImage =
+ supportedImageTypes.includes(file.type) ||
+ ["jpg", "jpeg", "png", "gif", "webp", "bmp", "svg"].includes(ext);
+ const isPDF = file.type.includes("pdf") || ext === "pdf";
+ if (!isImage && !isPDF) {
+ uni.showToast({
+ title: `鏂囦欢 ${file.name} 鏍煎紡涓嶆敮鎸乣,
+ icon: "none",
+ });
+ return null;
+ }
+ const blobUrl = URL.createObjectURL(file);
+ blobUrls.value.push(blobUrl);
+ return {
+ name: file.name,
+ path: blobUrl,
+ url: blobUrl,
+ uploadPath: blobUrl,
+ type: file.type,
+ size: file.size,
+ raw: file,
+ status: "pending",
+ };
+ })
+ .filter((f) => f);
+ addFilesToCurrentTab(newFiles);
+ input.remove();
+ };
+ input.click();
+ // #endif
+
+ // #ifdef MP-WEIXIN
+ uni.showActionSheet({
+ itemList: ["鎷嶇収/鐩稿唽", "浠庤亰澶╄褰曢�夋嫨鏂囦欢"],
+ success: (res) => {
+ const remain = props.maxCount - currentFileList.value.length;
+ if (remain <= 0) {
+ uni.showToast({
+ title: `鏈�澶氫笂浼�${props.maxCount}涓枃浠禶,
+ icon: "none",
+ });
+ return;
+ }
+ if (res.tapIndex === 0) {
+ uni.chooseImage({
+ count: remain,
+ sizeType: ["original", "compressed"],
+ sourceType: ["album", "camera"],
+ success: (chooseRes) => {
+ const files = chooseRes.tempFiles.map((file) => ({
+ name: file.name || "image.jpg",
+ path: file.path,
+ url: file.path,
+ uploadPath: file.path,
+ type: file.type || "image/jpeg",
+ size: file.size,
+ raw: file,
+ status: "pending",
+ }));
+ addFilesToCurrentTab(files);
+ },
+ });
+ } else if (res.tapIndex === 1) {
+ uni.chooseMessageFile({
+ count: remain,
+ type: "all",
+ success: (chooseRes) => {
+ const files = chooseRes.tempFiles.map((file) => ({
+ name: file.name,
+ path: file.path,
+ url: file.path,
+ uploadPath: file.path,
+ type: file.type,
+ size: file.size,
+ raw: file,
+ status: "pending",
+ }));
+ addFilesToCurrentTab(files);
+ },
+ });
+ }
+ },
+ });
+ // #endif
};
const removeFile = (type, index, event) => {
- if (event) {
- event.stopPropagation();
+ if (event) event.stopPropagation();
+ const file =
+ type === "grade" ? gradeFiles.value[index] : baseFiles.value[index];
+ if (file.url && file.url.startsWith("blob:")) {
+ URL.revokeObjectURL(file.url);
+ const idx = blobUrls.value.indexOf(file.url);
+ if (idx !== -1) blobUrls.value.splice(idx, 1);
}
-
- // 涓ユ牸鎸夌被鍨嬪垹闄�
- if (type === 'grade') {
+ if (type === "grade") {
gradeFiles.value.splice(index, 1);
emit("update:gradesFiles", gradeFiles.value);
} else {
@@ -392,199 +460,169 @@
// 棰勮鏂囦欢
const previewFile = (file) => {
- const fullUrl = getFullUrl(file.url);
-
+ let previewUrl = file.url;
+ if (
+ previewUrl &&
+ !previewUrl.startsWith("blob:") &&
+ !previewUrl.startsWith("file://") &&
+ !previewUrl.startsWith("/")
+ ) {
+ previewUrl = getFullUrl(previewUrl);
+ }
if (file.type && supportedImageTypes.includes(file.type)) {
- // 棰勮鍥剧墖
- const allFiles = getAllFiles();
- uni.previewImage({
- urls: allFiles
- .filter(f => f.type && supportedImageTypes.includes(f.type))
- .map(f => getFullUrl(f.url)),
- current: fullUrl,
- });
+ 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),
+ );
+ uni.previewImage({ urls: imageUrls, current: previewUrl });
} else if (file.type && file.type.includes("pdf")) {
- // 棰勮PDF
uni.downloadFile({
- url: fullUrl,
+ url: previewUrl,
success: (res) => {
- const filePath = res.tempFilePath;
- uni.openDocument({
- filePath: filePath,
- fileType: "pdf",
- success: () => console.log("鎵撳紑PDF鎴愬姛"),
- fail: (err) => {
- console.error("鎵撳紑PDF澶辫触", err);
- uni.showToast({
- title: "鎵撳紑PDF澶辫触",
- icon: "none",
- });
- },
- });
+ uni.openDocument({ filePath: res.tempFilePath, fileType: "pdf" });
},
- fail: (err) => {
- console.error("涓嬭浇PDF澶辫触", err);
- uni.showToast({
- title: "涓嬭浇PDF澶辫触",
- icon: "none",
- });
- },
+ fail: () => uni.showToast({ title: "鎵撳紑PDF澶辫触", icon: "none" }),
});
} else {
- // 鍏朵粬鏂囦欢绫诲瀷瑙﹀彂棰勮浜嬩欢
emit("preview", file);
}
};
-// 鏂囦欢涓婁紶鏂规硶
const uploadFile = (file, type) => {
return new Promise((resolve, reject) => {
const token = uni.getStorageSync('token');
-
+ const filePath = file.uploadPath || file.url || file.path;
+
+ if (!filePath || typeof filePath !== 'string') {
+ reject(new Error('鏃犳晥鐨勬枃浠惰矾寰�'));
+ return;
+ }
+
+ // #ifdef H5
+ const uploadUrl = '/api/common/upload';
+ // #endif
+
+ // #ifdef MP-WEIXIN
+ const uploadUrl = `${userStore.baseUrlHt}/common/upload`;
+ // #endif
+
uni.uploadFile({
- url: '/api/common/upload',
- filePath: file.path || file.url,
+ url: uploadUrl,
+ filePath,
name: 'file',
header: {
- 'Authorization': `Bearer ${token}`
+ Authorization: `Bearer ${token}`
},
success: (res) => {
if (res.statusCode === 200) {
- const data = JSON.parse(res.data);
- console.log(data,'鏂囦欢');
-
- if (data.code === 200) {
- resolve({
- ...data,
- fileName: data.fileName
- });
- } else {
- reject(new Error(data.msg || '涓婁紶澶辫触'));
+ try {
+ const data = JSON.parse(res.data);
+ if (data.code === 200) {
+ resolve({ ...data, fileName: data.fileName });
+ } else {
+ reject(new Error(data.msg || '涓婁紶澶辫触'));
+ }
+ } catch {
+ reject(new Error('鍝嶅簲瑙f瀽澶辫触'));
}
} else {
reject(new Error(`涓婁紶澶辫触锛岀姸鎬佺爜: ${res.statusCode}`));
}
},
- fail: (err) => {
- reject(err);
- }
+ fail: reject
});
});
};
// 纭涓婁紶
const confirmUpload = async () => {
- // 妫�鏌ユ垚缁╁崟闄勪欢鏄惁蹇呭~
- if (props.showGradeSlip && props.isGradeRequired && gradeFiles.value.length === 0) {
- uni.showToast({
- title: "璇蜂笂浼犳垚缁╁崟闄勪欢",
- icon: "none",
- });
- currentTab.value = 'grade';
+ if (
+ props.showGradeSlip &&
+ props.isGradeRequired &&
+ gradeFiles.value.length === 0
+ ) {
+ uni.showToast({ title: "璇蜂笂浼犳垚缁╁崟闄勪欢", icon: "none" });
+ currentTab.value = "grade";
return;
}
-
- const allFiles = getAllFiles();
- if (allFiles.length === 0) {
- uni.showToast({
- title: "璇峰厛娣诲姞闄勪欢",
- icon: "none",
- });
+ const totalPending = [...baseFiles.value, ...gradeFiles.value].filter(
+ (f) => !f.url || f.status === "pending",
+ ).length;
+ if (totalPending === 0) {
+ uni.showToast({ title: "娌℃湁寰呬笂浼犵殑鏂囦欢", icon: "none" });
return;
}
-
- uni.showLoading({
- title: '涓婁紶涓�',
- mask: true
- });
-
+ uni.showLoading({ title: "涓婁紶涓�", mask: true });
try {
- // 鍒嗗埆澶勭悊鍩虹闄勪欢鍜屾垚缁╁崟闄勪欢鐨勪笂浼�
- const pendingBaseFiles = baseFiles.value.filter(file =>
- !file.url || file.status === 'pending');
- const pendingGradeFiles = gradeFiles.value.filter(file =>
- !file.url || file.status === 'pending');
-
- // 涓婁紶鍩虹闄勪欢
- for (const file of pendingBaseFiles) {
+ 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';
- const res = await uploadFile(file.file, 'base');
+ file.status = "uploading";
+ const res = await uploadFile(file, "base");
Object.assign(file, {
url: res.url,
fileName: res.name,
newFileName: res.newFileName,
originalFilename: res.originalFilename,
- status: 'success',
- size:res.size
+ status: "success",
+ size: res.size,
});
emit("upload-base", file);
- } catch (error) {
- console.error('鍩虹闄勪欢涓婁紶澶辫触:', error);
- file.status = 'error';
- uni.showToast({
- title: `鏂囦欢 ${file.name} 涓婁紶澶辫触`,
- icon: 'none'
- });
+ } catch (err) {
+ file.status = "error";
+ uni.showToast({ title: `鏂囦欢 ${file.name} 涓婁紶澶辫触`, icon: "none" });
}
}
-
- // 涓婁紶鎴愮哗鍗曢檮浠�
- for (const file of pendingGradeFiles) {
+ for (const file of pendingGrade) {
try {
- file.status = 'uploading';
- const res = await uploadFile(file.file, 'grade');
+ file.status = "uploading";
+ const res = await uploadFile(file, "grade");
Object.assign(file, {
url: res.fileName,
fileName: res.fileName,
newFileName: res.newFileName,
originalFilename: res.originalFilename,
- status: 'success'
+ status: "success",
});
emit("upload-grade", file);
- } catch (error) {
- console.error('鎴愮哗鍗曢檮浠朵笂浼犲け璐�:', error);
- file.status = 'error';
- uni.showToast({
- title: `鏂囦欢 ${file.name} 涓婁紶澶辫触`,
- icon: 'none'
- });
+ } catch (err) {
+ file.status = "error";
+ uni.showToast({ title: `鏂囦欢 ${file.name} 涓婁紶澶辫触`, icon: "none" });
}
}
- console.log(baseFiles.value,'1');
- console.log(gradeFiles.value,'2');
-
- // 鏇存柊鏂囦欢鍒楄〃
emit("update:files", baseFiles.value);
emit("update:gradesFiles", gradeFiles.value);
- // emit("upload", allFiles);
-
- uni.showToast({
- title: '涓婁紶瀹屾垚',
- icon: 'success'
- });
+ uni.showToast({ title: "涓婁紶瀹屾垚", icon: "success" });
closePopup();
} catch (error) {
- console.error('涓婁紶鍑洪敊:', error);
- uni.showToast({
- title: '涓婁紶鍑洪敊',
- icon: 'none'
- });
+ console.error("涓婁紶鍑洪敊:", error);
+ uni.showToast({ title: "涓婁紶鍑洪敊", icon: "none" });
} finally {
uni.hideLoading();
}
};
-// 鑾峰彇鐗瑰畾绫诲瀷鐨勬枃浠讹紙渚涚埗缁勪欢璋冪敤锛�
-const getFilesByType = (type) => {
- return type === 'grade' ? gradeFiles.value : baseFiles.value;
-};
+const getFilesByType = (type) =>
+ type === "grade" ? gradeFiles.value : baseFiles.value;
+const getAllFiles = () => [...baseFiles.value, ...gradeFiles.value];
-// 鏆撮湶鏂规硶缁欑埗缁勪欢
-defineExpose({
- getFilesByType,
- getAllFiles
+onBeforeUnmount(() => {
+ blobUrls.value.forEach((url) => URL.revokeObjectURL(url));
+ blobUrls.value = [];
});
+
+defineExpose({ getFilesByType, getAllFiles });
</script>
<style lang="scss">
@@ -593,21 +631,17 @@
display: flex;
border-bottom: 1px solid #eee;
margin-bottom: 20rpx;
-
.tab-item {
flex: 1;
text-align: center;
padding: 20rpx 0;
- position: relative;
font-size: 28rpx;
color: #666;
-
&.active {
- color: #67AFAB;
+ color: #67afab;
font-weight: bold;
- border-bottom: 4rpx solid #67AFAB;
+ border-bottom: 4rpx solid #67afab;
}
-
.required-mark {
color: red;
position: absolute;
@@ -617,8 +651,6 @@
}
}
}
-
- // 鍏朵粬鏍峰紡淇濇寔涓嶅彉
.attachment-btn {
position: fixed;
width: 160rpx;
@@ -633,12 +665,10 @@
font-size: 28rpx;
font-weight: bold;
transition: all 0.3s;
-
&:active {
opacity: 0.8;
transform: scale(0.95);
}
-
.badge {
position: absolute;
top: -10rpx;
@@ -654,13 +684,11 @@
justify-content: center;
}
}
-
.attachment-popup {
background-color: #fff;
border-radius: 24rpx 24rpx 0 0;
padding: 30rpx;
max-height: 70vh;
-
.popup-header {
display: flex;
justify-content: space-between;
@@ -668,13 +696,11 @@
margin-bottom: 30rpx;
padding-bottom: 20rpx;
border-bottom: 1rpx solid #f5f5f5;
-
.title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
-
.uni-icons {
padding: 10rpx;
&:active {
@@ -682,30 +708,23 @@
}
}
}
-
.file-list {
max-height: 50vh;
margin-bottom: 30rpx;
-
.file-item {
display: flex;
align-items: center;
padding: 20rpx 0;
border-bottom: 1rpx solid #f5f5f5;
- transition: all 0.2s;
-
&:active {
background-color: #f9f9f9;
}
-
.file-icon {
margin-right: 20rpx;
}
-
.file-info {
flex: 1;
overflow: hidden;
-
.file-name {
font-size: 28rpx;
color: #333;
@@ -715,24 +734,20 @@
overflow: hidden;
text-overflow: ellipsis;
}
-
.file-size {
font-size: 24rpx;
color: #999;
display: block;
}
-
.file-status {
font-size: 24rpx;
color: #666;
display: block;
-
&.error {
color: #ff4d4f;
}
}
}
-
.uni-icons {
padding: 10rpx;
&:active {
@@ -740,7 +755,6 @@
}
}
}
-
.empty {
display: flex;
flex-direction: column;
@@ -749,18 +763,14 @@
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
-
.uni-icons {
margin-bottom: 20rpx;
}
}
}
-
.popup-footer {
display: flex;
- justify-content: space-between;
gap: 20rpx;
-
.btn {
flex: 1;
height: 80rpx;
@@ -771,12 +781,9 @@
background-color: #f5f5f5;
color: #666;
border: none;
- transition: all 0.2s;
-
&:active {
opacity: 0.8;
}
-
&.primary {
background-color: #67afab;
color: #fff;
@@ -785,4 +792,4 @@
}
}
}
-</style>
\ No newline at end of file
+</style>
--
Gitblit v1.9.3