| | |
| | | |
| | | <el-table v-loading="loading" :data="recordsList" @selection-change="handleSelectionChange"> |
| | | <el-table-column type="selection" width="55" align="center" /> |
| | | |
| | | |
| | | |
| | | <el-table-column label="操作" align="center" width="190" class-name="small-padding fixed-width"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | v-if="scope.row.ownData" |
| | | |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-edit" |
| | | @click="handleInfo(scope.row)" |
| | | v-hasPermi="['system:records:edit']" |
| | | >案卷详细信息</el-button> |
| | | |
| | | <el-button |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-edit" |
| | | @click="handleCheck(scope.row)" |
| | | >查看</el-button> |
| | | <el-button |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-printer" |
| | | @click="viewAndPrintExcel(scope.row)" |
| | | title="查看并打印Excel文件" |
| | | >打印预整理清单</el-button> |
| | | <el-button |
| | | v-if="userId!==1&&scope.row.ownData" |
| | | |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-edit" |
| | | @click="handleSubmit(scope.row)" |
| | | v-hasPermi="['system:records:edit']" |
| | | >提交案卷</el-button> |
| | | <el-button |
| | | v-if="scope.row.ownData||userId===1" |
| | | |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-edit" |
| | | @click="handleUpdate(scope.row)" |
| | | v-hasPermi="['system:records:edit']" |
| | | >修改</el-button> |
| | | <el-button |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-delete" |
| | | @click="handleDelete(scope.row)" |
| | | v-hasPermi="['system:records:remove']" |
| | | >删除</el-button> |
| | | <el-dropdown size="mini" v-hasPermi="['system:records:remove']" @command="(command) => handleCommand(command, scope.row)"> |
| | | <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button> |
| | | <el-dropdown-menu slot="dropdown"> |
| | | |
| | | <el-dropdown-item command="handleAuthUser" icon="el-icon-user" |
| | | >分配用户</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </el-dropdown> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <el-table-column label="状态" align="center" prop="recordStatus" width="120"> |
| | | <template slot-scope="scope"> |
| | | <el-button :type="scope.row.recordStatus === '未录入' ? 'danger' : 'success'" size="mini"> |
| | | {{ scope.row.recordStatus }} |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | <!-- <el-table-column label="${comment}" align="center" prop="id" /> --> |
| | | <el-table-column label="档案号" align="center" prop="recordId" /> |
| | | <el-table-column label="发文号" align="center" prop="inquiryNumber" /> |
| | | <el-table-column label="项目名称" align="center" prop="everyProjectName" /> |
| | | |
| | | <el-table-column label="案卷题名" align="center" prop="caseTitle" show-overflow-tooltip /> |
| | | |
| | | <el-table-column label="案卷题名" align="center" prop="caseTitle" /> |
| | | <el-table-column label="公开属性" align="center" prop="publicAttribute" /> |
| | | <el-table-column label="编制单位" align="center" prop="preparationUnit" /> |
| | | <el-table-column label="编制日期" align="center" prop="preparationDate" width="180"> |
| | |
| | | <el-table-column label="缩微号" align="center" prop="microfilmNumber" /> |
| | | <el-table-column label="备注" align="center" prop="remarks" /> |
| | | <el-table-column label="历史相关发文号" align="center" prop="historicalReferenceNumber" /> |
| | | |
| | | <el-table-column label="状态" align="center" prop="recordStatus"> |
| | | <template slot-scope="scope"> |
| | | <el-button :type="scope.row.recordStatus === '未录入' ? 'danger' : 'success'" size="mini"> |
| | | {{ scope.row.recordStatus }} |
| | | </el-button> |
| | | </template> |
| | | </el-table-column> |
| | | |
| | | |
| | | <el-table-column label="操作" align="center" width="190" class-name="small-padding fixed-width"> |
| | | <template slot-scope="scope"> |
| | | <el-button |
| | | v-if="scope.row.ownData" |
| | | |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-edit" |
| | | @click="handleInfo(scope.row)" |
| | | v-hasPermi="['system:records:edit']" |
| | | >案卷详细信息</el-button> |
| | | |
| | | <el-button |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-edit" |
| | | @click="handleCheck(scope.row)" |
| | | >查看</el-button> |
| | | <el-button |
| | | v-if="userId!==1&&scope.row.ownData" |
| | | |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-edit" |
| | | @click="handleSubmit(scope.row)" |
| | | v-hasPermi="['system:records:edit']" |
| | | >提交案卷</el-button> |
| | | <el-button |
| | | v-if="scope.row.ownData||userId===1" |
| | | |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-edit" |
| | | @click="handleUpdate(scope.row)" |
| | | v-hasPermi="['system:records:edit']" |
| | | >修改</el-button> |
| | | <el-button |
| | | size="mini" |
| | | type="text" |
| | | icon="el-icon-delete" |
| | | @click="handleDelete(scope.row)" |
| | | v-hasPermi="['system:records:remove']" |
| | | >删除</el-button> |
| | | <el-dropdown size="mini" v-hasPermi="['system:records:remove']" @command="(command) => handleCommand(command, scope.row)"> |
| | | <el-button size="mini" type="text" icon="el-icon-d-arrow-right">更多</el-button> |
| | | <el-dropdown-menu slot="dropdown"> |
| | | |
| | | <el-dropdown-item command="handleAuthUser" icon="el-icon-user" |
| | | >分配用户</el-dropdown-item> |
| | | </el-dropdown-menu> |
| | | </el-dropdown> |
| | | </template> |
| | | </el-table-column> |
| | | <el-table-column label="项目名称" align="center" prop="everyProjectName" /> |
| | | </el-table> |
| | | |
| | | <pagination |
| | |
| | | :limit.sync="queryParams.pageSize" |
| | | @pagination="getList" |
| | | /> |
| | | <!-- Excel操作弹窗 --> |
| | | <el-dialog :visible.sync="excelDialogVisible" class="excel-dialog-overlay" @click="closeExcelDialog"> |
| | | <div class="excel-dialog" @click.stop> |
| | | <div class="excel-dialog-header"> |
| | | <h3>Excel操作</h3> |
| | | <p class="excel-dialog-tip">请选择以下操作处理Excel文件</p> |
| | | |
| | | <!-- <button class="excel-dialog-close" @click="closeExcelDialog">×</button> --> |
| | | </div> |
| | | <div class="excel-dialog-body"> |
| | | <!-- 选择框区域 --> |
| | | <div class="excel-options-section"> |
| | | <!-- 二维码选择 --> |
| | | <div class="option-group"> |
| | | <label class="option-label"> |
| | | <input type="checkbox" v-model="excelOptions.includeQrCode"> |
| | | <span>包含二维码</span> |
| | | </label> |
| | | </div> |
| | | |
| | | <!-- 注解选择 --> |
| | | <div class="option-group"> |
| | | <div class="option-label">选择注解:</div> |
| | | <div class="annotation-options"> |
| | | <label v-for="(annotation, index) in excelOptions.selectedAnnotations" :key="index" class="signature-checkbox"> |
| | | <input type="checkbox" v-model="excelOptions.subselectedAnnotations" :value="annotation"> |
| | | <span>{{ annotation }} |
| | | </span> |
| | | </label> |
| | | </div> |
| | | </div> |
| | | |
| | | <!-- 签名栏选择 --> |
| | | <div class="option-group"> |
| | | <div class="option-label">签名栏设置:</div> |
| | | <div class="signature-options"> |
| | | <div class="signature-checkboxes"> |
| | | <label v-for="(signature, index) in excelOptions.selectedSignatures" :key="index" class="signature-checkbox"> |
| | | <input type="checkbox" v-model="excelOptions.subselectedSignatures" :value="signature"> |
| | | <span>{{ signature }}</span> |
| | | </label> |
| | | |
| | | |
| | | |
| | | </div> |
| | | <!-- <p v-if="excelOptions.selectedSignatures.length === 0" class="option-tip">请选择至少一个签名栏</p> --> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <!-- 优化的Excel预览组件 --> |
| | | <el-dialog class="excel-preview-wrapper" :visible.sync="showExcelPreview" :modal="false" width="80%"> |
| | | |
| | | <div > |
| | | <!-- 主要预览组件 --> |
| | | <vue-office-excel |
| | | v-if="currentExcelUrl" |
| | | :src="currentExcelUrl" |
| | | style="width: 100%; height: 500px;" |
| | | @rendered="renderedHandler" |
| | | @error="handleExcelRenderError" |
| | | /> |
| | | |
| | | <!-- 错误提示 --> |
| | | <div v-if="excelRenderError" class="excel-error-message"> |
| | | <h3>Excel渲染失败</h3> |
| | | <p>{{ excelRenderError }}</p> |
| | | <p>请尝试以下解决方案:</p> |
| | | <ul> |
| | | <li>下载文件后使用Excel软件打开</li> |
| | | <li>确认文件格式是否为支持的.xls或.xlsx</li> |
| | | </ul> |
| | | <button class="excel-dialog-btn download-btn" @click="handleDownloadClick">下载Excel文件</button> |
| | | </div> |
| | | </div> |
| | | </el-dialog> |
| | | <div class="excel-dialog-footer"> |
| | | <button class="excel-dialog-btn preview-btn" @click="handlePreviewClick">预览</button> |
| | | <button class="excel-dialog-btn print-btn" @click="handlePrintClick">打印</button> |
| | | <button class="excel-dialog-btn download-btn" @click="handleDownloadClick">下载</button> |
| | | </div> |
| | | </div> |
| | | |
| | | |
| | | |
| | | </el-dialog> |
| | | <!-- 查看数据按钮 --> |
| | | <el-dialog :title="title" :visible.sync="open_check" width="800px" append-to-body> |
| | | <el-form ref="form" :model="form" :rules="rules" label-width="120px"> |
| | |
| | | </template> |
| | | |
| | | <script> |
| | | import VueOfficeExcel from '@vue-office/excel' |
| | | import '@vue-office/excel/lib/index.css' |
| | | |
| | | import axios from 'axios' |
| | | import { getToken } from '@/utils/auth' |
| | | import { enload, batchSubmitRecords,updateStatusById,listRecords,getMaxId, getRecords, delRecords, addRecords, updateRecords } from "@/api/system/records" |
| | | import { listAllCategory } from "@/api/system/category" |
| | | import { listAllProjectName } from "@/api/system/projectName" |
| | | import { listPlaceName, listAllPlaceName } from "@/api/system/placeName" |
| | | export default { |
| | | components: { |
| | | VueOfficeExcel |
| | | }, |
| | | name: "Records", |
| | | data() { |
| | | return { |
| | | excel: 'http://localhost:8080/profile/upload/12.xls', //设置文档网络地址,可以是相对地址 |
| | | |
| | | open_check: false, |
| | | securityLevelOptions: [ |
| | | { value: '秘密', label: '秘密' }, |
| | |
| | | remarks: null, |
| | | historicalReferenceNumber: null |
| | | }, |
| | | // Excel弹窗相关数据 |
| | | excelDialogVisible: false, |
| | | currentExcelUrl: '', |
| | | currentExcelBlob: null, |
| | | currentExcelId: '', |
| | | excelLoading: false, |
| | | excelPreviewTimeout: null, |
| | | excelRenderError: '', // Excel渲染错误信息 |
| | | // Excel选项配置 |
| | | excelOptions: { |
| | | includeQrCode: false, // 是否包含二维码 |
| | | selectedAnnotations: ["本清单由档案形成部门完成", |
| | | "文件类型必须录入,包括结论材料、过程材料、申请材料,其他材料", |
| | | "公开属性必须录入,主动公开、依申请公开、免予公开", |
| | | "保管期限:30年或永久", |
| | | "页号按照正式录入页码为准"], // 选中的注解列表 |
| | | includeSignature: false, // 是否包含签名栏 |
| | | selectedSignatures: ['业务科室移交人:', '审批科移交人:', '档案整理公司:'], // 选中的签名栏列表 |
| | | subselectedSignatures: [], |
| | | subselectedAnnotations: [], |
| | | signaturePosition: 'bottom' // 签名栏位置:top/bottom |
| | | }, |
| | | // 表单参数 |
| | | form: { |
| | | recordSeq: '', |
| | |
| | | } |
| | | }, |
| | | created() { |
| | | |
| | | // 监听ESC键关闭弹窗 |
| | | document.addEventListener('keydown', this.handleKeyDown); |
| | | this.userId = this.$store.state.user.id; |
| | | |
| | | // 获取用户角色 |
| | |
| | | immediate: true |
| | | } |
| | | }, |
| | | beforeDestroy() { |
| | | // 清理事件监听器和定时器 |
| | | document.removeEventListener('keydown', this.handleKeyDown); |
| | | if (this.excelPreviewTimeout) { |
| | | clearTimeout(this.excelPreviewTimeout); |
| | | } |
| | | if (this.currentExcelUrl) { |
| | | URL.revokeObjectURL(this.currentExcelUrl); |
| | | } |
| | | }, |
| | | methods: { |
| | | /** Excel渲染完成处理 */ |
| | | renderedHandler() { |
| | | console.log("Excel渲染完成"); |
| | | this.excelLoading = false; |
| | | this.excelRenderError = ''; |
| | | }, |
| | | /** Excel渲染错误处理 */ |
| | | handleExcelRenderError(error) { |
| | | console.error("Excel渲染失败:", error); |
| | | this.excelLoading = false; |
| | | |
| | | // 设置友好的错误信息 |
| | | if (error && error.message) { |
| | | this.excelRenderError = error.message; |
| | | } else { |
| | | this.excelRenderError = '无法渲染此Excel文件,可能是文件格式不兼容或已损坏。'; |
| | | } |
| | | |
| | | // 尝试备选方案 |
| | | this.tryAlternativePreview(); |
| | | }, |
| | | /** 尝试备选预览方案 */ |
| | | tryAlternativePreview() { |
| | | console.log('尝试备选预览方案...'); |
| | | }, |
| | | getId() |
| | | { |
| | | var _this = this; |
| | |
| | | // 生成案卷题名 |
| | | generateCaseTitle() { |
| | | let titleParts = []; |
| | | |
| | | |
| | | if (this.form.constructionUnit) { |
| | | titleParts.push(this.form.constructionUnit); |
| | | } |
| | | |
| | | |
| | | if (this.form.constructionAddress) { |
| | | titleParts.push(this.form.constructionAddress); |
| | | } |
| | | |
| | | |
| | | if (this.form.projectName) { |
| | | titleParts.push(this.form.projectName); |
| | | } |
| | | |
| | | |
| | | this.form.caseTitle = titleParts.join(''); |
| | | }, |
| | | async getZoneOptions() |
| | |
| | | console.log("1111111333333",response.data) |
| | | this.zoneTypeOptions = response.data.data.map(item => ({ |
| | | value: item.nnumber, |
| | | label: item.name |
| | | label: item.nnumber |
| | | })) |
| | | } catch (error) { |
| | | console.error('获取项目名称列表失败:', error) |
| | |
| | | listAllCategory().then(response => { |
| | | this.recordTypeOptions = response.data.map(item => ({ |
| | | value: item.numb, |
| | | label: item.nname |
| | | label: item.numb |
| | | })) |
| | | resolve() |
| | | }) |
| | |
| | | .map(item => item.id); |
| | | // 检查选中的ID是否全部属于自己 |
| | | const invalidIds = this.ids.filter(id => !myValidIds.includes(id)); |
| | | |
| | | |
| | | if (invalidIds.length > 0) { |
| | | this.$message.error(`包含无权操作的ID: ${invalidIds.join(',')}`); |
| | | return false; |
| | |
| | | handleAuthUser: function(row) { |
| | | const roleId = 2 |
| | | var archiveRecordsId = row.recordId |
| | | alert(roleId) |
| | | |
| | | this.$router.push("/archiveManager/infoManagerAu/user/" + roleId+"/"+archiveRecordsId) |
| | | }, |
| | | /** 删除按钮操作 */ |
| | |
| | | }, |
| | | /** 导出按钮操作 */ |
| | | handleExport() { |
| | | this.download('system/records/export', { |
| | | ...this.queryParams |
| | | }, `records_${new Date().getTime()}.xlsx`) |
| | | // 检查是否有选中的记录 |
| | | //alert(234) |
| | | // alert(this.ids.length) |
| | | if (this.ids && this.ids.length > 0) { |
| | | // 只导出选中的记录 |
| | | this.download('system/records/export', { |
| | | ids: this.ids.join(',') // 将选中的ID数组转换为逗号分隔的字符串 |
| | | }, `records_${new Date().getTime()}.xlsx`) |
| | | } else { |
| | | // 没有选中记录时,导出符合查询条件的所有记录 |
| | | this.download('system/records/export', { |
| | | ...this.queryParams |
| | | }, `records_${new Date().getTime()}.xlsx`) |
| | | } |
| | | }, |
| | | |
| | | /** 查看并打印Excel文件 */ |
| | | viewAndPrintExcel(row) { |
| | | const id = row.id || this.ids; |
| | | this.$modal.loading('正在获取Excel文件,请稍候...'); |
| | | |
| | | // 从后端获取Excel文件 |
| | | this.getExcelFile(id).then(blob => { |
| | | this.$modal.closeLoading(); |
| | | // 保存文件信息并显示静态弹窗 |
| | | this.currentExcelUrl = URL.createObjectURL(blob); |
| | | this.currentExcelBlob = blob; |
| | | this.currentExcelId = id; |
| | | this.excelDialogVisible = true; |
| | | this.excelLoading = false; |
| | | }).catch(error => { |
| | | this.$modal.closeLoading(); |
| | | console.error('获取Excel文件失败:', error); |
| | | this.$modal.msgError('获取Excel文件失败,请稍后重试'); |
| | | }); |
| | | }, |
| | | |
| | | /** 处理键盘事件 - ESC键关闭弹窗 */ |
| | | handleKeyDown(e) { |
| | | if (e.key === 'Escape' && this.excelDialogVisible) { |
| | | this.closeExcelDialog(); |
| | | } |
| | | }, |
| | | |
| | | /** 关闭Excel弹窗并清理资源 */ |
| | | closeExcelDialog() { |
| | | this.excelDialogVisible = false; |
| | | if (this.excelPreviewTimeout) { |
| | | clearTimeout(this.excelPreviewTimeout); |
| | | this.excelPreviewTimeout = null; |
| | | } |
| | | if (this.currentExcelUrl) { |
| | | URL.revokeObjectURL(this.currentExcelUrl); |
| | | this.currentExcelUrl = ''; |
| | | } |
| | | this.currentExcelBlob = null; |
| | | }, |
| | | |
| | | /** 处理预览按钮点击 */ |
| | | handlePreviewClick() { |
| | | this.showExcelPreview = true; |
| | | this.excelRenderError = ''; |
| | | |
| | | // 重置vue-office-excel组件 |
| | | if (this.currentExcelUrl) { |
| | | const tempUrl = this.currentExcelUrl; |
| | | this.currentExcelUrl = ''; |
| | | this.$nextTick(() => { |
| | | this.currentExcelUrl = tempUrl; |
| | | }); |
| | | } |
| | | |
| | | const previewContainer = this.$refs.excelPreviewContainer; |
| | | |
| | | // 清空预览容器 |
| | | if (previewContainer) { |
| | | previewContainer.innerHTML = ''; |
| | | |
| | | // 尝试使用微软Office Online预览服务作为备选 |
| | | const officeOnlineUrl = `https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(this.currentExcelUrl)}`; |
| | | |
| | | // 创建iframe用于预览 |
| | | const iframe = document.createElement('iframe'); |
| | | iframe.style.width = '100%'; |
| | | iframe.style.height = '100%'; |
| | | iframe.style.border = 'none'; |
| | | iframe.style.minHeight = '600px'; |
| | | iframe.src = officeOnlineUrl; |
| | | iframe.title = 'Excel文件预览'; |
| | | |
| | | // 创建加载指示器 |
| | | const loadingIndicator = document.createElement('div'); |
| | | loadingIndicator.className = 'loading-indicator'; |
| | | loadingIndicator.innerHTML = ` |
| | | <div class="loading-spinner"></div> |
| | | <p>正在加载Excel文件,请稍候...</p> |
| | | `; |
| | | previewContainer.style.position = 'relative'; |
| | | previewContainer.appendChild(iframe); |
| | | previewContainer.appendChild(loadingIndicator); |
| | | |
| | | // 监听iframe加载完成 |
| | | iframe.onload = () => { |
| | | this.excelLoading = false; |
| | | if (loadingIndicator && loadingIndicator.parentNode) { |
| | | loadingIndicator.parentNode.removeChild(loadingIndicator); |
| | | } |
| | | }; |
| | | |
| | | // 设置超时处理 |
| | | this.excelPreviewTimeout = setTimeout(() => { |
| | | this.excelLoading = false; |
| | | if (loadingIndicator && loadingIndicator.parentNode) { |
| | | loadingIndicator.parentNode.removeChild(loadingIndicator); |
| | | } |
| | | |
| | | // 尝试直接预览作为备选方案 |
| | | previewContainer.innerHTML = ''; |
| | | const directIframe = document.createElement('iframe'); |
| | | directIframe.style.width = '100%'; |
| | | directIframe.style.height = '100%'; |
| | | directIframe.style.border = 'none'; |
| | | directIframe.style.minHeight = '600px'; |
| | | directIframe.src = this.currentExcelUrl; |
| | | |
| | | const fallbackMessage = document.createElement('div'); |
| | | fallbackMessage.textContent = 'Office预览服务加载超时,正在尝试直接预览...'; |
| | | fallbackMessage.style.cssText = ` |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | padding: 10px; |
| | | background-color: #f56c6c; |
| | | color: white; |
| | | text-align: center; |
| | | font-size: 14px; |
| | | z-index: 10; |
| | | `; |
| | | |
| | | previewContainer.appendChild(directIframe); |
| | | previewContainer.appendChild(fallbackMessage); |
| | | |
| | | directIframe.onload = () => { |
| | | if (fallbackMessage && fallbackMessage.parentNode) { |
| | | fallbackMessage.parentNode.removeChild(fallbackMessage); |
| | | } |
| | | }; |
| | | |
| | | // 二次超时处理 |
| | | setTimeout(() => { |
| | | if (directIframe && directIframe.parentNode) { |
| | | directIframe.parentNode.removeChild(directIframe); |
| | | } |
| | | const errorMessage = document.createElement('div'); |
| | | errorMessage.innerHTML = ` |
| | | <div style="text-align: center; padding: 40px;"> |
| | | <h3 style="color: #f56c6c; margin-bottom: 20px;">预览失败</h3> |
| | | <p style="color: #666; margin-bottom: 30px;">无法在浏览器中预览Excel文件,请点击下方按钮下载文件后查看。</p> |
| | | <button onclick="this.parentNode.parentNode.querySelector('.download-btn').click()" |
| | | style="padding: 8px 20px; background: #409EFF; color: white; border: none; border-radius: 4px; cursor: pointer;"> |
| | | 下载Excel文件 |
| | | </button> |
| | | </div> |
| | | `; |
| | | previewContainer.appendChild(errorMessage); |
| | | }, 20000); |
| | | }, 25000); |
| | | } |
| | | }, |
| | | |
| | | /** 处理打印按钮点击 */ |
| | | handlePrintClick() { |
| | | if (this.currentExcelUrl) { |
| | | // 创建一个临时iframe用于打印 |
| | | const iframe = document.createElement('iframe'); |
| | | iframe.style.position = 'absolute'; |
| | | iframe.style.left = '-9999px'; |
| | | iframe.style.top = '-9999px'; |
| | | iframe.style.width = '210mm'; |
| | | iframe.style.height = '297mm'; |
| | | document.body.appendChild(iframe); |
| | | |
| | | // 监听iframe加载完成 |
| | | iframe.onload = () => { |
| | | try { |
| | | // 执行打印 |
| | | iframe.contentWindow.print(); |
| | | |
| | | // 设置超时移除iframe |
| | | setTimeout(() => { |
| | | if (iframe && iframe.parentNode) { |
| | | iframe.parentNode.removeChild(iframe); |
| | | } |
| | | }, 1000); |
| | | } catch (error) { |
| | | console.error('Print error:', error); |
| | | // 打印失败时,提示用户下载 |
| | | this.$confirm('打印失败,是否下载文件?', '提示', { |
| | | confirmButtonText: '下载', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | this.handleDownloadClick(); |
| | | }); |
| | | |
| | | // 移除iframe |
| | | if (iframe && iframe.parentNode) { |
| | | iframe.parentNode.removeChild(iframe); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 设置iframe的src |
| | | iframe.src = this.currentExcelUrl; |
| | | } |
| | | }, |
| | | |
| | | /** 处理下载按钮点击 */ |
| | | handleDownloadClick() { |
| | | if (this.currentExcelUrl) { |
| | | // 获取用户选择的选项 |
| | | const { includeQrCode, selectedAnnotations } = this.excelOptions; |
| | | console.log('下载选项:', { includeQrCode, selectedAnnotations }); |
| | | |
| | | // 创建下载链接,文件名包含选项信息 |
| | | const link = document.createElement('a'); |
| | | link.href = this.currentExcelUrl; |
| | | |
| | | // 构建文件名,包含选项信息 |
| | | let filename = `record_${this.currentExcelId}`; |
| | | if (includeQrCode) filename += '_qr'; |
| | | if (selectedAnnotations.length > 0) { |
| | | filename += `_anno${selectedAnnotations.join('')}`; |
| | | } |
| | | filename += `_${new Date().getTime()}.xlsx`; |
| | | |
| | | link.download = filename; |
| | | |
| | | // 触发下载 |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | document.body.removeChild(link); |
| | | |
| | | // 提示下载成功 |
| | | this.$modal.msgSuccess('Excel文件下载成功'); |
| | | } |
| | | }, |
| | | |
| | | /** 检查浏览器是否可能支持直接预览Excel */ |
| | | canPreviewExcelInBrowser() { |
| | | // 现在我们使用微软Office Online服务,对所有现代浏览器都支持预览 |
| | | return true; |
| | | }, |
| | | |
| | | /** 处理Excel预览超时情况 */ |
| | | handleExcelPreviewTimeout(url, iframe) { |
| | | // 超时后,提供在新窗口打开的选项 |
| | | this.$confirm('Excel文件加载超时,是否在新窗口中打开?', '提示', { |
| | | confirmButtonText: '打开', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | window.open(url, '_blank'); |
| | | }).finally(() => { |
| | | // 清理:移除iframe并释放URL对象 |
| | | this.cleanupExcelPreview(iframe, url); |
| | | }); |
| | | }, |
| | | |
| | | /** 清理Excel预览相关资源 */ |
| | | cleanupExcelPreview(iframe, url) { |
| | | setTimeout(() => { |
| | | if (iframe && iframe.parentNode) { |
| | | document.body.removeChild(iframe); |
| | | } |
| | | if (url) { |
| | | URL.revokeObjectURL(url); |
| | | } |
| | | this.excelRenderError = ''; |
| | | }, 1000); |
| | | }, |
| | | |
| | | /** 从后端获取Excel文件 */ |
| | | getExcelFile(id) { |
| | | var includeQrCode = this.excelOptions.includeQrCode; |
| | | return new Promise((resolve, reject) => { |
| | | // 首先尝试使用axios(项目已有的HTTP客户端) |
| | | try { |
| | | // 获取用户选择的注解 |
| | | const { selectedAnnotations } = this.excelOptions; |
| | | |
| | | // 构建参数,包含注解内容 |
| | | const params = { |
| | | recordId: id, |
| | | |
| | | }; |
| | | alert(355) |
| | | axios({ |
| | | method: 'Post', |
| | | url: `${process.env.VUE_APP_BASE_API}/system/records/recordFileList`+"/"+includeQrCode, |
| | | params: params, |
| | | responseType: 'blob', |
| | | headers: { 'Authorization': 'Bearer ' + getToken() } |
| | | }).then(response => { |
| | | resolve(response.data); |
| | | }).catch(error => { |
| | | // 如果axios失败,回退到XMLHttpRequest |
| | | console.warn('Axios请求失败,尝试使用XMLHttpRequest:', error); |
| | | this.fallbackGetExcelFile(id, resolve, reject); |
| | | }); |
| | | } catch (e) { |
| | | // 捕获任何意外错误 |
| | | reject(new Error('获取Excel文件时发生错误: ' + e.message)); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | /** 备用的XMLHttpRequest获取Excel文件方法 */ |
| | | fallbackGetExcelFile(id, resolve, reject) { |
| | | try { |
| | | const xhr = new XMLHttpRequest(); |
| | | |
| | | // 构建查询参数,包含注解内容 |
| | | const queryParams = new URLSearchParams({ |
| | | id: id, |
| | | annotation1: "本清单由档案形成部门完成", |
| | | annotation2: "文件类型必须录入,包括结论材料、过程材料、申请材料,其他材料", |
| | | annotation3: "公开属性必须录入,主动公开、依申请公开、免予公开", |
| | | annotation4: "保管期限:30年或永久", |
| | | annotation5: "页号按照正式录入页码为准" |
| | | }).toString(); |
| | | |
| | | // 尝试不同的API路径,以适应可能的后端实现 |
| | | const apiUrls = [ |
| | | `${process.env.VUE_APP_BASE_API}/system/records/model?${queryParams}`, |
| | | `${process.env.VUE_APP_BASE_API}/system/records/model` |
| | | ]; |
| | | |
| | | let currentUrlIndex = 0; |
| | | |
| | | const tryNextUrl = () => { |
| | | if (currentUrlIndex >= apiUrls.length) { |
| | | reject(new Error('所有API路径都请求失败')); |
| | | return; |
| | | } |
| | | |
| | | const url = apiUrls[currentUrlIndex]; |
| | | currentUrlIndex++; |
| | | |
| | | xhr.open('GET', url, true); |
| | | xhr.setRequestHeader('Authorization', 'Bearer ' + getToken()); |
| | | xhr.responseType = 'blob'; |
| | | |
| | | xhr.onload = () => { |
| | | if (xhr.status === 200) { |
| | | // 验证返回的是否为有效的Blob |
| | | if (xhr.response instanceof Blob && xhr.response.size > 0) { |
| | | resolve(xhr.response); |
| | | } else { |
| | | console.warn('返回的数据不是有效的Blob,尝试下一个URL'); |
| | | tryNextUrl(); |
| | | } |
| | | } else if (currentUrlIndex < apiUrls.length) { |
| | | console.warn(`URL ${url} 请求失败 (${xhr.status}),尝试下一个URL`); |
| | | tryNextUrl(); |
| | | } else { |
| | | reject(new Error(`请求失败: ${xhr.status} ${xhr.statusText}`)); |
| | | } |
| | | }; |
| | | |
| | | xhr.onerror = () => { |
| | | if (currentUrlIndex < apiUrls.length) { |
| | | console.warn(`URL ${url} 网络错误,尝试下一个URL`); |
| | | tryNextUrl(); |
| | | } else { |
| | | reject(new Error('网络错误,无法获取Excel文件')); |
| | | } |
| | | }; |
| | | |
| | | // 设置请求超时 |
| | | xhr.timeout = 30000; // 30秒 |
| | | xhr.ontimeout = () => { |
| | | if (currentUrlIndex < apiUrls.length) { |
| | | console.warn(`URL ${url} 请求超时,尝试下一个URL`); |
| | | tryNextUrl(); |
| | | } else { |
| | | reject(new Error('请求超时,无法获取Excel文件')); |
| | | } |
| | | }; |
| | | |
| | | xhr.send(); |
| | | }; |
| | | |
| | | // 开始尝试第一个URL |
| | | tryNextUrl(); |
| | | } catch (e) { |
| | | reject(new Error('XMLHttpRequest请求失败: ' + e.message)); |
| | | } |
| | | }, |
| | | |
| | | /** 批量打印Excel文件 */ |
| | | batchPrintExcel() { |
| | | if (this.ids.length === 0) { |
| | | this.$modal.msgWarning('请选择要打印的记录'); |
| | | return; |
| | | } |
| | | |
| | | this.$confirm(`确定要打印选中的 ${this.ids.length} 条记录吗?`, '批量打印确认', { |
| | | confirmButtonText: '确定', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | // 对于批量操作,我们可以选择: |
| | | // 1. 如果后端支持批量导出,直接调用批量导出接口 |
| | | this.$modal.loading('正在准备批量打印文件,请稍候...'); |
| | | |
| | | // 尝试批量导出API |
| | | this.getBatchExcelFile(this.ids).then(blob => { |
| | | this.$modal.closeLoading(); |
| | | this.handleExcelBlobForPrint(blob, 'batch_records'); |
| | | }).catch(error => { |
| | | this.$modal.closeLoading(); |
| | | console.warn('批量导出失败,尝试逐个处理:', error); |
| | | |
| | | // 2. 如果批量导出失败,提示用户逐个打印或下载 |
| | | this.$confirm('批量打印失败,是否下载所有文件?', '提示', { |
| | | confirmButtonText: '下载', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | // 逐个下载文件 |
| | | this.downloadMultipleExcelFiles(this.ids); |
| | | }).catch(() => {}); |
| | | }); |
| | | }).catch(() => {}); |
| | | }, |
| | | |
| | | /** 获取批量Excel文件 */ |
| | | getBatchExcelFile(ids) { |
| | | return new Promise((resolve, reject) => { |
| | | try { |
| | | if (typeof axios !== 'undefined') { |
| | | axios({ |
| | | method: 'get', |
| | | url: `${process.env.VUE_APP_BASE_API}/system/records/batchExport`, |
| | | params: { ids: ids.join(',') }, |
| | | responseType: 'blob', |
| | | headers: { 'Authorization': 'Bearer ' + this.getToken() } |
| | | }).then(response => { |
| | | resolve(response.data); |
| | | }).catch(reject); |
| | | } else { |
| | | reject(new Error('批量导出功能不可用')); |
| | | } |
| | | } catch (e) { |
| | | reject(e); |
| | | } |
| | | }); |
| | | }, |
| | | |
| | | /** 处理Excel Blob用于打印 */ |
| | | handleExcelBlobForPrint(blob, prefix = 'record') { |
| | | const url = URL.createObjectURL(blob); |
| | | |
| | | if (this.canPreviewExcelInBrowser()) { |
| | | const iframe = document.createElement('iframe'); |
| | | iframe.style.display = 'none'; |
| | | document.body.appendChild(iframe); |
| | | |
| | | iframe.src = url; |
| | | |
| | | const timeoutId = setTimeout(() => { |
| | | this.handleExcelPreviewTimeout(url, iframe); |
| | | }, 5000); |
| | | |
| | | iframe.onload = () => { |
| | | clearTimeout(timeoutId); |
| | | this.$confirm('Excel文件已准备好,是否打印?', '打印确认', { |
| | | confirmButtonText: '打印', |
| | | cancelButtonText: '取消', |
| | | type: 'warning' |
| | | }).then(() => { |
| | | try { |
| | | iframe.contentWindow.print(); |
| | | } catch (e) { |
| | | this.$modal.msgWarning('打印失败,将在新窗口打开文件'); |
| | | window.open(url, '_blank'); |
| | | } finally { |
| | | this.cleanupExcelPreview(iframe, url); |
| | | } |
| | | }).catch(() => { |
| | | window.open(url, '_blank'); |
| | | this.cleanupExcelPreview(iframe, url); |
| | | }); |
| | | }; |
| | | } else { |
| | | // 直接下载 |
| | | const link = document.createElement('a'); |
| | | link.href = url; |
| | | link.download = `${prefix}_${new Date().getTime()}.xlsx`; |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | document.body.removeChild(link); |
| | | URL.revokeObjectURL(url); |
| | | } |
| | | }, |
| | | |
| | | /** 下载多个Excel文件 */ |
| | | downloadMultipleExcelFiles(ids) { |
| | | // 这里简单处理为逐个下载 |
| | | // 实际应用中可能需要考虑性能优化或使用压缩包 |
| | | ids.forEach((id, index) => { |
| | | // 使用setTimeout避免浏览器限制同时下载 |
| | | setTimeout(() => { |
| | | this.getExcelFile(id).then(blob => { |
| | | const url = URL.createObjectURL(blob); |
| | | const link = document.createElement('a'); |
| | | link.href = url; |
| | | link.download = `record_${id}_${new Date().getTime()}.xlsx`; |
| | | document.body.appendChild(link); |
| | | link.click(); |
| | | document.body.removeChild(link); |
| | | URL.revokeObjectURL(url); |
| | | }); |
| | | }, index * 1000); // 每个文件间隔1秒下载 |
| | | }); |
| | | }, |
| | | |
| | | // /** 获取Token的辅助方法 */ |
| | | // getToken() { |
| | | // return localStorage.getItem('token') || ''; |
| | | // }, |
| | | /** 导入模板下载操作*/ |
| | | handleExportTemplate() |
| | | { |
| | |
| | | }); |
| | | |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | } |
| | |
| | | ::v-deep .el-table__body-wrapper::-webkit-scrollbar-thumb:hover { |
| | | background: #2f91ec; |
| | | } |
| | | |
| | | /* Excel操作弹窗样式 */ |
| | | .excel-dialog-overlay { |
| | | position: fixed; |
| | | top: 0; |
| | | left: 0; |
| | | } |
| | | |
| | | /* Excel预览包装器样式 */ |
| | | .excel-preview-wrapper { |
| | | width: 100%; |
| | | height: 100%; |
| | | min-height: 500px; |
| | | display: flex; |
| | | flex-direction: column; |
| | | background: #f9f9f9; |
| | | border-radius: 8px; |
| | | padding: 10px; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | /* Excel错误提示样式 */ |
| | | .excel-error-message { |
| | | background: #fff2f0; |
| | | border: 1px solid #ffccc7; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | margin: 10px 0; |
| | | color: #f56c6c; |
| | | } |
| | | |
| | | .excel-error-message h3 { |
| | | margin-top: 0; |
| | | margin-bottom: 10px; |
| | | color: #f56c6c; |
| | | font-size: 16px; |
| | | } |
| | | |
| | | .excel-error-message p { |
| | | margin: 8px 0; |
| | | line-height: 1.5; |
| | | } |
| | | |
| | | .excel-error-message ul { |
| | | text-align: left; |
| | | margin: 10px 0; |
| | | } |
| | | |
| | | .excel-error-message li { |
| | | margin: 5px 0; |
| | | padding-left: 5px; |
| | | } |
| | | |
| | | /* 优化按钮样式 */ |
| | | .excel-dialog-btn.download-btn { |
| | | background: #67c23a; |
| | | border-color: #67c23a; |
| | | color: white; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | .excel-dialog-btn.download-btn:hover { |
| | | background: #85ce61; |
| | | border-color: #85ce61; |
| | | } |
| | | |
| | | /* 选择框区域样式 */ |
| | | .excel-options-section { |
| | | background: #f5f7fa; |
| | | border-radius: 8px; |
| | | padding: 20px; |
| | | margin-bottom: 20px; |
| | | } |
| | | |
| | | /* 选项组样式 */ |
| | | .option-group { |
| | | margin-bottom: 15px; |
| | | } |
| | | |
| | | .option-group:last-child { |
| | | margin-bottom: 0; |
| | | } |
| | | |
| | | /* 选项标签样式 */ |
| | | .option-label { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 14px; |
| | | color: #303133; |
| | | cursor: pointer; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | /* 复选框样式 */ |
| | | .option-label input[type="checkbox"] { |
| | | width: 16px; |
| | | height: 16px; |
| | | margin-right: 8px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | /* 注解选项容器 */ |
| | | .annotation-options { |
| | | display: flex; |
| | | flex-wrap: wrap; |
| | | gap: 15px; |
| | | margin-top: 10px; |
| | | } |
| | | |
| | | /* 注解复选框样式 */ |
| | | .annotation-checkbox { |
| | | display: flex; |
| | | align-items: center; |
| | | font-size: 14px; |
| | | color: #303133; |
| | | cursor: pointer; |
| | | background: white; |
| | | padding: 8px 12px; |
| | | border-radius: 4px; |
| | | border: 1px solid #dcdfe6; |
| | | transition: all 0.3s; |
| | | } |
| | | |
| | | .annotation-checkbox:hover { |
| | | border-color: #c0c4cc; |
| | | background: #fafafa; |
| | | } |
| | | |
| | | .annotation-checkbox input[type="checkbox"] { |
| | | width: 14px; |
| | | height: 14px; |
| | | margin-right: 6px; |
| | | cursor: pointer; |
| | | } |
| | | .excel-dialog { |
| | | background-color: white; |
| | | border-radius: 8px; |
| | | width: 96%; |
| | | max-width: 900px; |
| | | max-height: 100vh; |
| | | overflow: hidden; |
| | | box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); |
| | | animation: slideUp 0.3s ease; |
| | | display: flex; |
| | | flex-direction: column; |
| | | } |
| | | |
| | | .excel-dialog-header { |
| | | padding: 20px 24px; |
| | | border-bottom: 1px solid #e9ecef; |
| | | display: flex; |
| | | justify-content: space-between; |
| | | align-items: center; |
| | | background-color: #f8f9fa; |
| | | } |
| | | |
| | | .excel-dialog-header h3 { |
| | | margin: 0; |
| | | font-size: 18px; |
| | | font-weight: 600; |
| | | color: #333; |
| | | } |
| | | |
| | | .excel-dialog-close { |
| | | background: none; |
| | | border: none; |
| | | font-size: 24px; |
| | | cursor: pointer; |
| | | color: #666; |
| | | width: 32px; |
| | | height: 32px; |
| | | display: flex; |
| | | align-items: center; |
| | | justify-content: center; |
| | | border-radius: 4px; |
| | | transition: all 0.2s; |
| | | } |
| | | |
| | | .excel-dialog-close:hover { |
| | | background-color: #e9ecef; |
| | | color: #333; |
| | | } |
| | | |
| | | .excel-dialog-body { |
| | | padding: 24px; |
| | | flex: 1; |
| | | overflow-y: auto; |
| | | } |
| | | |
| | | .excel-preview-container { |
| | | width: 100%; |
| | | height: 400px; |
| | | border: 1px solid #ddd; |
| | | border-radius: 4px; |
| | | margin-bottom: 16px; |
| | | position: relative; |
| | | background-color: #f8f9fa; |
| | | overflow: hidden; |
| | | } |
| | | |
| | | .loading-indicator { |
| | | position: absolute; |
| | | top: 0; |
| | | left: 0; |
| | | right: 0; |
| | | bottom: 0; |
| | | display: flex; |
| | | flex-direction: column; |
| | | align-items: center; |
| | | justify-content: center; |
| | | background-color: rgba(255, 255, 255, 0.9); |
| | | color: #666; |
| | | z-index: 10; |
| | | } |
| | | |
| | | .loading-spinner { |
| | | width: 40px; |
| | | height: 40px; |
| | | border: 3px solid #f3f3f3; |
| | | border-top: 3px solid #2f91ec; |
| | | border-radius: 50%; |
| | | animation: spin 1s linear infinite; |
| | | margin-bottom: 10px; |
| | | } |
| | | |
| | | .excel-dialog-tip { |
| | | margin: 0; |
| | | color: #666; |
| | | text-align: center; |
| | | font-size: 14px; |
| | | } |
| | | |
| | | .excel-dialog-footer { |
| | | padding: 16px 24px; |
| | | border-top: 1px solid #e9ecef; |
| | | display: flex; |
| | | justify-content: center; |
| | | gap: 16px; |
| | | background-color: #f8f9fa; |
| | | } |
| | | |
| | | .excel-dialog-btn { |
| | | padding: 10px 24px; |
| | | border: none; |
| | | border-radius: 4px; |
| | | cursor: pointer; |
| | | font-size: 14px; |
| | | font-weight: 500; |
| | | transition: all 0.2s; |
| | | min-width: 100px; |
| | | } |
| | | |
| | | .preview-btn { |
| | | background-color: #2f91ec; |
| | | color: white; |
| | | } |
| | | |
| | | .preview-btn:hover { |
| | | background-color: #1c7ed6; |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 2px 8px rgba(47, 145, 236, 0.3); |
| | | } |
| | | |
| | | .print-btn { |
| | | background-color: #20c997; |
| | | color: white; |
| | | } |
| | | |
| | | .print-btn:hover { |
| | | background-color: #17a589; |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 2px 8px rgba(32, 201, 151, 0.3); |
| | | } |
| | | |
| | | .download-btn { |
| | | background-color: #6c757d; |
| | | color: white; |
| | | } |
| | | |
| | | .download-btn:hover { |
| | | background-color: #5a6268; |
| | | transform: translateY(-1px); |
| | | box-shadow: 0 2px 8px rgba(108, 117, 125, 0.3); |
| | | } |
| | | |
| | | @keyframes fadeIn { |
| | | from { opacity: 0; } |
| | | to { opacity: 1; } |
| | | } |
| | | |
| | | @keyframes slideUp { |
| | | from { |
| | | opacity: 0; |
| | | transform: translateY(20px); |
| | | } |
| | | to { |
| | | opacity: 1; |
| | | transform: translateY(0); |
| | | } |
| | | } |
| | | |
| | | @keyframes spin { |
| | | 0% { transform: rotate(0deg); } |
| | | 100% { transform: rotate(360deg); } |
| | | } |
| | | </style> |