diff --git a/src/api/base/wjApi.ts b/src/api/base/wjApi.ts index b86aa40..0f3198e 100644 --- a/src/api/base/wjApi.ts +++ b/src/api/base/wjApi.ts @@ -46,6 +46,20 @@ export const questionnaireAnswerFindByUserApi = async (params: { questionnaireId return await get("/api/questionnaireAnswer/findByUser", params); }; +/** + * 家长端:本人或同学生其他家长是否已填写(任一则视为已填) + */ +export const questionnaireAnswerFindByUserOrFamilyApi = async (params: { + questionnaireId: string; + xxtsId?: string; + xsId?: string; +}) => { + const q: Record = { questionnaireId: params.questionnaireId }; + if (params.xxtsId) q.xxtsId = params.xxtsId; + if (params.xsId) q.xsId = params.xsId; + return await get("/api/questionnaireAnswer/findByUserOrFamily", q); +}; + /** * 获取问卷填写人列表(分页) */ diff --git a/src/pages/base/jl/detail.vue b/src/pages/base/jl/detail.vue index 0732ab8..5362d39 100644 --- a/src/pages/base/jl/detail.vue +++ b/src/pages/base/jl/detail.vue @@ -118,7 +118,15 @@ import { ref, computed, watch, nextTick } from "vue"; import { onLoad } from "@dcloudio/uni-app"; import { getByJlIdApi, jlzxFindByJlParamsApi, relayFinishApi } from "@/api/base/server"; import { imagUrl } from "@/utils"; -import { BASE_IMAGE_URL } from "@/config"; +import { + canPreview, + isImage, + isVideo, + previewFile, + previewImage, + previewVideo, + downloadFile, +} from "@/utils/filePreview"; import { useUserStore } from "@/store/modules/user"; import { showLoading, hideLoading } from "@/utils/uniapp"; @@ -395,59 +403,33 @@ onLoad(async (options) => { } }); -// 附件预览函数 +// 附件:与 zhxy-jsd 教学资源 indexList 一致 — 图片 / 视频 / kkFileView 文档预览 const previewAttachment = (filePath: string) => { if (!filePath) { uni.showToast({ title: "附件链接无效", icon: "none" }); return; } + const fileName = getFileName(filePath); + const ext = fileName.includes(".") ? (fileName.split(".").pop() || "").toLowerCase() : ""; + const fullUrl = imagUrl(filePath); - // 构建完整的文件URL - const baseUrl = BASE_IMAGE_URL; // 使用配置文件中的URL - const fullUrl = filePath.startsWith('http') ? filePath : baseUrl + filePath; - - // 判断文件类型 - const fileExtension = filePath.split('.').pop()?.toLowerCase(); - const isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension || ''); - - // 如果是图片类型,直接预览 - if (isImage) { - uni.previewImage({ - urls: [fullUrl], - current: fullUrl + if (isVideo(ext)) { + const title = fileName.replace(/\.[^.]+$/i, "") || fileName; + previewVideo(fullUrl, title); + return; + } + if (isImage(ext)) { + previewImage(fullUrl); + return; + } + if (canPreview(fileName)) { + previewFile(fullUrl, fileName, ext).catch(() => { + downloadFile(fullUrl, fileName); }); return; } - - uni.showLoading({ title: "正在准备附件..." }); - - uni.downloadFile({ - url: fullUrl, - success: (res) => { - if (res.statusCode === 200) { - const tempFilePath = res.tempFilePath; - uni.hideLoading(); - // Attempt to open the downloaded file - uni.openDocument({ - filePath: tempFilePath, - success: function (res) { - // 打开文档成功 - }, - fail: function (err) { - uni.showToast({ title: "无法打开该文件类型", icon: "none" }); - uni.hideLoading(); // Ensure loading is hidden on failure too - }, - }); - } else { - uni.hideLoading(); - uni.showToast({ title: "下载附件失败", icon: "none" }); - } - }, - fail: (err) => { - uni.hideLoading(); - uni.showToast({ title: "下载附件失败", icon: "none" }); - }, - }); + uni.showToast({ title: "该文件格式暂不支持预览", icon: "none" }); + downloadFile(fullUrl, fileName); }; watch(noticeDetail, (val) => { diff --git a/src/pages/base/jl/detailwb.vue b/src/pages/base/jl/detailwb.vue index 985a54b..7237ddf 100644 --- a/src/pages/base/jl/detailwb.vue +++ b/src/pages/base/jl/detailwb.vue @@ -138,7 +138,15 @@ import { ref, computed, watch, nextTick, onUnmounted } from "vue"; import { onLoad } from "@dcloudio/uni-app"; import { getByJlIdApi, jlzxFindByJlParamsApi, relayFinishApi } from "@/api/base/server"; import { imagUrl } from "@/utils"; -import { BASE_IMAGE_URL } from "@/config"; +import { + canPreview, + isImage, + isVideo, + previewFile, + previewImage, + previewVideo, + downloadFile, +} from "@/utils/filePreview"; import { useUserStore } from "@/store/modules/user"; import { showLoading, hideLoading } from "@/utils/uniapp"; @@ -503,59 +511,33 @@ onLoad(async (options) => { } }); -// 附件预览函数 +// 附件:与 zhxy-jsd 教学资源 indexList 一致 — 图片 / 视频 / kkFileView 文档预览 const previewAttachment = (filePath: string) => { if (!filePath) { uni.showToast({ title: "附件链接无效", icon: "none" }); return; } + const fileName = getFileName(filePath); + const ext = fileName.includes(".") ? (fileName.split(".").pop() || "").toLowerCase() : ""; + const fullUrl = imagUrl(filePath); - // 构建完整的文件URL - const baseUrl = BASE_IMAGE_URL; // 使用配置文件中的URL - const fullUrl = filePath.startsWith('http') ? filePath : baseUrl + filePath; - - // 判断文件类型 - const fileExtension = filePath.split('.').pop()?.toLowerCase(); - const isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension || ''); - - // 如果是图片类型,直接预览 - if (isImage) { - uni.previewImage({ - urls: [fullUrl], - current: fullUrl + if (isVideo(ext)) { + const title = fileName.replace(/\.[^.]+$/i, "") || fileName; + previewVideo(fullUrl, title); + return; + } + if (isImage(ext)) { + previewImage(fullUrl); + return; + } + if (canPreview(fileName)) { + previewFile(fullUrl, fileName, ext).catch(() => { + downloadFile(fullUrl, fileName); }); return; } - - uni.showLoading({ title: "正在准备附件..." }); - - uni.downloadFile({ - url: fullUrl, - success: (res) => { - if (res.statusCode === 200) { - const tempFilePath = res.tempFilePath; - uni.hideLoading(); - // Attempt to open the downloaded file - uni.openDocument({ - filePath: tempFilePath, - success: function (res) { - // 打开文档成功 - }, - fail: function (err) { - uni.showToast({ title: "无法打开该文件类型", icon: "none" }); - uni.hideLoading(); // Ensure loading is hidden on failure too - }, - }); - } else { - uni.hideLoading(); - uni.showToast({ title: "下载附件失败", icon: "none" }); - } - }, - fail: (err) => { - uni.hideLoading(); - uni.showToast({ title: "下载附件失败", icon: "none" }); - }, - }); + uni.showToast({ title: "该文件格式暂不支持预览", icon: "none" }); + downloadFile(fullUrl, fileName); }; watch(noticeDetail, (val) => { diff --git a/src/pages/base/wj/indexwb.vue b/src/pages/base/wj/indexwb.vue index d21012b..1067083 100644 --- a/src/pages/base/wj/indexwb.vue +++ b/src/pages/base/wj/indexwb.vue @@ -353,7 +353,7 @@ import { questionnaireCheckPermissionApi, questionnaireQuestionFindPageApi, questionnaireAnswerSaveApi, - questionnaireAnswerFindByUserApi, + questionnaireAnswerFindByUserOrFamilyApi, questionnaireAnswerFindDetailApi } from '@/api/base/wjApi'; import { useUserStore } from '@/store/modules/user'; @@ -368,6 +368,7 @@ const options = ref({}); const questionnaireId = ref(''); const openId = ref(""); // 微信 openId const xxtsId = ref(""); // 消息推送ID(从URL参数id获取) +const xsId = ref(""); // 学生ID(推送链接中的 xsId,用于「同一生多家长」去重) const loading = ref(true); const submitting = ref(false); // 提交中状态 const currentStep = ref<'fill' | 'success' | 'noPermission' | 'alreadyFilled' | 'timeInvalid'>('fill'); @@ -415,6 +416,7 @@ onLoad(async (params) => { options.value = params; openId.value = params?.openId || ''; xxtsId.value = params?.id || ''; // 从URL参数id获取xxtsId + xsId.value = (params?.xsId as string) || ''; // 如果有 openId,先进行认证 if (openId.value) { @@ -500,8 +502,10 @@ const initializePage = async () => { // 4. 检查是否已填写(如果不允许重复提交) if (!allowResubmit.value) { - const answerResult = await questionnaireAnswerFindByUserApi({ - questionnaireId: questionnaireId.value + const answerResult = await questionnaireAnswerFindByUserOrFamilyApi({ + questionnaireId: questionnaireId.value, + xxtsId: xxtsId.value || undefined, + xsId: xsId.value || undefined, }); if (answerResult && answerResult.resultCode === 1) { const hasAnswered = answerResult.result || answerResult.data; @@ -1091,6 +1095,9 @@ const doSubmitQuestionnaire = async () => { if (xxtsId.value) { submitParams.xxtsId = xxtsId.value; } + if (xsId.value) { + submitParams.xsId = xsId.value; + } // 提交答案 const result = await questionnaireAnswerSaveApi(submitParams); diff --git a/src/utils/filePreview.ts b/src/utils/filePreview.ts index 4385188..f7ceb45 100644 --- a/src/utils/filePreview.ts +++ b/src/utils/filePreview.ts @@ -5,6 +5,16 @@ import { KK_FILE_VIEW_URL } from '@/config'; +export const isVideo = (fileType: string): boolean => { + const videoTypes = ['mp4', 'avi', 'mov', 'wmv', 'flv', 'webm', 'mkv', '3gp', 'm4v']; + return videoTypes.includes(fileType.toLowerCase()); +}; + +export const isImage = (fileType: string): boolean => { + const imageTypes = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp']; + return imageTypes.includes(fileType.toLowerCase()); +}; + // 检查是否是压缩包文件 const isCompressedFile = (fileName: string): boolean => { const compressedExtensions = ['zip', 'rar', '7z', 'tar', 'gz', 'bz2']; @@ -13,7 +23,7 @@ const isCompressedFile = (fileName: string): boolean => { }; // 检查文件是否可以预览 -const canPreview = (fileName: string): boolean => { +export const canPreview = (fileName: string): boolean => { const previewableExtensions = [ 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt', 'rtf', 'odt', 'ods', 'odp', @@ -269,3 +279,15 @@ export const previewVideo = (videoUrl: string, videoTitle: string) => { }); }); }; + +// 图片预览 +export const previewImage = (imageUrl: string) => { + return new Promise((resolve) => { + uni.previewImage({ + urls: [imageUrl], + current: imageUrl, + success: resolve, + fail: resolve, + }); + }); +};