公文使用通用的附件预览
This commit is contained in:
parent
33ae8f8115
commit
4a4573e51c
@ -52,11 +52,53 @@
|
|||||||
<view v-else class="no-files">
|
<view v-else class="no-files">
|
||||||
<text>暂无附件</text>
|
<text>暂无附件</text>
|
||||||
</view>
|
</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>
|
</view>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import {
|
import {
|
||||||
isVideo,
|
isVideo,
|
||||||
isImage,
|
isImage,
|
||||||
@ -100,6 +142,13 @@ const emit = defineEmits<{
|
|||||||
(e: 'download', file: FileInfo): void;
|
(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 hasAttachments = computed(() => {
|
||||||
const attachments = [];
|
const attachments = [];
|
||||||
@ -315,21 +364,8 @@ const downloadFileAction = (file: FileInfo) => {
|
|||||||
// 获取原始文件名
|
// 获取原始文件名
|
||||||
const originalFileName = getOriginalFileName(file);
|
const originalFileName = getOriginalFileName(file);
|
||||||
|
|
||||||
// 调用下载工具函数
|
// 显示下载路径选择弹窗
|
||||||
downloadFileUtil(finalUrl, originalFileName)
|
showDownloadPathModal(finalUrl, originalFileName, file);
|
||||||
.then(() => {
|
|
||||||
uni.showToast({
|
|
||||||
title: "下载成功",
|
|
||||||
icon: "success",
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.error('下载失败:', error);
|
|
||||||
uni.showToast({
|
|
||||||
title: "下载失败",
|
|
||||||
icon: "error",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取原始文件名
|
// 获取原始文件名
|
||||||
@ -358,6 +394,288 @@ const getOriginalFileName = (file: FileInfo) => {
|
|||||||
|
|
||||||
return fileName;
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@ -455,4 +773,125 @@ const getOriginalFileName = (file: FileInfo) => {
|
|||||||
color: #999;
|
color: #999;
|
||||||
font-size: 14px;
|
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>
|
</style>
|
||||||
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<BasicLayout>
|
<BasicLayout>
|
||||||
<view class="px-15 pb-15">
|
<view class="p-15">
|
||||||
<!-- 公文基本信息 -->
|
<!-- 公文基本信息 -->
|
||||||
<view class="gw-info-section">
|
<view class="gw-info-section">
|
||||||
<view class="section-title">公文信息</view>
|
<view class="section-title">公文信息</view>
|
||||||
@ -26,131 +26,18 @@
|
|||||||
</view>
|
</view>
|
||||||
</view>
|
</view>
|
||||||
|
|
||||||
<!-- 文件信息 -->
|
<!-- 附件预览 -->
|
||||||
<view class="file-section">
|
<BasicFilePreview
|
||||||
<view class="section-title">附件</view>
|
v-if="gwInfo.fileUrl"
|
||||||
<view class="file-list" v-if="hasAttachments">
|
:file-url="gwInfo.fileUrl"
|
||||||
<!-- 显示所有解析后的附件 -->
|
:file-name="gwInfo.fileName"
|
||||||
<view
|
:file-format="gwInfo.fileFormat"
|
||||||
v-for="(file, index) in parsedAttachments"
|
class="mb-0"
|
||||||
: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>
|
|
||||||
|
|
||||||
</view>
|
</view>
|
||||||
<!-- 审批流程 -->
|
<!-- 审批流程 -->
|
||||||
<LcglSp :yw-id="gwId" yw-type="GW"/>
|
<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>
|
<template #bottom>
|
||||||
<YwConfirm v-if="showButton"
|
<YwConfirm v-if="showButton"
|
||||||
:spApi="gwSpApi"
|
:spApi="gwSpApi"
|
||||||
@ -172,22 +59,11 @@
|
|||||||
import { onLoad } from "@dcloudio/uni-app";
|
import { onLoad } from "@dcloudio/uni-app";
|
||||||
import {ref, onMounted, computed} from "vue";
|
import {ref, onMounted, computed} from "vue";
|
||||||
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
import BasicLayout from "@/components/BasicLayout/Layout.vue";
|
||||||
import {navigateTo} from "@/utils/uniapp";
|
|
||||||
import {getGwFlowByIdApi, gwSpApi, gwTransferApi, gwStopApi} from "@/api/routine/gw";
|
import {getGwFlowByIdApi, gwSpApi, gwTransferApi, gwStopApi} from "@/api/routine/gw";
|
||||||
import dayjs from "dayjs";
|
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 LcglSp from "@/components/LcglSp/index.vue";
|
||||||
import YwConfirm from "@/pages/components/YwConfirm/index.vue";
|
import YwConfirm from "@/pages/components/YwConfirm/index.vue";
|
||||||
|
import BasicFilePreview from "@/components/BasicFile/preview.vue";
|
||||||
import {useDataStore} from "@/store/modules/data";
|
import {useDataStore} from "@/store/modules/data";
|
||||||
import { GwPageUtils } from "@/utils/gwPageUtils";
|
import { GwPageUtils } from "@/utils/gwPageUtils";
|
||||||
const { setGwData, getXxts } = useDataStore();
|
const { setGwData, getXxts } = useDataStore();
|
||||||
@ -264,7 +140,6 @@ interface OperationLog {
|
|||||||
remark?: string;
|
remark?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 获取页面参数
|
// 获取页面参数
|
||||||
const gwId = ref("");
|
const gwId = ref("");
|
||||||
|
|
||||||
@ -275,9 +150,6 @@ const downloadUrl = ref('');
|
|||||||
const downloadFileName = ref('');
|
const downloadFileName = ref('');
|
||||||
const isDownloading = ref(false);
|
const isDownloading = ref(false);
|
||||||
|
|
||||||
// 用户store
|
|
||||||
const {getUser, getJs} = useUserStore();
|
|
||||||
|
|
||||||
// 数据
|
// 数据
|
||||||
const gwInfo = ref<GwInfo>({} as GwInfo);
|
const gwInfo = ref<GwInfo>({} as GwInfo);
|
||||||
const approvers = ref<Approver[]>([]);
|
const approvers = ref<Approver[]>([]);
|
||||||
@ -291,101 +163,6 @@ const ccExpanded = ref(false);
|
|||||||
// 操作记录展开状态
|
// 操作记录展开状态
|
||||||
const logExpanded = 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 () => {
|
const getGwInfo = async () => {
|
||||||
try {
|
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) => {
|
const formatTime = (time: any) => {
|
||||||
return dayjs(time).format("YYYY-MM-DD HH:mm:ss");
|
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 getUrgencyClass = (level: string) => {
|
||||||
const levelMap: Record<string, string> = {
|
const levelMap: Record<string, string> = {
|
||||||
@ -799,314 +226,6 @@ const getUrgencyText = (level: string) => {
|
|||||||
return levelMap[level] || "未知";
|
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) => {
|
const getCreatorName = (tjrId: string) => {
|
||||||
if (!tjrId) return "未知";
|
if (!tjrId) return "未知";
|
||||||
@ -1158,11 +277,7 @@ onLoad(async (data?: any) => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.gw-info-section,
|
.gw-info-section {
|
||||||
.file-section,
|
|
||||||
.approver-section,
|
|
||||||
.cc-section,
|
|
||||||
.log-section {
|
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
@ -1170,10 +285,6 @@ onLoad(async (data?: any) => {
|
|||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.log-section {
|
|
||||||
margin-bottom: 40px; // 操作记录区域增加底部间距
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
.section-title {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|||||||
@ -8,6 +8,7 @@ const { getGwData, setXxts, setGwData, getXxts } = useDataStore();
|
|||||||
export const GwPageUtils = {
|
export const GwPageUtils = {
|
||||||
// 初始化校验
|
// 初始化校验
|
||||||
async init(data?: any) {
|
async init(data?: any) {
|
||||||
|
setXxts({});
|
||||||
let ret = {
|
let ret = {
|
||||||
success: true,
|
success: true,
|
||||||
dbFlag: false,
|
dbFlag: false,
|
||||||
|
|||||||
@ -32,6 +32,7 @@ const qrStatus: any = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const init = async (data?: any) => {
|
const init = async (data?: any) => {
|
||||||
|
setXxts({});
|
||||||
let ret = {
|
let ret = {
|
||||||
success: true,
|
success: true,
|
||||||
dbFlag: false,
|
dbFlag: false,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ const { getData, setXxts, setData, getXxts } = useDataStore();
|
|||||||
export const XkTfPageUtils = {
|
export const XkTfPageUtils = {
|
||||||
// 初始化校验
|
// 初始化校验
|
||||||
async init(data?: any) {
|
async init(data?: any) {
|
||||||
|
setXxts({});
|
||||||
let ret = {
|
let ret = {
|
||||||
success: true,
|
success: true,
|
||||||
dbFlag: false,
|
dbFlag: false,
|
||||||
@ -31,6 +32,8 @@ export const XkTfPageUtils = {
|
|||||||
const xxtsRes = await xxtsFindByIdApi({ id: data.id });
|
const xxtsRes = await xxtsFindByIdApi({ id: data.id });
|
||||||
if (xxtsRes && xxtsRes.result) {
|
if (xxtsRes && xxtsRes.result) {
|
||||||
const xxts = xxtsRes.result;
|
const xxts = xxtsRes.result;
|
||||||
|
setXxts(xxts);
|
||||||
|
ret.xkTfId = xxts.xxzbId;
|
||||||
// 检查待办状态
|
// 检查待办状态
|
||||||
if (xxts.dbZt === "B") {
|
if (xxts.dbZt === "B") {
|
||||||
setData({ id: xxts.xxzbId });
|
setData({ id: xxts.xxzbId });
|
||||||
@ -38,8 +41,7 @@ export const XkTfPageUtils = {
|
|||||||
uni.reLaunch({ url });
|
uni.reLaunch({ url });
|
||||||
ret.success = false;
|
ret.success = false;
|
||||||
} else {
|
} else {
|
||||||
setXxts(xxts);
|
ret.success = true;
|
||||||
ret.xkTfId = xxts.xxzbId;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user