公文使用通用的附件预览
This commit is contained in:
parent
33ae8f8115
commit
4a4573e51c
@ -52,11 +52,53 @@
|
||||
<view v-else class="no-files">
|
||||
<text>暂无附件</text>
|
||||
</view>
|
||||
|
||||
<!-- 下载路径选择弹窗 -->
|
||||
<u-popup :show="showDownloadModal" @close="showDownloadModal = false" mode="center">
|
||||
<view class="download-modal">
|
||||
<view class="download-header">
|
||||
<text class="download-title">文件下载</text>
|
||||
</view>
|
||||
<view class="download-content">
|
||||
<view class="file-info-section">
|
||||
<text class="file-label">文件名:</text>
|
||||
<text class="file-name">{{ downloadFileName }}</text>
|
||||
</view>
|
||||
<view class="path-info-section">
|
||||
<text class="path-label">下载路径:</text>
|
||||
<text class="path-text">将下载到默认下载目录</text>
|
||||
</view>
|
||||
<view class="download-tips">
|
||||
<text class="tips-text">点击确认后将开始下载文件</text>
|
||||
</view>
|
||||
<!-- 下载中状态 -->
|
||||
<view class="download-progress" v-if="isDownloading">
|
||||
<view class="progress-spinner"></view>
|
||||
<text class="progress-text">正在下载文件,请稍候...</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="download-actions" v-if="!isDownloading">
|
||||
<u-button
|
||||
text="取消"
|
||||
type="default"
|
||||
size="large"
|
||||
@click="cancelDownload"
|
||||
style="margin-right: 10px;"
|
||||
/>
|
||||
<u-button
|
||||
text="确认下载"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="confirmDownload"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { computed, ref } from 'vue';
|
||||
import {
|
||||
isVideo,
|
||||
isImage,
|
||||
@ -100,6 +142,13 @@ const emit = defineEmits<{
|
||||
(e: 'download', file: FileInfo): void;
|
||||
}>();
|
||||
|
||||
// 弹窗控制
|
||||
const showDownloadModal = ref(false);
|
||||
const downloadUrl = ref('');
|
||||
const downloadFileName = ref('');
|
||||
const isDownloading = ref(false);
|
||||
const currentDownloadFile = ref<FileInfo | null>(null);
|
||||
|
||||
// 检查是否有附件
|
||||
const hasAttachments = computed(() => {
|
||||
const attachments = [];
|
||||
@ -315,21 +364,8 @@ const downloadFileAction = (file: FileInfo) => {
|
||||
// 获取原始文件名
|
||||
const originalFileName = getOriginalFileName(file);
|
||||
|
||||
// 调用下载工具函数
|
||||
downloadFileUtil(finalUrl, originalFileName)
|
||||
.then(() => {
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "success",
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('下载失败:', error);
|
||||
uni.showToast({
|
||||
title: "下载失败",
|
||||
icon: "error",
|
||||
});
|
||||
});
|
||||
// 显示下载路径选择弹窗
|
||||
showDownloadPathModal(finalUrl, originalFileName, file);
|
||||
};
|
||||
|
||||
// 获取原始文件名
|
||||
@ -358,6 +394,288 @@ const getOriginalFileName = (file: FileInfo) => {
|
||||
|
||||
return fileName;
|
||||
};
|
||||
|
||||
// 显示下载路径选择弹窗
|
||||
const showDownloadPathModal = (url: string, fileName: string, file: FileInfo) => {
|
||||
downloadUrl.value = url;
|
||||
downloadFileName.value = fileName;
|
||||
currentDownloadFile.value = file;
|
||||
showDownloadModal.value = true;
|
||||
};
|
||||
|
||||
// 确认下载
|
||||
const confirmDownload = () => {
|
||||
// 设置下载状态
|
||||
isDownloading.value = true;
|
||||
|
||||
// 检查当前平台
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const {platform} = systemInfo;
|
||||
|
||||
// 备用检测方法
|
||||
const isH5 = platform === 'web' || typeof window !== 'undefined';
|
||||
|
||||
console.log('平台检测:', {platform, systemInfo, isH5});
|
||||
|
||||
if (isH5) {
|
||||
console.log('使用H5下载方式');
|
||||
// H5环境下使用直接链接下载,避免跨域问题
|
||||
downloadForH5(downloadUrl.value, downloadFileName.value);
|
||||
} else {
|
||||
console.log('使用原生下载方式');
|
||||
// 原生环境下使用原有下载方式
|
||||
downloadFileUtil(downloadUrl.value, downloadFileName.value)
|
||||
.then(() => {
|
||||
// 下载成功后关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "success",
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('下载失败:', error);
|
||||
// 下载失败后也关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载失败",
|
||||
icon: "error",
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// H5环境下的下载方法
|
||||
const downloadForH5 = (url: string, fileName: string) => {
|
||||
try {
|
||||
console.log('H5下载开始:', {url, fileName});
|
||||
|
||||
// 直接使用强制下载方式,避免打开文件
|
||||
forceDownload(url, fileName);
|
||||
|
||||
} catch (error) {
|
||||
console.error('H5下载失败:', error);
|
||||
// 如果整个方法失败,回退到直接链接方式
|
||||
fallbackDownload(url, fileName);
|
||||
}
|
||||
};
|
||||
|
||||
// 强制下载方法
|
||||
const forceDownload = (url: string, fileName: string) => {
|
||||
try {
|
||||
console.log('尝试强制下载:', {url, fileName});
|
||||
|
||||
// 方法1: 使用fetch下载文件内容,然后创建blob下载
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
cache: 'no-cache'
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.blob();
|
||||
})
|
||||
.then(blob => {
|
||||
console.log('文件下载成功,创建blob下载');
|
||||
|
||||
// 创建blob URL
|
||||
const blobUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
// 创建下载链接
|
||||
const link = document.createElement('a');
|
||||
link.href = blobUrl;
|
||||
link.download = fileName;
|
||||
link.style.display = 'none';
|
||||
|
||||
// 添加到DOM并触发点击
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// 清理DOM和blob URL
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
|
||||
// 下载成功后关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "success",
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch下载失败,尝试其他方法:', error);
|
||||
// 如果fetch失败,尝试其他方法
|
||||
tryAlternativeDownload(url, fileName);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('强制下载失败,尝试其他方法:', error);
|
||||
tryAlternativeDownload(url, fileName);
|
||||
}
|
||||
};
|
||||
|
||||
// 尝试替代下载方法
|
||||
const tryAlternativeDownload = (url: string, fileName: string) => {
|
||||
console.log('尝试替代下载方法');
|
||||
|
||||
// 方法1: 使用XMLHttpRequest下载
|
||||
try {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = 'blob';
|
||||
|
||||
xhr.onload = function () {
|
||||
if (xhr.status === 200) {
|
||||
const blob = xhr.response;
|
||||
const blobUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = blobUrl;
|
||||
link.download = fileName;
|
||||
link.style.display = 'none';
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
|
||||
// 下载成功后关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
console.log('XMLHttpRequest下载成功');
|
||||
} else {
|
||||
throw new Error(`HTTP error! status: ${xhr.status}`);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function () {
|
||||
console.error('XMLHttpRequest下载失败');
|
||||
console.log('调用手动下载提示');
|
||||
showManualDownloadModal(url, fileName);
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
|
||||
} catch (error) {
|
||||
console.error('XMLHttpRequest失败:', error);
|
||||
console.log('调用手动下载提示(catch)');
|
||||
showManualDownloadModal(url, fileName);
|
||||
}
|
||||
};
|
||||
|
||||
// 显示手动下载提示
|
||||
const showManualDownloadModal = (url: string, fileName: string) => {
|
||||
console.log('尝试原生下载');
|
||||
|
||||
// 尝试使用浏览器原生下载
|
||||
try {
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = fileName;
|
||||
link.target = '_blank';
|
||||
link.style.display = 'none';
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
console.log('原生下载已触发');
|
||||
|
||||
// 延迟关闭弹窗,给用户时间看到下载开始
|
||||
setTimeout(() => {
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
}, 1000);
|
||||
|
||||
uni.showToast({
|
||||
title: "开始下载",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('原生下载失败:', error);
|
||||
// 下载失败也关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载失败",
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 直接下载方法
|
||||
const fallbackDownload = (url: string, fileName: string) => {
|
||||
try {
|
||||
console.log('使用备用下载方法');
|
||||
|
||||
// 使用直接下载方法
|
||||
directDownload(url, fileName);
|
||||
|
||||
} catch (error) {
|
||||
console.error('备用下载也失败:', error);
|
||||
// 最后的方法:提示用户手动下载
|
||||
uni.showModal({
|
||||
title: '下载提示',
|
||||
content: `由于浏览器限制,无法自动下载文件。请长按链接手动保存:\n${url}`,
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 备用下载方法
|
||||
const directDownload = (url: string, fileName: string) => {
|
||||
try {
|
||||
// 修改URL添加下载参数
|
||||
const downloadUrl = url.includes('?')
|
||||
? `${url}&download=1&attachment=1`
|
||||
: `${url}?download=1&attachment=1`;
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = downloadUrl;
|
||||
link.download = fileName;
|
||||
link.target = '_self'; // 使用_self而不是_blank
|
||||
link.style.display = 'none';
|
||||
|
||||
// 添加到DOM并触发点击
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// 清理DOM
|
||||
document.body.removeChild(link);
|
||||
|
||||
uni.showToast({
|
||||
title: "开始下载",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('直接下载失败:', error);
|
||||
// 最后的方法:提示用户手动下载
|
||||
uni.showModal({
|
||||
title: '下载提示',
|
||||
content: `由于浏览器限制,无法自动下载文件。请长按链接手动保存:\n${url}`,
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 取消下载
|
||||
const cancelDownload = () => {
|
||||
showDownloadModal.value = false;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@ -455,4 +773,125 @@ const getOriginalFileName = (file: FileInfo) => {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.download-modal {
|
||||
width: 85vw;
|
||||
max-width: 450px;
|
||||
padding: 20px;
|
||||
background: #fff;
|
||||
border-radius: 12px;
|
||||
|
||||
.download-header {
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #eee;
|
||||
|
||||
.download-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
|
||||
.download-content {
|
||||
margin-bottom: 25px;
|
||||
|
||||
.file-info-section {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.file-label {
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
margin-right: 10px;
|
||||
flex-shrink: 0;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.file-name {
|
||||
color: #333;
|
||||
font-size: 14px;
|
||||
word-break: break-all;
|
||||
flex: 1;
|
||||
background: #f8f9fa;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e9ecef;
|
||||
}
|
||||
}
|
||||
|
||||
.path-info-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
|
||||
.path-label {
|
||||
font-weight: 500;
|
||||
color: #666;
|
||||
margin-right: 10px;
|
||||
flex-shrink: 0;
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
.path-text {
|
||||
color: #007aff;
|
||||
font-size: 14px;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.download-tips {
|
||||
text-align: center;
|
||||
|
||||
.tips-text {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.download-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 10px;
|
||||
|
||||
.u-button {
|
||||
flex: 1;
|
||||
max-width: 120px;
|
||||
}
|
||||
}
|
||||
|
||||
.download-progress {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px 0;
|
||||
|
||||
.progress-spinner {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: 2px solid #f3f3f3;
|
||||
border-top: 2px solid #007aff;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<BasicLayout>
|
||||
<view class="px-15 pb-15">
|
||||
<view class="p-15">
|
||||
<!-- 公文基本信息 -->
|
||||
<view class="gw-info-section">
|
||||
<view class="section-title">公文信息</view>
|
||||
@ -26,131 +26,18 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 文件信息 -->
|
||||
<view class="file-section">
|
||||
<view class="section-title">附件</view>
|
||||
<view class="file-list" v-if="hasAttachments">
|
||||
<!-- 显示所有解析后的附件 -->
|
||||
<view
|
||||
v-for="(file, index) in parsedAttachments"
|
||||
:key="(file as any).id || index"
|
||||
class="file-item"
|
||||
>
|
||||
<view class="file-icon">
|
||||
<image
|
||||
:src="getFileIcon(getFileSuffix(file))"
|
||||
class="icon-image"
|
||||
mode="aspectFit"
|
||||
/>
|
||||
</view>
|
||||
<view class="file-info">
|
||||
<text class="file-name">{{ getFileName(file) }}</text>
|
||||
</view>
|
||||
<view class="file-actions">
|
||||
<u-button
|
||||
v-if="canPreview(getFileSuffix(file)) && !isVideo(getFileSuffix(file))"
|
||||
text="预览"
|
||||
size="mini"
|
||||
type="primary"
|
||||
@click="previewFile(file)"
|
||||
/>
|
||||
<u-button
|
||||
v-if="isVideo(getFileSuffix(file))"
|
||||
text="播放"
|
||||
size="mini"
|
||||
type="success"
|
||||
@click="previewFile(file)"
|
||||
/>
|
||||
<u-button
|
||||
v-if="isImage(getFileSuffix(file))"
|
||||
text="查看"
|
||||
size="mini"
|
||||
type="warning"
|
||||
@click="previewFile(file)"
|
||||
/>
|
||||
<u-button
|
||||
text="下载"
|
||||
size="mini"
|
||||
type="info"
|
||||
@click="downloadFileAction(file)"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view v-else class="no-files">
|
||||
<text>暂无附件</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 附件预览 -->
|
||||
<BasicFilePreview
|
||||
v-if="gwInfo.fileUrl"
|
||||
:file-url="gwInfo.fileUrl"
|
||||
:file-name="gwInfo.fileName"
|
||||
:file-format="gwInfo.fileFormat"
|
||||
class="mb-0"
|
||||
/>
|
||||
</view>
|
||||
<!-- 审批流程 -->
|
||||
<LcglSp :yw-id="gwId" yw-type="GW"/>
|
||||
|
||||
<!-- 操作记录详情弹窗 -->
|
||||
<u-popup :show="showLogDetailModal" @close="showLogDetailModal = false" mode="center">
|
||||
<view class="detail-modal">
|
||||
<view class="detail-header">
|
||||
<text class="detail-title">操作详情</text>
|
||||
<u-button text="关闭" @click="showLogDetailModal = false"/>
|
||||
</view>
|
||||
<view class="detail-content">
|
||||
<view class="detail-item" v-if="currentLog.beforeChange">
|
||||
<text class="detail-label">变更前:</text>
|
||||
<text class="detail-value">{{ currentLog.beforeChange }}</text>
|
||||
</view>
|
||||
<view class="detail-item" v-if="currentLog.afterChange">
|
||||
<text class="detail-label">变更后:</text>
|
||||
<text class="detail-value">{{ currentLog.afterChange }}</text>
|
||||
</view>
|
||||
<view class="detail-item" v-if="currentLog.remark">
|
||||
<text class="detail-label">备注:</text>
|
||||
<text class="detail-value">{{ currentLog.remark }}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
|
||||
<!-- 下载路径选择弹窗 -->
|
||||
<u-popup :show="showDownloadModal" @close="showDownloadModal = false" mode="center">
|
||||
<view class="download-modal">
|
||||
<view class="download-header">
|
||||
<text class="download-title">文件下载</text>
|
||||
</view>
|
||||
<view class="download-content">
|
||||
<view class="file-info-section">
|
||||
<text class="file-label">文件名:</text>
|
||||
<text class="file-name">{{ downloadFileName }}</text>
|
||||
</view>
|
||||
<view class="path-info-section">
|
||||
<text class="path-label">下载路径:</text>
|
||||
<text class="path-text">将下载到默认下载目录</text>
|
||||
</view>
|
||||
<view class="download-tips">
|
||||
<text class="tips-text">点击确认后将开始下载文件</text>
|
||||
</view>
|
||||
<!-- 下载中状态 -->
|
||||
<view class="download-progress" v-if="isDownloading">
|
||||
<view class="progress-spinner"></view>
|
||||
<text class="progress-text">正在下载文件,请稍候...</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="download-actions" v-if="!isDownloading">
|
||||
<u-button
|
||||
text="取消"
|
||||
type="default"
|
||||
size="large"
|
||||
@click="cancelDownload"
|
||||
style="margin-right: 10px;"
|
||||
/>
|
||||
<u-button
|
||||
text="确认下载"
|
||||
type="primary"
|
||||
size="large"
|
||||
@click="confirmDownload"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
</u-popup>
|
||||
<template #bottom>
|
||||
<YwConfirm v-if="showButton"
|
||||
:spApi="gwSpApi"
|
||||
@ -172,22 +59,11 @@
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import {ref, onMounted, computed} from "vue";
|
||||
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
||||
import {navigateTo} from "@/utils/uniapp";
|
||||
import {getGwFlowByIdApi, gwSpApi, gwTransferApi, gwStopApi} from "@/api/routine/gw";
|
||||
import dayjs from "dayjs";
|
||||
import {useUserStore} from "@/store/modules/user";
|
||||
import {imagUrl} from "@/utils";
|
||||
import {
|
||||
isVideo,
|
||||
isImage,
|
||||
canPreview,
|
||||
previewFile as previewFileUtil,
|
||||
previewVideo as previewVideoUtil,
|
||||
previewImage as previewImageUtil,
|
||||
downloadFile
|
||||
} from "@/utils/filePreview";
|
||||
import LcglSp from "@/components/LcglSp/index.vue";
|
||||
import YwConfirm from "@/pages/components/YwConfirm/index.vue";
|
||||
import BasicFilePreview from "@/components/BasicFile/preview.vue";
|
||||
import {useDataStore} from "@/store/modules/data";
|
||||
import { GwPageUtils } from "@/utils/gwPageUtils";
|
||||
const { setGwData, getXxts } = useDataStore();
|
||||
@ -264,7 +140,6 @@ interface OperationLog {
|
||||
remark?: string;
|
||||
}
|
||||
|
||||
|
||||
// 获取页面参数
|
||||
const gwId = ref("");
|
||||
|
||||
@ -275,9 +150,6 @@ const downloadUrl = ref('');
|
||||
const downloadFileName = ref('');
|
||||
const isDownloading = ref(false);
|
||||
|
||||
// 用户store
|
||||
const {getUser, getJs} = useUserStore();
|
||||
|
||||
// 数据
|
||||
const gwInfo = ref<GwInfo>({} as GwInfo);
|
||||
const approvers = ref<Approver[]>([]);
|
||||
@ -291,101 +163,6 @@ const ccExpanded = ref(false);
|
||||
// 操作记录展开状态
|
||||
const logExpanded = ref(false);
|
||||
|
||||
// 计算属性:解析后的附件列表
|
||||
const parsedAttachments = computed(() => {
|
||||
const attachments = [];
|
||||
|
||||
// 处理files数组
|
||||
if (gwInfo.value.files && gwInfo.value.files.length > 0) {
|
||||
attachments.push(...gwInfo.value.files);
|
||||
}
|
||||
// 处理逗号分隔的fileUrl字符串
|
||||
else if (gwInfo.value.fileUrl) {
|
||||
const fileUrls = gwInfo.value.fileUrl.split(',').map(url => url.trim()).filter(url => url);
|
||||
|
||||
// 解析fileName字符串(如果存在)
|
||||
let fileNames: string[] = [];
|
||||
if (gwInfo.value.fileName) {
|
||||
fileNames = gwInfo.value.fileName.split(',').map(name => name.trim()).filter(name => name);
|
||||
}
|
||||
|
||||
// 将URL字符串转换为文件对象
|
||||
fileUrls.forEach((url, index) => {
|
||||
// 优先使用解析出的文件名,如果没有则从URL提取
|
||||
let displayName = fileNames[index] || url.split('/').pop() || `文件${index + 1}`;
|
||||
const fileFormat = url.split('.').pop() || 'unknown';
|
||||
|
||||
// 如果文件名包含扩展名,去掉扩展名(保持resourName不包含扩展名)
|
||||
let resourName = displayName;
|
||||
if (displayName.includes('.' + fileFormat)) {
|
||||
resourName = displayName.replace('.' + fileFormat, '');
|
||||
}
|
||||
|
||||
attachments.push({
|
||||
id: `file_${index}`,
|
||||
name: displayName, // 保持原始文件名(可能包含扩展名)
|
||||
url: url,
|
||||
resourUrl: url,
|
||||
resourName: resourName, // 不包含扩展名的文件名
|
||||
resSuf: fileFormat,
|
||||
size: 0 // 无法从URL获取大小
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return attachments;
|
||||
});
|
||||
|
||||
// 计算属性:是否有附件
|
||||
const hasAttachments = computed(() => {
|
||||
return parsedAttachments.value.length > 0;
|
||||
});
|
||||
|
||||
// 计算属性:显示的抄送人列表
|
||||
const displayedCcUsers = computed(() => {
|
||||
if (ccExpanded.value || ccUsers.value.length <= 2) {
|
||||
return ccUsers.value;
|
||||
}
|
||||
return ccUsers.value.slice(0, 2);
|
||||
});
|
||||
|
||||
// 计算属性:显示的操作记录列表
|
||||
const displayedOperationLogs = computed(() => {
|
||||
if (logExpanded.value || operationLogs.value.length <= 2) {
|
||||
return operationLogs.value;
|
||||
}
|
||||
return operationLogs.value.slice(0, 2);
|
||||
});
|
||||
|
||||
// 计算属性:当前用户是否可以操作(转办/同意)
|
||||
const canCurrentUserOperate = computed(() => {
|
||||
const userStore = useUserStore();
|
||||
const getUser = userStore.getUser;
|
||||
const getJs = userStore.getJs;
|
||||
const currentUserId = getJs?.id;
|
||||
|
||||
if (!currentUserId || !approvers.value || approvers.value.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 查找当前用户对应的审批人记录
|
||||
const currentUserApprover = approvers.value.find(approver => {
|
||||
return approver.userId === currentUserId || approver.id === currentUserId;
|
||||
});
|
||||
|
||||
if (!currentUserApprover) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 如果审批状态是approved或rejected,则不能操作
|
||||
const approveStatus = currentUserApprover.approveStatus;
|
||||
if (approveStatus === 'approved' || approveStatus === 'rejected') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
// 获取公文信息
|
||||
const getGwInfo = async () => {
|
||||
try {
|
||||
@ -418,361 +195,11 @@ const getGwInfo = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// 显示操作日志详情
|
||||
const showLogDetail = (log: OperationLog) => {
|
||||
currentLog.value = log;
|
||||
showLogDetailModal.value = true;
|
||||
};
|
||||
|
||||
// 切换抄送人展开状态
|
||||
const toggleCcExpanded = () => {
|
||||
ccExpanded.value = !ccExpanded.value;
|
||||
};
|
||||
|
||||
// 切换操作记录展开状态
|
||||
const toggleLogExpanded = () => {
|
||||
logExpanded.value = !logExpanded.value;
|
||||
};
|
||||
|
||||
// 驳回处理
|
||||
const handleReject = () => {
|
||||
uni.showModal({
|
||||
title: "驳回公文",
|
||||
content: "确定要驳回这个公文吗?",
|
||||
success: async (res) => {
|
||||
if (res.confirm) {
|
||||
try {
|
||||
// 这里调用驳回API
|
||||
console.log("驳回公文:", gwId.value);
|
||||
uni.showToast({
|
||||
title: "驳回成功",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("驳回失败:", error);
|
||||
uni.showToast({
|
||||
title: "驳回失败",
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
// 转办处理
|
||||
const handleTransfer = () => {
|
||||
// 构建跳转参数,包含所有必要的数据
|
||||
const params = {
|
||||
id: gwId.value,
|
||||
title: encodeURIComponent(gwInfo.value.title || ''),
|
||||
xxtsInfo: encodeURIComponent(JSON.stringify({
|
||||
id: gwId.value, // 这里应该是xxtsInfo的ID,需要根据实际数据结构调整
|
||||
// 其他xxtsInfo相关字段
|
||||
})),
|
||||
gwInfo: encodeURIComponent(JSON.stringify(gwInfo.value)),
|
||||
approvers: encodeURIComponent(JSON.stringify(approvers.value)),
|
||||
ccUsers: encodeURIComponent(JSON.stringify(ccUsers.value)) // 添加抄送人数据
|
||||
};
|
||||
|
||||
// 同时存储到本地存储,作为备用方案
|
||||
uni.setStorageSync('transferData', {
|
||||
xxtsInfo: {id: gwId.value},
|
||||
gwInfo: gwInfo.value,
|
||||
approvers: approvers.value,
|
||||
ccUsers: ccUsers.value // 添加抄送人数据
|
||||
});
|
||||
|
||||
// 跳转到转办页面
|
||||
navigateTo(`/pages/view/routine/gwlz/gwTransfer?id=${params.id}&title=${params.title}&xxtsInfo=${params.xxtsInfo}&gwInfo=${params.gwInfo}&approvers=${params.approvers}&ccUsers=${params.ccUsers}`);
|
||||
};
|
||||
|
||||
// 预览单个附件(从gwInfo直接获取)
|
||||
const previewSingleFile = (event?: Event) => {
|
||||
// 手动阻止事件冒泡
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (!gwInfo.value.fileUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const fileUrl = imagUrl(gwInfo.value.fileUrl);
|
||||
const fileName = gwInfo.value.fileName || '未知文件';
|
||||
const fileFormat = gwInfo.value.fileFormat || '';
|
||||
|
||||
// 根据文件类型选择预览方式
|
||||
if (isVideo(fileFormat)) {
|
||||
handlePreviewVideoSingle(fileUrl, fileName);
|
||||
} else if (isImage(fileFormat)) {
|
||||
handlePreviewImageSingle(fileUrl);
|
||||
} else if (canPreview(fileFormat)) {
|
||||
handlePreviewDocumentSingle(fileUrl, fileName, fileFormat);
|
||||
} else {
|
||||
// 不支持预览的文件类型,直接下载
|
||||
downloadSingleFile();
|
||||
}
|
||||
};
|
||||
|
||||
// 下载单个附件
|
||||
const downloadSingleFile = (event?: Event) => {
|
||||
// 手动阻止事件冒泡
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
if (!gwInfo.value.fileUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
const finalUrl = imagUrl(gwInfo.value.fileUrl);
|
||||
const fileName = gwInfo.value.fileName || '未知文件';
|
||||
const fileFormat = gwInfo.value.fileFormat || '';
|
||||
const fullFileName = fileFormat ? `${fileName}.${fileFormat}` : fileName;
|
||||
|
||||
// 显示下载路径选择弹窗
|
||||
showDownloadPathModal(finalUrl, fullFileName);
|
||||
};
|
||||
|
||||
// 文件预览
|
||||
const previewFile = (file: FileInfo, event?: Event) => {
|
||||
// 手动阻止事件冒泡
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
// 确定文件URL和名称
|
||||
const fileUrl = file.resourUrl ? imagUrl(file.resourUrl) : file.url;
|
||||
const fileName = file.resourName ? `${file.resourName}.${file.resSuf}` : file.name;
|
||||
const fileSuf = file.resSuf || file.name.split('.').pop() || '';
|
||||
|
||||
// 根据文件类型选择预览方式
|
||||
if (isVideo(fileSuf)) {
|
||||
handlePreviewVideo(file);
|
||||
} else if (isImage(fileSuf)) {
|
||||
handlePreviewImage(file);
|
||||
} else if (canPreview(fileSuf)) {
|
||||
handlePreviewDocument(file);
|
||||
} else {
|
||||
// 不支持预览的文件类型,直接下载
|
||||
downloadFileAction(file);
|
||||
}
|
||||
};
|
||||
|
||||
// 文档预览
|
||||
const handlePreviewDocument = (file: FileInfo) => {
|
||||
const fileUrl = file.resourUrl ? imagUrl(file.resourUrl) : file.url;
|
||||
const fileName = file.resourName ? `${file.resourName}.${file.resSuf}` : file.name;
|
||||
const fileSuf = file.resSuf || file.name.split('.').pop() || '';
|
||||
|
||||
previewFileUtil(fileUrl, fileName, fileSuf)
|
||||
.catch((error: any) => {
|
||||
// 预览失败时尝试下载
|
||||
downloadFileAction(file);
|
||||
});
|
||||
};
|
||||
|
||||
// 单个附件文档预览
|
||||
const handlePreviewDocumentSingle = (fileUrl: string, fileName: string, fileFormat: string) => {
|
||||
const fullFileName = fileFormat ? `${fileName}.${fileFormat}` : fileName;
|
||||
|
||||
previewFileUtil(fileUrl, fullFileName, fileFormat)
|
||||
.catch((error: any) => {
|
||||
// 预览失败时尝试下载
|
||||
downloadSingleFile();
|
||||
});
|
||||
};
|
||||
|
||||
// 视频预览
|
||||
const handlePreviewVideo = (file: FileInfo) => {
|
||||
const videoUrl = file.resourUrl ? imagUrl(file.resourUrl) : file.url;
|
||||
const videoName = file.resourName || file.name;
|
||||
|
||||
previewVideoUtil(videoUrl, videoName)
|
||||
.catch((error: any) => {
|
||||
// 视频预览失败时的处理
|
||||
});
|
||||
};
|
||||
|
||||
// 单个附件视频预览
|
||||
const handlePreviewVideoSingle = (videoUrl: string, videoName: string) => {
|
||||
previewVideoUtil(videoUrl, videoName)
|
||||
.catch((error: any) => {
|
||||
// 视频预览失败时的处理
|
||||
});
|
||||
};
|
||||
|
||||
// 图片预览
|
||||
const handlePreviewImage = (file: FileInfo) => {
|
||||
const imageUrl = file.resourUrl ? imagUrl(file.resourUrl) : file.url;
|
||||
|
||||
previewImageUtil(imageUrl)
|
||||
.catch((error: any) => {
|
||||
// 图片预览失败时的处理
|
||||
});
|
||||
};
|
||||
|
||||
// 单个附件图片预览
|
||||
const handlePreviewImageSingle = (imageUrl: string) => {
|
||||
previewImageUtil(imageUrl)
|
||||
.catch((error: any) => {
|
||||
// 图片预览失败时的处理
|
||||
});
|
||||
};
|
||||
|
||||
// 文件下载 - 支持选择下载路径
|
||||
const downloadFileAction = (file: FileInfo, event?: Event) => {
|
||||
// 手动阻止事件冒泡
|
||||
if (event) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
const finalUrl = file.resourUrl ? imagUrl(file.resourUrl) : imagUrl(file.url);
|
||||
// 获取原始文件名
|
||||
const originalFileName = getOriginalFileName(file);
|
||||
|
||||
console.log('下载文件:', {finalUrl, originalFileName, file});
|
||||
|
||||
// 显示下载路径选择弹窗
|
||||
showDownloadPathModal(finalUrl, originalFileName);
|
||||
};
|
||||
|
||||
// 格式化时间
|
||||
const formatTime = (time: any) => {
|
||||
return dayjs(time).format("YYYY-MM-DD HH:mm:ss");
|
||||
};
|
||||
|
||||
// 格式化文件大小
|
||||
const formatFileSize = (size: any) => {
|
||||
if (!size) return "0B";
|
||||
if (size < 1024) return size + "B";
|
||||
if (size < 1024 * 1024) return (size / 1024).toFixed(2) + "KB";
|
||||
return (size / (1024 * 1024)).toFixed(2) + "MB";
|
||||
};
|
||||
|
||||
// 获取文件名
|
||||
const getFileName = (file: FileInfo) => {
|
||||
if (file.resourName) {
|
||||
return file.resourName;
|
||||
}
|
||||
if (file.name) {
|
||||
// 如果name包含扩展名,去掉扩展名
|
||||
const lastDotIndex = file.name.lastIndexOf('.');
|
||||
if (lastDotIndex > 0) {
|
||||
return file.name.substring(0, lastDotIndex);
|
||||
}
|
||||
return file.name;
|
||||
}
|
||||
return '未知文件';
|
||||
};
|
||||
|
||||
// 获取文件后缀
|
||||
const getFileSuffix = (file: FileInfo) => {
|
||||
if (file.resSuf) {
|
||||
return file.resSuf;
|
||||
}
|
||||
if (file.name) {
|
||||
const lastDotIndex = file.name.lastIndexOf('.');
|
||||
if (lastDotIndex > 0) {
|
||||
return file.name.substring(lastDotIndex + 1);
|
||||
}
|
||||
}
|
||||
return 'unknown';
|
||||
};
|
||||
|
||||
// 获取文件图标
|
||||
const getFileIcon = (fileType: string) => {
|
||||
const type = fileType.toLowerCase();
|
||||
|
||||
switch (type) {
|
||||
case 'pdf':
|
||||
return '/static/base/view/pdf.png';
|
||||
case 'doc':
|
||||
case 'docx':
|
||||
return '/static/base/view/word.png';
|
||||
case 'xls':
|
||||
case 'xlsx':
|
||||
return '/static/base/view/excel.png';
|
||||
case 'ppt':
|
||||
case 'pptx':
|
||||
return '/static/base/view/ppt.png';
|
||||
case 'zip':
|
||||
case 'rar':
|
||||
case '7z':
|
||||
return '/static/base/view/zip.png';
|
||||
default:
|
||||
return '/static/base/view/more.png';
|
||||
}
|
||||
};
|
||||
|
||||
// 获取状态样式类
|
||||
const getStatusClass = (status: any) => {
|
||||
const statusMap: Record<string, string> = {
|
||||
draft: "status-draft",
|
||||
pending: "status-pending",
|
||||
approved: "status-approved",
|
||||
rejected: "status-rejected",
|
||||
};
|
||||
return statusMap[status] || "status-default";
|
||||
};
|
||||
|
||||
// 获取状态文本
|
||||
const getStatusText = (status: any) => {
|
||||
const statusMap: Record<string, string> = {
|
||||
draft: "草稿",
|
||||
pending: "待审批",
|
||||
approved: "已通过",
|
||||
rejected: "已驳回",
|
||||
};
|
||||
return statusMap[status] || "未知";
|
||||
};
|
||||
|
||||
// 获取审批人状态样式类
|
||||
const getApproverStatusClass = (status: any) => {
|
||||
const statusMap: Record<string, string> = {
|
||||
pending: "status-pending",
|
||||
approved: "status-approved",
|
||||
rejected: "status-rejected",
|
||||
skipped: "status-skipped",
|
||||
};
|
||||
return statusMap[status] || "status-default";
|
||||
};
|
||||
|
||||
// 获取审批人状态文本
|
||||
const getApproverStatusText = (status: any) => {
|
||||
const statusMap: Record<string, string> = {
|
||||
pending: "待审批",
|
||||
approved: "已同意",
|
||||
rejected: "已驳回",
|
||||
skipped: "已跳过",
|
||||
};
|
||||
return statusMap[status] || "未知";
|
||||
};
|
||||
|
||||
// 获取抄送人状态样式类
|
||||
const getCCStatusClass = (status: any) => {
|
||||
const statusMap: Record<string, string> = {
|
||||
unread: "status-unread",
|
||||
read: "status-read",
|
||||
};
|
||||
return statusMap[status] || "status-default";
|
||||
};
|
||||
|
||||
// 获取抄送人状态文本
|
||||
const getCCStatusText = (status: any) => {
|
||||
const statusMap: Record<string, string> = {
|
||||
unread: "未读",
|
||||
read: "已读",
|
||||
};
|
||||
return statusMap[status] || "未知";
|
||||
};
|
||||
|
||||
// 获取紧急程度样式类
|
||||
const getUrgencyClass = (level: string) => {
|
||||
const levelMap: Record<string, string> = {
|
||||
@ -799,314 +226,6 @@ const getUrgencyText = (level: string) => {
|
||||
return levelMap[level] || "未知";
|
||||
};
|
||||
|
||||
// 获取原始文件名
|
||||
const getOriginalFileName = (file: FileInfo) => {
|
||||
// 优先使用resourName,如果没有则使用name,确保文件名正确
|
||||
let fileName = '';
|
||||
if (file.resourName) {
|
||||
// 如果resourName已经包含扩展名,直接使用
|
||||
if (file.resSuf && !file.resourName.includes('.' + file.resSuf)) {
|
||||
fileName = `${file.resourName}.${file.resSuf}`;
|
||||
} else {
|
||||
fileName = file.resourName;
|
||||
}
|
||||
} else if (file.name) {
|
||||
// 如果name已经包含扩展名,直接使用
|
||||
if (file.resSuf && !file.name.includes('.' + file.resSuf)) {
|
||||
fileName = `${file.name}.${file.resSuf}`;
|
||||
} else {
|
||||
fileName = file.name;
|
||||
}
|
||||
} else {
|
||||
// 最后备用方案,从URL提取文件名
|
||||
const urlFileName = file.url.split('/').pop() || '未知文件';
|
||||
fileName = urlFileName;
|
||||
}
|
||||
|
||||
return fileName;
|
||||
};
|
||||
|
||||
// 显示下载路径选择弹窗
|
||||
const showDownloadPathModal = (url: string, fileName: string) => {
|
||||
downloadUrl.value = url;
|
||||
downloadFileName.value = fileName;
|
||||
showDownloadModal.value = true;
|
||||
};
|
||||
|
||||
// 确认下载
|
||||
const confirmDownload = () => {
|
||||
// 设置下载状态
|
||||
isDownloading.value = true;
|
||||
|
||||
// 检查当前平台
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const {platform} = systemInfo;
|
||||
|
||||
// 备用检测方法
|
||||
const isH5 = platform === 'web' || typeof window !== 'undefined';
|
||||
|
||||
console.log('平台检测:', {platform, systemInfo, isH5});
|
||||
|
||||
if (isH5) {
|
||||
console.log('使用H5下载方式');
|
||||
// H5环境下使用直接链接下载,避免跨域问题
|
||||
downloadForH5(downloadUrl.value, downloadFileName.value);
|
||||
} else {
|
||||
console.log('使用原生下载方式');
|
||||
// 原生环境下使用原有下载方式
|
||||
downloadFile(downloadUrl.value, downloadFileName.value)
|
||||
.then(() => {
|
||||
// 下载成功后关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "success",
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('下载失败:', error);
|
||||
// 下载失败后也关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载失败",
|
||||
icon: "error",
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// H5环境下的下载方法
|
||||
const downloadForH5 = (url: string, fileName: string) => {
|
||||
try {
|
||||
console.log('H5下载开始:', {url, fileName});
|
||||
|
||||
// 直接使用强制下载方式,避免打开文件
|
||||
forceDownload(url, fileName);
|
||||
|
||||
} catch (error) {
|
||||
console.error('H5下载失败:', error);
|
||||
// 如果整个方法失败,回退到直接链接方式
|
||||
fallbackDownload(url, fileName);
|
||||
}
|
||||
};
|
||||
|
||||
// 强制下载方法
|
||||
const forceDownload = (url: string, fileName: string) => {
|
||||
try {
|
||||
console.log('尝试强制下载:', {url, fileName});
|
||||
|
||||
// 方法1: 使用fetch下载文件内容,然后创建blob下载
|
||||
fetch(url, {
|
||||
method: 'GET',
|
||||
mode: 'cors',
|
||||
cache: 'no-cache'
|
||||
})
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
return response.blob();
|
||||
})
|
||||
.then(blob => {
|
||||
console.log('文件下载成功,创建blob下载');
|
||||
|
||||
// 创建blob URL
|
||||
const blobUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
// 创建下载链接
|
||||
const link = document.createElement('a');
|
||||
link.href = blobUrl;
|
||||
link.download = fileName;
|
||||
link.style.display = 'none';
|
||||
|
||||
// 添加到DOM并触发点击
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// 清理DOM和blob URL
|
||||
document.body.removeChild(link);
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
|
||||
// 下载成功后关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "success",
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Fetch下载失败,尝试其他方法:', error);
|
||||
// 如果fetch失败,尝试其他方法
|
||||
tryAlternativeDownload(url, fileName);
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('强制下载失败,尝试其他方法:', error);
|
||||
tryAlternativeDownload(url, fileName);
|
||||
}
|
||||
};
|
||||
|
||||
// 尝试替代下载方法
|
||||
const tryAlternativeDownload = (url: string, fileName: string) => {
|
||||
console.log('尝试替代下载方法');
|
||||
|
||||
// 方法1: 使用XMLHttpRequest下载
|
||||
try {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', url, true);
|
||||
xhr.responseType = 'blob';
|
||||
|
||||
xhr.onload = function () {
|
||||
if (xhr.status === 200) {
|
||||
const blob = xhr.response;
|
||||
const blobUrl = window.URL.createObjectURL(blob);
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = blobUrl;
|
||||
link.download = fileName;
|
||||
link.style.display = 'none';
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
|
||||
// 下载成功后关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载成功",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
console.log('XMLHttpRequest下载成功');
|
||||
} else {
|
||||
throw new Error(`HTTP error! status: ${xhr.status}`);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onerror = function () {
|
||||
console.error('XMLHttpRequest下载失败');
|
||||
console.log('调用手动下载提示');
|
||||
showManualDownloadModal(url, fileName);
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
|
||||
} catch (error) {
|
||||
console.error('XMLHttpRequest失败:', error);
|
||||
console.log('调用手动下载提示(catch)');
|
||||
showManualDownloadModal(url, fileName);
|
||||
}
|
||||
};
|
||||
|
||||
// 显示手动下载提示
|
||||
const showManualDownloadModal = (url: string, fileName: string) => {
|
||||
console.log('尝试原生下载');
|
||||
|
||||
// 尝试使用浏览器原生下载
|
||||
try {
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = fileName;
|
||||
link.target = '_blank';
|
||||
link.style.display = 'none';
|
||||
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
console.log('原生下载已触发');
|
||||
|
||||
// 延迟关闭弹窗,给用户时间看到下载开始
|
||||
setTimeout(() => {
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
}, 1000);
|
||||
|
||||
uni.showToast({
|
||||
title: "开始下载",
|
||||
icon: "success",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('原生下载失败:', error);
|
||||
// 下载失败也关闭弹窗
|
||||
isDownloading.value = false;
|
||||
showDownloadModal.value = false;
|
||||
uni.showToast({
|
||||
title: "下载失败",
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 直接下载方法
|
||||
const directDownload = (url: string, fileName: string) => {
|
||||
try {
|
||||
// 修改URL添加下载参数
|
||||
const downloadUrl = url.includes('?')
|
||||
? `${url}&download=1&attachment=1`
|
||||
: `${url}?download=1&attachment=1`;
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = downloadUrl;
|
||||
link.download = fileName;
|
||||
link.target = '_self'; // 使用_self而不是_blank
|
||||
link.style.display = 'none';
|
||||
|
||||
// 添加到DOM并触发点击
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
|
||||
// 清理DOM
|
||||
document.body.removeChild(link);
|
||||
|
||||
uni.showToast({
|
||||
title: "开始下载",
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('直接下载失败:', error);
|
||||
// 最后的方法:提示用户手动下载
|
||||
uni.showModal({
|
||||
title: '下载提示',
|
||||
content: `由于浏览器限制,无法自动下载文件。请长按链接手动保存:\n${url}`,
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 备用下载方法
|
||||
const fallbackDownload = (url: string, fileName: string) => {
|
||||
try {
|
||||
console.log('使用备用下载方法');
|
||||
|
||||
// 使用直接下载方法
|
||||
directDownload(url, fileName);
|
||||
|
||||
} catch (error) {
|
||||
console.error('备用下载也失败:', error);
|
||||
// 最后的方法:提示用户手动下载
|
||||
uni.showModal({
|
||||
title: '下载提示',
|
||||
content: `由于浏览器限制,无法自动下载文件。请长按链接手动保存:\n${url}`,
|
||||
showCancel: false,
|
||||
confirmText: '知道了'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 取消下载
|
||||
const cancelDownload = () => {
|
||||
showDownloadModal.value = false;
|
||||
};
|
||||
|
||||
// 获取创建人名称
|
||||
const getCreatorName = (tjrId: string) => {
|
||||
if (!tjrId) return "未知";
|
||||
@ -1158,11 +277,7 @@ onLoad(async (data?: any) => {
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.gw-info-section,
|
||||
.file-section,
|
||||
.approver-section,
|
||||
.cc-section,
|
||||
.log-section {
|
||||
.gw-info-section {
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background: #fff;
|
||||
@ -1170,10 +285,6 @@ onLoad(async (data?: any) => {
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.log-section {
|
||||
margin-bottom: 40px; // 操作记录区域增加底部间距
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
|
||||
@ -8,6 +8,7 @@ const { getGwData, setXxts, setGwData, getXxts } = useDataStore();
|
||||
export const GwPageUtils = {
|
||||
// 初始化校验
|
||||
async init(data?: any) {
|
||||
setXxts({});
|
||||
let ret = {
|
||||
success: true,
|
||||
dbFlag: false,
|
||||
|
||||
@ -32,6 +32,7 @@ const qrStatus: any = {
|
||||
};
|
||||
|
||||
const init = async (data?: any) => {
|
||||
setXxts({});
|
||||
let ret = {
|
||||
success: true,
|
||||
dbFlag: false,
|
||||
|
||||
@ -8,6 +8,7 @@ const { getData, setXxts, setData, getXxts } = useDataStore();
|
||||
export const XkTfPageUtils = {
|
||||
// 初始化校验
|
||||
async init(data?: any) {
|
||||
setXxts({});
|
||||
let ret = {
|
||||
success: true,
|
||||
dbFlag: false,
|
||||
@ -31,6 +32,8 @@ export const XkTfPageUtils = {
|
||||
const xxtsRes = await xxtsFindByIdApi({ id: data.id });
|
||||
if (xxtsRes && xxtsRes.result) {
|
||||
const xxts = xxtsRes.result;
|
||||
setXxts(xxts);
|
||||
ret.xkTfId = xxts.xxzbId;
|
||||
// 检查待办状态
|
||||
if (xxts.dbZt === "B") {
|
||||
setData({ id: xxts.xxzbId });
|
||||
@ -38,8 +41,7 @@ export const XkTfPageUtils = {
|
||||
uni.reLaunch({ url });
|
||||
ret.success = false;
|
||||
} else {
|
||||
setXxts(xxts);
|
||||
ret.xkTfId = xxts.xxzbId;
|
||||
ret.success = true;
|
||||
}
|
||||
} else {
|
||||
uni.showToast({
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user