Browse Source

所有文件地址加上token

jack.zhou 3 weeks ago
parent
commit
e9f2588d8d

+ 55 - 4
src/utils/url.ts

@@ -1,6 +1,57 @@
 /**
 /**
  * URL处理工具函数
  * URL处理工具函数
  */
  */
+import { Local } from './storage';
+
+/**
+ * 给文件地址拼接登录用户 token 参数
+ * 用于 <a href> / window.open / van-image :src / showImagePreview 等无法携带 Authorization 头的直链访问
+ * @param url 原始文件地址
+ * @returns 拼接 token 后的地址(非 http(s) / 空 / data: / blob: 直接原样返回,避免本地静态资源被污染)
+ */
+export function withToken(url?: string | null): string {
+  if (url === null || url === undefined) return '';
+  const str = String(url).trim();
+  if (!str) return str;
+  if (str.startsWith('data:') || str.startsWith('blob:') || str.startsWith('about:') || str.startsWith('#')) return str;
+  // 仅 http(s) 文件直链需要鉴权,本地静态资源直接返回
+  if (!/^https?:\/\//i.test(str)) return str;
+  let token = '';
+  try {
+    token = Local.get('token') || '';
+  } catch (e) {
+    token = '';
+  }
+  if (!token) return str;
+  // 已带 token 则不再重复拼接
+  if (/[?&]token=/.test(str)) return str;
+  const sep = str.includes('?') ? '&' : '?';
+  return `${str}${sep}token=${encodeURIComponent(token)}`;
+}
+
+/**
+ * 文件地址统一入口(withToken 别名,语义更明确)
+ */
+export function getFileUrl(url?: string | null): string {
+  return withToken(url);
+}
+
+/**
+ * 去掉地址中的 token 参数
+ * 上传回显用 withToken 做展示时,提交给后端前需调用此方法还原为原始地址,避免把 token 持久化存储
+ */
+export function stripToken(url?: string | null): string {
+  if (url === null || url === undefined) return '';
+  const str = String(url);
+  if (!str || !/[?&]token=/.test(str)) return str;
+  // 去掉 ?token=xxx 或 &token=xxx,并清理多余的 ? & 符号
+  let cleaned = str.replace(/([?&])token=[^&]*/g, (match, sep) => (sep === '?' ? '?' : ''));
+  cleaned = cleaned.replace(/\?&/, '?').replace(/&&+/g, '&');
+  cleaned = cleaned.replace(/[?&]$/, '');
+  // ? 后第一个是 & 的情况:? &a=1 => ?a=1
+  cleaned = cleaned.replace(/\?&/, '?');
+  return cleaned;
+}
 
 
 /**
 /**
  * 获取完整的图片URL
  * 获取完整的图片URL
@@ -8,8 +59,8 @@
  * @returns 完整的图片URL
  * @returns 完整的图片URL
  */
  */
 export function getImageUrl(url: string): string {
 export function getImageUrl(url: string): string {
-  // 图片是相对路径不需要拼 
-  return url
+  // 图片是相对路径不需要拼,但文件直链需要拼接登录 token 鉴权
+  return withToken(url);
   // if (!url) return ''
   // if (!url) return ''
 
 
   // // 如果已经包含http或https协议,直接返回
   // // 如果已经包含http或https协议,直接返回
@@ -36,9 +87,9 @@ export function getImageUrl(url: string): string {
 export function getResourceUrl(url: string, baseUrlKey: string = 'VITE_IMAGE_BASE_URL'): string {
 export function getResourceUrl(url: string, baseUrlKey: string = 'VITE_IMAGE_BASE_URL'): string {
   if (!url) return ''
   if (!url) return ''
 
 
-  // 如果已经包含http或https协议,直接返回
+  // 如果已经包含http或https协议,直接拼接 token 后返回
   if (url.startsWith('http://') || url.startsWith('https://')) {
   if (url.startsWith('http://') || url.startsWith('https://')) {
-    return url
+    return withToken(url)
   }
   }
 
 
   // 获取环境变量中的基础URL
   // 获取环境变量中的基础URL

+ 2 - 1
src/view/Application.vue

@@ -312,6 +312,7 @@
 
 
   import { deepClone } from '/@/utils/other';
   import { deepClone } from '/@/utils/other';
   import { getUploadHeaders } from '/@/utils/upload';
   import { getUploadHeaders } from '/@/utils/upload';
+  import { getFileUrl } from '/@/utils/url';
   import { useUserInfo } from '/@/stores/userInfo';
   import { useUserInfo } from '/@/stores/userInfo';
 
 
   const uploadUrl = (import.meta as any).env.VITE_UPLOAD;
   const uploadUrl = (import.meta as any).env.VITE_UPLOAD;
@@ -646,7 +647,7 @@
 
 
   const handlePreview = (file: UploadFile) => {
   const handlePreview = (file: UploadFile) => {
     if (file.url) {
     if (file.url) {
-      window.open(file.url, '_blank');
+      window.open(getFileUrl(file.url), '_blank');
     }
     }
   };
   };
 
 

+ 7 - 6
src/view/animal/application/components/Application.vue

@@ -225,6 +225,7 @@ import { deepClone } from '/@/utils/other'
 import { useUserInfo } from '/@/stores/userInfo'
 import { useUserInfo } from '/@/stores/userInfo'
 import { ProcurementChannels, FeedingSpecial, UploadFileType } from '/@/constants/pageConstants'
 import { ProcurementChannels, FeedingSpecial, UploadFileType } from '/@/constants/pageConstants'
 import { handleUpload } from '/@/utils/upload'
 import { handleUpload } from '/@/utils/upload'
+import { getFileUrl } from '/@/utils/url'
 import { formatDate } from '/@/utils/formatTime'
 import { formatDate } from '/@/utils/formatTime'
 
 
 const stores = useUserInfo()
 const stores = useUserInfo()
@@ -514,11 +515,11 @@ const openDialog = async (type: 'add' | 'edit', row?: any) => {
     state.form.ethicsCheckFile = isValidJsonArray(row.ethicsCheckFile) ? JSON.parse(row.ethicsCheckFile) : []
     state.form.ethicsCheckFile = isValidJsonArray(row.ethicsCheckFile) ? JSON.parse(row.ethicsCheckFile) : []
     state.form.ethicsAdviceFile = isValidJsonArray(row.ethicsAdviceFile) ? JSON.parse(row.ethicsAdviceFile) : []
     state.form.ethicsAdviceFile = isValidJsonArray(row.ethicsAdviceFile) ? JSON.parse(row.ethicsAdviceFile) : []
 
 
-    licenseNumberFileList.value = (state.form.licenseNumberFile || []).map((f: any) => ({ url: f.url, name: f.name }))
-    animalTestDateFileList.value = (state.form.animalTestDateFile || []).map((f: any) => ({ url: f.url, name: f.name }))
-    geneIdentificationFileList.value = (state.form.geneIdentificationFile || []).map((f: any) => ({ url: f.url, name: f.name }))
-    ethicsCheckFileList.value = (state.form.ethicsCheckFile || []).map((f: any) => ({ url: f.url, name: f.name }))
-    ethicsAdviceFileList.value = (state.form.ethicsAdviceFile || []).map((f: any) => ({ url: f.url, name: f.name }))
+    licenseNumberFileList.value = (state.form.licenseNumberFile || []).map((f: any) => ({ url: getFileUrl(f.url), name: f.name }))
+    animalTestDateFileList.value = (state.form.animalTestDateFile || []).map((f: any) => ({ url: getFileUrl(f.url), name: f.name }))
+    geneIdentificationFileList.value = (state.form.geneIdentificationFile || []).map((f: any) => ({ url: getFileUrl(f.url), name: f.name }))
+    ethicsCheckFileList.value = (state.form.ethicsCheckFile || []).map((f: any) => ({ url: getFileUrl(f.url), name: f.name }))
+    ethicsAdviceFileList.value = (state.form.ethicsAdviceFile || []).map((f: any) => ({ url: getFileUrl(f.url), name: f.name }))
   }
   }
 
 
   safePromise.value = false
   safePromise.value = false
@@ -580,7 +581,7 @@ const handleFileUpload = async (file: any, type: UploadFileType) => {
         return
         return
       }
       }
       item.status = 'done'
       item.status = 'done'
-      item.url = res
+      item.url = getFileUrl(res as string)
       item.name = item.file.name
       item.name = item.file.name
 
 
       // 保存到 form
       // 保存到 form

+ 8 - 7
src/view/animal/application/components/Detail.vue

@@ -73,7 +73,7 @@
             <van-cell title="生产许可证">
             <van-cell title="生产许可证">
               <template #value>
               <template #value>
                 <div class="file-links">
                 <div class="file-links">
-                  <a v-for="item in state.form.licenseNumberFile" :key="item.url" :href="item.url" target="_blank"
+                  <a v-for="item in state.form.licenseNumberFile" :key="item.url" :href="getFileUrl(item.url)" target="_blank"
                     class="file-link">
                     class="file-link">
                 {{ item.name }}
                 {{ item.name }}
                   </a>
                   </a>
@@ -87,7 +87,7 @@
             <van-cell title="近三个月动物质量检测证明">
             <van-cell title="近三个月动物质量检测证明">
               <template #value>
               <template #value>
                 <div class="file-links">
                 <div class="file-links">
-                  <a v-for="item in state.form.animalTestDateFile" :key="item.url" :href="item.url" target="_blank"
+                  <a v-for="item in state.form.animalTestDateFile" :key="item.url" :href="getFileUrl(item.url)" target="_blank"
                     class="file-link">
                     class="file-link">
                 {{ item.name }}
                 {{ item.name }}
                   </a>
                   </a>
@@ -102,7 +102,7 @@
             <van-cell title="基因鉴定报告">
             <van-cell title="基因鉴定报告">
               <template #value>
               <template #value>
                 <div class="file-links">
                 <div class="file-links">
-                  <a v-for="item in state.form.geneIdentificationFile" :key="item.url" :href="item.url" target="_blank"
+                  <a v-for="item in state.form.geneIdentificationFile" :key="item.url" :href="getFileUrl(item.url)" target="_blank"
                     class="file-link">
                     class="file-link">
                 {{ item.name }}
                 {{ item.name }}
                   </a>
                   </a>
@@ -116,7 +116,7 @@
             <van-cell title="近三个月饲养环境检测证明">
             <van-cell title="近三个月饲养环境检测证明">
               <template #value>
               <template #value>
                 <div class="file-links">
                 <div class="file-links">
-                  <a v-for="item in state.form.envTestDateFile" :key="item.url" :href="item.url" target="_blank"
+                  <a v-for="item in state.form.envTestDateFile" :key="item.url" :href="getFileUrl(item.url)" target="_blank"
                     class="file-link">
                     class="file-link">
                 {{ item.name }}
                 {{ item.name }}
                   </a>
                   </a>
@@ -130,7 +130,7 @@
             <van-cell title="笼位预约表">
             <van-cell title="笼位预约表">
               <template #value>
               <template #value>
                 <div class="file-links">
                 <div class="file-links">
-                  <a v-for="item in state.form.cageAppointFile" :key="item.url" :href="item.url" target="_blank"
+                  <a v-for="item in state.form.cageAppointFile" :key="item.url" :href="getFileUrl(item.url)" target="_blank"
                     class="file-link">
                     class="file-link">
                 {{ item.name }}
                 {{ item.name }}
                   </a>
                   </a>
@@ -144,7 +144,7 @@
             <van-cell title="实验动物福利伦理审查申请表">
             <van-cell title="实验动物福利伦理审查申请表">
               <template #value>
               <template #value>
                 <div class="file-links">
                 <div class="file-links">
-                  <a v-for="item in state.form.ethicsCheckFile" :key="item.url" :href="item.url" target="_blank"
+                  <a v-for="item in state.form.ethicsCheckFile" :key="item.url" :href="getFileUrl(item.url)" target="_blank"
                     class="file-link">
                     class="file-link">
                 {{ item.name }}
                 {{ item.name }}
                   </a>
                   </a>
@@ -158,7 +158,7 @@
             <van-cell title="实验动物福利伦理审查意见表">
             <van-cell title="实验动物福利伦理审查意见表">
               <template #value>
               <template #value>
                 <div class="file-links">
                 <div class="file-links">
-                  <a v-for="item in state.form.ethicsAdviceFile" :key="item.url" :href="item.url" target="_blank"
+                  <a v-for="item in state.form.ethicsAdviceFile" :key="item.url" :href="getFileUrl(item.url)" target="_blank"
                     class="file-link">
                     class="file-link">
                 {{ item.name }}
                 {{ item.name }}
                   </a>
                   </a>
@@ -183,6 +183,7 @@ import { nextTick, reactive, ref, defineAsyncComponent, watch, computed } from '
   import dayjs from 'dayjs'
   import dayjs from 'dayjs'
 
 
   import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
   import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
+  import { getFileUrl } from '/@/utils/url'
   import { ApproveStatusList, ProcurementChannels, FeedingSpecial, LeavelList ,AnimalPurpose} from '/@/constants/pageConstants'
   import { ApproveStatusList, ProcurementChannels, FeedingSpecial, LeavelList ,AnimalPurpose} from '/@/constants/pageConstants'
 
 
   const FlowTable = defineAsyncComponent(() => import('/@/components/FlowTable.vue'))
   const FlowTable = defineAsyncComponent(() => import('/@/components/FlowTable.vue'))

+ 2 - 1
src/view/entry/components/details.vue

@@ -75,7 +75,7 @@
         <h4 class="mb10">入室申请附件</h4>
         <h4 class="mb10">入室申请附件</h4>
         <el-descriptions border :column="2" class="mb20" direction="vertical">
         <el-descriptions border :column="2" class="mb20" direction="vertical">
           <el-descriptions-item v-for="item in state.form.fileList" label-class-name="cell-item" :label="item.fileName">
           <el-descriptions-item v-for="item in state.form.fileList" label-class-name="cell-item" :label="item.fileName">
-            <el-link type="primary" target="_blank" :href="item.fileUrl">下载</el-link>
+            <el-link type="primary" target="_blank" :href="getFileUrl(item.fileUrl)">下载</el-link>
           </el-descriptions-item>
           </el-descriptions-item>
         </el-descriptions>
         </el-descriptions>
       </template> -->
       </template> -->
@@ -118,6 +118,7 @@
   import { usePlatformAppointApi } from '/@/api/platform/appoint'
   import { usePlatformAppointApi } from '/@/api/platform/appoint'
   import { useSystemApi } from '/@/api/scientific/system'
   import { useSystemApi } from '/@/api/scientific/system'
   import { getDictLabel } from '/@/utils/other' // 字典转换
   import { getDictLabel } from '/@/utils/other' // 字典转换
+  import { getFileUrl } from '/@/utils/url'
   import { ElMessage } from 'element-plus'
   import { ElMessage } from 'element-plus'
   const emit = defineEmits(['refresh'])
   const emit = defineEmits(['refresh'])
   const FlowTable = defineAsyncComponent(() => import('/@/components/FlowTable.vue'))
   const FlowTable = defineAsyncComponent(() => import('/@/components/FlowTable.vue'))

+ 6 - 5
src/view/entry/components/upload.vue

@@ -48,6 +48,7 @@ import { storeToRefs } from 'pinia';
 import { useDictApi } from '/@/api/base/system/dict';
 import { useDictApi } from '/@/api/base/system/dict';
 import { SUPPORT_FILE_UPLOAD_TYPE_MAX } from '/@/constants/pageConstants'
 import { SUPPORT_FILE_UPLOAD_TYPE_MAX } from '/@/constants/pageConstants'
 import { getUploadHeaders } from '/@/utils/upload'
 import { getUploadHeaders } from '/@/utils/upload'
+import { getFileUrl, stripToken } from '/@/utils/url'
 
 
 const stores = useUserInfo();
 const stores = useUserInfo();
 const { userInfos } = storeToRefs(stores);
 const { userInfos } = storeToRefs(stores);
@@ -131,7 +132,7 @@ const openDialog = async (row: any, type: 'add' | 'edit') => {
 			billList = [
 			billList = [
 				{
 				{
 					name: file.fileName,
 					name: file.fileName,
-					url: file.fileUrl,
+					url: getFileUrl(file.fileUrl),
 					status: 'success',
 					status: 'success',
 					uid: 1,
 					uid: 1,
 				},
 				},
@@ -145,7 +146,7 @@ const openDialog = async (row: any, type: 'add' | 'edit') => {
 			fileList: files.map((item: any, idx: number) => {
 			fileList: files.map((item: any, idx: number) => {
 				return {
 				return {
 					name: item.fileName,
 					name: item.fileName,
-					url: item.fileUrl,
+					url: getFileUrl(item.fileUrl),
 					status: 'success',
 					status: 'success',
 					uid: idx,
 					uid: idx,
 				};
 				};
@@ -169,7 +170,7 @@ const billSuccess = (response: any, uploadFile: UploadFile, uploadFiles: UploadF
 			uid: uploadFile.uid,
 			uid: uploadFile.uid,
 			status: uploadFile.status,
 			status: uploadFile.status,
 			name: uploadFile.name,
 			name: uploadFile.name,
-			url: response.Data,
+			url: getFileUrl(response.Data),
 		},
 		},
 	];
 	];
 };
 };
@@ -192,7 +193,7 @@ const otherSuccess = (response: any, uploadFile: UploadFile, uploadFiles: Upload
 			uid: item.uid,
 			uid: item.uid,
 			status: item.status,
 			status: item.status,
 			name: item.name,
 			name: item.name,
-			url: item?.response?.Data || item.url,
+			url: getFileUrl(item?.response?.Data || item.url),
 		};
 		};
 	});
 	});
 };
 };
@@ -204,7 +205,7 @@ const onSubmit = async () => {
 		params.fileList = [...params.billList, ...params.fileList].map((item) => {
 		params.fileList = [...params.billList, ...params.fileList].map((item) => {
 			return {
 			return {
 				fileName: item.name,
 				fileName: item.name,
-				fileUrl: item.url,
+				fileUrl: stripToken(item.url),
 			};
 			};
 		});
 		});
 		delete params.billList;
 		delete params.billList;

+ 4 - 3
src/view/entry/detail.vue

@@ -280,6 +280,7 @@
   import { usePlatformAppointApi } from '/@/api/platform/appoint'
   import { usePlatformAppointApi } from '/@/api/platform/appoint'
   import { useFlowApi } from '/@/api/execution/flow'
   import { useFlowApi } from '/@/api/execution/flow'
   import { handleUpload } from '/@/utils/upload'
   import { handleUpload } from '/@/utils/upload'
+  import { getFileUrl, stripToken } from '/@/utils/url'
   import { showNotify } from 'vant'
   import { showNotify } from 'vant'
   const FlowTable = defineAsyncComponent(() => import('/@/components/FlowTable.vue'))
   const FlowTable = defineAsyncComponent(() => import('/@/components/FlowTable.vue'))
   const platformAppointApi = usePlatformAppointApi()
   const platformAppointApi = usePlatformAppointApi()
@@ -382,7 +383,7 @@
           return
           return
         }
         }
         file.status = 'success'
         file.status = 'success'
-        file.url = res
+        file.url = getFileUrl(res as string)
         file.name = file.file.name
         file.name = file.file.name
       }
       }
     } else {
     } else {
@@ -394,7 +395,7 @@
         return
         return
       }
       }
       file.status = 'success'
       file.status = 'success'
-      file.url = res
+      file.url = getFileUrl(res as string)
       file.name = file.file.name
       file.name = file.file.name
     }
     }
   }
   }
@@ -404,7 +405,7 @@
     params.fileList = [...params.billList, ...params.fileList].map((item) => {
     params.fileList = [...params.billList, ...params.fileList].map((item) => {
       return {
       return {
         fileName: item.name,
         fileName: item.name,
-        fileUrl: item.url,
+        fileUrl: stripToken(item.url),
       }
       }
     })
     })
     delete params.billList
     delete params.billList

+ 3 - 2
src/view/instr/addAuthorization/index.vue

@@ -154,6 +154,7 @@
   const grantApplyApi = useGrantApplyApi()
   const grantApplyApi = useGrantApplyApi()
   import { deepClone } from '/@/utils/other'
   import { deepClone } from '/@/utils/other'
   import { getUploadHeaders } from '/@/utils/upload'
   import { getUploadHeaders } from '/@/utils/upload'
+  import { getFileUrl } from '/@/utils/url'
   import { storeToRefs } from 'pinia'
   import { storeToRefs } from 'pinia'
   import mittBus from '/@/utils/mitt'
   import mittBus from '/@/utils/mitt'
   import { useUserInfo } from '/@/stores/userInfo'
   import { useUserInfo } from '/@/stores/userInfo'
@@ -249,7 +250,7 @@
     if (res?.code == 200) {
     if (res?.code == 200) {
       console.log(res.data)
       console.log(res.data)
       state.form = res.data
       state.form = res.data
-      state.form.fileList = [{ name: res.data.curtName, url: res.data.curtFile }]
+      state.form.fileList = [{ name: res.data.curtName, url: getFileUrl(res.data.curtFile) }]
       state.form.curUser = { userId: res.data.userId, userName: res.data.userName }
       state.form.curUser = { userId: res.data.userId, userName: res.data.userName }
       state.form.date = res.data.startTime ? [res.data.startTime, res.data.endTime] : null
       state.form.date = res.data.startTime ? [res.data.startTime, res.data.endTime] : null
     }
     }
@@ -271,7 +272,7 @@
     state.isShowDialog = false
     state.isShowDialog = false
   }
   }
   const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
   const handlePictureCardPreview: UploadProps['onPreview'] = (uploadFile) => {
-    dialogImageUrl.value = uploadFile.url!
+    dialogImageUrl.value = getFileUrl(uploadFile.url!)
     dialogVisible.value = true
     dialogVisible.value = true
   }
   }
   const handleSuccess = (res: any, uploadFile: UploadFile) => {
   const handleSuccess = (res: any, uploadFile: UploadFile) => {

+ 2 - 1
src/view/instr/appointList/SampleAppointList.vue

@@ -70,7 +70,7 @@
           </div>
           </div>
           <div style="flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
           <div style="flex: 1; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;">
             <span class="fontSize14 primary-color pointer">
             <span class="fontSize14 primary-color pointer">
-              <a :href="v.testResult" target="_blank" class="file-link">
+              <a :href="getFileUrl(v.testResult)" target="_blank" class="file-link">
                 {{ v.testResultName }}
                 {{ v.testResultName }}
               </a>
               </a>
             </span>
             </span>
@@ -136,6 +136,7 @@ import { reactive, ref, onMounted } from 'vue'
 import { useSampleApi } from '/@/api/instr/sample'
 import { useSampleApi } from '/@/api/instr/sample'
 import to from 'await-to-js'
 import to from 'await-to-js'
 import { formatDate } from '/@/utils/formatTime'
 import { formatDate } from '/@/utils/formatTime'
+import { getFileUrl } from '/@/utils/url'
 import { showDialog, showNotify } from 'vant'
 import { showDialog, showNotify } from 'vant'
 
 
 const props = defineProps({
 const props = defineProps({

+ 6 - 4
src/view/instr/detail.vue

@@ -148,7 +148,7 @@
               <div class="inst-title" v-if="item.testResultName">
               <div class="inst-title" v-if="item.testResultName">
                 <span>检测结果</span>
                 <span>检测结果</span>
                 <span class="title ml8">
                 <span class="title ml8">
-                  <a :href="item.testResult" target="_blank" class="file-link" @click.stop>
+                  <a :href="getFileUrl(item.testResult)" target="_blank" class="file-link" @click.stop>
                     {{ item.testResultName }}
                     {{ item.testResultName }}
                   </a>
                   </a>
                 </span>
                 </span>
@@ -321,7 +321,7 @@ import { useBlackApi } from '/@/api/blacklist'
 import AddAuthDialog from './addAuthorization/index.vue'
 import AddAuthDialog from './addAuthorization/index.vue'
 import { useUserInfos } from '/@/hooks/useUserInfos'
 import { useUserInfos } from '/@/hooks/useUserInfos'
 import { useTrainingApi } from '/@/api/instr/inst/training'
 import { useTrainingApi } from '/@/api/instr/inst/training'
-import { getImageUrl } from '/@/utils/url'
+import { getImageUrl, getFileUrl } from '/@/utils/url'
 
 
 const route = useRoute()
 const route = useRoute()
 const router = useRouter()
 const router = useRouter()
@@ -422,13 +422,15 @@ const getDocs = async () => {
   state.instFiles = res?.data.list || []
   state.instFiles = res?.data.list || []
 }
 }
 const realDown = (filename: string, fileurl: string) => {
 const realDown = (filename: string, fileurl: string) => {
+  const authedUrl = getFileUrl(fileurl)
+  const sep = authedUrl.includes('?') ? '&' : '?'
   let ua = navigator.userAgent.toLowerCase()
   let ua = navigator.userAgent.toLowerCase()
   if (ua.includes('mac')) {
   if (ua.includes('mac')) {
     //iOS 将文件url转换为文件流 在下载
     //iOS 将文件url转换为文件流 在下载
-    downloadFun(fileurl + '?response-content-type=application/octet-stream', filename)
+    downloadFun(`${authedUrl}${sep}response-content-type=application/octet-stream`, filename)
   } else {
   } else {
     //android 直接用插件的方法下载即可
     //android 直接用插件的方法下载即可
-    download(fileurl, filename)
+    download(authedUrl, filename)
   }
   }
 }
 }
 // 创建a标签 实现下载
 // 创建a标签 实现下载

+ 4 - 3
src/view/instr/repairReport/add.vue

@@ -79,6 +79,7 @@
   import { formatDate } from '/@/utils/formatTime'
   import { formatDate } from '/@/utils/formatTime'
   import { useRouter } from 'vue-router'
   import { useRouter } from 'vue-router'
   import { handleUpload } from '/@/utils/upload'
   import { handleUpload } from '/@/utils/upload'
+  import { getFileUrl, stripToken } from '/@/utils/url'
   import { useRepairReportApi } from '/@/api/instr/repairReport'
   import { useRepairReportApi } from '/@/api/instr/repairReport'
 
 
   const SelectInstPopup = defineAsyncComponent(() => import('/@/components/select-inst.vue'))
   const SelectInstPopup = defineAsyncComponent(() => import('/@/components/select-inst.vue'))
@@ -149,7 +150,7 @@
     const files = params.faultPhoto.map((item: any) => {
     const files = params.faultPhoto.map((item: any) => {
       return {
       return {
         name: item.name,
         name: item.name,
-        url: item.url
+        url: stripToken(item.url)
       }
       }
     })
     })
     params.faultPhoto = JSON.stringify(files) // 将图片数组转换为符合后端要求的格式
     params.faultPhoto = JSON.stringify(files) // 将图片数组转换为符合后端要求的格式
@@ -214,7 +215,7 @@
           return
           return
         }
         }
         file.status = 'success'
         file.status = 'success'
-        file.url = res
+        file.url = getFileUrl(res as string)
         file.name = file.file.name
         file.name = file.file.name
       }
       }
     } else {
     } else {
@@ -226,7 +227,7 @@
         return
         return
       }
       }
       file.status = 'success'
       file.status = 'success'
-      file.url = res
+      file.url = getFileUrl(res as string)
       file.name = file.file.name
       file.name = file.file.name
     }
     }
   }
   }

+ 6 - 5
src/view/instr/repairReport/confirm.vue

@@ -30,7 +30,7 @@
             v-for="(v, i) in state.form.faultPhoto"
             v-for="(v, i) in state.form.faultPhoto"
             width="100"
             width="100"
             height="100"
             height="100"
-            :src="v.url"
+            :src="getFileUrl(v.url)"
             @click="showPreviewImg(state.form.faultPhoto, i)"
             @click="showPreviewImg(state.form.faultPhoto, i)"
           />
           />
         </div>
         </div>
@@ -85,6 +85,7 @@
   import { formatDate } from '/@/utils/formatTime'
   import { formatDate } from '/@/utils/formatTime'
   import { useRouter } from 'vue-router'
   import { useRouter } from 'vue-router'
   import { handleUpload } from '/@/utils/upload'
   import { handleUpload } from '/@/utils/upload'
+  import { getFileUrl, stripToken } from '/@/utils/url'
   import { useRepairReportApi } from '/@/api/instr/repairReport'
   import { useRepairReportApi } from '/@/api/instr/repairReport'
 
 
   const repairReportApi = useRepairReportApi()
   const repairReportApi = useRepairReportApi()
@@ -145,7 +146,7 @@
     const files = params.faultPhoto.map((item: any) => {
     const files = params.faultPhoto.map((item: any) => {
       return {
       return {
         name: item.name,
         name: item.name,
-        url: item.url
+        url: stripToken(item.url)
       }
       }
     })
     })
     params.faultPhoto = JSON.stringify(files) // 将图片数组转换为符合后端要求的格式
     params.faultPhoto = JSON.stringify(files) // 将图片数组转换为符合后端要求的格式
@@ -177,7 +178,7 @@
           return
           return
         }
         }
         file.status = 'success'
         file.status = 'success'
-        file.url = res
+        file.url = getFileUrl(res as string)
         file.name = file.file.name
         file.name = file.file.name
       }
       }
     } else {
     } else {
@@ -189,13 +190,13 @@
         return
         return
       }
       }
       file.status = 'success'
       file.status = 'success'
-      file.url = res
+      file.url = getFileUrl(res as string)
       file.name = file.file.name
       file.name = file.file.name
     }
     }
   }
   }
 
 
   const showPreviewImg = (fullPhoto: any, index: number) => {
   const showPreviewImg = (fullPhoto: any, index: number) => {
-    const images = fullPhoto.map((item: any) => item.url)
+    const images = fullPhoto.map((item: any) => getFileUrl(item.url))
     showImagePreview({
     showImagePreview({
       images,
       images,
       startPosition: index
       startPosition: index

+ 3 - 2
src/view/instr/repairReport/index.vue

@@ -47,7 +47,7 @@
                 <span>故障图片</span>
                 <span>故障图片</span>
                 <div>
                 <div>
                   <van-image class="mr10 mb10" v-for="(v, i) in JSON.parse(item.faultPhoto)" width="100" height="100"
                   <van-image class="mr10 mb10" v-for="(v, i) in JSON.parse(item.faultPhoto)" width="100" height="100"
-                    :src="v.url" @click="showPreviewImg(item.faultPhoto, i)" />
+                    :src="getFileUrl(v.url)" @click="showPreviewImg(item.faultPhoto, i)" />
                 </div>
                 </div>
               </div>
               </div>
               <footer class="flex justify-between mt4">
               <footer class="flex justify-between mt4">
@@ -92,6 +92,7 @@ import { onMounted, reactive, ref } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import { useRouter, useRoute } from 'vue-router'
 import { useRepairReportApi } from '/@/api/instr/repairReport'
 import { useRepairReportApi } from '/@/api/instr/repairReport'
 import { showImagePreview, showConfirmDialog, showNotify } from 'vant'
 import { showImagePreview, showConfirmDialog, showNotify } from 'vant'
+import { getFileUrl } from '/@/utils/url'
 import 'vant/es/image-preview/style'
 import 'vant/es/image-preview/style'
 import { useUserInfo } from '/@/stores/userInfo'
 import { useUserInfo } from '/@/stores/userInfo'
 import { useInstrApi } from '/@/api/instr/index'
 import { useInstrApi } from '/@/api/instr/index'
@@ -157,7 +158,7 @@ const onClose = async (item: any) => {
 
 
 const showPreviewImg = (fullPhoto: string, index: number) => {
 const showPreviewImg = (fullPhoto: string, index: number) => {
   console.log('fullPhoto', fullPhoto)
   console.log('fullPhoto', fullPhoto)
-  const images = JSON.parse(fullPhoto).map((item: any) => item.url)
+  const images = JSON.parse(fullPhoto).map((item: any) => getFileUrl(item.url))
   showImagePreview({
   showImagePreview({
     images,
     images,
     startPosition: index
     startPosition: index

+ 4 - 3
src/view/laboratory/inspection/addInspTask.vue

@@ -140,6 +140,7 @@
   import { formatDate } from '/@/utils/formatTime'
   import { formatDate } from '/@/utils/formatTime'
   import { useRouter } from 'vue-router'
   import { useRouter } from 'vue-router'
   import { handleUpload } from '/@/utils/upload'
   import { handleUpload } from '/@/utils/upload'
+  import { getFileUrl, stripToken } from '/@/utils/url'
   import { useRectificationNewApi } from '/@/api/laboratory/rectification/indexNew'
   import { useRectificationNewApi } from '/@/api/laboratory/rectification/indexNew'
   import { useLabApi } from '/@/api/laboratory/lab'
   import { useLabApi } from '/@/api/laboratory/lab'
   import { useSystemApi } from '/@/api/laboratory/system'
   import { useSystemApi } from '/@/api/laboratory/system'
@@ -214,7 +215,7 @@
     params.photos = params.photos.map((item: any) => {
     params.photos = params.photos.map((item: any) => {
       return {
       return {
         name: item.name,
         name: item.name,
-        url: item.url,
+        url: stripToken(item.url),
       }
       }
     })
     })
     console.log(params)
     console.log(params)
@@ -261,7 +262,7 @@
           return
           return
         }
         }
         file.status = 'success'
         file.status = 'success'
-        file.url = res
+        file.url = getFileUrl(res as string)
         file.name = file.file.name
         file.name = file.file.name
       }
       }
     } else {
     } else {
@@ -273,7 +274,7 @@
         return
         return
       }
       }
       file.status = 'success'
       file.status = 'success'
-      file.url = res
+      file.url = getFileUrl(res as string)
       file.name = file.file.name
       file.name = file.file.name
     }
     }
   }
   }

+ 4 - 3
src/view/laboratory/inspection/details.vue

@@ -32,7 +32,7 @@
                 v-for="(v, i) in state.form.photos"
                 v-for="(v, i) in state.form.photos"
                 width="100"
                 width="100"
                 height="100"
                 height="100"
-                :src="v.url"
+                :src="getFileUrl(v.url)"
                 @click="showPreviewImg(state.form.photos, i)"
                 @click="showPreviewImg(state.form.photos, i)"
               />
               />
             </div>
             </div>
@@ -56,7 +56,7 @@
                 v-for="(v, i) in state.form.alterPhotos"
                 v-for="(v, i) in state.form.alterPhotos"
                 width="100"
                 width="100"
                 height="100"
                 height="100"
-                :src="v.url"
+                :src="getFileUrl(v.url)"
                 @click="showPreviewImg(state.form.alterPhotos, i)"
                 @click="showPreviewImg(state.form.alterPhotos, i)"
               />
               />
             </div>
             </div>
@@ -72,6 +72,7 @@
   import { onMounted, reactive, ref } from 'vue'
   import { onMounted, reactive, ref } from 'vue'
   import { showNotify, showImagePreview } from 'vant'
   import { showNotify, showImagePreview } from 'vant'
   import { formatDate } from '/@/utils/formatTime'
   import { formatDate } from '/@/utils/formatTime'
+  import { getFileUrl } from '/@/utils/url'
   import { useRouter } from 'vue-router'
   import { useRouter } from 'vue-router'
   import { useRectificationNewApi } from '/@/api/laboratory/rectification/indexNew'
   import { useRectificationNewApi } from '/@/api/laboratory/rectification/indexNew'
 
 
@@ -111,7 +112,7 @@
   }
   }
 
 
   const showPreviewImg = (photos: string, index: number) => {
   const showPreviewImg = (photos: string, index: number) => {
-    const images = JSON.parse(photos).map((item: any) => item.url)
+    const images = JSON.parse(photos).map((item: any) => getFileUrl(item.url))
     showImagePreview({
     showImagePreview({
       images,
       images,
       startPosition: index
       startPosition: index

+ 6 - 5
src/view/laboratory/inspection/feedback.vue

@@ -66,7 +66,7 @@
                 v-for="(v, i) in state.form.photos"
                 v-for="(v, i) in state.form.photos"
                 width="100"
                 width="100"
                 height="100"
                 height="100"
-                :src="v.url"
+                :src="getFileUrl(v.url)"
                 @click="showPreviewImg(state.form.photos, i)"
                 @click="showPreviewImg(state.form.photos, i)"
               />
               />
             </div>
             </div>
@@ -151,6 +151,7 @@
   import { formatDate } from '/@/utils/formatTime'
   import { formatDate } from '/@/utils/formatTime'
   import { useRouter } from 'vue-router'
   import { useRouter } from 'vue-router'
   import { handleUpload } from '/@/utils/upload'
   import { handleUpload } from '/@/utils/upload'
+  import { getFileUrl, stripToken } from '/@/utils/url'
   import { useRectificationNewApi } from '/@/api/laboratory/rectification/indexNew'
   import { useRectificationNewApi } from '/@/api/laboratory/rectification/indexNew'
 
 
   const rectificationApi = useRectificationNewApi()
   const rectificationApi = useRectificationNewApi()
@@ -202,7 +203,7 @@
     let params = { ...state.alterForm, id: Number(router.currentRoute.value.query.id), frcnStatus: '40' }
     let params = { ...state.alterForm, id: Number(router.currentRoute.value.query.id), frcnStatus: '40' }
     params.alterPhotos = params.alterPhotos.map((item) => ({
     params.alterPhotos = params.alterPhotos.map((item) => ({
       name: item.name,
       name: item.name,
-      url: item.url,
+      url: stripToken(item.url),
     }))
     }))
     console.log(params)
     console.log(params)
     loading.value = true
     loading.value = true
@@ -237,7 +238,7 @@
           return
           return
         }
         }
         file.status = 'success'
         file.status = 'success'
-        file.url = res
+        file.url = getFileUrl(res as string)
         file.name = file.file.name
         file.name = file.file.name
       }
       }
     } else {
     } else {
@@ -249,12 +250,12 @@
         return
         return
       }
       }
       file.status = 'success'
       file.status = 'success'
-      file.url = res
+      file.url = getFileUrl(res as string)
       file.name = file.file.name
       file.name = file.file.name
     }
     }
   }
   }
   const showPreviewImg = (photos: string, index: number) => {
   const showPreviewImg = (photos: string, index: number) => {
-    const images = JSON.parse(photos).map((item: any) => item.url)
+    const images = JSON.parse(photos).map((item: any) => getFileUrl(item.url))
     showImagePreview({
     showImagePreview({
       images,
       images,
       startPosition: index,
       startPosition: index,

+ 2 - 1
src/view/laboratory/inspection/index.vue

@@ -98,6 +98,7 @@ import { onMounted, reactive, ref } from 'vue'
 import { useRouter, useRoute } from 'vue-router'
 import { useRouter, useRoute } from 'vue-router'
 import { useRectificationNewApi } from '/@/api/laboratory/inspection'
 import { useRectificationNewApi } from '/@/api/laboratory/inspection'
 import { showImagePreview, showConfirmDialog, showNotify } from 'vant'
 import { showImagePreview, showConfirmDialog, showNotify } from 'vant'
+import { getFileUrl } from '/@/utils/url'
 import 'vant/es/image-preview/style'
 import 'vant/es/image-preview/style'
 
 
 const inspectionNewApi = useRectificationNewApi()
 const inspectionNewApi = useRectificationNewApi()
@@ -170,7 +171,7 @@ const onClose = async (item: any) => {
 
 
 const showPreviewImg = (fullPhoto: string, index: number) => {
 const showPreviewImg = (fullPhoto: string, index: number) => {
   console.log('fullPhoto', fullPhoto)
   console.log('fullPhoto', fullPhoto)
-  const images = JSON.parse(fullPhoto).map((item: any) => item.url)
+  const images = JSON.parse(fullPhoto).map((item: any) => getFileUrl(item.url))
   showImagePreview({
   showImagePreview({
     images,
     images,
     startPosition: index,
     startPosition: index,

+ 2 - 1
src/view/todo/component/approveTasks.vue

@@ -64,6 +64,7 @@
   import { genFileId } from 'element-plus'
   import { genFileId } from 'element-plus'
   import { Session } from '/@/utils/storage'
   import { Session } from '/@/utils/storage'
   import { getUploadHeaders } from '/@/utils/upload'
   import { getUploadHeaders } from '/@/utils/upload'
+  import { getFileUrl } from '/@/utils/url'
   import { SUPPORT_FILE_UPLOAD_TYPE_MAX } from '/@/constants/pageConstants'
   import { SUPPORT_FILE_UPLOAD_TYPE_MAX } from '/@/constants/pageConstants'
 
 
   // 定义变量内容
   // 定义变量内容
@@ -133,7 +134,7 @@
     state.form.fileList = [
     state.form.fileList = [
       {
       {
         name: uploadFile?.name,
         name: uploadFile?.name,
-        url: res.Data,
+        url: getFileUrl(res.Data),
         uid: uploadFile?.uid
         uid: uploadFile?.uid
       }
       }
     ]
     ]

+ 6 - 5
src/view/todo/component/plat_cage_applications.vue

@@ -96,7 +96,7 @@
       >
       >
         <template #value>
         <template #value>
           <a
           <a
-            :href="parseFileInfo(state.form.licenseNumberFile).url"
+            :href="getFileUrl(parseFileInfo(state.form.licenseNumberFile).url)"
             target="_blank"
             target="_blank"
             class="file-link"
             class="file-link"
           >
           >
@@ -110,7 +110,7 @@
       >
       >
         <template #value>
         <template #value>
           <a
           <a
-            :href="parseFileInfo(state.form.animalTestDateFile).url"
+            :href="getFileUrl(parseFileInfo(state.form.animalTestDateFile).url)"
             target="_blank"
             target="_blank"
             class="file-link"
             class="file-link"
           >
           >
@@ -124,7 +124,7 @@
       >
       >
         <template #value>
         <template #value>
           <a
           <a
-            :href="parseFileInfo(state.form.geneIdentificationFile).url"
+            :href="getFileUrl(parseFileInfo(state.form.geneIdentificationFile).url)"
             target="_blank"
             target="_blank"
             class="file-link"
             class="file-link"
           >
           >
@@ -138,7 +138,7 @@
       >
       >
         <template #value>
         <template #value>
           <a
           <a
-            :href="parseFileInfo(state.form.ethicsCheckFile).url"
+            :href="getFileUrl(parseFileInfo(state.form.ethicsCheckFile).url)"
             target="_blank"
             target="_blank"
             class="file-link"
             class="file-link"
           >
           >
@@ -152,7 +152,7 @@
       >
       >
         <template #value>
         <template #value>
           <a
           <a
-            :href="parseFileInfo(state.form.ethicsAdviceFile).url"
+            :href="getFileUrl(parseFileInfo(state.form.ethicsAdviceFile).url)"
             target="_blank"
             target="_blank"
             class="file-link"
             class="file-link"
           >
           >
@@ -171,6 +171,7 @@
 
 
   import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
   import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
   import { ProcurementChannels, FeedingSpecial, AnimalPurpose } from '/@/constants/pageConstants'
   import { ProcurementChannels, FeedingSpecial, AnimalPurpose } from '/@/constants/pageConstants'
+  import { getFileUrl } from '/@/utils/url'
 
 
   const checkProcurementChannels = computed(() => {
   const checkProcurementChannels = computed(() => {
     return state.form.buyFrom === ProcurementChannels.PURCHASED_BY_OTHERS ? '动物房代购' : '自行购买'
     return state.form.buyFrom === ProcurementChannels.PURCHASED_BY_OTHERS ? '动物房代购' : '自行购买'

+ 2 - 1
src/view/todo/component/plat_service_commission.vue

@@ -168,7 +168,7 @@
                   <span class="kv-label">附件</span>
                   <span class="kv-label">附件</span>
                   <a
                   <a
                     v-if="service?.file?.[0]?.fileUrl"
                     v-if="service?.file?.[0]?.fileUrl"
-                    :href="service?.file[0]?.fileUrl"
+                    :href="getFileUrl(service?.file[0]?.fileUrl)"
                     target="_blank"
                     target="_blank"
                     class="file-link"
                     class="file-link"
                   >
                   >
@@ -290,6 +290,7 @@
   import to from 'await-to-js'
   import to from 'await-to-js'
   import { nextTick, reactive, watch, computed } from 'vue'
   import { nextTick, reactive, watch, computed } from 'vue'
   import { usePlatCommissionApi } from '/@/api/platform/techService/commission'
   import { usePlatCommissionApi } from '/@/api/platform/techService/commission'
+  import { getFileUrl } from '/@/utils/url'
 
 
   // 定义子组件向父组件传值/事件
   // 定义子组件向父组件传值/事件
   const props = defineProps({
   const props = defineProps({

+ 4 - 3
src/view/todo/component/platform_animal_appointment_ethics.vue

@@ -50,7 +50,7 @@
         <template #value>
         <template #value>
           <a
           <a
             v-if="state.form.applyFiles?.length"
             v-if="state.form.applyFiles?.length"
-            :href="state.form.applyFiles[0].url"
+            :href="getFileUrl(state.form.applyFiles[0].url)"
             target="_blank"
             target="_blank"
             class="file-link"
             class="file-link"
           >
           >
@@ -63,7 +63,7 @@
         <template #value>
         <template #value>
           <a
           <a
             v-if="state.form.ethicsFiles?.length"
             v-if="state.form.ethicsFiles?.length"
-            :href="state.form.ethicsFiles[0].url"
+            :href="getFileUrl(state.form.ethicsFiles[0].url)"
             target="_blank"
             target="_blank"
             class="file-link"
             class="file-link"
           >
           >
@@ -81,7 +81,7 @@
             <a
             <a
               v-for="item in state.form.otherFiles"
               v-for="item in state.form.otherFiles"
               :key="item.url"
               :key="item.url"
-              :href="item.url"
+              :href="getFileUrl(item.url)"
               target="_blank"
               target="_blank"
               class="file-link"
               class="file-link"
             >
             >
@@ -100,6 +100,7 @@
   import to from 'await-to-js'
   import to from 'await-to-js'
 
 
   import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
   import { usePlatAnimalCageApplicationApi } from '/@/api/platform/animal'
+  import { getFileUrl } from '/@/utils/url'
 
 
   // 定义子组件向父组件传值/事件
   // 定义子组件向父组件传值/事件
   const props = defineProps({
   const props = defineProps({

+ 2 - 2
src/view/user/edit.vue

@@ -19,7 +19,7 @@
         <van-cell class="flex" is-link size="normal" title="头像" @click="editAvatar">
         <van-cell class="flex" is-link size="normal" title="头像" @click="editAvatar">
           <template #value>
           <template #value>
             <!-- <img class="avatar" width="30" height="30" :src="userInfos.avatar" alt="" /> -->
             <!-- <img class="avatar" width="30" height="30" :src="userInfos.avatar" alt="" /> -->
-            <van-image width="30px" height="30px" :src="userInfos.avatar" />
+            <van-image width="30px" height="30px" :src="getFileUrl(userInfos.avatar)" />
           </template>
           </template>
         </van-cell>
         </van-cell>
         <van-field v-model="state.form.nickName" label="用户昵称" placeholder="用户昵称"
         <van-field v-model="state.form.nickName" label="用户昵称" placeholder="用户昵称"
@@ -82,7 +82,7 @@ import 'cropperjs/dist/cropper.css'
 import axios from 'axios'
 import axios from 'axios'
 import { Local } from '/@/utils/storage'
 import { Local } from '/@/utils/storage'
 import { userImgSize } from '/@/constants/pageConstants'
 import { userImgSize } from '/@/constants/pageConstants'
-import { getResourceUrl } from '/@/utils/url'
+import { getResourceUrl, getFileUrl } from '/@/utils/url'
 
 
 const router = useRouter()
 const router = useRouter()
 const storesUseUserInfo = useUserInfo()
 const storesUseUserInfo = useUserInfo()

+ 2 - 1
src/view/user/index.vue

@@ -2,7 +2,7 @@
   <div class="app-container">
   <div class="app-container">
     <header>
     <header>
       <!-- <img :src="userInfos.avatar" alt="" /> -->
       <!-- <img :src="userInfos.avatar" alt="" /> -->
-      <van-image class="mr10" width="100px" height="100px" round :src="userInfos.avatar" />
+      <van-image class="mr10" width="100px" height="100px" round :src="getFileUrl(userInfos.avatar)" />
       <div class="content">
       <div class="content">
         <p class="bold">
         <p class="bold">
           <van-text-ellipsis :content="`${userInfos.nickName}(信用分:${userInfos.creditScore})`" />
           <van-text-ellipsis :content="`${userInfos.nickName}(信用分:${userInfos.creditScore})`" />
@@ -217,6 +217,7 @@ import { showConfirmDialog, showDialog, showToast } from 'vant'
 import { useRouter } from 'vue-router'
 import { useRouter } from 'vue-router'
 
 
 import { useUserInfo } from '/@/stores/userInfo'
 import { useUserInfo } from '/@/stores/userInfo'
+import { getFileUrl } from '/@/utils/url'
 import { Local, Session } from '/@/utils/storage'
 import { Local, Session } from '/@/utils/storage'
 import { useBillApi } from '/@/api/instr/finance/bill'
 import { useBillApi } from '/@/api/instr/finance/bill'
 import { useLoginApi } from '/@/api/login'
 import { useLoginApi } from '/@/api/login'