|
|
@@ -289,6 +289,125 @@
|
|
|
<el-descriptions-item label="管理员备注" :span="2" v-if="viewData.adminRemark">{{ viewData.adminRemark }}</el-descriptions-item>
|
|
|
</el-descriptions>
|
|
|
|
|
|
+ <!-- 附件区域 -->
|
|
|
+ <div v-if="viewData" style="margin-top: 20px;">
|
|
|
+ <!-- 出国境登记表盖章文件 -->
|
|
|
+ <div v-if="viewData.stampedFileUploadStatus === '1'"
|
|
|
+ style="margin-bottom: 15px; padding: 12px; border: 1px solid #e4e7ed; border-radius: 4px; background: #f9fafb;">
|
|
|
+ <div style="font-size: 14px; color: #606266; margin-bottom: 8px;">
|
|
|
+ <el-icon><Document /></el-icon>
|
|
|
+ <span style="margin-left: 5px; font-weight: 500;">出国境登记表盖章文件</span>
|
|
|
+ </div>
|
|
|
+ <div style="display: flex; align-items: center; justify-content: space-between;">
|
|
|
+ <div style="flex: 1;">
|
|
|
+ <el-tag type="success" size="small">
|
|
|
+ <el-icon><Document /></el-icon>
|
|
|
+ {{ viewData.stampedRegistrationFileName }}
|
|
|
+ </el-tag>
|
|
|
+ <span style="margin-left: 10px; font-size: 12px; color: #909399;">
|
|
|
+ 上传时间: {{ viewData.stampedFileUploadTime }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div style="display: flex; gap: 8px;">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ @click="handlePreviewStampedFile(viewData)"
|
|
|
+ >
|
|
|
+ <el-icon><View /></el-icon> 查看
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ @click="handleDownloadStampedFile(viewData)"
|
|
|
+ >
|
|
|
+ <el-icon><Download /></el-icon> 下载
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 党籍保留附件 -->
|
|
|
+ <div v-if="viewData.partyRetentionUploadStatus === '1'"
|
|
|
+ style="margin-bottom: 15px; padding: 12px; border: 1px solid #e4e7ed; border-radius: 4px; background: #fff5f5;">
|
|
|
+ <div style="font-size: 14px; color: #ff4757; margin-bottom: 8px;">
|
|
|
+ <el-icon><Warning /></el-icon>
|
|
|
+ <span style="margin-left: 5px; font-weight: 500;">党籍保留附件</span>
|
|
|
+ </div>
|
|
|
+ <div style="display: flex; align-items: center; justify-content: space-between;">
|
|
|
+ <div style="flex: 1;">
|
|
|
+ <el-tag type="danger" size="small">
|
|
|
+ <el-icon><Document /></el-icon>
|
|
|
+ {{ viewData.partyRetentionFileName }}
|
|
|
+ </el-tag>
|
|
|
+ <span style="margin-left: 10px; font-size: 12px; color: #909399;">
|
|
|
+ 上传时间: {{ viewData.partyRetentionUploadTime }}
|
|
|
+ </span>
|
|
|
+ </div>
|
|
|
+ <div style="display: flex; gap: 8px;">
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ @click="handlePreviewPartyRetentionFile(viewData)"
|
|
|
+ >
|
|
|
+ <el-icon><View /></el-icon> 查看
|
|
|
+ </el-button>
|
|
|
+ <el-button
|
|
|
+ link
|
|
|
+ type="primary"
|
|
|
+ size="small"
|
|
|
+ @click="handleDownloadPartyRetentionFile(viewData)"
|
|
|
+ >
|
|
|
+ <el-icon><Download /></el-icon> 下载
|
|
|
+ </el-button>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 其他申请附件列表 -->
|
|
|
+ <div v-if="viewAttachmentList.length > 0" style="margin-top: 15px;">
|
|
|
+ <div style="font-size: 14px; color: #606266; margin-bottom: 8px;">
|
|
|
+ <el-icon><Paperclip /></el-icon>
|
|
|
+ <span style="margin-left: 5px; font-weight: 500;">其他申请附件</span>
|
|
|
+ </div>
|
|
|
+ <el-table
|
|
|
+ :data="viewAttachmentList"
|
|
|
+ border
|
|
|
+ size="small"
|
|
|
+ >
|
|
|
+ <el-table-column label="序号" type="index" width="60" align="center" />
|
|
|
+ <el-table-column label="附件标题" prop="attachmentTitle" min-width="150" />
|
|
|
+ <el-table-column label="附件说明" prop="attachmentContent" min-width="200" show-overflow-tooltip>
|
|
|
+ <template #default="scope">
|
|
|
+ {{ scope.row.attachmentContent || '-' }}
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="文件名" prop="fileOriginalName" min-width="150" show-overflow-tooltip />
|
|
|
+ <el-table-column label="文件大小" prop="fileSizeFormatted" width="100" align="center" />
|
|
|
+ <el-table-column label="上传时间" prop="uploadTime" width="160" align="center" />
|
|
|
+ <el-table-column label="操作" width="100" align="center">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-button link type="primary" size="small" @click="handleDownloadAttachment(scope.row)">
|
|
|
+ <el-icon><Download /></el-icon> 下载
|
|
|
+ </el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <!-- 无任何附件时的提示 -->
|
|
|
+ <el-empty
|
|
|
+ v-if="viewData.stampedFileUploadStatus !== '1'
|
|
|
+ && viewData.partyRetentionUploadStatus !== '1'
|
|
|
+ && viewAttachmentList.length === 0"
|
|
|
+ description="暂无附件"
|
|
|
+ :image-size="100"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+
|
|
|
<!-- 查看审批记录 -->
|
|
|
<div class="mt-4">
|
|
|
<h4>审批记录</h4>
|
|
|
@@ -408,19 +527,27 @@ import {
|
|
|
approveOverseasApplication,
|
|
|
exportOverseasApplication,
|
|
|
exportOverseasApproval,
|
|
|
+ listOverseasAttachments,
|
|
|
type OverseasApplicationQuery,
|
|
|
type OverseasApplicationVO,
|
|
|
type OverseasApprovalQuery,
|
|
|
type OverseasApprovalVO,
|
|
|
type ApprovalRequest,
|
|
|
+ type OverseasAttachmentVO,
|
|
|
fixOverseasApprovalData
|
|
|
} from '@/api/rs/overseas';
|
|
|
import { ElMessage, ElMessageBox } from 'element-plus';
|
|
|
+import { Document, Warning, Paperclip, View, Download } from '@element-plus/icons-vue';
|
|
|
import animate from '@/animate';
|
|
|
+import request from '@/utils/request';
|
|
|
+import { getToken } from '@/utils/auth';
|
|
|
|
|
|
// 响应式数据
|
|
|
const { proxy } = getCurrentInstance() as any;
|
|
|
|
|
|
+// 附件列表数据
|
|
|
+const viewAttachmentList = ref<OverseasAttachmentVO[]>([]);
|
|
|
+
|
|
|
const state = reactive({
|
|
|
// 选项卡相关
|
|
|
activeTab: 'pending',
|
|
|
@@ -667,17 +794,25 @@ const resetRecordQuery = () => {
|
|
|
|
|
|
// 查看申请详情
|
|
|
const handleViewApplication = async (row: OverseasApplicationVO) => {
|
|
|
+ console.log('📄 [查看详情] 开始查看申请详情,申请ID:', row.applicationId);
|
|
|
try {
|
|
|
const response = await getOverseasApplication(row.applicationId);
|
|
|
state.viewData = response.data;
|
|
|
+ console.log('✅ [查看详情] 申请详情获取成功:', response.data);
|
|
|
|
|
|
// 获取审批记录
|
|
|
const approvalResponse = await getOverseasApprovalByApplication(row.applicationId);
|
|
|
state.applicationApprovalList = approvalResponse.data;
|
|
|
|
|
|
+ // 加载附件列表
|
|
|
+ console.log('🔄 [查看详情] 开始加载附件列表...');
|
|
|
+ await loadViewAttachmentList(row.applicationId);
|
|
|
+ console.log('✅ [查看详情] 附件列表加载完成');
|
|
|
+
|
|
|
state.viewDialog.visible = true;
|
|
|
} catch (error) {
|
|
|
- console.error('获取申请详情失败:', error);
|
|
|
+ console.error('❌ [查看详情] 获取申请详情失败:', error);
|
|
|
+ ElMessage.error('获取申请详情失败');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
@@ -747,19 +882,26 @@ const handleExportRecord = async () => {
|
|
|
|
|
|
// 查看审批记录详情
|
|
|
const handleViewRecord = async (row: OverseasApprovalVO) => {
|
|
|
+ console.log('📄 [查看记录详情] 开始查看审批记录详情,申请ID:', row.applicationId);
|
|
|
try {
|
|
|
// 通过申请ID获取申请详情
|
|
|
const response = await getOverseasApplication(row.applicationId);
|
|
|
state.viewData = response.data;
|
|
|
+ console.log('✅ [查看记录详情] 申请详情获取成功');
|
|
|
|
|
|
// 获取完整的审批记录历史
|
|
|
const approvalResponse = await getOverseasApprovalByApplication(row.applicationId);
|
|
|
state.applicationApprovalList = approvalResponse.data;
|
|
|
|
|
|
+ // 加载附件列表
|
|
|
+ console.log('🔄 [查看记录详情] 开始加载附件列表...');
|
|
|
+ await loadViewAttachmentList(row.applicationId);
|
|
|
+ console.log('✅ [查看记录详情] 附件列表加载完成');
|
|
|
+
|
|
|
// 显示查看对话框
|
|
|
state.viewDialog.visible = true;
|
|
|
} catch (error: any) {
|
|
|
- console.error('获取审批记录详情失败:', error);
|
|
|
+ console.error('❌ [查看记录详情] 获取审批记录详情失败:', error);
|
|
|
proxy.$modal.msgError('获取详情失败: ' + (error?.message || String(error)));
|
|
|
}
|
|
|
};
|
|
|
@@ -851,6 +993,219 @@ const getApprovalStatusTagType = (status: string): 'success' | 'warning' | 'dang
|
|
|
};
|
|
|
return typeMap[status] || 'info';
|
|
|
};
|
|
|
+
|
|
|
+// ============== 附件相关方法 ==============
|
|
|
+
|
|
|
+// 加载附件列表
|
|
|
+const loadViewAttachmentList = async (applicationId: number | string) => {
|
|
|
+ console.log('🔍 [附件加载] 开始加载附件列表,applicationId:', applicationId);
|
|
|
+ try {
|
|
|
+ const response = await listOverseasAttachments(applicationId);
|
|
|
+ console.log('✅ [附件加载] API响应成功:', response);
|
|
|
+
|
|
|
+ viewAttachmentList.value = response.data || [];
|
|
|
+
|
|
|
+ if (!response.data || response.data.length === 0) {
|
|
|
+ console.warn('⚠️ [附件加载] 该申请暂无附件数据');
|
|
|
+ } else {
|
|
|
+ console.log('✨ [附件加载] 附件列表:', viewAttachmentList.value);
|
|
|
+ }
|
|
|
+ } catch (error: any) {
|
|
|
+ console.error('❌ [附件加载] 加载附件列表失败:', error);
|
|
|
+ viewAttachmentList.value = [];
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 下载附件(从详情页)
|
|
|
+const handleDownloadAttachment = (row: OverseasAttachmentVO) => {
|
|
|
+ console.log('📥 下载附件:', row.fileOriginalName);
|
|
|
+ // 直接通过链接下载
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = row.filePath;
|
|
|
+ link.download = row.fileOriginalName;
|
|
|
+ link.target = '_blank';
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+};
|
|
|
+
|
|
|
+// 下载出国境登记表盖章文件
|
|
|
+const handleDownloadStampedFile = async (data: OverseasApplicationVO) => {
|
|
|
+ console.log('📥 下载出国境登记表盖章文件:', data.stampedRegistrationFileName);
|
|
|
+
|
|
|
+ if (!data.stampedFileOssId) {
|
|
|
+ ElMessage.warning('文件OSS ID不存在,无法下载');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 使用request下载文件
|
|
|
+ const response = await request({
|
|
|
+ url: `/resource/oss/download/${data.stampedFileOssId}`,
|
|
|
+ method: 'get',
|
|
|
+ responseType: 'blob'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建带MIME类型的Blob并触发下载
|
|
|
+ const blob = response instanceof Blob
|
|
|
+ ? new Blob([response], { type: 'application/pdf' })
|
|
|
+ : new Blob([response.data], { type: 'application/pdf' });
|
|
|
+ const url = window.URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.download = data.stampedRegistrationFileName || '出国境登记表盖章文件.pdf';
|
|
|
+
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+
|
|
|
+ // 清理资源
|
|
|
+ document.body.removeChild(link);
|
|
|
+ window.URL.revokeObjectURL(url);
|
|
|
+
|
|
|
+ ElMessage.success('文件下载成功');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('下载出国境登记表盖章文件失败:', error);
|
|
|
+ ElMessage.error('下载文件失败,请检查文件权限或稍后重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 下载党籍保留附件
|
|
|
+const handleDownloadPartyRetentionFile = async (data: OverseasApplicationVO) => {
|
|
|
+ console.log('📥 下载党籍保留附件:', data.partyRetentionFileName);
|
|
|
+
|
|
|
+ if (!data.partyRetentionFileOssId) {
|
|
|
+ ElMessage.warning('文件OSS ID不存在,无法下载');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 使用request下载文件
|
|
|
+ const response = await request({
|
|
|
+ url: `/resource/oss/download/${data.partyRetentionFileOssId}`,
|
|
|
+ method: 'get',
|
|
|
+ responseType: 'blob'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建带MIME类型的Blob并触发下载
|
|
|
+ const blob = response instanceof Blob
|
|
|
+ ? new Blob([response], { type: 'application/pdf' })
|
|
|
+ : new Blob([response.data], { type: 'application/pdf' });
|
|
|
+ const url = window.URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.download = data.partyRetentionFileName || '党籍保留附件.pdf';
|
|
|
+
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+
|
|
|
+ // 清理资源
|
|
|
+ document.body.removeChild(link);
|
|
|
+ window.URL.revokeObjectURL(url);
|
|
|
+
|
|
|
+ ElMessage.success('文件下载成功');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('下载党籍保留附件失败:', error);
|
|
|
+ ElMessage.error('下载文件失败,请检查文件权限或稍后重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 预览党籍保留附件
|
|
|
+const handlePreviewPartyRetentionFile = async (data: OverseasApplicationVO) => {
|
|
|
+ console.log('👁️ 预览党籍保留附件:', data.partyRetentionFileName);
|
|
|
+
|
|
|
+ if (!data.partyRetentionFileOssId) {
|
|
|
+ ElMessage.warning('文件OSS ID不存在,无法预览');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取文件扩展名
|
|
|
+ const fileName = data.partyRetentionFileName || '';
|
|
|
+ const fileExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
|
|
|
+
|
|
|
+ // 使用request获取文件blob
|
|
|
+ const response = await request({
|
|
|
+ url: `/resource/oss/download/${data.partyRetentionFileOssId}`,
|
|
|
+ method: 'get',
|
|
|
+ responseType: 'blob'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建带MIME类型的Blob(关键:指定type为application/pdf才能正常预览)
|
|
|
+ const blob = response instanceof Blob
|
|
|
+ ? new Blob([response], { type: 'application/pdf' })
|
|
|
+ : new Blob([response.data], { type: 'application/pdf' });
|
|
|
+ const fileUrl = window.URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ // 根据文件类型进行预览
|
|
|
+ if (fileExt === 'pdf') {
|
|
|
+ // PDF直接在新标签页打开
|
|
|
+ window.open(fileUrl, '_blank');
|
|
|
+
|
|
|
+ // 60秒后清理URL
|
|
|
+ setTimeout(() => {
|
|
|
+ window.URL.revokeObjectURL(fileUrl);
|
|
|
+ }, 60000);
|
|
|
+ }
|
|
|
+ // 其他文件类型提示下载
|
|
|
+ else {
|
|
|
+ ElMessage.info('该文件类型不支持在线预览,请下载后查看');
|
|
|
+ await handleDownloadPartyRetentionFile(data);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('预览党籍保留附件失败:', error);
|
|
|
+ ElMessage.error('预览文件失败,请检查文件权限或稍后重试');
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
+// 预览出国境登记表盖章文件
|
|
|
+const handlePreviewStampedFile = async (data: OverseasApplicationVO) => {
|
|
|
+ console.log('👁️ 预览出国境登记表盖章文件:', data.stampedRegistrationFileName);
|
|
|
+
|
|
|
+ if (!data.stampedFileOssId) {
|
|
|
+ ElMessage.warning('文件OSS ID不存在,无法预览');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取文件扩展名
|
|
|
+ const fileName = data.stampedRegistrationFileName || '';
|
|
|
+ const fileExt = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
|
|
|
+
|
|
|
+ // 使用request获取文件blob
|
|
|
+ const response = await request({
|
|
|
+ url: `/resource/oss/download/${data.stampedFileOssId}`,
|
|
|
+ method: 'get',
|
|
|
+ responseType: 'blob'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 创建带MIME类型的Blob(关键:指定type为application/pdf才能正常预览)
|
|
|
+ const blob = response instanceof Blob
|
|
|
+ ? new Blob([response], { type: 'application/pdf' })
|
|
|
+ : new Blob([response.data], { type: 'application/pdf' });
|
|
|
+ const fileUrl = window.URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ // 根据文件类型进行预览
|
|
|
+ if (fileExt === 'pdf') {
|
|
|
+ // PDF直接在新标签页打开
|
|
|
+ window.open(fileUrl, '_blank');
|
|
|
+
|
|
|
+ // 60秒后清理URL
|
|
|
+ setTimeout(() => {
|
|
|
+ window.URL.revokeObjectURL(fileUrl);
|
|
|
+ }, 60000);
|
|
|
+ }
|
|
|
+ // 其他文件类型提示下载
|
|
|
+ else {
|
|
|
+ ElMessage.info('该文件类型不支持在线预览,请下载后查看');
|
|
|
+ await handleDownloadStampedFile(data);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.error('预览出国境登记表盖章文件失败:', error);
|
|
|
+ ElMessage.error('预览文件失败,请检查文件权限或稍后重试');
|
|
|
+ }
|
|
|
+};
|
|
|
</script>
|
|
|
|
|
|
<style scoped>
|