src/App.vue
@@ -3,12 +3,16 @@ <keep-alive> <router-view /> </keep-alive> <file-preview ref="filePreview" /> </div> </template> <script> import FilePreview from "@/components/FilePreview/index.vue"; export default { name: 'App', components: { FilePreview }, metaInfo() { return { title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title, src/assets/styles/pdf-resize-dialog.scss
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,109 @@ /* 票æ®/éä»¶é¢è§å¼¹çªï¼å¯ææ½å³ä¸è§æ¹å大å°ï¼å 容åºéå¼¹çªé«åº¦èªéåº */ .pdf-resize-dialog { width: 80vw !important; height: 82vh !important; min-width: 720px; min-height: 480px; max-width: 96vw; max-height: 94vh; overflow: auto; resize: both; display: flex; flex-direction: column; } .pdf-resize-dialog .el-dialog__header, .pdf-resize-dialog .el-dialog__footer { flex: 0 0 auto; } .pdf-resize-dialog .el-dialog__body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 10px 20px; } .pdf-resize-dialog .pdfimg { height: 600px; min-height: 520px; } .pdf-resize-dialog .pdfimg .box-pdf { height: 100%; overflow: auto; } .pdf-resize-dialog .pdfimgmin { min-height: 520px; } .pdf-resize-dialog .pdfimgmin .el-image, .pdf-resize-dialog .pdfimgmin .el-image__inner, .pdf-resize-dialog .pdfimgmin img { max-height: 100%; } .pdf-resize-dialog.is-fullscreen, .pdf-resize-dialog.pdf-fullscreen { width: 100vw !important; height: 100vh !important; max-width: 100vw !important; max-height: 100vh !important; margin: 0 !important; top: 0 !important; left: 0 !important; resize: none; } .pdf-fullscreen-btn { float: right; margin-right: 28px; } .file-preview-dialog.is-fullscreen { width: 100vw !important; height: 100vh !important; max-width: 100vw !important; max-height: 100vh !important; margin: 0 !important; top: 0 !important; left: 0 !important; resize: none; } /* å ¨å± PDF/å¾çé¢è§å¼¹çªä¹æ¯æææ½æ¹åå¤§å° */ .file-preview-dialog { width: 80vw !important; height: 82vh !important; min-width: 720px; min-height: 480px; max-width: 96vw; max-height: 94vh; overflow: auto; resize: both; display: flex; flex-direction: column; } .file-preview-dialog .el-dialog__header, .file-preview-dialog .el-dialog__footer { flex: 0 0 auto; } .file-preview-dialog .el-dialog__body { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 10px 20px; } .file-preview-dialog .file-preview { height: 70vh; min-height: 420px; } .file-preview-dialog .file-preview__pdf, .file-preview-dialog .file-preview__list { height: 100%; } src/components/AttachmentPreviewPane/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,172 @@ <template> <div class="attachment-preview-pane"> <div v-if="!file" class="attachment-preview-pane__tip"> è¯·éæ©å·¦ä¾§æä»¶é¢è§ </div> <template v-else> <div v-if="fileType === 'image'" class="attachment-preview-pane__toolbar"> <el-button-group> <el-button size="mini" icon="el-icon-zoom-out" title="缩å°" @click="zoom(-0.2)" /> <el-button size="mini" class="attachment-preview-pane__scale"> {{ Math.round(scale * 100) }}% </el-button> <el-button size="mini" icon="el-icon-zoom-in" title="æ¾å¤§" @click="zoom(0.2)" /> </el-button-group> <el-button-group> <el-button size="mini" icon="el-icon-refresh-left" title="åå·¦æè½¬" @click="rotate(-90)" /> <el-button size="mini" icon="el-icon-refresh-right" title="åå³æè½¬" @click="rotate(90)" /> </el-button-group> <el-button size="mini" icon="el-icon-refresh" @click="reset" >éç½®</el-button > </div> <div v-if="fileType === 'image'" class="attachment-preview-pane__wrap"> <img :src="file.url" class="attachment-preview-pane__image" :style="{ transform: 'scale(' + scale + ') rotate(' + deg + 'deg)' }" alt="å¾çé¢è§" /> </div> <iframe v-else-if="fileType === 'pdf'" :src="file.url" class="attachment-preview-pane__pdf" title="PDFé¢è§" /> <div v-else class="attachment-preview-pane__tip"> 该æä»¶ç±»åæä¸æ¯æé¢è§ï¼è¯·ä¸è½½åæ¥ç </div> </template> </div> </template> <script> export default { name: "AttachmentPreviewPane", props: { file: { type: Object, default: null } }, data() { return { scale: 1, deg: 0 }; }, computed: { fileType() { if (!this.file) { return "other"; } if (this.file.type) { return this.file.type; } const ext = String(this.file.name || "") .split(".") .pop() .toLowerCase(); if (ext === "pdf") { return "pdf"; } if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { return "image"; } return "other"; } }, watch: { file() { this.reset(); } }, methods: { zoom(delta) { const next = Math.round((this.scale + delta) * 100) / 100; this.scale = Math.min(5, Math.max(0.2, next)); }, rotate(deg) { this.deg += deg; }, reset() { this.scale = 1; this.deg = 0; } } }; </script> <style scoped> .attachment-preview-pane { width: 100%; height: 100%; min-height: 420px; display: flex; flex-direction: column; align-items: stretch; justify-content: flex-start; } .attachment-preview-pane__toolbar { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 4px 0 10px; } .attachment-preview-pane__scale { min-width: 64px; cursor: default; } .attachment-preview-pane__wrap { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; align-items: center; justify-content: center; } .attachment-preview-pane__image { max-width: 100%; max-height: 100%; transition: transform 0.2s ease; transform-origin: center center; } .attachment-preview-pane__pdf { flex: 1 1 auto; width: 100%; min-height: 420px; border: 0; } .attachment-preview-pane__tip { color: #909399; font-size: 14px; text-align: center; padding: 20px; } </style> src/components/FilePreview/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,465 @@ <template> <el-dialog :visible.sync="visible" width="80%" top="5vh" append-to-body :close-on-click-modal="false" :destroy-on-close="false" :fullscreen="fullscreen" custom-class="file-preview-dialog" @closed="handleClosed" > <div slot="title" class="file-preview-title"> <span>{{ currentFile ? currentFile.name : "æä»¶é¢è§" }}</span> <el-button class="file-preview-fullscreen-btn" size="mini" :icon="fullscreen ? 'el-icon-close' : 'el-icon-full-screen'" @click="fullscreen = !fullscreen" >{{ fullscreen ? "è¿å" : "å ¨å±" }}</el-button > </div> <div v-loading="loading" class="file-preview"> <div class="file-preview__list"> <el-table :data="previewFiles" highlight-current-row size="mini" height="70vh" @row-click="handleSelect" > <el-table-column prop="name" label="æä»¶" show-overflow-tooltip /> </el-table> </div> <div class="file-preview__body"> <template v-if="currentFile"> <div v-if="currentFile.error && !currentFile.previewUrl" class="file-preview__tip"> æä»¶å 载失败ï¼{{ currentFile.error }} </div> <iframe v-else-if="currentFile.type === 'pdf'" :src="currentFile.previewUrl" class="file-preview__pdf" title="PDFé¢è§" /> <div v-else-if="currentFile.type === 'image'" class="file-preview__image-pane" > <div class="file-preview__toolbar"> <el-button-group> <el-button size="mini" icon="el-icon-zoom-out" title="缩å°" @click="zoomImage(-0.2)" /> <el-button size="mini" class="file-preview__scale"> {{ Math.round(imageScale * 100) }}% </el-button> <el-button size="mini" icon="el-icon-zoom-in" title="æ¾å¤§" @click="zoomImage(0.2)" /> </el-button-group> <el-button-group> <el-button size="mini" icon="el-icon-refresh-left" title="åå·¦æè½¬" @click="rotateImage(-90)" /> <el-button size="mini" icon="el-icon-refresh-right" title="åå³æè½¬" @click="rotateImage(90)" /> </el-button-group> <el-button size="mini" icon="el-icon-refresh" @click="resetImage" >éç½®</el-button > </div> <div class="file-preview__image-wrap"> <img :src="currentFile.previewUrl" class="file-preview__image" :style="{ transform: 'scale(' + imageScale + ') rotate(' + imageRotate + 'deg)' }" alt="å¾çé¢è§" /> </div> </div> <div v-else class="file-preview__tip"> 该æä»¶ç±»åæä¸æ¯æé¢è§ï¼è¯·ä¸è½½åæ¥ç </div> </template> <div v-else class="file-preview__tip">ææ å¯é¢è§æä»¶</div> </div> </div> <span slot="footer" class="dialog-footer"> <span class="file-preview-pager"> <el-button v-if="currentIndex > 0" size="mini" icon="el-icon-arrow-left" @click="prevFile" >ä¸ä¸å¼ </el-button > <span class="file-preview-pager__text"> {{ previewFiles.length ? currentIndex + 1 : 0 }} / {{ previewFiles.length }} </span> <el-button v-if="currentIndex < previewFiles.length - 1" size="mini" @click="nextFile" >ä¸ä¸å¼ <i class="el-icon-arrow-right el-icon--right"></i ></el-button> </span> <el-button v-if="currentFile && currentFile.type === 'pdf' && currentFile.previewUrl" icon="el-icon-top-right" @click="openInNewWindow" >æ°çªå£æå¼</el-button > <el-button type="primary" icon="el-icon-download" @click="handleDownload" >ä¸è½½</el-button > <el-button @click="visible = false">å ³é</el-button> </span> </el-dialog> </template> <script> import { getToken } from "@/utils/auth"; const IMAGE_EXT = ["jpg", "jpeg", "png", "gif", "bmp", "webp"]; export default { name: "FilePreview", data() { return { visible: false, loading: false, fileList: [], previewFiles: [], currentIndex: 0, imageScale: 1, imageRotate: 0, fullscreen: false }; }, computed: { currentFile() { return this.previewFiles[this.currentIndex] || null; } }, methods: { /** * æå¼é¢è§ * files: [{ name, url }] æå个 { name, url } * index: é»è®¤éä¸ä¸æ */ open(files, index = 0) { this.revokeUrls(); this.resetImage(); this.fullscreen = true; this.fileList = Array.isArray(files) ? files : files ? [files] : []; this.currentIndex = Math.max(0, Number(index) || 0); this.previewFiles = []; this.visible = true; this.loadFiles(); }, async loadFiles() { if (!this.fileList.length) { this.loading = false; return; } this.loading = true; const token = getToken(); const result = await Promise.all( this.fileList.map((file, idx) => this.loadOne(file, idx, token)) ); if (!this.visible) { result.forEach(item => { if (item.owned && item.previewUrl) URL.revokeObjectURL(item.previewUrl); }); return; } this.previewFiles = result; if (this.currentIndex >= this.previewFiles.length) { this.currentIndex = 0; } this.loading = false; }, async loadOne(file, idx, token) { const name = file.name || "æªå½åæä»¶"; const type = this.getFileType(name); const item = { name, type, rawUrl: file.url, previewUrl: "", owned: false, error: "" }; // å ¶ä»ç±»åä¸å è½½é¢è§ï¼ä¿çä¸è½½å°åå³å¯ if (type === "other") { return item; } try { const url = this.resolveUrl(file.url); let previewUrl = url; // blob/data URL å·²ç»æ¯æ¬å°èµæºï¼æ é忬¡è¯·æ± if (!/^(blob:|data:)/i.test(url)) { const headers = token ? { Authorization: "Bearer " + token } : {}; const response = await fetch(url, { headers, cache: "no-store" }); if (!response.ok) { throw new Error("HTTP " + response.status); } const blob = await response.blob(); if (type === "pdf") { await this.assertPdf(blob); } else if (type === "image" && blob.type && !/^image\//i.test(blob.type)) { throw new Error("æä»¶å 容䏿¯ææå¾çï¼å¯è½è¿åäºæ¥å£æç¤ºä¿¡æ¯"); } const typedBlob = type === "pdf" ? new Blob([blob], { type: "application/pdf" }) : blob; previewUrl = URL.createObjectURL(typedBlob); item.owned = true; } else if (type === "pdf" && /^blob:/i.test(url)) { // è°ç¨æ¹ä¼ å ¥ç PDF blob å¯è½æ²¡ææ£ç¡®ç MIMEï¼éæ°å è£ const response = await fetch(url); const blob = await response.blob(); await this.assertPdf(blob); previewUrl = URL.createObjectURL( new Blob([blob], { type: "application/pdf" }) ); item.owned = true; } else if (type === "image" && /^blob:/i.test(url)) { // æ ¡éªè°ç¨æ¹ä¼ å ¥çå¾ç blobï¼é¿å æ JSON é误ååºå½å¾çæ¾ç¤º const response = await fetch(url); const blob = await response.blob(); if (blob.type && !/^image\//i.test(blob.type)) { throw new Error("æä»¶å 容䏿¯ææå¾çï¼å¯è½è¿åäºæ¥å£æç¤ºä¿¡æ¯"); } previewUrl = URL.createObjectURL(blob); item.owned = true; } item.previewUrl = previewUrl; } catch (e) { item.error = e && e.message ? e.message : "å 载失败"; // å 容鿳æ¶ä¸è¦éååå°åï¼å¦åæµè§å¨åªä¼å次æ¾ç¤ºç©ºç½/âæªè½å è½½â item.previewUrl = type === "pdf" || /䏿¯ææ/.test(item.error) ? "" : this.resolveUrl(file.url); } return item; }, async assertPdf(blob) { const head = await blob.slice(0, 5).text(); if (head !== "%PDF-") { throw new Error( "æä»¶å 容䏿¯ææ PDFï¼å¯è½æ¯ç»å½å¤±æææä»¶å°åé误ï¼è¿åäºæ¥å£æç¤ºä¿¡æ¯ï¼" ); } }, resolveUrl(url) { if (!url) { return ""; } if (/^(blob:|data:|https?:)/i.test(url)) { return url; } return (process.env.VUE_APP_BASE_API || "") + url; }, getFileType(name) { const ext = String(name || "") .split(".") .pop() .toLowerCase(); if (ext === "pdf") { return "pdf"; } if (IMAGE_EXT.indexOf(ext) > -1) { return "image"; } return "other"; }, handleSelect(row) { const index = this.previewFiles.indexOf(row); if (index > -1) { this.currentIndex = index; this.resetImage(); } }, prevFile() { if (this.currentIndex > 0) { this.currentIndex -= 1; this.resetImage(); } }, nextFile() { if (this.currentIndex < this.previewFiles.length - 1) { this.currentIndex += 1; this.resetImage(); } }, zoomImage(delta) { const next = Math.round((this.imageScale + delta) * 100) / 100; this.imageScale = Math.min(5, Math.max(0.2, next)); }, rotateImage(deg) { this.imageRotate += deg; }, resetImage() { this.imageScale = 1; this.imageRotate = 0; }, handleDownload() { const file = this.currentFile; if (!file) { return; } const href = file.previewUrl || this.resolveUrl(file.rawUrl); if (!href) { return; } const a = document.createElement("a"); a.href = href; a.download = file.name; document.body.appendChild(a); a.click(); document.body.removeChild(a); }, openInNewWindow() { if (this.currentFile && this.currentFile.previewUrl) { window.open(this.currentFile.previewUrl, "_blank"); } }, handleClosed() { this.revokeUrls(); this.previewFiles = []; this.fileList = []; this.currentIndex = 0; this.resetImage(); this.fullscreen = false; }, revokeUrls() { this.previewFiles.forEach(item => { if (item.owned && item.previewUrl && /^blob:/i.test(item.previewUrl)) { URL.revokeObjectURL(item.previewUrl); } }); } }, beforeDestroy() { this.revokeUrls(); } }; </script> <style scoped> .file-preview-title { font-weight: 600; font-size: 15px; display: flex; align-items: center; justify-content: space-between; padding-right: 30px; } .file-preview-fullscreen-btn { margin-left: 12px; } .file-preview-pager { float: left; display: inline-flex; align-items: center; gap: 8px; } .file-preview-pager__text { color: #606266; font-size: 12px; } .file-preview { display: flex; height: 70vh; min-height: 420px; } .file-preview__list { width: 240px; flex: 0 0 240px; border-right: 1px solid #ebeef5; padding-right: 10px; overflow: hidden; } .file-preview__body { flex: 1; min-width: 0; display: flex; align-items: center; justify-content: center; overflow: auto; } .file-preview__pdf { width: 100%; height: 70vh; border: 0; } .file-preview__image { max-width: 100%; max-height: 100%; transition: transform 0.2s ease; transform-origin: center center; } .file-preview__image-pane { width: 100%; height: 100%; display: flex; flex-direction: column; min-height: 0; } .file-preview__toolbar { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 4px 0 10px; } .file-preview__scale { min-width: 64px; cursor: default; } .file-preview__image-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; align-items: center; justify-content: center; } .file-preview__tip { color: #909399; font-size: 14px; } </style> src/main.js
@@ -18,7 +18,9 @@ // è¿è¡æ¶ä¸»é¢å± + ç»ä»¶é»è®¤å¤è§ï¼å¿ é¡»æäº element-ui ä¸ ruoyi.scssï¼å¦åè¦çä¸çæ import '@/assets/styles/theme-runtime.scss' import '@/assets/styles/element-override.scss' import '@/assets/styles/pdf-resize-dialog.scss' import App from './App' import FilePreview from '@/components/FilePreview/index.vue' import store from './store' import router from './router' import directive from './directive' //directive @@ -43,6 +45,7 @@ import FileUpload from "@/components/FileUpload" // å¾çä¸ä¼ ç»ä»¶ import ImageUpload from "@/components/ImageUpload" import AttachmentPreviewPane from "@/components/AttachmentPreviewPane/index.vue" // åå ¸æ ç¾ç»ä»¶ import DictTag from '@/components/DictTag' // 头鍿 ç¾ç»ä»¶ @@ -90,6 +93,30 @@ Vue.component('Editor', Editor) Vue.component('FileUpload', FileUpload) Vue.component('ImageUpload', ImageUpload) Vue.component('AttachmentPreviewPane', AttachmentPreviewPane) // éä»¶å åµé¢è§ï¼æææ¥éé¡µå ±ç¨ Vue.mixin({ data() { return { embeddedFile: null, pdfFullscreen: false } }, methods: { openEmbeddedPreview(item) { if (!item) return const ext = String(item.name || '').toLowerCase().split('.').pop() const type = ext === 'pdf' ? 'pdf' : ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext) ? 'image' : 'other' this.embeddedFile = { name: item.name, url: item.url, type } this.pdfVisible = true } } }) Vue.use(directive) Vue.use(plugins) @@ -116,9 +143,28 @@ Vue.config.productionTip = false new Vue({ // å端æå»ºæ è¯ï¼ç¨äºç¡®è®¤æµè§å¨å®é å è½½çæ¯åªä¸ç代ç window.__APP_BUILD__ = '2026-11-03-PDF-PREVIEW-15' const app = new Vue({ el: '#app', router, store, render: h => h(App) }) // æä»¶é¢è§ï¼App å æè½½çå ¨å±ç»ä»¶ï¼é¿å å¨åºç¨å¤æå·¥ $mount let fallbackPreview = null Vue.prototype.$previewFile = (files, index = 0) => { if (app.$refs.filePreview) { app.$refs.filePreview.open(files, index) return } // å åºï¼App å ç»ä»¶å°æªæè½½æ¶ï¼ä»ä¿è¯æé¢è§å ¥å£ if (!fallbackPreview) { const FilePreviewCtor = Vue.extend(FilePreview) fallbackPreview = new FilePreviewCtor().$mount() document.body.appendChild(fallbackPreview.$el) } fallbackPreview.open(files, index) } src/utils/fileNameCheck.js
@@ -1,11 +1,12 @@ /** * æ¥éåéä»¶æä»¶åè§èæ ¡éªï¼2026-10-15ï¼ * æ¥éåéä»¶æä»¶åè§èæ ¡éªï¼2026-11-03 è°æ´ï¼ * * ä¸å¡å£å¾ï¼ä¸å¡æ¹ç¡®è®¤ï¼ï¼ * 1. å¿ é¡»å å«ä¸æï¼è³å° 1 个æ±åï¼ââ"为æ¹ä¾¿æ¥éªéä»¶ï¼è¯·ç¨ä¸æè§èå½åéä»¶ï¼" * 2. 廿æ©å±ååçä¸»å¹²ï¼æå符æ°è®¡ç®ä¸è½è¶ è¿ 20 个åââ"为æ¹ä¾¿æ¥éªéä»¶ï¼éä»¶ååé¿åº¦ä¸è½è¶ è¿20个åï¼" * ä¸å¡å£å¾ï¼ * 1. å 许æä»¶åä¸å«ä¸æï¼å«ä¸æ/çº¯è±æ/æ°ååå¯ * 2. 廿æ©å±ååçä¸»å¹²ï¼æå符æ°è®¡ç®ä¸è½è¶ è¿ 20 个å * 3. ä¸è½å å«ç©ºæ ¼å / \ : * ? " < > | # % çç¹æ®å符 * 4. å䏿ç»è¡å ä¸è½éåï¼æ¯è¾æ¶å¿½ç¥æ©å±å大å°åä¸é¦å°¾ç©ºæ ¼ï¼ * 5. åªæ ¡éªæ°ä¸ä¼ /æ°ä¿åçéä»¶ï¼åå²éä»¶ç±å端æ existingNames æ¾è¡ * * 使ç¨åºæ¯ï¼ * - ä¸ä¼ æååè°ï¼ä¸åæ ¼ â å¼¹æç¤ºä¸ä¸å å ¥åè¡¨ï¼ @@ -16,13 +17,10 @@ /** 主干ï¼å»æ©å±åï¼æå¤§åç¬¦æ° */ export const MAX_MAIN_LENGTH = 20; /** æ±å */ const RE_CHINESE = /[\u4e00-\u9fa5]/; /** éæ³å符ï¼ç©ºæ ¼ï¼å«å类空ç½ï¼+ / \ : * ? " < > | # % */ const RE_ILLEGAL = /[\s/\\:*?"<>|#%]/; export const MSG_NO_CHINESE = "为æ¹ä¾¿æ¥éªéä»¶ï¼è¯·ç¨ä¸æè§èå½åéä»¶ï¼"; export const MSG_EMPTY_NAME = "为æ¹ä¾¿æ¥éªéä»¶ï¼éä»¶åä¸è½ä¸ºç©ºï¼"; export const MSG_TOO_LONG = "为æ¹ä¾¿æ¥éªéä»¶ï¼éä»¶ååé¿åº¦ä¸è½è¶ è¿20个åï¼"; export const MSG_ILLEGAL = '为æ¹ä¾¿æ¥éªéä»¶ï¼éä»¶åä¸è½å å«ç©ºæ ¼å / \\ : * ? " < > | # % çç¹æ®å符ï¼'; export const MSG_DUPLICATE = "为æ¹ä¾¿æ¥éªéä»¶ï¼åä¸è¡å ä¸è½æéåçéä»¶ï¼"; @@ -46,15 +44,13 @@ export function checkFileName(fileName) { const name = (fileName || "").trim(); if (!name) { return { ok: false, msg: MSG_NO_CHINESE, main: "" }; return { ok: false, msg: MSG_EMPTY_NAME, main: "" }; } if (RE_ILLEGAL.test(name)) { return { ok: false, msg: MSG_ILLEGAL, main: mainName(name) }; } const main = mainName(name); if (!RE_CHINESE.test(main)) { return { ok: false, msg: MSG_NO_CHINESE, main }; } // ä¸å强å¶è¦æ±ä¸æï¼å«ä¸æãçº¯è±æãæ°ååå¯ // æå符æ°è®¡ï¼ç¨æ©å±è¿ç®ç¬¦æç ç¹è®¡æ°ï¼ä¸æ/忝/æ°å/å ¨è§å计 1ï¼ if ([...main].length > MAX_MAIN_LENGTH) { return { ok: false, msg: MSG_TOO_LONG, main }; src/utils/filePreview.js
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,18 @@ import Vue from "vue"; import FilePreview from "@/components/FilePreview/index.vue"; let instance = null; /** * å ¨å±æä»¶é¢è§ï¼å¾çãPDF * @param {Array|Object} files [{ name, url }] æå个 { name, url } * @param {Number} index é»è®¤éä¸ä¸æ */ export default function previewFile(files, index = 0) { if (!instance) { const FilePreviewCtor = Vue.extend(FilePreview); instance = new FilePreviewCtor().$mount(); document.body.appendChild(instance.$el); } instance.open(files, index); } src/views/project/donationdetails/index.vue
@@ -2511,6 +2511,7 @@ :title="pdftitle" :visible.sync="pdfVisible" width="68%" custom-class="pdf-resize-dialog" > <!-- <el-tabs style="margin-top: 20px;" v-model="activeName" type="card"> <el-tab-pane :label="activetele" name="1"> </el-tab-pane> @@ -4282,14 +4283,8 @@ }, // è·å请æ±å¤´ Getnetworkheader() { let string = window.location.href; if (string.includes("9091")) { const index = string.indexOf("9091"); this.Networkheader = string.slice(0, index + 4); // æªå9091åå ¶åé¨å符 } else { const index = string.indexOf("8032"); this.Networkheader = string.slice(0, index + 4); // æªå8032åå ¶åé¨å符 } // 以å½åé¡µé¢ origin 为åï¼å ¼å®¹ 80/8032/9091 ååç»ç«¯å£è°æ´ this.Networkheader = window.location.origin; }, // è·åéä»¶æ°æ®å¹¶åç±»äºçº§å @@ -4337,7 +4332,7 @@ const config = { headers: { Authorization: "Bearer " + this.ICDtoken } }; const pdfimg = this.Networkheader + "/prod-api" + response.fileName; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName; console.log(this.Networkheader); //è·å票æ®ä¿¡æ¯ä½ç½® if (response.code == 200) { @@ -4398,7 +4393,7 @@ this.pdfVisible = true; if (this.annexfilesList.length) { this.annexfilesList.forEach((value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.annexurl; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.annexurl; fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -4433,18 +4428,13 @@ console.log(item, "ç¹å»æä»¶æ¿item"); this.pdftitle = "å ±" + this.donatelist.length + "项ï¼å½åéä¸" + item.annexname; let name = item.annexname.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { this.previewpdf = true; if (item.annexurl) { this.pdfimg = item.annexurl; } else { this.pdfimg = ""; } const ext = String(item.annexname || "pdf").toLowerCase().split(".").pop(); if (ext === "pdf") { this.$previewFile([{ name: item.annexname, url: item.annexurl }]); return; } else if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { this.$previewFile([{ name: item.annexname, url: item.annexurl }]); return; } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); src/views/project/donorcharge/donorchargedetail/index.vue
@@ -472,14 +472,8 @@ handleUploadError() {}, // è·å请æ±å¤´ Getnetworkheader() { let string = window.location.href; if (string.includes("9091")) { const index = string.indexOf("9091"); this.Networkheader = string.slice(0, index + 4); // æªå9091åå ¶åé¨å符 } else { const index = string.indexOf("8032"); this.Networkheader = string.slice(0, index + 4); // æªå8032åå ¶åé¨å符 } // 以å½åé¡µé¢ origin 为åï¼å ¼å®¹ 80/8032/9091 ååç»ç«¯å£è°æ´ this.Networkheader = window.location.origin; }, // åç¥¨åæ¢ handleClick(tab, event) { src/views/project/fund/applyDetail/index.vue
@@ -516,7 +516,24 @@ </span> </el-dialog> <el-dialog v-dialogDrags :modal="false" :close-on-click-modal="false" :title="pdftitle" :visible.sync="pdfVisible" width="60%"> :fullscreen="pdfFullscreen" width="60%" custom-class="pdf-resize-dialog" @closed="pdfFullscreen = false"> <template slot="title"> <span>{{ pdftitle }}</span> <el-button class="pdf-fullscreen-btn" size="mini" :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'" @click="pdfFullscreen = !pdfFullscreen">{{ pdfFullscreen ? "è¿å" : "å ¨å±" }}</el-button> </template> <el-alert :title=" activeName == 'invoice' ? 'å½åæ£å¨æä½ï¼å票æä»¶ï¼è¯·ç¡®è®¤ç¥¨æ®å±äºå票ï¼' : 'å½åæ£å¨æä½ï¼æ®ééä»¶ï¼è¯·å¿å¨æ¤ä¸ä¼ å票ï¼' " :type="activeName == 'invoice' ? 'success' : 'warning'" :closable="false" show-icon style="margin-bottom: 10px;" /> <div style="margin-bottom: 10px;"> <el-table :data="tableDatatop" style="width: 100%"> <el-table-column v-if="businessType == 4" prop="price" align="center" label="åä»·"> @@ -601,18 +618,7 @@ </div> </div> <div v-if="this.previewpdf && pdfimgsrcList.length" class="pdfimgmin"> <!-- <img :src="pdfimg" /> --> <el-image ref="imagePreview" style="width: 95%; height: 90%" :src="pdfimg" @click="handleImageClick(initialIndex)"> <!-- <div slot="error" class="image-slot"> <i class="el-icon-picture-outline"></i> </div> --> </el-image> <custom-image-viewer :url-list="pdfimgsrcList" :initial-index="currentIndex" :visible="viewerVisible" @update:visible="viewerVisible = $event" @close="handleViewerClose" /> </div> <div v-else class="pdfimgmins">{{ hintitle }}</div> <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" /> </div> </el-tab-pane> <el-tab-pane label="å票æä»¶" name="invoice"> @@ -653,19 +659,7 @@ </div> </div> <div v-if="this.previewpdf && invoicepdfimgsrcList.length" class="pdfimgmin"> <!-- <img :src="pdfimg" /> --> <el-image style="width: 95%; height: 90%" :src="invoicepdfimg" @click="invoicehandleImageClick(initialIndex)"> <!-- <div slot="error" class="image-slot"> <i class="el-icon-picture-outline"></i> </div> --> </el-image> <custom-image-viewer :url-list="invoicepdfimgsrcList" :initial-index="invoicecurrentIndex" :visible="invoiceviewerVisible" @update:visible="invoiceviewerVisible = $event" @close="invoicehandleViewerClose" /> </div> <div v-else class="pdfimgmins">{{ hintitle }}</div> <attachment-preview-pane :file="invoiceEmbeddedFile" style="flex: 1; min-width: 0;" /> </div> </el-tab-pane> </el-tabs> @@ -1121,7 +1115,7 @@ invoicepdfimg: "", invoicepdfimgsrcList: [], invoDatatop: [], activeName: "common", //æä»¶ç±»å activeName: "invoice", //æä»¶ç±»åï¼é»è®¤å票æä»¶ //ä¸ä¼ éä»¶è·¯å¾ uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", ICDtoken: getToken(), @@ -1132,6 +1126,7 @@ //ç¥¨æ®æä»¶ pdftitle: "", pdfimg: "", invoiceEmbeddedFile: null, pdfimgsrcList: [], currentIndex: 0, // åå§ç´¢å¼ invoicecurrentIndex: 0, // åå§ç´¢å¼ @@ -1234,14 +1229,8 @@ }, // è·å请æ±å¤´ Getnetworkheader() { let string = window.location.href; if (string.includes("9091")) { const index = string.indexOf("9091"); this.Networkheader = string.slice(0, index + 4); // æªå9091åå ¶åé¨å符 } else { const index = string.indexOf("8032"); this.Networkheader = string.slice(0, index + 4); // æªå8032åå ¶åé¨å符 } // 以å½åé¡µé¢ origin 为åï¼å ¼å®¹ 80/8032/9091 ååç»ç«¯å£è°æ´ this.Networkheader = window.location.origin; }, /** éè¿åæ°è·åä¸å¡ç±»å */ getroute() { @@ -2975,7 +2964,7 @@ /** * 2026-10-15ï¼ä¸ä¼ æ¶æ ¡éªéä»¶æä»¶åï¼ä¸å¡è¦æ±ï¼ä¸åæ ¼ç«å³æç¤ºä¸ä¸å å ¥å表ï¼ã * è§åä¸å端 AttachmentNameValidator åå£å¾ï¼å¿ é¡»å«ä¸æ / 廿æ©å±åå主干 â¤20 å / * è§åä¸å端 AttachmentNameValidator åå£å¾ï¼ä¸å¼ºå¶å«ä¸æ / 廿æ©å±åå主干 â¤20 å / * ä¸å«ç©ºæ ¼å / \ : * ? " < > | # % çç¹æ®å符ã */ checkUploadFileName(file) { @@ -3014,27 +3003,27 @@ const config = { headers: { Authorization: "Bearer " + this.ICDtoken } }; const pdfimg = this.Networkheader + "/prod-api" + response.fileName; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName; //è·å票æ®ä¿¡æ¯ä½ç½® if (this.activeName == "common") { if (response.code == 200) { this.previewpdf = true; fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { // å°è·åçæ°æ®æµè½¬æ¢ä¸ºURL this.pdfimg = URL.createObjectURL(blob); this.pdfimgsrcList.push(URL.createObjectURL(blob)); this.fileListto.push({ name: file.name, url: URL.createObjectURL(blob) }); }) .catch(error => { console.error("Error loading image", error); return; }); // æ°ä¸ä¼ æä»¶ç´æ¥ä½¿ç¨æµè§å¨æ¬å° Fileï¼é¿å æå¡ç«¯æä»¶å°å/Token // å¼å¸¸æ¶æ JSON é误ååºå½æå¾çæ PDF é¢è§ã const localBlob = file.raw; const localUrl = URL.createObjectURL(localBlob); this.pdfimg = localUrl; this.embeddedFile = { name: file.name, url: localUrl, type: /\.pdf$/i.test(file.name) ? "pdf" : "image" }; this.pdfimgsrcList.push(localUrl); this.fileListto.push({ name: file.name, url: localUrl }); this.$modal.msgSuccess(response.msg); @@ -3053,21 +3042,19 @@ } else { if (response.code == 200) { this.previewpdf = true; fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { // å°è·åçæ°æ®æµè½¬æ¢ä¸ºURL this.invoicepdfimg = URL.createObjectURL(blob); this.invoicepdfimgsrcList.push(URL.createObjectURL(blob)); this.invoicefileListto.push({ name: file.name, url: URL.createObjectURL(blob) }); }) .catch(error => { console.error("Error loading image", error); return; }); const localBlob = file.raw; const localUrl = URL.createObjectURL(localBlob); this.invoicepdfimg = localUrl; this.invoiceEmbeddedFile = { name: file.name, url: localUrl, type: /\.pdf$/i.test(file.name) ? "pdf" : "image" }; this.invoicepdfimgsrcList.push(localUrl); this.invoicefileListto.push({ name: file.name, url: localUrl }); this.$modal.msgSuccess(response.msg); @@ -3103,7 +3090,7 @@ if (this.rbDetails[index].annexfilesList) { // this.rbDetails[index].annexfilesList.forEach((value, indexson) => { // const pdfimg = this.Networkheader + "/prod-api" + value.url; // const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; // fetch(pdfimg, config) // .then(response => response.blob()) // .then(blob => { @@ -3125,7 +3112,7 @@ const fetchPromises = this.rbDetails[index].annexfilesList.map( (value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.url; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; return fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -3158,7 +3145,7 @@ if (this.rbDetails[index].invoicefilesList) { const fetchPromises = this.rbDetails[index].invoicefilesList.map( (value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.url; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; return fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -3201,50 +3188,17 @@ console.log(this.rbDetails[index].annexfilesList, "annexfilesList"); }, // ç¹å»å·²ä¸ä¼ æä»¶ // è´¹ç¨æ¥éï¼éä»¶ç»ä¸ä½¿ç¨ç¬ç« FilePreviewï¼å½å ¥ã审æ¹ã详æ ä¸è´ï¼ downFile(item) { if (this.activeName == "common") { this.pdftitle = "å ±" + this.pdfimgsrcList.length + "项ï¼å½åéä¸" + item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { console.log(item, "å±ç¤º"); this.previewpdf = true; if (item.url) { this.pdfimg = item.url; } else { this.pdfimg = ""; } } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; } } else { this.pdftitle = "å ±" + this.invoicepdfimgsrcList.length + "项ï¼å½åéä¸" + item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { this.previewpdf = true; if (item.url) { this.invoicepdfimg = item.url; } else { this.invoicepdfimg = ""; } } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; } const source = this.activeName == "common" ? this.fileListto : this.invoicefileListto; let list = (source || []).map(f => ({ name: f.name, url: f.url })); let index = list.findIndex(f => f.url === item.url); if (index < 0 && item && item.url) { list = [{ name: item.name, url: item.url }]; index = 0; } this.$previewFile(list, index > -1 ? index : 0); }, getIndexInArray(arr, obj) { return arr.indexOf(obj); src/views/project/fund/applyDetail0/index.vue
@@ -1034,8 +1034,21 @@ :close-on-click-modal="false" :title="pdftitle" :visible.sync="pdfVisible" :fullscreen="pdfFullscreen" width="60%" custom-class="pdf-resize-dialog" @closed="pdfFullscreen = false" > <template slot="title"> <span>{{ pdftitle }}</span> <el-button class="pdf-fullscreen-btn" size="mini" :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'" @click="pdfFullscreen = !pdfFullscreen" >{{ pdfFullscreen ? "è¿å" : "å ¨å±" }}</el-button > </template> <div class="pdfimg"> <div class="box-pdf"> <div> @@ -1125,16 +1138,7 @@ </div> --> </div> <div v-if="this.previewpdf" class="pdfimgmin"> <!-- <img :src="pdfimg" /> --> <el-image style="width: 95%; height: 90%" :src="pdfimg" :preview-src-list="pdfimgsrcList" > </el-image> </div> <div v-else class="pdfimgmins">{{ hintitle }}</div> <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" /> </div> </el-dialog> <el-dialog title="æç¤º" :visible.sync="Savereminder" width="30%"> @@ -1552,15 +1556,8 @@ }, // è·å请æ±å¤´ Getnetworkheader() { let string = window.location.href; if (string.includes("9091")) { const index = string.indexOf("9091"); this.Networkheader = string.slice(0, index + 4); // æªå9091åå ¶åé¨å符 // console.log(this.Networkheader); } else { const index = string.indexOf("8032"); this.Networkheader = string.slice(0, index + 4); // æªå8032åå ¶åé¨å符 } // 以å½åé¡µé¢ origin 为åï¼å ¼å®¹ 80/8032/9091 ååç»ç«¯å£è°æ´ this.Networkheader = window.location.origin; }, /** éè¿åæ°è·åä¸å¡ç±»å */ getroute() { @@ -3011,7 +3008,7 @@ // }, /** * 2026-10-15ï¼ä¸ä¼ æ¶æ ¡éªéä»¶æä»¶åï¼ä¸å¡è¦æ±ï¼ä¸åæ ¼ç«å³æç¤ºä¸ä¸å å ¥å表ï¼ã * è§åä¸å端 AttachmentNameValidator åå£å¾ï¼å¿ é¡»å«ä¸æ / 廿æ©å±åå主干 â¤20 å / * è§åä¸å端 AttachmentNameValidator åå£å¾ï¼ä¸å¼ºå¶å«ä¸æ / 廿æ©å±åå主干 â¤20 å / * ä¸å«ç©ºæ ¼å / \ : * ? " < > | # % çç¹æ®å符ã */ checkUploadFileName(file) { @@ -3056,9 +3053,15 @@ this.fileListto.push({ name: file.name, url: response.fileName }); // this.fileListto.push({ name: file.name, url: response.url }); this.pdfimgsrcList.push( this.Networkheader + "/prod-api" + response.fileName this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName ); this.pdfimg = this.Networkheader + "/prod-api" + response.fileName; this.pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName; const localUrl = URL.createObjectURL(file.raw); this.embeddedFile = { name: file.name, url: localUrl, type: /\.pdf$/i.test(file.name) ? "pdf" : "image" }; this.rbDetails[this.atpresent].annexfilesList = this.fileListto; } else { @@ -3073,11 +3076,11 @@ if (this.rbDetails[index].annexfilesList) { this.previewpdf = true; this.fileListto = this.rbDetails[index].annexfilesList; this.pdfimg = this.Networkheader + "/prod-api" + this.fileListto[0].url; this.pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + this.fileListto[0].url; // this.pdfimg = this.fileListto[0].url; this.pdfimgsrcList = []; this.fileListto.forEach(item => { this.pdfimgsrcList.push(this.Networkheader + "/prod-api" + item.url); this.pdfimgsrcList.push(this.Networkheader + process.env.VUE_APP_BASE_API + item.url); }); console.log(this.pdfimgsrcList); console.log(this.pdfimg); @@ -3088,34 +3091,31 @@ } }, // ç¹å»å·²ä¸ä¼ æä»¶ // ç¹å»å·²ä¸ä¼ æä»¶ï¼å¨éä»¶å¼¹çªå³ä¾§å åµé¢è§ downFile(item) { console.log(item); this.pdftitle = item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { this.previewpdf = true; if (item.url) { this.pdfimg = this.Networkheader + "/prod-api" + item.url; // if (!this.pdfimgsrcList.includes(this.pdfimg)) { // this.pdfimgsrcList.push(this.pdfimg); // console.log("å å ¥"); // } console.log(this.pdfimg); console.log(this.pdfimgsrcList, "imglist"); } else { this.pdfimg = this.Networkheader + "/prod-api" + item.url; } } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; if (this.operationType == "detail") { const list = (this.fileListto || []).map(f => ({ name: f.name, url: f.url })); const index = list.findIndex(f => f.url === item.url); this.$previewFile(list, index > -1 ? index : 0); return; } const ext = String(item.name || "").toLowerCase().split(".").pop(); const isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext); if (ext !== "pdf" && !isImage) { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); return; } this.embeddedFile = { name: item.name, url: item.url, type: ext === "pdf" ? "pdf" : "image" }; this.pdftitle = item.name; this.pdfVisible = true; }, getIndexInArray(arr, obj) { return arr.indexOf(obj); @@ -3126,7 +3126,7 @@ console.log(row); const indexlist = this.getIndexInArray( this.pdfimgsrcList, this.Networkheader + "/prod-api" + row.url this.Networkheader + process.env.VUE_APP_BASE_API + row.url ); console.log(indexlist); this.pdfimgsrcList.splice(indexlist, 1); src/views/project/fund/ethicalExpertFeeApply/index.vue
@@ -2064,8 +2064,16 @@ } }, // ä¸è½½æä»¶ // é¢è§/ä¸è½½æä»¶ downFile(item) { const ext = String(item.name || "") .split(".") .pop() .toLowerCase(); if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { this.$previewFile([{ name: item.name, url: item.url }]); return; } const url = process.env.VUE_APP_BASE_API + item.url; var a = document.createElement("a"); var event = new MouseEvent("click"); src/views/project/fund/expertFeeApply/index.vue
@@ -2661,8 +2661,16 @@ //æä»¶ä¸ä¼ handleUploadError() {}, /** ä¸è½½æä»¶æé®æä½ */ /** é¢è§/ä¸è½½æä»¶ */ downFile(item) { const ext = String(item.name || "") .split(".") .pop() .toLowerCase(); if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { this.$previewFile([{ name: item.name, url: item.url }]); return; } const url = process.env.VUE_APP_BASE_API + item.url; var a = document.createElement("a"); var event = new MouseEvent("click"); src/views/project/fund/medicalCostApply/index.vue
@@ -1366,18 +1366,18 @@ // ç¹å»å·²ä¸ä¼ æä»¶ downFile(item) { this.pdftitle = item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { this.previewpdf = true; if (item.url) { this.pdfimg = item.url; } else { this.pdfimg = item.response.url; } const ext = String(item.name || "pdf").toLowerCase().split(".").pop(); if (ext === "pdf") { this.$previewFile([{ name: item.name, url: item.url }]); return; } else if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { this.$previewFile([ { name: item.name, url: item.url || (item.response && item.response.url) } ]); return; } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); src/views/project/fund/officeExpenseApply/index.vue
@@ -1936,8 +1936,16 @@ console.log(response.msg); } }, // ä¸è½½æä»¶ // é¢è§/ä¸è½½æä»¶ downFile(item) { const ext = String(item.name || "") .split(".") .pop() .toLowerCase(); if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { this.$previewFile([{ name: item.name, url: item.url }]); return; } const url = process.env.VUE_APP_BASE_API + item.url; var a = document.createElement("a"); var event = new MouseEvent("click"); src/views/project/fund/performancedetails/index.vue
@@ -596,8 +596,28 @@ :close-on-click-modal="false" :title="pdftitle" :visible.sync="pdfVisible" :fullscreen="pdfFullscreen" width="60%" custom-class="pdf-resize-dialog" @closed="pdfFullscreen = false" > <template slot="title"> <span>{{ pdftitle }}</span> <el-button class="pdf-fullscreen-btn" size="mini" :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'" @click="pdfFullscreen = !pdfFullscreen">{{ pdfFullscreen ? "è¿å" : "å ¨å±" }}</el-button> </template> <el-alert :title=" activeName == 2 ? 'å½åæ£å¨æä½ï¼å票æä»¶ï¼è¯·ç¡®è®¤ç¥¨æ®å±äºå票ï¼' : 'å½åæ£å¨æä½ï¼æ®ééä»¶ï¼è¯·å¿å¨æ¤ä¸ä¼ å票ï¼' " :type="activeName == 2 ? 'success' : 'warning'" :closable="false" show-icon style="margin-bottom: 10px;" /> <div style="margin-bottom: 10px;"> <el-table :data="tableDatatop" style="width: 100%"> <el-table-column @@ -724,24 +744,7 @@ </div> </div> <div v-if="this.previewpdf && pdfimgsrcList.length" class="pdfimgmin" > <el-image style="width: 95%; height: 90%" :src="pdfimg" @click="handleImageClick(0)" /> <custom-image-viewer :url-list="pdfimgsrcList" :initial-index="currentIndex" :visible="viewerVisible" @update:visible="viewerVisible = $event" @close="handleViewerClose" /> </div> <div v-else class="pdfimgmins">{{ hintitle }}</div> <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" /> </div> </el-tab-pane> <el-tab-pane label="å票æä»¶" :name="2"> @@ -829,24 +832,7 @@ </div> </div> <div v-if="this.previewpdf && invoicepdfimgsrcList.length" class="pdfimgmin" > <el-image style="width: 95%; height: 90%" :src="invoicepdfimg" @click="invoiceHandleImageClick(0)" /> <custom-image-viewer :url-list="invoicepdfimgsrcList" :initial-index="invoiceCurrentIndex" :visible="invoiceViewerVisible" @update:visible="invoiceViewerVisible = $event" @close="invoiceHandleViewerClose" /> </div> <div v-else class="pdfimgmins">{{ hintitle }}</div> <attachment-preview-pane :file="invoiceEmbeddedFile" style="flex: 1; min-width: 0;" /> </div> </el-tab-pane> </el-tabs> @@ -1261,7 +1247,7 @@ invoicefileListto: [], invoicepdfimg: "", invoicepdfimgsrcList: [], activeName: 1, //æä»¶ç±»å activeName: 2, //æä»¶ç±»åï¼é»è®¤å票æä»¶ //ä¸ä¼ éä»¶è·¯å¾ uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", //æä»¶ä¸ä¼ token @@ -1271,6 +1257,7 @@ //ç¥¨æ®æä»¶ pdftitle: "", pdfimg: "", invoiceEmbeddedFile: null, pdfimgsrcList: [], pdfVisible: false, previewpdf: false, @@ -2826,18 +2813,12 @@ }, // è·å请æ±å¤´ Getnetworkheader() { let string = window.location.href; if (string.includes("9091")) { const index = string.indexOf("9091"); this.Networkheader = string.slice(0, index + 4); // æªå9091åå ¶åé¨å符 } else { const index = string.indexOf("8032"); this.Networkheader = string.slice(0, index + 4); // æªå8032åå ¶åé¨å符 } // 以å½åé¡µé¢ origin 为åï¼å ¼å®¹ 80/8032/9091 ååç»ç«¯å£è°æ´ this.Networkheader = window.location.origin; }, /** * 2026-10-15ï¼ä¸ä¼ æ¶æ ¡éªéä»¶æä»¶åï¼ä¸å¡è¦æ±ï¼ä¸åæ ¼ç«å³æç¤ºä¸ä¸å å ¥å表ï¼ã * è§åä¸å端 AttachmentNameValidator åå£å¾ï¼å¿ é¡»å«ä¸æ / 廿æ©å±åå主干 â¤20 å / * è§åä¸å端 AttachmentNameValidator åå£å¾ï¼ä¸å¼ºå¶å«ä¸æ / 廿æ©å±åå主干 â¤20 å / * ä¸å«ç©ºæ ¼å / \ : * ? " < > | # % çç¹æ®å符ã */ checkUploadFileName(file) { @@ -2876,27 +2857,23 @@ const config = { headers: { Authorization: "Bearer " + this.ICDtoken } }; const pdfimg = this.Networkheader + "/prod-api" + response.fileName; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName; //è·å票æ®ä¿¡æ¯ä½ç½® if (this.activeName == 1) { if (response.code == 200) { this.previewpdf = true; fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { // å°è·åçæ°æ®æµè½¬æ¢ä¸ºURL this.pdfimg = URL.createObjectURL(blob); this.pdfimgsrcList.push(URL.createObjectURL(blob)); this.fileListto.push({ name: file.name, url: URL.createObjectURL(blob) }); }) .catch(error => { console.error("Error loading image", error); return; }); const localUrl = URL.createObjectURL(file.raw); this.pdfimg = localUrl; this.embeddedFile = { name: file.name, url: localUrl, type: /\.pdf$/i.test(file.name) ? "pdf" : "image" }; this.pdfimgsrcList.push(localUrl); this.fileListto.push({ name: file.name, url: localUrl }); this.$modal.msgSuccess(response.msg); @@ -2915,21 +2892,18 @@ } else { if (response.code == 200) { this.previewpdf = true; fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { // å°è·åçæ°æ®æµè½¬æ¢ä¸ºURL this.invoicepdfimg = URL.createObjectURL(blob); this.invoicepdfimgsrcList.push(URL.createObjectURL(blob)); this.invoicefileListto.push({ name: file.name, url: URL.createObjectURL(blob) }); }) .catch(error => { console.error("Error loading image", error); return; }); const localUrl = URL.createObjectURL(file.raw); this.invoicepdfimg = localUrl; this.invoiceEmbeddedFile = { name: file.name, url: localUrl, type: /\.pdf$/i.test(file.name) ? "pdf" : "image" }; this.invoicepdfimgsrcList.push(localUrl); this.invoicefileListto.push({ name: file.name, url: localUrl }); this.$modal.msgSuccess(response.msg); @@ -2966,7 +2940,7 @@ if (this.rbDetails[index].annexfilesList) { const fetchPromises = this.rbDetails[index].annexfilesList.map( (value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.url; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; return fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -2999,7 +2973,7 @@ if (this.rbDetails[index].invoicefilesList) { const fetchPromises = this.rbDetails[index].invoicefilesList.map( (value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.url; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; return fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -3033,7 +3007,7 @@ this.pdftitle = ""; } if (this.activeName == "common") { if (this.activeName == 1) { this.pdftitle = "å ±" + this.pdfimgsrcList.length + "项"; } else { this.pdftitle = "å ±" + this.invoicepdfimgsrcList.length + "项"; @@ -3042,50 +3016,38 @@ console.log(this.rbDetails[index].annexfilesList, "annexfilesList"); }, // ç¹å»å·²ä¸ä¼ æä»¶ // ç¹å»å·²ä¸ä¼ æä»¶ï¼å¨éä»¶å¼¹çªå³ä¾§å åµé¢è§ downFile(item) { if (this.operationType == "detail") { const source = this.activeName == 1 ? this.fileListto : this.invoicefileListto; const list = (source || []).map(f => ({ name: f.name, url: f.url })); const index = list.findIndex(f => f.url === item.url); this.$previewFile(list, index > -1 ? index : 0); return; } const ext = String(item.name || "").toLowerCase().split(".").pop(); const isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext); if (ext !== "pdf" && !isImage) { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); return; } const file = { name: item.name, url: item.url, type: ext === "pdf" ? "pdf" : "image" }; if (this.activeName == 1) { this.embeddedFile = file; this.pdftitle = "å ±" + this.pdfimgsrcList.length + "项ï¼å½åéä¸" + item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { console.log(item, "å±ç¤º"); this.previewpdf = true; if (item.url) { this.pdfimg = item.url; } else { this.pdfimg = ""; } } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; } } else { this.invoiceEmbeddedFile = file; this.pdftitle = "å ±" + this.invoicepdfimgsrcList.length + "项ï¼å½åéä¸" + item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { this.previewpdf = true; if (item.url) { this.invoicepdfimg = item.url; } else { this.invoicepdfimg = ""; } } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; } } this.pdfVisible = true; }, getIndexInArray(arr, obj) { return arr.indexOf(obj); @@ -3173,7 +3135,7 @@ }, Downloadfile(row) { console.log(row); window.location.href = this.Networkheader + "/prod-api" + row.url; window.location.href = this.Networkheader + process.env.VUE_APP_BASE_API + row.url; }, //è¡¨æ ¼å计 getSummaries(param) { src/views/project/fundcheck/medicalCostCheck/index.vue
@@ -1760,8 +1760,21 @@ console.log(response.msg); } }, // ä¸è½½æä»¶ // é¢è§/ä¸è½½æä»¶ downFile(item) { const ext = String(item.name || "") .split(".") .pop() .toLowerCase(); if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { const list = (this.fileList || []).map(f => ({ name: f.name, url: f.url })); const index = list.findIndex(f => f.url === item.url); this.$previewFile(list, index > -1 ? index : 0); return; } const url = process.env.VUE_APP_BASE_API + item.url; var a = document.createElement("a"); var event = new MouseEvent("click"); src/views/project/fundcheck/officeExpenseCheck/index.vue
@@ -1765,8 +1765,21 @@ console.log(response.msg); } }, // ä¸è½½æä»¶ // é¢è§/ä¸è½½æä»¶ downFile(item) { const ext = String(item.name || "") .split(".") .pop() .toLowerCase(); if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { const list = (this.fileList || []).map(f => ({ name: f.name, url: f.url })); const index = list.findIndex(f => f.url === item.url); this.$previewFile(list, index > -1 ? index : 0); return; } const url = process.env.VUE_APP_BASE_API + item.url; var a = document.createElement("a"); var event = new MouseEvent("click"); src/views/project/statistics/applyStatistics/index.vue
@@ -338,6 +338,10 @@ /** æ¥è¯¢æç®åºç¡å表 */ getList() { if (!this.selecttime || this.selecttime.length !== 2) { this.$modal.msgWarning("è¯·éæ©æ¶é´èå´ååæ¥è¯¢"); return; } listbxiaostatistics(this.queryParams).then(res => { this.total = res.total; this.jxidata = res.rows; @@ -503,7 +507,6 @@ //çå½å¨æ - åå»ºå®æï¼å¯ä»¥è®¿é®å½åthiså®ä¾ï¼ created() { //è·åå表 this.getList(); this.listDept(); this.getUserList(); } src/views/project/statistics/casePanorama/index.vue
@@ -210,11 +210,14 @@ }, created() { this.getDeptOptions(); this.getList(); }, methods: { /** æ¥è¯¢æ¡ä¾å ¨æ¯ */ getList() { if (!this.dateRange || this.dateRange.length !== 2) { this.$modal.msgWarning("è¯·éæ©æ¶é´èå´ååæ¥è¯¢"); return; } this.loading = true; listCasePanorama(this.queryParams) .then(res => { src/views/project/statistics/caseStatistics/index.vue
@@ -340,6 +340,10 @@ /** æ¥è¯¢æç®åºç¡å表 */ getList() { if (!this.selecttime || this.selecttime.length !== 2) { this.$modal.msgWarning("è¯·éæ©æ¶é´èå´ååæ¥è¯¢"); return; } listanlstatistics(this.queryParams).then(res => { this.jxidata = res.rows; this.jxidata.forEach(($obj, $index) => { @@ -486,7 +490,6 @@ //çå½å¨æ - åå»ºå®æï¼å¯ä»¥è®¿é®å½åthiså®ä¾ï¼ created() { //è·åå表 this.getList(); this.listDept(); } // //çå½å¨æ - æè½½å®æï¼å¯ä»¥è®¿é®DOMå ç´ ï¼ src/views/project/statistics/chargeStatistics/index.vue
@@ -337,6 +337,10 @@ /** æ¥è¯¢æ¶æ¬¾ç»è®¡ */ getList() { if (!this.selecttime || this.selecttime.length !== 2) { this.$modal.msgWarning("è¯·éæ©æ¶é´èå´ååæ¥è¯¢"); return; } this.loading = true; listsfeistatistics(this.queryParams) .then(res => { src/views/project/statistics/performanceStaristics/index.vue
@@ -281,6 +281,10 @@ /** æ¥è¯¢æç®åºç¡å表 */ getList() { if (!this.selecttime || this.selecttime.length !== 2) { this.$modal.msgWarning("è¯·éæ©æ¶é´èå´ååæ¥è¯¢"); return; } listjixstatistics(this.buildQueryParams()).then(res => { this.jxidata = res.rows; this.jxidata.forEach(($obj, $index) => { @@ -447,7 +451,6 @@ //çå½å¨æ - åå»ºå®æï¼å¯ä»¥è®¿é®å½åthiså®ä¾ï¼ created() { //è·åå表 this.getList(); this.listDept(); } // //çå½å¨æ - æè½½å®æï¼å¯ä»¥è®¿é®DOMå ç´ ï¼ src/views/project/tallage/computingBill/index.vue
@@ -439,8 +439,17 @@ :close-on-click-modal="false" :title="pdftitle" :visible.sync="pdfVisible" :fullscreen="pdfFullscreen" width="60%" custom-class="pdf-resize-dialog" @closed="pdfFullscreen = false" > <template slot="title"> <span>{{ pdftitle }}</span> <el-button class="pdf-fullscreen-btn" size="mini" :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'" @click="pdfFullscreen = !pdfFullscreen">{{ pdfFullscreen ? "è¿å" : "å ¨å±" }}</el-button> </template> <div class="pdfimg"> <div class="box-pdf"> <div> @@ -526,19 +535,7 @@ </div> </div> <div v-if="this.previewpdf && pdfimgsrcList.length" class="pdfimgmin"> <!-- <img :src="pdfimg" /> --> <el-image style="width: 95%; height: 90%" :src="pdfimg" :preview-src-list="pdfimgsrcList" > <!-- <div slot="error" class="image-slot"> <i class="el-icon-picture-outline"></i> </div> --> </el-image> </div> <div v-else class="pdfimgmins">{{ hintitle }}</div> <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" /> </div> </el-dialog> </div> @@ -751,6 +748,7 @@ created() { console.log(234); this.Networkheader = window.location.origin; this.GetMaxTaxid(); //è·ååæ° @@ -1201,25 +1199,23 @@ const config = { headers: { Authorization: "Bearer " + this.ICDtoken } }; const pdfimg = this.Networkheader + "/prod-api" + response.fileName; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName; //è·å票æ®ä¿¡æ¯ä½ç½® if (response.code == 200) { this.previewpdf = true; fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { // å°è·åçæ°æ®æµè½¬æ¢ä¸ºURL this.pdfimg = URL.createObjectURL(blob); this.pdfimgsrcList.push(URL.createObjectURL(blob)); this.fileListto.push({ name: file.name, url: URL.createObjectURL(blob) }); }) .catch(error => { console.error("Error loading image", error); return; }); const localBlob = file.raw; const localUrl = URL.createObjectURL(localBlob); this.pdfimg = localUrl; this.embeddedFile = { name: file.name, url: localUrl, type: /\.pdf$/i.test(file.name) ? "pdf" : "image" }; this.pdfimgsrcList.push(localUrl); this.fileListto.push({ name: file.name, url: localUrl }); this.$modal.msgSuccess(response.msg); @@ -1257,7 +1253,7 @@ if (this.donorchargeorgans[index].annexFilesList) { const fetchPromises = this.donorchargeorgans[index].annexFilesList.map( (value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.url; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; return fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -1296,28 +1292,32 @@ ); }, // ç¹å»å·²ä¸ä¼ æä»¶ // ç¹å»å·²ä¸ä¼ æä»¶ï¼å¨éä»¶å¼¹çªå³ä¾§å åµé¢è§ downFile(item) { if (this.operationType == "detail") { const list = (this.fileListto || []).map(f => ({ name: f.name, url: f.url })); const index = list.findIndex(f => f.url === item.url); this.$previewFile(list, index > -1 ? index : 0); return; } const ext = String(item.name || "").toLowerCase().split(".").pop(); const isImage = ["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext); if (ext !== "pdf" && !isImage) { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); return; } this.embeddedFile = { name: item.name, url: item.url, type: ext === "pdf" ? "pdf" : "image" }; this.pdftitle = "å ±" + this.pdfimgsrcList.length + "项ï¼å½åéä¸" + item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { console.log(item, "å±ç¤º"); this.previewpdf = true; if (item.url) { this.pdfimg = item.url; } else { this.pdfimg = ""; } } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; } this.pdfVisible = true; }, getIndexInArray(arr, obj) { return arr.indexOf(obj); src/views/project/travelexpenseapply/edit.vue
@@ -382,17 +382,19 @@ }, methods: { handleUploadError() { }, // ä¸è½½æä»¶ // é¢è§/ä¸è½½æä»¶ downFile(item) { const ext = String(item.name || '').split('.').pop().toLowerCase(); if (['pdf', 'jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(ext)) { this.$previewFile([{ name: item.name, url: item.url }]); return; } const url = process.env.VUE_APP_BASE_API + item.url var a = document.createElement('a'); var event = new MouseEvent('click'); a.download = item.name; a.href = url; a.dispatchEvent(event); }, remove(file) { src/views/project/travelexpenseapply/index.vue
@@ -1265,8 +1265,16 @@ console.log("䏿¥", e); }, // ä¸è½½æä»¶ // é¢è§/ä¸è½½æä»¶ downFile(item) { const ext = String(item.name || "") .split(".") .pop() .toLowerCase(); if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { this.$previewFile([{ name: item.name, url: item.url }]); return; } const url = process.env.VUE_APP_BASE_API + item.url; var a = document.createElement("a"); var event = new MouseEvent("click"); src/views/project/travelexpenseapply/travelexpensedetail/index.vue
@@ -3,37 +3,19 @@ <div class="boxdiv"> <div class="top-text">{{ title }}</div> <el-form ref="form" :model="form" :rules="rules" label-width="120px"> <el-row ><el-col :span="5"> <el-row><el-col :span="5"> <el-form-item label="ç³è¯·æ¥æ" prop="applyTime"> <el-date-picker style="width: 100%" v-model="form.applyTime" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" placeholder="ç³è¯·æ¥æ" :disabled="true" > <el-date-picker style="width: 100%" v-model="form.applyTime" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" placeholder="ç³è¯·æ¥æ" :disabled="true"> </el-date-picker> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="ç»å人" prop="username"> <el-select v-model="form.username" clearable filterable allow-create ref="getReportname" default-first-option placeholder="è¯·éæ©" > <el-option v-for="item in personsList" :key="item.reportNo" :label="item.reportName" :value="item.reportName" > <el-select v-model="form.username" clearable filterable allow-create ref="getReportname" default-first-option placeholder="è¯·éæ©"> <el-option v-for="(item, index) in personsList" :key="item.reportNo + '-' + index" :label="item.reportName" :value="item.reportName"> </el-option> </el-select> </el-form-item> @@ -58,87 +40,44 @@ </el-col> <el-col :span="5"> <el-form-item label="æ¥éç±»å«" prop="costtype"> <el-select v-model="form.costtype" value-key="value" placeholder="è¯·éæ©æ¥é人åç±»å«" > <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label" :value="dict.value" ></el-option> <el-select v-model="form.costtype" value-key="value" placeholder="è¯·éæ©æ¥é人åç±»å«"> <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label" :value="dict.value"></el-option> </el-select> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="æç®è " prop="infoid" v-show="form.costtype == 3 || form.costtype == 4" > <el-select v-model="form.infoid" @change="selectbaseinfo" clearable filterable placeholder="è¯·éæ©æç®è " > <el-option v-for="item in baselist" :key="item.index" :label="item.name" :value="item.infoid" > <el-form-item label="æç®è " prop="infoid" v-show="form.costtype == 3 || form.costtype == 4"> <el-select v-model="form.infoid" @change="selectbaseinfo" clearable filterable placeholder="è¯·éæ©æç®è "> <el-option v-for="(item, index) in baselist" :key="item.index + '-' + index" :label="item.name" :value="item.infoid"> </el-option> </el-select> </el-form-item> </el-col> <el-col :span="4"> <div style="margin-left: 10px;"> <dict-tag :options="dict.type.sys_DonationStatus" :value="form.invoicecount" /> <dict-tag :options="dict.type.sys_DonationStatus" :value="form.invoicecount" /> </div> </el-col> </el-row> <el-row style="margin-top: 10px"> <el-col :span="5"> <el-form-item label="å®¡æ ¸ç¶æ" prop="flowlevel"> <el-select v-model="form.recordstatus" placeholder="è¯·éæ©å®¡æ ¸ç¶æ" clearable :disabled="true" size="small" > <el-option v-for="dict in dict.type.sys_recordstatus" :key="dict.value" :label="dict.label" :value="dict.value" /> <el-select v-model="form.recordstatus" placeholder="è¯·éæ©å®¡æ ¸ç¶æ" clearable :disabled="true" size="small"> <el-option v-for="dict in dict.type.sys_recordstatus" :key="dict.value" :label="dict.label" :value="dict.value" /> </el-select> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="æ¥ééé¢" prop="amountrequested"> <el-input :disabled="true" v-model="form.amountrequested" placeholder="æ¥éå计éé¢" /> <el-input :disabled="true" v-model="form.amountrequested" placeholder="æ¥éå计éé¢" /> </el-form-item> </el-col> <el-col :span="8"> <el-form-item label="大åéé¢" prop="bigstrmoney"> <el-input :disabled="true" v-model="form.bigstrmoney" placeholder="æ¥é大åéé¢" /> <el-input :disabled="true" v-model="form.bigstrmoney" placeholder="æ¥é大åéé¢" /> </el-form-item> </el-col> </el-row> @@ -234,324 +173,145 @@ <el-row v-if="jurisdiction"> <!-- <el-alert title="å½å为æ¥çç¶æï¼ä¸æ¯æä¿®æ¹åå¨ã" type="warning"> </el-alert> --> <el-alert title="å½å为æ¥çç¶æï¼ä¸æ¯æä¿®æ¹åå¨ã" type="warning" show-icon > <el-alert title="å½å为æ¥çç¶æï¼ä¸æ¯æä¿®æ¹åå¨ã" type="warning" show-icon> </el-alert> </el-row> <el-row style="margin-top: 25px; margin-bottom: 5px"> <el-col :span="20">æ¥éæç»</el-col> </el-row> <el-row> <el-table :data="rbDetails" ref="table" border max-height="800" highlight-current-row :summary-method="getSummaries" show-summary > <el-table-column prop="orderno" slot="" label="åºå·" align="center" fixed width="88" > <el-table :data="rbDetails" ref="table" border max-height="800" highlight-current-row :summary-method="getSummaries" show-summary> <el-table-column prop="orderno" slot="" label="åºå·" align="center" fixed width="88"> <template slot-scope="scope"> <el-input v-model="scope.row.orderno" placeholder="åºå·" /> </template> </el-table-column> <!--主é®ãå¤ä¸å±ç¤º--> <el-table-column prop="id" slot="" label="主é®" align="center" fixed width="95" v-if="false" > <el-table-column prop="id" slot="" label="主é®" align="center" fixed width="95" v-if="false"> <template slot-scope="scope"> <el-input v-model="scope.row.id" placeholder="id" /> </template> </el-table-column> <el-table-column prop="rbid" slot="" label="å¤é®" align="center" fixed width="95" v-if="false" > <el-table-column prop="rbid" slot="" label="å¤é®" align="center" fixed width="95" v-if="false"> <template slot-scope="scope"> <el-input v-model="scope.row.rbid" placeholder="rbid" /> </template> </el-table-column> <el-table-column prop="persontype" slot="" label="人åç±»å«" align="center" fixed width="130" > <el-table-column prop="persontype" slot="" label="人åç±»å«" align="center" fixed width="130"> <template slot-scope="scope"> <el-select v-model="scope.row.persontype" value-key="value" placeholder="人åç±»å«" @change="getPersons(scope.row)" > <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label" :value="dict.label" ></el-option> <el-select v-model="scope.row.persontype" value-key="value" placeholder="人åç±»å«" @change="getPersons(scope.row)"> <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label" :value="dict.label"></el-option> </el-select> </template> </el-table-column> <el-table-column prop="personname" slot="" label="è´¹ç¨äººå" align="center" fixed width="110" > <el-table-column prop="personname" slot="" label="è´¹ç¨äººå" align="center" fixed width="110"> <template slot-scope="scope"> <el-select v-model="scope.row.personname" clearable filterable allow-create default-first-option placeholder="è¯·éæ©" > <el-option v-for="item in personsSel" :key="item.id" :label="item.reportNameDesc" :value="item.reportName" > <el-select v-model="scope.row.personname" clearable filterable allow-create default-first-option placeholder="è¯·éæ©"> <el-option v-for="item in personsSel" :key="item.id" :label="item.reportNameDesc" :value="item.reportName"> </el-option> </el-select> </template> </el-table-column> <el-table-column prop="starttime" slot="" label="å¼å§æ¥æ" fixed align="center" width="150" > <el-table-column prop="starttime" slot="" label="å¼å§æ¥æ" fixed align="center" width="150"> <template slot-scope="scope"> <el-date-picker :picker-options="{ disabledDate: time => { if (scope.row.endtime) { return ( time.getTime() > new Date(scope.row.endtime.replace(/-/g, '/')) ); } <el-date-picker :picker-options="{ disabledDate: time => { if (scope.row.endtime) { return ( time.getTime() > new Date(scope.row.endtime.replace(/-/g, '/')) ); } }" clearable size="small" style="width: 100%" v-model="scope.row.starttime" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" placeholder="å¼å§æ¥æ" @blur="getdays(scope.row)" > } }" clearable size="small" style="width: 100%" v-model="scope.row.starttime" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" placeholder="å¼å§æ¥æ" @blur="getdays(scope.row)"> </el-date-picker> </template> </el-table-column> <el-table-column prop="endtime" slot="" label="ç»ææ¥æ" align="center" fixed width="150" > <el-table-column prop="endtime" slot="" label="ç»ææ¥æ" align="center" fixed width="150"> <template slot-scope="scope"> <el-date-picker :picker-options="{ disabledDate: time => { if (scope.row.starttime) { return ( time.getTime() < new Date(scope.row.starttime.replace(/-/g, '/')) ); } <el-date-picker :picker-options="{ disabledDate: time => { if (scope.row.starttime) { return ( time.getTime() < new Date(scope.row.starttime.replace(/-/g, '/')) ); } }" clearable size="small" style="width: 100%" v-model="scope.row.endtime" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" placeholder="ç»ææ¥æ" @blur="getdays(scope.row)" > } }" clearable size="small" style="width: 100%" v-model="scope.row.endtime" type="date" format="yyyy-MM-dd" value-format="yyyy-MM-dd HH:mm:ss" placeholder="ç»ææ¥æ" @blur="getdays(scope.row)"> </el-date-picker> </template> </el-table-column> <el-table-column prop="departure" slot="" label="åºåå°" align="center" width="100" > <el-table-column prop="departure" slot="" label="åºåå°" align="center" width="100"> <template slot-scope="scope"> <el-input v-model="scope.row.departure" placeholder="åºåå°" /> </template> </el-table-column> <el-table-column label="å°è¾¾å°" prop="destination" align="center" width="140" > <el-table-column label="å°è¾¾å°" prop="destination" align="center" width="140"> <template slot-scope="scope"> <!-- <el-input v-model="scope.row.destination" placeholder="å°è¾¾å°" @blur="getallowance(scope.row)" /> --> <el-select filterable allow-create v-model="scope.row.destination" value-key="value" placeholder="å°è¾¾å°" @change="getallowance(scope.row)" > <el-option v-for="dict in dict.type.sys_area_name" :key="dict.value" :label="dict.label" :value="dict.label" ></el-option> <el-select filterable allow-create v-model="scope.row.destination" value-key="value" placeholder="å°è¾¾å°" @change="getallowance(scope.row)"> <el-option v-for="dict in dict.type.sys_area_name" :key="dict.value" :label="dict.label" :value="dict.label"></el-option> </el-select> </template> </el-table-column> <el-table-column prop="days" label="天æ°" width="100" align="center" > <el-table-column prop="days" label="天æ°" width="100" align="center"> <template slot-scope="scope"> <el-input v-model="scope.row.days" @blur="getallowance(scope.row)" placeholder="天æ°" /> <el-input v-model="scope.row.days" @blur="getallowance(scope.row)" placeholder="天æ°" /> </template> </el-table-column> <el-table-column prop="traffictype" label="åºå交éå·¥å ·" align="center" width="100" > <el-table-column prop="traffictype" label="åºå交éå·¥å ·" align="center" width="100"> <template slot-scope="scope"> <el-select v-model="scope.row.traffictype" placeholder="åºå交éå·¥å ·" > <el-option v-for="dict in dict.type.sys_traffictype" :key="dict.value" :label="dict.label" :value="dict.label" ></el-option> <el-select v-model="scope.row.traffictype" placeholder="åºå交éå·¥å ·"> <el-option v-for="dict in dict.type.sys_traffictype" :key="dict.value" :label="dict.label" :value="dict.label"></el-option> </el-select> </template> </el-table-column> <el-table-column prop="traffictype2" label="è¿å交éå·¥å ·" align="center" width="100" > <el-table-column prop="traffictype2" label="è¿å交éå·¥å ·" align="center" width="100"> <template slot-scope="scope"> <el-select v-model="scope.row.traffictype2" placeholder="è¿å交éå·¥å ·" > <el-option v-for="dict in dict.type.sys_traffictype" :key="dict.value" :label="dict.label" :value="dict.label" ></el-option> <el-select v-model="scope.row.traffictype2" placeholder="è¿å交éå·¥å ·"> <el-option v-for="dict in dict.type.sys_traffictype" :key="dict.value" :label="dict.label" :value="dict.label"></el-option> </el-select> </template> </el-table-column> <el-table-column prop="trafficexpense" label="交éè´¹" align="center" width="120" > <el-table-column prop="trafficexpense" label="交éè´¹" align="center" width="120"> <template slot-scope="scope"> <el-input v-model="scope.row.trafficexpense" placeholder="交éè´¹" @blur=" val => { sumRowFee(scope.row); } " /> <el-input v-model="scope.row.trafficexpense" placeholder="交éè´¹" @blur=" val => { sumRowFee(scope.row); } " /> </template> </el-table-column> <el-table-column prop="cityfee" label="å¸å 交éè´¹" align="center" width="120" > <el-table-column prop="cityfee" label="å¸å 交éè´¹" align="center" width="120"> <template slot-scope="scope"> <el-input v-model="scope.row.cityfee" placeholder="å¸å 交éè´¹" @blur=" val => { sumRowFee(scope.row); } " >{{ Number(scope.row.cityfee).toFixed(2) }} <el-input v-model="scope.row.cityfee" placeholder="å¸å 交éè´¹" @blur=" val => { sumRowFee(scope.row); } ">{{ Number(scope.row.cityfee).toFixed(2) }} </el-input> </template> </el-table-column> <el-table-column prop="hotelexpense" label="ä½å®¿è´¹" align="center" width="120" > <el-table-column prop="hotelexpense" label="ä½å®¿è´¹" align="center" width="120"> <template slot-scope="scope"> <el-input v-model="scope.row.hotelexpense" placeholder="ä½å®¿è´¹" @blur=" val => { sumRowFee(scope.row); } " /> <el-input v-model="scope.row.hotelexpense" placeholder="ä½å®¿è´¹" @blur=" val => { sumRowFee(scope.row); } " /> </template> </el-table-column> @@ -573,118 +333,55 @@ /> </template> </el-table-column> --> <el-table-column prop="foodallowance" label="ä¼é£è¡¥å©" align="center" width="120" > <el-table-column prop="foodallowance" label="ä¼é£è¡¥å©" align="center" width="120"> <template slot-scope="scope"> <el-input v-model="scope.row.foodallowance" placeholder="ä¼é£è´¹è¡¥å©" @blur=" val => { sumRowFee(scope.row); } " /> <el-input v-model="scope.row.foodallowance" placeholder="ä¼é£è´¹è¡¥å©" @blur=" val => { sumRowFee(scope.row); } " /> </template> </el-table-column> <el-table-column prop="otherexpense" label="å ¬æè´¹è¡¥å©" align="center" width="120" > <el-table-column prop="otherexpense" label="å ¬æè´¹è¡¥å©" align="center" width="120"> <template slot-scope="scope"> <el-input v-model="scope.row.otherexpense" placeholder="æè´¹" @blur=" val => { sumRowFee(scope.row); } " /> <el-input v-model="scope.row.otherexpense" placeholder="æè´¹" @blur=" val => { sumRowFee(scope.row); } " /> </template> </el-table-column> <el-table-column prop="otherfeeamount" label="å ¶ä»è´¹ç¨" align="center" width="120" > <el-table-column prop="otherfeeamount" label="å ¶ä»è´¹ç¨" align="center" width="120"> <template slot-scope="scope"> <el-input v-model="scope.row.otherfeeamount" placeholder="å ¶ä»è´¹ç¨" @blur=" val => { sumRowFee(scope.row); } " /> <el-input v-model="scope.row.otherfeeamount" placeholder="å ¶ä»è´¹ç¨" @blur=" val => { sumRowFee(scope.row); } " /> </template> </el-table-column> <el-table-column prop="departure" slot="" label="å ¶ä»è´¹ç¨è¯´æ" align="center" width="120" > <el-table-column prop="departure" slot="" label="å ¶ä»è´¹ç¨è¯´æ" align="center" width="120"> <template slot-scope="scope"> <el-input v-model="scope.row.otherfeedesc" placeholder="å ¶ä»è´¹ç¨è¯´æ" /> <el-input v-model="scope.row.otherfeedesc" placeholder="å ¶ä»è´¹ç¨è¯´æ" /> </template> </el-table-column> <el-table-column prop="total" label="å计" align="center" width="110" fixed="right" > <el-table-column prop="total" label="å计" align="center" width="110" fixed="right"> <template slot-scope="scope"> <el-input v-model="scope.row.total" placeholder="å计" /> </template> </el-table-column> <el-table-column fixed="right" label="æä½" align="center" width="120" > <el-table-column fixed="right" label="æä½" align="center" width="120"> <template slot-scope="scope"> <el-button type="text" size="mini" @click="addDetailRow(scope.$index)" v-if="operationType == 'edit'" >æ°å¢</el-button > <el-button @click.native.prevent=" deleteDetailRow(scope.$index, rbDetails, scope.row) " type="text" size="small" v-if="operationType == 'edit'" >å é¤</el-button > <el-button @click.native.prevent=" Filepopup(scope.$index, rbDetails, scope.row) " type="text" size="small" >票æ®</el-button > <el-button type="text" size="mini" @click="addDetailRow(scope.$index)" v-if="operationType == 'edit'">æ°å¢</el-button> <el-button @click.native.prevent=" deleteDetailRow(scope.$index, rbDetails, scope.row) " type="text" size="small" v-if="operationType == 'edit'">å é¤</el-button> <el-button @click.native.prevent=" Filepopup(scope.$index, rbDetails, scope.row) " type="text" size="small">票æ®</el-button> </template> </el-table-column> </el-table> @@ -693,154 +390,60 @@ <el-col :span="20">ææ¬¾æç»</el-col> </el-row> <el-row style="margin-top: 5px"> <el-table :data="rbPayees" border max-height="400" highlight-current-row :summary-method="getSummaries" show-summary > <el-table-column prop="orderno" slot="" label="åºå·" align="center" fixed width="65" > <el-table :data="rbPayees" border max-height="400" highlight-current-row :summary-method="getSummaries" show-summary> <el-table-column prop="orderno" slot="" label="åºå·" align="center" fixed width="65"> <template slot-scope="scope"> <el-input v-model="scope.row.orderno" placeholder="åºå·" /> </template> </el-table-column> <!--主é®ãå¤é®ä¸å±ç¤º--> <el-table-column prop="id" slot="" label="主é®" align="center" fixed width="95" v-if="false" > <el-table-column prop="id" slot="" label="主é®" align="center" fixed width="95" v-if="false"> <template slot-scope="scope"> <el-input v-model="scope.row.id" placeholder="id" /> </template> </el-table-column> <el-table-column prop="rbid" slot="" label="å¤é®" align="center" fixed width="95" v-if="false" > <el-table-column prop="rbid" slot="" label="å¤é®" align="center" fixed width="95" v-if="false"> <template slot-scope="scope"> <el-input v-model="scope.row.rbid" placeholder="rbid" /> </template> </el-table-column> <el-table-column prop="persontype" slot="" label="æ¶æ¬¾äººç±»å«" align="center" fixed width="150" > <el-table-column prop="persontype" slot="" label="æ¶æ¬¾äººç±»å«" align="center" fixed width="150"> <template slot-scope="scope"> <el-select v-model="scope.row.persontype" value-key="value" placeholder="æ¶æ¬¾äººç±»å«" @change="getPersons(scope.row)" > <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label" :value="dict.label" ></el-option> <el-select v-model="scope.row.persontype" value-key="value" placeholder="æ¶æ¬¾äººç±»å«" @change="getPersons(scope.row)"> <el-option v-for="dict in dict.type.sys_travelexpensebelong" :key="dict.value" :label="dict.label" :value="dict.label"></el-option> </el-select> </template> </el-table-column> <el-table-column prop="personname" slot="" label="æ¶æ¬¾äºº" align="center" fixed width="200" > <el-table-column prop="personname" slot="" label="æ¶æ¬¾äºº" align="center" fixed width="200"> <template slot-scope="scope"> <el-select v-model="scope.row.personname" clearable filterable allow-create ref="getReportname" default-first-option placeholder="è¯·éæ©" @change="getAccountinfo2(scope.row, scope.row.persontype)" > <el-option v-for="item in personsSel" :key="item.id" :label="item.reportNameDesc" :value="item.id" > <el-select v-model="scope.row.personname" clearable filterable allow-create ref="getReportname" default-first-option placeholder="è¯·éæ©" @change="getAccountinfo2(scope.row, scope.row.persontype)"> <el-option v-for="item in personsSel" :key="item.id" :label="item.reportNameDesc" :value="item.id"> </el-option> </el-select> </template> </el-table-column> <el-table-column prop="bankname" slot="" label="æ¶æ¬¾é¶è¡" align="center" fixed width="250" > <el-table-column prop="bankname" slot="" label="æ¶æ¬¾é¶è¡" align="center" fixed width="250"> <template slot-scope="scope"> <el-input v-model="scope.row.bankname" placeholder="æ¶æ¬¾é¶è¡" /> </template> </el-table-column> <el-table-column prop="bankcardno" slot="" label="é¶è¡è´¦å·" align="center" fixed width="200" > <el-table-column prop="bankcardno" slot="" label="é¶è¡è´¦å·" align="center" fixed width="200"> <template slot-scope="scope"> <el-input v-model="scope.row.bankcardno" placeholder="é¶è¡è´¦å·" /> <el-input v-model="scope.row.bankcardno" placeholder="é¶è¡è´¦å·" /> </template> </el-table-column> <el-table-column prop="amount" slot="" label="ææ¬¾éé¢" align="center" fixed width="130" > <el-table-column prop="amount" slot="" label="ææ¬¾éé¢" align="center" fixed width="130"> <template slot-scope="scope"> <el-input v-model="scope.row.amount" placeholder="ææ¬¾éé¢" /> </template> </el-table-column> <el-table-column prop="remark" slot="" label="请款说æ" align="center" fixed > <el-table-column prop="remark" slot="" label="请款说æ" align="center" fixed> <template slot-scope="scope"> <el-input v-model="scope.row.remark" placeholder="说æ" /> </template> @@ -853,74 +456,36 @@ </el-date-picker> </template> </el-table-column>--> <el-table-column label="æä½" align="center" width="100" v-if="operationType == 'edit'" > <el-table-column label="æä½" align="center" width="100" v-if="operationType == 'edit'"> <template slot-scope="scope"> <el-button type="text" size="mini" @click="addPayeeRow(scope.$index)" >æ°å¢</el-button > <el-button @click.native.prevent=" deletePayeeRow(scope.$index, rbPayees, scope.row) " type="text" size="small" > <el-button type="text" size="mini" @click="addPayeeRow(scope.$index)">æ°å¢</el-button> <el-button @click.native.prevent=" deletePayeeRow(scope.$index, rbPayees, scope.row) " type="text" size="small"> å é¤ </el-button> </template> </el-table-column> </el-table> </el-row> <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType != 'edit'" > <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType != 'edit'"> <el-col :span="20">å®¡æ ¸è®°å½</el-col> </el-row> <el-row v-if="operationType != 'add'"> <el-table :data="fundflowList" border> <el-table-column label="å®¡æ ¸æ¥æ" align="center" width="200" prop="createTime" /> <el-table-column label="å®¡æ ¸äºº" align="center" width="150" prop="checkusername" /> <el-table-column label="å®¡æ ¸ç»æ" align="center" width="200" prop="flowconclusion" > <el-table-column label="å®¡æ ¸æ¥æ" align="center" width="200" prop="createTime" /> <el-table-column label="å®¡æ ¸äºº" align="center" width="150" prop="checkusername" /> <el-table-column label="å®¡æ ¸ç»æ" align="center" width="200" prop="flowconclusion"> <template slot-scope="scope"> <span v-if="scope.row.flowconclusion == 1">éè¿</span> <span v-if="scope.row.flowconclusion == 2">ä¸éè¿</span> </template> </el-table-column> <el-table-column label="å®¡æ ¸å¤æ³¨" align="center" prop="flowcontent" /> <el-table-column label="å®¡æ ¸å¤æ³¨" align="center" prop="flowcontent" /> </el-table> </el-row> <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType == 'check' && userprofile.nickName == 'éæ å'" > <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType == 'check' && userprofile.nickName == 'éæ å'"> <el-col :span="12"> <el-form-item label="é¢å®¡ææ" prop="infoid"> <el-radio-group v-model="form.checkstatus" align="left"> @@ -941,10 +506,7 @@ </el-col> </el-row> <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType == 'check'" > <el-row style="margin-top: 25px; margin-bottom: 5px" v-if="operationType == 'check'"> <el-col :span="7"> <el-form-item label="å®¡æ ¸ç»æ" align="left"> <el-radio-group v-model="checkObj.flowlevelone" align="left"> @@ -963,42 +525,50 @@ </el-row> </el-form> <div slot="footer" class="dialog-footer"> <el-button type="primary" @click="submitForm" v-if="operationType == 'edit' || userprofile.nickName == 'éæ å'" >ä¿ å</el-button > <el-button type="primary" @click="checksubmit" v-if="operationType == 'check'" >æäº¤å®¡æ ¸</el-button > <el-button type="primary" @click="submitForm" v-if="operationType == 'edit' || userprofile.nickName == 'éæ å'">ä¿ å</el-button> <el-button type="primary" @click="checksubmit" v-if="operationType == 'check'">æäº¤å®¡æ ¸</el-button> <!--<el-button @click="cancel">é åº</el-button>--> </div> </div> <el-dialog v-dialogDrags :modal="false" :close-on-click-modal="false" :title="pdftitle" :visible.sync="pdfVisible" width="60%" > <el-dialog v-dialogDrags :modal="false" :close-on-click-modal="false" :title="pdftitle" :visible.sync="pdfVisible" :fullscreen="pdfFullscreen" width="60%" custom-class="pdf-resize-dialog" @closed="pdfFullscreen = false"> <template slot="title"> <span>{{ pdftitle }}</span> <el-button class="pdf-fullscreen-btn" size="mini" :icon="pdfFullscreen ? 'el-icon-close' : 'el-icon-full-screen'" @click="pdfFullscreen = !pdfFullscreen">{{ pdfFullscreen ? "è¿å" : "å ¨å±" }}</el-button> </template> <el-alert :title=" activeName == 2 ? 'å½åæ£å¨æä½ï¼å票æä»¶ï¼è¯·ç¡®è®¤ç¥¨æ®å±äºå票ï¼' : 'å½åæ£å¨æä½ï¼æ®ééä»¶ï¼è¯·å¿å¨æ¤ä¸ä¼ å票ï¼' " :type="activeName == 2 ? 'success' : 'warning'" :closable="false" show-icon style="margin-bottom: 10px;" /> <div style="margin-bottom: 10px;"> <el-table :data="tableDatatop" style="width: 100%"> <el-table-column prop="orderno" label="åºå·"> </el-table-column> <el-table-column prop="personname" label="è´¹ç¨äººå"> </el-table-column> <el-table-column prop="starttime" label="å¼å§æ¥æ"> </el-table-column> <el-table-column prop="endtime" label="ç»ææ¥æ"> </el-table-column> <el-table-column prop="starttime" label="å¼å§æ¥æ"> <template slot-scope="scope"> {{ scope.row.starttime ? parseTime(scope.row.starttime, "{y}-{m}-{d}") : "" }} </template> </el-table-column> <el-table-column prop="endtime" label="ç»ææ¥æ"> <template slot-scope="scope"> {{ scope.row.endtime ? parseTime(scope.row.endtime, "{y}-{m}-{d}") : "" }} </template> </el-table-column> <el-table-column prop="departure" label="åºåå°"> </el-table-column> <el-table-column prop="destination" label="å°è¾¾å°"> </el-table-column> <el-table-column prop="days" label="天æ°"> </el-table-column> </el-table> <el-table :data="tableDatatop" style="width: 100%"> <el-table-column prop="traffictype" label="åºå交éå·¥å ·"> </el-table-column> <el-table-column prop="traffictype2" label="è¿å交éå·¥å ·"> @@ -1016,66 +586,27 @@ </el-table-column> </el-table> </div> <el-alert title="æ°ä¸ä¼ æä»¶éå¨æäº¤ä¿ååæå¯è¿è¡æ¡ä¾å ³èï¼å¦åè§ä¸ºæ¾å¼" type="error" show-icon close-text="ç¥éäº" > <el-alert title="æ°ä¸ä¼ æä»¶éå¨æäº¤ä¿ååæå¯è¿è¡æ¡ä¾å ³èï¼å¦åè§ä¸ºæ¾å¼" type="error" show-icon close-text="ç¥éäº"> </el-alert> <el-tabs style="margin-top: 20px;" v-model="activeName" type="border-card" @tab-click="handleClick" > <el-tabs style="margin-top: 20px;" v-model="activeName" type="border-card" @tab-click="handleClick"> <el-tab-pane label="æ®ééä»¶" :name="1"> <div class="pdfimg"> <div class="box-pdf"> <div> <el-upload size="mini" class="upload-demo" :action="uploadFileUrl" :file-list="fileListto" :show-file-list="false" multiple drag :headers="headers" :on-success=" (response, file, fileList) => <el-upload size="mini" class="upload-demo" :action="uploadFileUrl" :file-list="fileListto" :show-file-list="false" multiple drag :headers="headers" :on-success="(response, file, fileList) => uploadSccess(response, file, fileList) " :on-preview="downFile" :disabled="operationType == 'detail'" :on-error="handleUploadError" :on-remove="remove" accept="image/*,.pdf" > " :on-preview="downFile" :disabled="operationType == 'detail'" :on-error="handleUploadError" :on-remove="remove" accept="image/*,.pdf"> <i class="el-icon-upload"></i> <div class="el-upload__text"> å°ç¥¨æ®æå°æ¤å¤ï¼æ <em ><el-button :disabled="operationType == 'detail'" size="small" type="primary" >ç¹å»ä¸ä¼ </el-button ></em > <em><el-button :disabled="operationType == 'detail'" size="small" type="primary">ç¹å»ä¸ä¼ </el-button></em> </div> </el-upload> <el-table :data="fileListto" @row-click="downFile" style="width: 100%" height="400" > <el-table-column prop="name" :show-overflow-tooltip="true" label="åç§°" > <el-table :data="fileListto" @row-click="downFile" style="width: 100%" height="400"> <el-table-column prop="name" :show-overflow-tooltip="true" label="åç§°"> <template slot-scope="scope"> <i style="color:#409EFF" class=" el-icon-s-order" />{{ scope.row.name @@ -1083,110 +614,39 @@ </template> </el-table-column> <el-table-column prop="name" width="180" :show-overflow-tooltip="true" label="åè½" > <el-table-column prop="name" width="180" :show-overflow-tooltip="true" label="åè½"> <template slot-scope="scope"> <el-button type="danger" size="mini" @click.native.prevent.stop="deletedowfile(scope.row)" >å é¤</el-button > <el-button type="primary" size="mini" @click.native.prevent.stop="moveupdowfile(scope.row)" >ä¸ç§»</el-button > <el-button type="danger" size="mini" @click.native.prevent.stop="deletedowfile(scope.row)">å é¤</el-button> <el-button type="primary" size="mini" @click.native.prevent.stop="moveupdowfile(scope.row)">ä¸ç§»</el-button> </template> </el-table-column> </el-table> </div> </div> <div v-if="this.previewpdf && pdfimgsrcList.length" class="pdfimgmin" > <!-- <img :src="pdfimg" /> --> <!-- <el-image style="width: 95%; height: 90%" :src="pdfimg" :preview-src-list="pdfimgsrcList" > --> <el-image ref="imagePreview" style="width: 95%; height: 90%" :src="pdfimg" @click="handleImageClick(initialIndex)" > </el-image> <custom-image-viewer :url-list="pdfimgsrcList" :initial-index="currentIndex" :visible="viewerVisible" @update:visible="viewerVisible = $event" @close="handleViewerClose" /> <!-- <div slot="error" class="image-slot"> <i class="el-icon-picture-outline"></i> </div> --> <!-- </el-image> --> </div> <div v-else class="pdfimgmins">{{ hintitle }}</div> <attachment-preview-pane :file="embeddedFile" style="flex: 1; min-width: 0;" /> </div> </el-tab-pane> <el-tab-pane label="å票æä»¶" :name="2"> <div class="pdfimg"> <div class="box-pdf"> <div> <el-upload size="mini" class="upload-demo" :action="uploadFileUrl" :file-list="invoicefileList" :show-file-list="false" multiple drag :headers="headers" :on-success=" (response, file, fileList) => <el-upload size="mini" class="upload-demo" :action="uploadFileUrl" :file-list="invoicefileList" :show-file-list="false" multiple drag :headers="headers" :on-success="(response, file, fileList) => uploadSccess(response, file, fileList) " :on-preview="downFile" :disabled="operationType == 'detail'" :on-error="handleUploadError" :on-remove="remove" accept="image/*,.pdf" > " :on-preview="downFile" :disabled="operationType == 'detail'" :on-error="handleUploadError" :on-remove="remove" accept="image/*,.pdf"> <i class="el-icon-upload"></i> <div class="el-upload__text"> å°å票æä»¶æå°æ¤å¤ï¼æ <em ><el-button :disabled="operationType == 'detail'" size="small" type="primary" >ç¹å»ä¸ä¼ </el-button ></em > <em><el-button :disabled="operationType == 'detail'" size="small" type="primary">ç¹å»ä¸ä¼ </el-button></em> </div> </el-upload> <el-table :data="invoicefileListto" @row-click="downFile" style="width: 100%" height="400" > <el-table-column prop="name" :show-overflow-tooltip="true" label="åç§°" > <el-table :data="invoicefileListto" @row-click="downFile" style="width: 100%" height="400"> <el-table-column prop="name" :show-overflow-tooltip="true" label="åç§°"> <template slot-scope="scope"> <i style="color:#409EFF" class=" el-icon-s-order" />{{ scope.row.name @@ -1194,64 +654,28 @@ </template> </el-table-column> <el-table-column prop="name" width="180" :show-overflow-tooltip="true" label="åè½" > <el-table-column prop="name" width="180" :show-overflow-tooltip="true" label="åè½"> <template slot-scope="scope"> <el-button type="primary" size="mini" @click.native.prevent.stop="deletedowfile(scope.row)" >å é¤</el-button > <el-button type="primary" size="mini" @click.native.prevent.stop="moveupdowfile(scope.row)" >ä¸ç§»</el-button > <el-button type="primary" size="mini" @click.native.prevent.stop="deletedowfile(scope.row)">å é¤</el-button> <el-button type="primary" size="mini" @click.native.prevent.stop="moveupdowfile(scope.row)">ä¸ç§»</el-button> </template> </el-table-column> </el-table> </div> </div> <div v-if="this.previewpdf && invoicepdfimgsrcList.length" class="pdfimgmin" > <!-- <img :src="pdfimg" /> --> <el-image style="width: 95%; height: 90%" :src="invoicepdfimg" @click="invoicehandleImageClick(initialIndex)" > </el-image> <custom-image-viewer :url-list="invoicepdfimgsrcList" :initial-index="invoicecurrentIndex" :visible="invoiceviewerVisible" @update:visible="invoiceviewerVisible = $event" @close="invoicehandleViewerClose" /> </div> <div v-else class="pdfimgmins">{{ hintitle }}</div> <attachment-preview-pane :file="invoiceEmbeddedFile" style="flex: 1; min-width: 0;" /> </div> </el-tab-pane> </el-tabs> </el-dialog> <el-dialog title="æç¤º" :visible.sync="Savereminder" width="30%"> <el-alert :title=" 'æ¨å·²æ·»å ' + totalquantity + 'æ¡æ°æ®ï¼ä¸ºé²æ¢æ°æ®ä¸¢å¤±æ¯å¦æäº¤ä¿ååç»§ç»æ·»å ã' " type="warning" > <el-alert :title="'æ¨å·²æ·»å ' + totalquantity + 'æ¡æ°æ®ï¼ä¸ºé²æ¢æ°æ®ä¸¢å¤±æ¯å¦æäº¤ä¿ååç»§ç»æ·»å ã' " type="warning"> </el-alert> <span slot="footer" class="dialog-footer"> <el-button @click="unsave">å æ¶</el-button> @@ -1340,13 +764,14 @@ personsList: [], //䏿å¯ä»¥éæ©äººåå表 personsSel: [], activeName: 1, //æä»¶ç±»å activeName: 2, //æä»¶ç±»åï¼é»è®¤å票æä»¶ // é¨é¨æ é项 deptOptions: undefined, //ç¥¨æ®æä»¶ pdftitle: "", pdfimg: "", invoiceEmbeddedFile: null, pdfVisible: false, costtypeobj: { value: 0, @@ -1655,17 +1080,8 @@ handleUploadError() { }, // è·å请æ±å¤´ Getnetworkheader() { console.log(window.location.href); let string = window.location.href; if (string.includes("9091")) { const index = string.indexOf("9091"); this.Networkheader = string.slice(0, index + 4); // æªå9091åå ¶åé¨å符 console.log(this.Networkheader); } else { const index = string.indexOf("8032"); this.Networkheader = string.slice(0, index + 4); // æªå8032åå ¶åé¨å符 console.log(this.Networkheader); } // 以å½åé¡µé¢ origin 为åï¼å ¼å®¹ 80/8032/9091 ååç»ç«¯å£è°æ´ this.Networkheader = window.location.origin; }, // åç¥¨åæ¢ handleClick(tab, event) { @@ -1693,7 +1109,7 @@ //æä»¶ä¸ä¼ æååè° /** * 2026-10-15ï¼ä¸ä¼ æ¶æ ¡éªéä»¶æä»¶åï¼ä¸å¡è¦æ±ï¼ä¸åæ ¼ç«å³æç¤ºä¸ä¸å å ¥å表ï¼ã * è§åä¸å端 AttachmentNameValidator åå£å¾ï¼å¿ é¡»å«ä¸æ / 廿æ©å±åå主干 â¤20 å / * è§åä¸å端 AttachmentNameValidator åå£å¾ï¼ä¸å¼ºå¶å«ä¸æ / 廿æ©å±åå主干 â¤20 å / * ä¸å«ç©ºæ ¼å / \ : * ? " < > | # % çç¹æ®å符ã */ checkUploadFileName(file) { @@ -1732,33 +1148,27 @@ const config = { headers: { Authorization: "Bearer " + this.ICDtoken } }; const pdfimg = this.Networkheader + "/prod-api" + response.fileName; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName; //è·å票æ®ä¿¡æ¯ä½ç½® if (this.activeName == 1) { if (response.code == 200) { this.previewpdf = true; fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { // å°è·åçæ°æ®æµè½¬æ¢ä¸ºURL this.pdfimg = URL.createObjectURL(blob); this.pdfimgsrcList.push(URL.createObjectURL(blob)); this.fileListto.push({ name: file.name, url: URL.createObjectURL(blob) }); // 2026-10-15ï¼å é¤è¿éçç¬¬äºæ¬¡ pushã忥䏿¬¡ä¸ä¼ ä¼å fileListto / pdfimgsrcList // åå两æ¡ï¼ä¸ç¬¬äºæ¡ç name åçæ¯ file.response.fileNameï¼åå¨è·¯å¾ï¼ï¼è remove() // 伿æ´ä¸ª fileListto ååå° rbDetails[atpresent].annexfilesListï¼å¯¼è´æç»éä»¶é // æ··å ¥è·¯å¾å½¢æç nameï¼è¢«éä»¶æä»¶åæ ¡éªè¯¯æ¦ï¼å端没æ"è·¯å¾å½¢æè·³è¿"è±å ï¼ï¼ // åæ¶ç¥¨æ®å表ä¼å¤åºä¸è¡ã console.log(URL.createObjectURL(blob), "ur转æ¢"); }) .catch(error => { console.error("Error loading image", error); return; }); // æ°ä¸ä¼ æä»¶ç´æ¥ä½¿ç¨æµè§å¨æ¬å° Fileï¼é¿å æå¡ç«¯æä»¶å°å/Token // å¼å¸¸æ¶æ JSON é误ååºå½æå¾çæ PDF é¢è§ã const localBlob = file.raw; const localUrl = URL.createObjectURL(localBlob); this.pdfimg = localUrl; this.embeddedFile = { name: file.name, url: localUrl, type: /\.pdf$/i.test(file.name) ? "pdf" : "image" }; this.pdfimgsrcList.push(localUrl); this.fileListto.push({ name: file.name, url: localUrl }); this.$modal.msgSuccess(response.msg); @@ -1777,21 +1187,19 @@ } else { if (response.code == 200) { this.previewpdf = true; fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { // å°è·åçæ°æ®æµè½¬æ¢ä¸ºURL this.invoicepdfimg = URL.createObjectURL(blob); this.invoicepdfimgsrcList.push(URL.createObjectURL(blob)); this.invoicefileListto.push({ name: file.name, url: URL.createObjectURL(blob) }); }) .catch(error => { console.error("Error loading image", error); return; }); const localBlob = file.raw; const localUrl = URL.createObjectURL(localBlob); this.invoicepdfimg = localUrl; this.invoiceEmbeddedFile = { name: file.name, url: localUrl, type: /\.pdf$/i.test(file.name) ? "pdf" : "image" }; this.invoicepdfimgsrcList.push(localUrl); this.invoicefileListto.push({ name: file.name, url: localUrl }); this.$modal.msgSuccess(response.msg); @@ -1827,7 +1235,7 @@ if (this.rbDetails[index].annexfilesList) { const fetchPromises = this.rbDetails[index].annexfilesList.map( (value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.url; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; return fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -1860,7 +1268,7 @@ if (this.rbDetails[index].invoicefilesList) { const fetchPromises = this.rbDetails[index].invoicefilesList.map( (value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.url; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; return fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -1894,7 +1302,7 @@ this.pdftitle = ""; } if (this.activeName == "common") { if (this.activeName == 1) { this.pdftitle = "å ±" + this.pdfimgsrcList.length + "项"; } else { this.pdftitle = "å ±" + this.invoicepdfimgsrcList.length + "项"; @@ -1903,50 +1311,17 @@ console.log(this.rbDetails[index].annexfilesList, "annexfilesList"); }, // ç¹å»å·²ä¸ä¼ æä»¶ // å·®æ æ¥éï¼éä»¶ç»ä¸ä½¿ç¨ç¬ç« FilePreviewï¼å½å ¥ã审æ¹ã详æ ä¸è´ï¼ downFile(item) { if (this.activeName == 1) { this.pdftitle = "å ±" + this.pdfimgsrcList.length + "项ï¼å½åéä¸" + item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { console.log(item, "å±ç¤º"); this.previewpdf = true; if (item.url) { this.pdfimg = item.url; } else { this.pdfimg = ""; } } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; } } else { this.pdftitle = "å ±" + this.invoicepdfimgsrcList.length + "项ï¼å½åéä¸" + item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { this.previewpdf = true; if (item.url) { this.invoicepdfimg = item.url; } else { this.invoicepdfimg = ""; } } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; } const source = this.activeName == 1 ? this.fileListto : this.invoicefileListto; let list = (source || []).map(f => ({ name: f.name, url: f.url })); let index = list.findIndex(f => f.url === item.url); if (index < 0 && item && item.url) { list = [{ name: item.name, url: item.url }]; index = 0; } this.$previewFile(list, index > -1 ? index : 0); }, getIndexInArray(arr, obj) { return arr.indexOf(obj); @@ -2182,8 +1557,8 @@ row.otherexpense = ""; } else if ( tempStr.includes("æ¡åº") || tempStr.includes("建德") || tempStr.includes("æ·³å®") tempStr.includes("建德") || tempStr.includes("æ·³å®") ) { row.otherexpense = (parseInt(row.days) * 60).toString(); } else { @@ -2775,7 +2150,7 @@ path: this.$route.path, query: { id: next.id, pos: 4 } }) .catch(() => {}); .catch(() => { }); }) .catch(() => { this.exitToPage(); @@ -2882,7 +2257,7 @@ //ä¿åæç» for (let i = 0; i < rbDetails.length; i++) { if (rbDetails[i].rbid != null) { if (rbDetails[i].persontype == "å®¶å±"||rbDetails[i].persontype == "ä¸å®¶") { if (rbDetails[i].persontype == "å®¶å±" || rbDetails[i].persontype == "ä¸å®¶") { if (this.form.infoid) { updateReimbursementdetail(rbDetails[i]); } else { src/views/project/travelexpensecheck/index.vue
@@ -1443,8 +1443,21 @@ } }, // ä¸è½½æä»¶ // é¢è§/ä¸è½½æä»¶ downFile(item) { const ext = String(item.name || "") .split(".") .pop() .toLowerCase(); if (["pdf", "jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { const list = (this.fileList || []).map(f => ({ name: f.name, url: f.url })); const index = list.findIndex(f => f.url === item.url); this.$previewFile(list, index > -1 ? index : 0); return; } const url = process.env.VUE_APP_BASE_API + item.url; var a = document.createElement("a"); var event = new MouseEvent("click"); src/views/project/unitCost/particulars/index.vue
@@ -489,6 +489,7 @@ :title="pdftitle" :visible.sync="pdfVisible" width="60%" custom-class="pdf-resize-dialog" > <div class="pdfimg"> <div class="box-pdf"> @@ -981,14 +982,8 @@ }, // è·å请æ±å¤´ Getnetworkheader() { let string = window.location.href; if (string.includes("9091")) { const index = string.indexOf("9091"); this.Networkheader = string.slice(0, index + 4); // æªå9091åå ¶åé¨å符 } else { const index = string.indexOf("8032"); this.Networkheader = string.slice(0, index + 4); // æªå8032åå ¶åé¨å符 } // 以å½åé¡µé¢ origin 为åï¼å ¼å®¹ 80/8032/9091 ååç»ç«¯å£è°æ´ this.Networkheader = window.location.origin; }, // 表åéç½® reset() { @@ -1255,7 +1250,7 @@ const config = { headers: { Authorization: "Bearer " + this.ICDtoken } }; const pdfimg = this.Networkheader + "/prod-api" + response.fileName; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + response.fileName; //è·å票æ®ä¿¡æ¯ä½ç½® if (response.code == 200) { this.previewpdf = true; @@ -1311,7 +1306,7 @@ if (this.donorchargeorgans[index].annexFilesList) { const fetchPromises = this.donorchargeorgans[index].annexFilesList.map( (value, indexson) => { const pdfimg = this.Networkheader + "/prod-api" + value.url; const pdfimg = this.Networkheader + process.env.VUE_APP_BASE_API + value.url; return fetch(pdfimg, config) .then(response => response.blob()) .then(blob => { @@ -1354,19 +1349,13 @@ downFile(item) { this.pdftitle = "å ±" + this.pdfimgsrcList.length + "项ï¼å½åéä¸" + item.name; let name = item.name.split("."); if (name[1] == "pdf") { this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§"); this.previewpdf = false; this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; } else if (name[1] == "jpg" || "png") { console.log(item, "å±ç¤º"); this.previewpdf = true; if (item.url) { this.pdfimg = item.url; } else { this.pdfimg = ""; } const ext = String(item.name || "pdf").toLowerCase().split(".").pop(); if (ext === "pdf") { this.$previewFile([{ name: item.name, url: item.url }]); return; } else if (["jpg", "jpeg", "png", "gif", "bmp", "webp"].includes(ext)) { this.$previewFile([{ name: item.name, url: item.url }]); return; } else { this.hintitle = "å½åæä»¶æä¸æ¯æé¢è§"; this.$modal.msgWarning("å½åæä»¶æä¸æ¯æé¢è§");