build/plugins.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
package.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/api/item/index.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/system/component/pdfPreview.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/system/dept/detail.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/system/dept/uploadform.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/system/dept/utils/detail.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/system/dept/utils/hook.tsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/views/system/dept/utils/types.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
vite.config.ts | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
build/plugins.ts
@@ -12,6 +12,7 @@ import removeConsole from "vite-plugin-remove-console"; import { codeInspectorPlugin } from "code-inspector-plugin"; import { vitePluginFakeServer } from "vite-plugin-fake-server"; import basicSsl from "@vitejs/plugin-basic-ssl"; export function getPluginsList( VITE_CDN: boolean, @@ -19,6 +20,7 @@ ): PluginOption[] { const lifecycle = process.env.npm_lifecycle_event; return [ basicSsl(), tailwindcss(), vue(), // jsx、tsx语法支持 package.json
@@ -88,6 +88,7 @@ "@types/path-browserify": "^1.0.3", "@types/qs": "^6.9.18", "@types/sortablejs": "^1.15.8", "@vitejs/plugin-basic-ssl": "^2.1.0", "@vitejs/plugin-vue": "^5.2.3", "@vitejs/plugin-vue-jsx": "^4.1.2", "boxen": "^8.0.1", src/api/item/index.ts
@@ -111,11 +111,6 @@ }; // 招标代理分页查询非政府订单处理 export const findWechatOpenId = (data?: object) => { return http.request<PageResult>("post", baseUrlApi(""), { data }); }; // 采购代理人增加非政府订单处理获取联系方式 export const addgetcontact = () => { src/views/system/component/pdfPreview.vue
@@ -6,7 +6,6 @@ > <iframe id="printIframe" :src="pdfSrc" frameborder="0" style="width: 100%; height: 100%" @load="iframeLoaded" @@ -16,10 +15,14 @@ <script setup lang="ts"> import { ref, defineProps } from "vue"; defineProps({ pdfSrc: { type: String, default: "" const props = defineProps({ // fileInfo: { // type: String, // default: "" // } fileInfo: { type: Object, required: true } }); let isLoading = ref(true); @@ -28,6 +31,31 @@ isLoading.value = false; }; console.log(props.fileInfo, "props.fileInfo"); const pdfUrl = props.fileInfo.filePath; // 用fetch获取文件流,强制转为预览格式 fetch(pdfUrl) .then(response => { // 检查响应是否成功 if (!response.ok) throw new Error("文件获取失败"); // 强制获取Blob对象(指定PDF类型) return response.blob(); }) .then(blob => { // 生成临时预览URL(浏览器本地临时链接,无下载触发) const blobUrl = URL.createObjectURL( new Blob([blob], { type: "application/pdf" }) // 明确指定PDF类型 ); // 赋值给iframe并显示 const iframe = document.getElementById("printIframe"); iframe.src = blobUrl; iframe.style.display = "block"; document.getElementById("loading").style.display = "none"; }) .catch(error => { // document.getElementById("loading").innerText = `加载失败:${error.message}`; }); </script> <style> .pdf-container { src/views/system/dept/detail.vue
@@ -11,6 +11,11 @@ interface Emits { (e: "backListPage"): void; } import MaterialIconThemePdf from "~icons/material-icon-theme/pdf"; import MaterialIconThemeImage from "~icons/material-icon-theme/image"; import MaterialIconThemeWord from "~icons/material-icon-theme/word"; import MaterialIconThemeTable from "~icons/material-icon-theme/table"; import MaterialIconThemeZip from "~icons/material-icon-theme/zip"; const emit = defineEmits<Emits>(); const props = defineProps({ nowID: null @@ -23,26 +28,79 @@ defineOptions({ name: "itemdetail" }); const convertFujianToObjects = (fujianStr, fujianNameStr) => { // 分割字符串为数组并过滤空值 const srcArray = fujianStr.split(",").filter(Boolean); const nameArray = fujianNameStr.split(",").filter(Boolean); // 提取文件后缀作为valu const getFileExtension = fileName => { const lastDotIndex = fileName.lastIndexOf("."); // 如果没有后缀或文件名以点结尾,返回空字符串 if (lastDotIndex === -1 || lastDotIndex === fileName.length - 1) { return ""; } return fileName.slice(lastDotIndex + 1).toLowerCase(); }; // 映射为目标对象数组 return srcArray.map((src, index) => { // 确保名称数组有对应索引的元素 const name = nameArray[index]?.trim() || `未知文件${index + 1}`; return { name: name, filePath: src.trim(), fileType: getFileExtension(name) }; }); }; onMounted(async () => { let res = await getTenderOrderDetail({ id: props.nowID }); state.nowInfo = res.result; if (state.nowInfo.fujian) { state.nowInfo.fujianList = convertFujianToObjects( state.nowInfo.fujian, state.nowInfo.fujianName ); } }); const backListPage = () => { emit("backListPage"); }; const previewPdf = pdfUrl => { addDialog({ title: `预览pdf`, props: {}, width: "60%", draggable: true, fullscreen: deviceDetection(), fullscreenIcon: true, sureBtnLoading: true, closeOnClickModal: false, contentRenderer: () => h(pdfPreview, { pdfSrc: pdfUrl }) // jsx 语法 (注意在.vue文件启用jsx语法,需要在script开启lang="tsx") }); console.log(pdfUrl, "pdfUrl"); switch (pdfUrl.fileType) { case "png": showImg(pdfUrl.filePath); break; case "jepg": showImg(pdfUrl.filePath); break; case "pdf": addDialog({ title: `预览pdf`, props: {}, width: "60%", draggable: true, fullscreen: deviceDetection(), fullscreenIcon: true, sureBtnLoading: true, closeOnClickModal: false, contentRenderer: () => h(pdfPreview, { fileInfo: pdfUrl }) // jsx 语法 (注意在.vue文件启用jsx语法,需要在script开启lang="tsx") }); break; default: window.location.href = pdfUrl.filePath; break; } }; const showPreview = ref(false); const showImg = (name: string | number) => { showPreview.value = true; state.srcList = [name]; }; </script> @@ -135,6 +193,7 @@ </el-button> <el-button v-if="state.nowInfo.zhaobiaowenjian" :disabled="!!state.nowInfo.changeOrder" type="primary" plain size="small" @@ -142,20 +201,96 @@ > 上传变更公告 </el-button> <el-button type="primary" plain size="small" @click="changeDialog('上传变更', state.nowInfo)" > 修改标题 </el-button> </el-form-item> <el-form-item v-if="state.nowInfo.zhaobiaowenjian" label=" "> <div class="border-1 w-[100%] rounded-md p-3"> <p>{{ state.nowInfo.projectName }}</p> <p>上传时间:2025-8-12 13:41:00</p> <el-button <p>上传时间:{{ state.nowInfo.fabuDate }}</p> <p class="flex items-center cursor-pointer" @click=" previewPdf({ name: state.nowInfo.zhaobiaowenjian, filePath: state.nowInfo.zhaobiaowenjianName, fileType: 'pdf' }) " > 招标文件:<MaterialIconThemePdf style="font-size: 1.5em" />{{ state.nowInfo.zhaobiaowenjianName }} </p> <p v-if="state.nowInfo?.changeOrder" class="flex items-center cursor-pointer" @click=" previewPdf({ name: state.nowInfo.changeOrder.biangengwenjianName, filePath: state.nowInfo.changeOrder.biangengwenjian, fileType: 'pdf' }) " > 变更公告: <MaterialIconThemePdf style="font-size: 1.5em" /> {{ state.nowInfo.changeOrder.biangengwenjianName }} </p> <div v-if="state.nowInfo.fujian" class="flex"> 附件: <div> <p v-for="item in state.nowInfo.fujianList" :key="item.src" class="flex items-center cursor-pointer" @click="previewPdf(item)" > <MaterialIconThemeImage v-if=" item.fileType == 'png' || item.fileType == 'jepg' " style="font-size: 1.5em" /> <MaterialIconThemePdf v-else-if="item.fileType == 'pdf'" style="font-size: 1.5em" /> <MaterialIconThemeTable v-else-if="item.fileType == 'xlsx'" style="font-size: 1.5em" /> <MaterialIconThemeWord v-else-if=" item.fileType == 'doc' || item.fileType == 'docx' " style="font-size: 1.5em" /> <MaterialIconThemeZip v-else style="font-size: 1.5em" /> {{ item.name }} </p> </div> </div> <!-- <el-button type="primary" plain size="small" @click="previewPdf(state.nowInfo.zhaobiaowenjian)" > 点击预览 </el-button> <el-button </el-button> --> <!-- <el-button v-if="state.nowInfo?.changeOrder" type="primary" plain @@ -165,15 +300,15 @@ " > 点击预览变更公告 </el-button> <el-button </el-button> --> <!-- <el-button type="primary" plain size="small" @click="changeDialog('上传变更', state.nowInfo)" > 修改标题 </el-button> </el-button> --> </div> </el-form-item> <!-- <el-form-item label="磋商文件:"> @@ -242,6 +377,12 @@ </el-tabs> </el-card> </div> <el-image-viewer v-if="showPreview" :url-list="state.srcList" show-progress @close="showPreview = false" /> </div> </template> src/views/system/dept/uploadform.vue
@@ -27,6 +27,7 @@ zhaobiaowenjianName: "", biangengwenjian: "", fujian: "", // 附件(可选,最大长度512字符,可为空) fujianName: "", // 附件(可选,最大长度512字符,可为空) kaibiaodidian: "" // 开标地点(必填,长度1-250字符) }), isChange: null, @@ -116,6 +117,7 @@ const newFormInline = ref(props.formInline); const validateForm = reactive({ fileList: [], fileListFile: [], date: "" }); const upload = ref<UploadInstance>(); @@ -159,22 +161,41 @@ fetchCredentials(file); // upload.value!.submit(); }; const handleChangeFile = file => { console.log(file); const handleChangeFile = async file => { if (file.status !== "ready") return; // let suffName = file.name.substring(file.name.lastIndexOf(".") + 1); // const extension = suffName === "pdf"; // // const isLt10M = file.size / 1024 / 1024 < 10; // if (!extension) { // message(`仅支持pdf格式,请上传pdf`, { // type: "error" // }); // validateForm.fileList = []; // return false; // } // const isLt10M = file.size / 1024 / 1024 < 10; // fetchCredentials(file); // upload.value!.submit(); // 这里应调用你自己的后端接口获取临时凭证 let res = await getUploadToken(); if (res.code == 200) { let keyVal = generateTimestampWithRandom(res.result.DirPath, file.name); let upUrl = res.result.url; let upPath = res.result.DirPath; let formData = new FormData(); formData.append("policy", res.result.policy); formData.append( "x-oss-signature-version", res.result.x_oss_signature_version ); formData.append("x-oss-credential", res.result.x_oss_credential); formData.append("x-oss-date", res.result.x_oss_date); // formData.append("Signature", res.result.signature); formData.append("x-oss-signature", res.result.signature); formData.append("x-oss-security-token", res.result.security_token); // formData.append("x-oss-content-type", "application/pdf"); formData.append("success_action_status", "200"); formData.append("key", keyVal); // 文件名 formData.append("file", file.raw); // file 必须为最后一个表单域 uploadFileAli(formData, res.result.url).then(res => { let path = `${upUrl}${keyVal}`; newFormInline.value.fujian += newFormInline.value.fujian ? `,${path}` : path; newFormInline.value.fujianName += newFormInline.value.fujianName ? `,${file.name}` : file.name; }); } }; // state.formDataNew = { // policy: res.result.policy, //表单域 @@ -267,7 +288,7 @@ </el-row> <el-row v-else :gutter="30"> <div v-if="props.isChange" style="width: 100%"> <re-col :value="24" :xs="24" :sm="24"> <!-- <re-col :value="24" :xs="24" :sm="24"> <el-form-item label="标题" prop="projectName"> <el-input v-model="newFormInline.projectName" @@ -275,7 +296,7 @@ placeholder="请输入标题" /> </el-form-item> </re-col> </re-col> --> <re-col :value="24" :xs="24" :sm="24"> <el-form-item label="变更文件" prop="biangengwenjian"> <el-upload @@ -362,7 +383,7 @@ <el-form-item label="附件" prop=""> <el-upload ref="upload" v-model:file-list="validateForm.fileList" v-model:file-list="validateForm.fileListFile" multiple :on-exceed="handleExceed" :auto-upload="false" @@ -393,6 +414,7 @@ .el-date-editor.el-input__wrapper { width: 100%; } .upload__tip { width: 100%; } src/views/system/dept/utils/detail.tsx
@@ -29,6 +29,7 @@ kaibiaoDate: row?.kaibiaoDate ?? "", //开标时间 biangengwenjian: "", //招标文件 fujian: row?.fujian ?? "", //附件 fujianName: row?.fujianName ?? "", //附件 kaibiaodidian: row?.kaibiaodidian ?? "" //开标地点 } }, @@ -180,7 +181,8 @@ Authorization: `Bearer ${getToken()?.accessToken}` }, nowInfo: Object as PropType<FormItemProps>, formDataNew: {} formDataNew: {}, srcList: [] }); //生成时间戳+随机数 // 生成时间戳+随机数的函数 src/views/system/dept/utils/hook.tsx
@@ -2,7 +2,7 @@ import editForm from "../form.vue"; import { handleTree } from "@/utils/tree"; import { message } from "@/utils/message"; import { zhaobiaoPageOrder, findWechatOpenId } from "@/api/item/index"; import { zhaobiaoPageOrder } from "@/api/item/index"; import { getCaigoufangshiList, @@ -25,7 +25,7 @@ import type { PaginationProps } from "@pureadmin/table"; import { useUserStoreHook } from "@/store/modules/user"; import pdfPreview from "../../component/pdfPreview.vue"; import pdfPreview from "../../component/pdfPreview2.vue"; // const nowRole = computed(() => { // return useUserStoreHook().nowRole; // }); @@ -315,7 +315,6 @@ } }; async function onSearch() { findWechatOpenId(); const obj = cloneDeep(form); obj.tousu = obj.tousu.join(""); obj.zhiyi = obj.zhiyi.join(""); src/views/system/dept/utils/types.ts
@@ -55,6 +55,7 @@ biangengwenjianName?: string | null | undefined; // 附件,可为空,最大长度512字符 fujian?: string; fujianName?: string; // 开标地点,长度1-250字符 kaibiaodidian: string; } vite.config.ts
@@ -20,6 +20,7 @@ }, // 服务端渲染 server: { https: true, // 启用 HTTPS // 端口号 port: VITE_PORT, host: "0.0.0.0",