23a2fff92f73b9759849a8016601a6817d7470b1..dade6a8b4772abc113383246d05ab59162630e7c
2025-08-27 zhangwei
'上传变更公告获取详情与删除'
dade6a 对比 | 目录
2025-08-27 zhangwei
'feat上传附件及预览文件'
f0c7f4 对比 | 目录
13个文件已修改
482 ■■■■ 已修改文件
build/plugins.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pnpm-lock.yaml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/item/index.ts 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/types.ts 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/ReDialog/index.vue 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/component/pdfPreview.vue 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/detail.vue 178 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/uploadform.vue 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/utils/detail.tsx 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/utils/hook.tsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/system/dept/utils/types.ts 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
vite.config.ts 1 ●●●● 补丁 | 查看 | 原始文档 | 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",
pnpm-lock.yaml
@@ -123,6 +123,9 @@
      '@types/sortablejs':
        specifier: ^1.15.8
        version: 1.15.8
      '@vitejs/plugin-basic-ssl':
        specifier: ^2.1.0
        version: 2.1.0(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))
      '@vitejs/plugin-vue':
        specifier: ^5.2.3
        version: 5.2.3(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))
@@ -1325,6 +1328,12 @@
  '@typescript-eslint/visitor-keys@8.31.0':
    resolution: {integrity: sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==}
    engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
  '@vitejs/plugin-basic-ssl@2.1.0':
    resolution: {integrity: sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==}
    engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
    peerDependencies:
      vite: ^6.0.0 || ^7.0.0
  '@vitejs/plugin-vue-jsx@4.1.2':
    resolution: {integrity: sha512-4Rk0GdE0QCdsIkuMmWeg11gmM4x8UmTnZR/LWPm7QJ7+BsK4tq08udrN0isrrWqz5heFy9HLV/7bOLgFS8hUjA==}
@@ -4755,6 +4764,10 @@
      '@typescript-eslint/types': 8.31.0
      eslint-visitor-keys: 4.2.0
  '@vitejs/plugin-basic-ssl@2.1.0(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))':
    dependencies:
      vite: 6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1)
  '@vitejs/plugin-vue-jsx@4.1.2(vite@6.3.3(@types/node@20.17.30)(jiti@2.4.2)(lightningcss@1.29.2)(sass@1.87.0)(yaml@2.7.1))(vue@3.5.13(typescript@5.8.3))':
    dependencies:
      '@babel/core': 7.26.10
src/api/item/index.ts
@@ -6,7 +6,7 @@
import { http } from "@/utils/http";
import { baseUrlApi } from "../util";
import type { Result, PageResult } from "../types";
import type { Result, PageResult, ChangeDetail } from "../types";
// 获取行政区域列表
export const getRegionList = () => {
@@ -111,11 +111,6 @@
};
// 招标代理分页查询非政府订单处理
export const findWechatOpenId = (data?: object) => {
  return http.request<PageResult>("post", baseUrlApi(""), {
    data
  });
};
// 采购代理人增加非政府订单处理获取联系方式
export const addgetcontact = () => {
@@ -208,7 +203,7 @@
  );
};
// 采购代理人发布招标
// 采购代理人发布变更公告
export const changezhaobiao = (data?: object) => {
  return http.request<Result>(
    "post",
@@ -218,3 +213,58 @@
    }
  );
};
// 获取变更公告详情
export const changeDetail = params => {
  return http.request<ChangeDetail>(
    "get",
    baseUrlApi("/api/tenderOrder/changeDetail"),
    {
      params
    }
  );
};
// 采购代理人删除变更公告
export const cHangeDelete = (data?: object) => {
  return http.request<Result>(
    "post",
    baseUrlApi("/api/tenderOrder/cHangeDelete"),
    {
      data
    }
  );
};
// 采购代理人确认供应商已支付报名费
export const querenBaomingfei = (data?: object) => {
  return http.request<Result>(
    "post",
    baseUrlApi("/api/tenderOrder/querenBaomingfei"),
    {
      data
    }
  );
};
// 代理商发布中标文件
export const addZhongbiao = (data?: object) => {
  return http.request<Result>(
    "post",
    baseUrlApi("/api/tenderOrder/addZhongbiao"),
    {
      data
    }
  );
};
// 采购代理人确认供应商已支付代理费
export const querenDailifei = (data?: object) => {
  return http.request<Result>(
    "post",
    baseUrlApi("/api/tenderOrder/querenDailifei"),
    {
      data
    }
  );
};
src/api/types.ts
@@ -1,3 +1,5 @@
import type { TenderInfo } from "@/views/system/dept/utils/types";
export type Result = {
  success: boolean;
  result: Array<any>;
@@ -117,3 +119,10 @@
  code: string | number;
  result: RoleItem[];
};
export type ChangeDetail = {
  message: string;
  success: boolean;
  code: string | number;
  result: TenderInfo;
};
src/components/ReDialog/index.vue
@@ -17,11 +17,56 @@
const sureBtnMap = ref({});
const fullscreen = ref(false);
const isPush = (footerButtons, options) => {
  let arr = [
    {
      label: "取消",
      text: true,
      bg: true,
      btnClick: ({ dialog: { options, index } }) => {
        const done = () => closeDialog(options, index, { command: "cancel" });
        if (options?.beforeCancel && isFunction(options?.beforeCancel)) {
          options.beforeCancel(done, { options, index });
        } else {
          done();
        }
      }
    },
    {
      label: "确定",
      type: "primary",
      text: true,
      bg: true,
      popconfirm: options?.popconfirm,
      btnClick: ({ dialog: { options, index } }) => {
        if (options?.sureBtnLoading) {
          sureBtnMap.value[index] = Object.assign({}, sureBtnMap.value[index], {
            loading: true
          });
        }
        const closeLoading = () => {
          if (options?.sureBtnLoading) {
            sureBtnMap.value[index].loading = false;
          }
        };
        const done = () => {
          closeLoading();
          closeDialog(options, index, { command: "sure" });
        };
        if (options?.beforeSure && isFunction(options?.beforeSure)) {
          options.beforeSure(done, { options, index, closeLoading });
        } else {
          done();
        }
      }
    }
  ];
  return [...footerButtons, ...arr];
};
const footerButtons = computed(() => {
  return (options: DialogOptions) => {
    return options?.footerButtons?.length > 0
      ? options.footerButtons
      ? isPush(options.footerButtons, options)
      : ([
          {
            label: "取消",
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>
@@ -142,20 +200,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 +299,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 +376,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
@@ -19,6 +19,8 @@
const props = withDefaults(defineProps<TenderProps>(), {
  formInline: () => ({
    id: "", // 主键Id(必填)
    tenderId: "",
    higherDeptOptions: [],
    projectName: "",
    toubiaoStartDate: "", // 投标报名开始时间(必填,格式:yyyy-MM-dd HH:mm:ss)
    toubiaoEndDate: "", // 投标报名结束时间(必填,格式:yyyy-MM-dd HH:mm:ss)
@@ -26,7 +28,9 @@
    zhaobiaowenjian: "", // 招标文件(必填,长度1-512字符)
    zhaobiaowenjianName: "",
    biangengwenjian: "",
    biangengwenjianName: "",
    fujian: "", // 附件(可选,最大长度512字符,可为空)
    fujianName: "", // 附件(可选,最大长度512字符,可为空)
    kaibiaodidian: "" // 开标地点(必填,长度1-250字符)
  }),
  isChange: null,
@@ -116,6 +120,7 @@
const newFormInline = ref(props.formInline);
const validateForm = reactive({
  fileList: [],
  fileListFile: [],
  date: ""
});
const upload = ref<UploadInstance>();
@@ -159,22 +164,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, //表单域
@@ -244,7 +268,16 @@
  upload.value!.handleStart(file);
};
defineExpose({ getRef });
onMounted(async () => {});
onMounted(async () => {
  if (props.formInline.biangengwenjianName) {
    validateForm.fileList = [
      {
        name: props.formInline.biangengwenjianName,
        url: props.formInline.biangengwenjian
      }
    ];
  }
});
</script>
<template>
@@ -362,7 +395,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 +426,7 @@
.el-date-editor.el-input__wrapper {
  width: 100%;
}
.upload__tip {
  width: 100%;
}
src/views/system/dept/utils/detail.tsx
@@ -1,6 +1,6 @@
import tenderForm from "../uploadform.vue";
import { ref, h, reactive } from "vue";
import { addDialog } from "@/components/ReDialog";
import { addDialog, closeDialog } from "@/components/ReDialog";
import type { TenderInfo } from "./types";
import { message } from "@/utils/message";
import { cloneDeep, deviceDetection } from "@pureadmin/utils";
@@ -10,26 +10,35 @@
  fabuzhaobiao,
  changezhaobiao,
  getTenderOrderDetail,
  updateTittle
  updateTittle,
  changeDetail,
  cHangeDelete
} from "@/api/item/index";
const formRef = ref();
export function useDetail() {
  function openUploadDialog(title = "上传", row?: TenderInfo) {
  async function openUploadDialog(title = "上传", row?: TenderInfo) {
    const detail = await changeDetail({ id: row.id });
    if (detail.result) {
      row = detail.result;
    }
    addDialog({
      title: `${title}公告`,
      props: {
        formInline: {
          tenderId: title == "上传变更" ? row?.id : "",
          id: title == "上传" ? row?.id : "",
          id: row?.id ?? "",
          projectName: row?.projectName ?? "",
          toubiaoStartDate: row?.toubiaoStartDate ?? "", //投标报名开始时间
          toubiaoEndDate: row?.toubiaoEndDate ?? "", //投标报名结束时间
          kaibiaoDate: row?.kaibiaoDate ?? "", //开标时间
          biangengwenjian: "", //招标文件
          fujian: row?.fujian ?? "", //附件
          kaibiaodidian: row?.kaibiaodidian ?? "" //开标地点
          fujianName: row?.fujianName ?? "", //附件
          kaibiaodidian: row?.kaibiaodidian ?? "", //开标地点
          biangengwenjian: row?.biangengwenjian ?? "",
          // 变更文件
          biangengwenjianName: row?.biangengwenjianName ?? ""
        }
      },
      width: "30%",
@@ -44,6 +53,33 @@
          formInline: null,
          isChange: title == "上传" ? false : true
        }),
      footerButtons: detail.result
        ? [
            {
              label: "删除",
              type: "danger",
              text: true,
              bg: true,
              popconfirm: { title: "是否确认删除当前变更公告" },
              btnClick: ({ dialog: { options, index }, button }) => {
                console.log(options, index, button);
                cHangeDelete({ id: row?.id }).then(res => {
                  if (res.code == "200") {
                    getTenderOrderDetail({ id: row?.tenderId }).then(res => {
                      state.nowInfo = res.result;
                    });
                    closeDialog(options, index); // 关闭弹框
                  } else {
                    // closeLoading();
                    message(res.message, {
                      type: "error"
                    });
                  }
                });
              }
            }
          ]
        : [],
      beforeSure: (done, { options, closeLoading }) => {
        const FormRef = formRef.value.getRef();
        const curData = cloneDeep(options.props.formInline as TenderInfo);
@@ -180,7 +216,8 @@
      Authorization: `Bearer ${getToken()?.accessToken}`
    },
    nowInfo: Object as PropType<FormItemProps>,
    formDataNew: {}
    formDataNew: {},
    srcList: []
  });
  //生成时间戳+随机数
  // 生成时间戳+随机数的函数
@@ -208,7 +245,8 @@
    );
    // 拼接时间戳和随机数
    return (
      `${dirPath}${timestamp}_${randomNumber}` + filename.match(/\.[^.]+$/)
      `${dirPath}${filename}${timestamp}_${randomNumber}` +
      filename.match(/\.[^.]+$/)
    );
  }
  return {
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
@@ -39,6 +39,7 @@
interface TenderInfo {
  // 主键Id
  id: string;
  tenderId: string;
  // 投标报名开始时间,格式为yyyy-MM-dd HH:mm:ss
  projectName: string;
  toubiaoStartDate: string;
@@ -55,6 +56,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",