Browse Source

feat(all): update

Hu Cheng 2 năm trước cách đây
mục cha
commit
bf4ad4c967

+ 4 - 3
.env.development

@@ -1,3 +1,4 @@
-VITE_API_BASE_URL="https://coldverify.coldbaozhida.com/api"
-VITE_API_LOCAL_BASE_URL="http://192.168.11.23:6400"
-VITE_API_COLD_BASE_URL="https://cold.coldbaozhida.com/api"
+VITE_API_BASE_URL1="https://coldverify.coldbaozhida.com/api"
+VITE_API_BASE_URL2="http://coldverifylocal.coldbaozhida.com"
+VITE_API_BASE_URL3="https://cold.coldbaozhida.com/api"
+VITE_API_BASE_URL4="http://192.168.11.23:6400"

+ 4 - 3
.env.production

@@ -1,3 +1,4 @@
-VITE_API_BASE_URL="https://coldverify.coldbaozhida.com/api"
-VITE_API_LOCAL_BASE_URL="http://192.168.11.23:6400"
-VITE_API_COLD_BASE_URL="https://cold.coldbaozhida.com/api"
+VITE_API_BASE_URL1="https://coldverify.coldbaozhida.com/api"
+VITE_API_BASE_URL2="http://coldverifylocal.coldbaozhida.com"
+VITE_API_BASE_URL3="https://cold.coldbaozhida.com/api"
+VITE_API_BASE_URL4="http://192.168.11.23:6400"

+ 10 - 9
src/api/index.js

@@ -1,9 +1,10 @@
-export * from "./modules/base";
-export * from "./modules/Device";
-export * from "./modules/DeviceClass";
-export * from "./modules/DeviceClassList";
-export * from "./modules/Task";
-export * from "./modules/TaskData";
-export * from "./modules/VerifyTemplateMapData";
-export * from "./modules/Data";
-export * from "./modules/GenerateReport";
+export * from './modules/base';
+export * from './modules/Device';
+export * from './modules/DeviceClass';
+export * from './modules/DeviceClassList';
+export * from './modules/Task';
+export * from './modules/TaskData';
+export * from './modules/VerifyTemplateMapData';
+export * from './modules/Data';
+export * from './modules/GenerateReport';
+export * from './modules/Certificate';

+ 12 - 0
src/api/modules/Certificate.js

@@ -0,0 +1,12 @@
+import service from '@/utils/axios';
+import { baseURL1 } from '../../constant';
+
+//
+export const getCertificate = (data) => {
+  return service.request({
+    method: 'POST',
+    url: '/Certificate/Get',
+    data,
+    baseURL: baseURL1,
+  });
+};

+ 5 - 4
src/api/modules/Data.js

@@ -1,10 +1,11 @@
-import service from "@/utils/axios";
-import { coldBaseUrl } from "@/constant";
+import service from '@/utils/axios';
+import { baseURL3 } from '../../constant';
 
 export const getV3DataList = (data) => {
   return service.request({
-    method: "POST",
-    url: `${coldBaseUrl}/v3/Data/List`,
+    method: 'POST',
+    url: '/v3/Data/List',
     data,
+    baseURL: baseURL3,
   });
 };

+ 5 - 3
src/api/modules/Device.js

@@ -1,10 +1,12 @@
-import service from "@/utils/axios";
+import service from '@/utils/axios';
+import { baseURL1 } from '../../constant';
 
 // 设备管理(列表)
 export const getDeviceList = (data) => {
   return service.request({
-    method: "POST",
-    url: "/Device/List",
+    method: 'POST',
+    url: '/Device/List',
     data,
+    baseURL: baseURL1,
   });
 };

+ 8 - 5
src/api/modules/DeviceClass.js

@@ -1,19 +1,22 @@
-import service from "@/utils/axios";
+import service from '@/utils/axios';
+import { baseURL1 } from '../../constant';
 
 // 设备分类(获取)
 export const getDeviceClass = (data) => {
   return service.request({
-    method: "POST",
-    url: "/DeviceClass/Get",
+    method: 'POST',
+    url: '/DeviceClass/Get',
     data,
+    baseURL: baseURL1,
   });
 };
 
 // 设备分类(编辑)
 export const editDeviceClass = (data) => {
   return service.request({
-    method: "POST",
-    url: "/DeviceClass/Up",
+    method: 'POST',
+    url: '/DeviceClass/Up',
     data,
+    baseURL: baseURL1,
   });
 };

+ 14 - 9
src/api/modules/DeviceClassList.js

@@ -1,37 +1,42 @@
-import service from "@/utils/axios";
+import service from '@/utils/axios';
+import { baseURL1 } from '../../constant';
 
 // 设备分类-设备列表(列表)
 export const getDeviceClassListList = (data) => {
   return service.request({
-    method: "POST",
-    url: "/DeviceClassList/List",
+    method: 'POST',
+    url: '/DeviceClassList/List',
     data,
+    baseURL: baseURL1,
   });
 };
 
 // 设备分类-设备列表(添加)
 export const addDeviceClassList = (data) => {
   return service.request({
-    method: "POST",
-    url: "/DeviceClassList/Add",
+    method: 'POST',
+    url: '/DeviceClassList/Add',
     data,
+    baseURL: baseURL1,
   });
 };
 
 // 设备分类-设备列表(编辑)
 export const editDeviceClassList = (data) => {
   return service.request({
-    method: "POST",
-    url: "/DeviceClassList/Up",
+    method: 'POST',
+    url: '/DeviceClassList/Up',
     data,
+    baseURL: baseURL1,
   });
 };
 
 // 设备分类-设备列表(删除)
 export const deleteDeviceClassList = (data) => {
   return service.request({
-    method: "POST",
-    url: "/DeviceClassList/Del",
+    method: 'POST',
+    url: '/DeviceClassList/Del',
     data,
+    baseURL: baseURL1,
   });
 };

+ 6 - 4
src/api/modules/GenerateReport.js

@@ -1,5 +1,4 @@
 import service from '@/utils/axios';
-import { coldBaseUrl } from '@/constant';
 
 /**
  * 验证报告生成 方案
@@ -9,8 +8,9 @@ import { coldBaseUrl } from '@/constant';
 export const generateScheme = (data) => {
   return service.request({
     method: 'POST',
-    url: `${coldBaseUrl}/GenerateReport/Generate_scheme`,
+    url: '/GenerateReport/Generate_scheme',
     data,
+    baseURL: '/api2',
   });
 };
 
@@ -22,8 +22,9 @@ export const generateScheme = (data) => {
 export const generateReport = (data) => {
   return service.request({
     method: 'POST',
-    url: `${coldBaseUrl}/GenerateReport/Generate_report`,
+    url: '/GenerateReport/Generate_report',
     data,
+    baseURL: '/api2',
   });
 };
 
@@ -35,7 +36,8 @@ export const generateReport = (data) => {
 export const generateKey = (data) => {
   return service.request({
     method: 'POST',
-    url: `${coldBaseUrl}/GenerateReport/Generate_key`,
+    url: '/GenerateReport/Generate_key',
     data,
+    baseURL: '/api2',
   });
 };

+ 11 - 7
src/api/modules/Task.js

@@ -1,4 +1,5 @@
-import service from "@/utils/axios";
+import service from '@/utils/axios';
+import { baseURL1 } from '../../constant';
 
 /**
  * 任务(获取)
@@ -7,9 +8,10 @@ import service from "@/utils/axios";
  */
 export const getTask = (data) => {
   return service.request({
-    method: "POST",
-    url: "/Task/Get",
+    method: 'POST',
+    url: '/Task/Get',
     data,
+    baseURL: baseURL1,
   });
 };
 
@@ -20,9 +22,10 @@ export const getTask = (data) => {
  */
 export const getTaskList = (data) => {
   return service.request({
-    method: "POST",
-    url: "/Task/List",
+    method: 'POST',
+    url: '/Task/List',
     data,
+    baseURL: baseURL1,
   });
 };
 
@@ -33,8 +36,9 @@ export const getTaskList = (data) => {
  */
 export const editTask = (data) => {
   return service.request({
-    method: "POST",
-    url: "/Task/Up",
+    method: 'POST',
+    url: '/Task/Up',
     data,
+    baseURL: baseURL1,
   });
 };

+ 35 - 24
src/api/modules/TaskData.js

@@ -1,101 +1,112 @@
-import service from "@/utils/axios";
-import { localBaseUrl } from "@/constant";
+import service from '@/utils/axios';
+import { baseURL4 } from '@/constant';
 
 // 任务数据 设备列表
 export const getTaskDataClassList = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/TaskDataClass_List`,
+    method: 'POST',
+    url: '/TaskData/TaskDataClass_List',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 任务数据(列表)
 export const checkTaskData = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/Check`,
+    method: 'POST',
+    url: '/TaskData/Check',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 任务数据(提取数据)
 export const extractTaskData = (data) => {
   return service.request({
-    method: "POST",
-    url: "/TaskData/Extract_TaskData",
+    method: 'POST',
+    url: '/TaskData/Extract_TaskData',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 设备分类-设备列表(列表)
 export const getTaskDataList = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/List`,
+    method: 'POST',
+    url: '/TaskData/List',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 更新线上数据
 export const updateTaskData = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/Up_TaskData`,
+    method: 'POST',
+    url: '/TaskData/Up_TaskData',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 任务数据(添加)
 export const addTaskData = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/Add`,
+    method: 'POST',
+    url: '/TaskData/Add',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 任务数据(编辑)
 export const editTaskData = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/Up`,
+    method: 'POST',
+    url: '/TaskData/Up',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 任务数据(编辑)
 export const deleteTaskData = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/Del`,
+    method: 'POST',
+    url: '/TaskData/Del',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 任务数据(导出excel)
 export const exportTaskData = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/Export_Data_Excel`,
+    method: 'POST',
+    url: '/TaskData/Export_Data_Excel',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 任务数据 设备编辑
 export const editTaskDataClass = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/TaskDataClass_Edit`,
+    method: 'POST',
+    url: '/TaskData/TaskDataClass_Edit',
     data,
+    baseURL: baseURL4,
   });
 };
 
 // 任务数据 设备删除
 export const deleteTaskDataClass = (data) => {
   return service.request({
-    method: "POST",
-    url: `${localBaseUrl}/TaskData/TaskDataClass_Del`,
+    method: 'POST',
+    url: '/TaskData/TaskDataClass_Del',
     data,
+    baseURL: baseURL4,
   });
 };

+ 8 - 5
src/api/modules/VerifyTemplateMapData.js

@@ -1,4 +1,5 @@
-import service from "@/utils/axios";
+import service from '@/utils/axios';
+import { baseURL1 } from '../../constant';
 
 /**
  * 验证模板-模板标签数据(列表)
@@ -7,9 +8,10 @@ import service from "@/utils/axios";
  */
 export const getVerifyTemplateMapDataList = (data) => {
   return service.request({
-    method: "POST",
-    url: "/VerifyTemplateMapData/List",
+    method: 'POST',
+    url: '/VerifyTemplateMapData/List',
     data,
+    baseURL: baseURL1,
   });
 };
 
@@ -20,8 +22,9 @@ export const getVerifyTemplateMapDataList = (data) => {
  */
 export const putVerifyTemplateMapData = (data) => {
   return service.request({
-    method: "POST",
-    url: "/VerifyTemplateMapData/Pu",
+    method: 'POST',
+    url: '/VerifyTemplateMapData/Pu',
     data,
+    baseURL: baseURL1,
   });
 };

+ 8 - 5
src/api/modules/base.js

@@ -1,20 +1,23 @@
-import service from "@/utils/axios";
+import service from '@/utils/axios';
+import { baseURL1 } from '../../constant';
 
 // 登录
 export const login = (data, role) => {
   return service.request({
-    method: "POST",
+    method: 'POST',
     url:
-      role === "管理员" ? "/Login_Admin_verification" : "/Login_verification",
+      role === '管理员' ? '/Login_Admin_verification' : '/Login_verification',
     data,
+    baseURL: baseURL1,
   });
 };
 
 // 获取上传token
 export const getUpFileToken = (data) => {
   return service.request({
-    method: "POST",
-    url: "/UpFileToken",
+    method: 'POST',
+    url: '/UpFileToken',
     data,
+    baseURL: baseURL1,
   });
 };

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 0 - 0
src/assets/data.json


+ 10 - 6
src/constant/index.js

@@ -1,13 +1,17 @@
-import { computed } from "vue";
+import { computed } from 'vue';
 
-export const TOKEN = "User_tokey";
+export const TOKEN = 'User_tokey';
 
-export const localBaseUrl = import.meta.env.VITE_API_LOCAL_BASE_URL;
+export const baseURL1 = import.meta.env.VITE_API_BASE_URL1;
 
-export const coldBaseUrl = import.meta.env.VITE_API_COLD_BASE_URL;
+export const baseURL2 = import.meta.env.VITE_API_BASE_URL2;
+
+export const baseURL3 = import.meta.env.VITE_API_BASE_URL3;
+
+export const baseURL4 = import.meta.env.VITE_API_BASE_URL4;
 
 export const task = computed(() => {
-  return window.sessionStorage.getItem("task")
-    ? JSON.parse(window.sessionStorage.getItem("task"))
+  return window.sessionStorage.getItem('task')
+    ? JSON.parse(window.sessionStorage.getItem('task'))
     : {};
 });

+ 8 - 8
src/layout/index.vue

@@ -24,15 +24,15 @@
 </template>
 
 <script setup>
-import { NIcon } from "naive-ui";
-import { removeToken } from "@/utils/storage/sessionToken";
-import { LogoutOutlined as LogoutIcon } from "@vicons/antd";
+import { NIcon } from 'naive-ui';
+import { removeToken } from '@/utils/storage/sessionToken';
+import { LogoutOutlined as LogoutIcon } from '@vicons/antd';
 
 const router = useRouter();
 
 const message = useMessage();
 
-const username = window.sessionStorage.getItem("username");
+const username = window.sessionStorage.getItem('username');
 
 const renderIcon = (icon) => {
   return () => {
@@ -45,8 +45,8 @@ const renderIcon = (icon) => {
 // 下拉菜单传入的 options
 const options = [
   {
-    label: "退出登录",
-    key: "/logout",
+    label: '退出登录',
+    key: '/logout',
     icon: renderIcon(LogoutIcon),
   },
 ];
@@ -54,8 +54,8 @@ const options = [
 // select 选中时触发的回调函数
 const handleSelect = () => {
   removeToken();
-  message.success("退出登录成功");
-  router.replace("/login");
+  message.success('退出登录成功');
+  router.replace('/login');
 };
 </script>
 

+ 7 - 8
src/utils/axios.js

@@ -1,7 +1,7 @@
-import axios from "axios";
-import { getToken } from "@/utils/storage/sessionToken";
-import { TOKEN } from "@/constant";
-import { loadingBar, message } from "@/plugin/naive-ui";
+import axios from 'axios';
+import { getToken } from '@/utils/storage/sessionToken';
+import { TOKEN } from '@/constant';
+import { loadingBar, message } from '@/plugin/naive-ui';
 
 // 显示消息
 const showMessage = (res) => {
@@ -11,7 +11,6 @@ const showMessage = (res) => {
 };
 
 const service = axios.create({
-  baseURL: import.meta.env.VITE_API_BASE_URL,
   timeout: 1000 * 60 * 8,
 });
 
@@ -21,11 +20,11 @@ service.interceptors.request.use(
     // 在发送请求之前做些什么
     loadingBar.start();
     const token = getToken();
-    if (config.url !== "/VerifyTemplateMapData/Pu") {
+    if (config.url !== '/VerifyTemplateMapData/Pu') {
       const formData = new FormData();
       if (
-        config.url !== "/Login_Admin_verification" &&
-        config.url !== "/Login_verification"
+        config.url !== '/Login_Admin_verification' &&
+        config.url !== '/Login_verification'
       ) {
         formData.append(TOKEN, token);
       }

+ 22 - 57
src/views/certificate/index.vue

@@ -3,7 +3,7 @@
     <n-page-header @back="$router.back">
       <template #title> 校准证书 </template>
     </n-page-header>
-    <div class="flex-1 grid grid-cols-[400px,1fr] gap-x-3">
+    <div class="flex-1 grid grid-cols-2 gap-x-3">
       <n-card>
         <n-list class="h-full">
           <template #header>
@@ -33,7 +33,7 @@
                   style="cursor: pointer"
                   @click="handleView(item)"
                 >
-                  {{ item.slice(item.lastIndexOf("-") + 1) }}
+                  {{ item.slice(item.lastIndexOf('-') + 1) }}
                 </n-card>
               </n-list-item>
             </template>
@@ -77,33 +77,26 @@
     :title="modal.title"
     positive-text="确认"
     negative-text="取消"
-    @positive-click="editTaskInfo"
+    @positive-click="addCertificate"
   >
     <n-form :model="formValue" label-width="auto" show-require-mark>
-      <n-form-item label="名称" path="T_name">
-        <n-input v-model:value="formValue.T_name" />
-      </n-form-item>
-      <n-form-item label="证书" path="T_pdf3">
-        <n-upload :default-upload="false" :max="1" @change="handleChange">
-          <n-button> 上传文件 </n-button>
-        </n-upload>
+      <n-form-item label="SN" path="T_sn">
+        <n-input v-model:value="formValue.T_sn" />
       </n-form-item>
     </n-form>
   </n-modal>
 </template>
 
 <script setup>
-import VuePdfEmbed from "vue-pdf-embed";
-import { PrinterOutlined as PrinterIcon } from "@vicons/antd";
-import { editTask, getTask } from "@/api";
-import * as qiniu from "qiniu-js";
-import { getFileToken } from "@/common";
-import { useWindowSize } from "@vueuse/core";
+import VuePdfEmbed from 'vue-pdf-embed';
+import { PrinterOutlined as PrinterIcon } from '@vicons/antd';
+import { getCertificate, getTask } from '@/api';
+import { useWindowSize } from '@vueuse/core';
 
 const { height } = useWindowSize();
 
-const task = window.sessionStorage.getItem("task")
-  ? JSON.parse(window.sessionStorage.getItem("task"))
+const task = window.sessionStorage.getItem('task')
+  ? JSON.parse(window.sessionStorage.getItem('task'))
   : {};
 
 const message = useMessage();
@@ -111,7 +104,7 @@ const message = useMessage();
 const pdfRef = ref(null);
 
 //
-const source = ref("");
+const source = ref('');
 
 // 任务信息
 const taskInfo = ref({});
@@ -121,14 +114,13 @@ const dataList = ref([]);
 
 // 模态框数据源
 const modal = reactive({
-  title: "",
+  title: '',
   showModal: false,
 });
 
 // 表单数据
 const formValue = reactive({
-  T_name: null,
-  T_pdf3: null,
+  T_sn: null,
 });
 
 // 打印pdf
@@ -138,16 +130,16 @@ const onPrint = () => {
 
 //
 const handleView = (row) => {
-  source.value = row.slice(0, row.lastIndexOf("-"));
+  source.value = row.slice(0, row.lastIndexOf('-'));
 };
 
 //
 const handleDelete = async (row) => {
   const arr = dataList.value.filter((item) => item !== row);
   try {
-    const { data: res } = await editTask({
+    const { data: res } = await getCertificate({
       T_task_id: task.T_task_id,
-      T_pdf3: arr.join("|"),
+      T_pdf3: arr.join('|'),
     });
     message.success(res.Msg);
     getTaskInfo();
@@ -156,44 +148,17 @@ const handleDelete = async (row) => {
   }
 };
 
-//
-const handleChange = async ({ file }) => {
-  const token = await getFileToken(file.name.split("/")[1]);
-  const observable = qiniu.upload(
-    file.file,
-    file.name,
-    token,
-    {},
-    {
-      useCdnDomain: true,
-    }
-  );
-  observable.subscribe({
-    next: (result) => {
-      // 主要用来展示进度
-      console.warn(result);
-    },
-    error: () => {
-      message.error("上传失败");
-    },
-    complete: (res) => {
-      formValue.T_pdf3 = `${res.key}-${formValue.T_name}|`;
-    },
-  });
-};
-
 // 显示添加
 const showAddModal = () => {
-  modal.title = "新增";
+  modal.title = '添加设备';
   modal.showModal = true;
 };
 
 // 添加
-const editTaskInfo = async () => {
+const addCertificate = async () => {
   try {
-    const { data: res } = await editTask({
-      T_task_id: task.T_task_id,
-      T_pdf3: taskInfo.value.T_pdf3 + formValue.T_pdf3,
+    const { data: res } = await getCertificate({
+      T_sn: formValue.T_sn,
     });
     message.success(res.Msg);
     getTaskInfo();
@@ -209,7 +174,7 @@ const getTaskInfo = async () => {
       T_task_id: task.T_task_id,
     });
     taskInfo.value = res.Data || {};
-    dataList.value = res.Data.T_pdf3.split("|").filter((item) => item);
+    dataList.value = res.Data.T_pdf3.split('|').filter((item) => item);
   } catch (e) {
     console.log(e);
   }

+ 27 - 27
src/views/data/source/index.vue

@@ -70,25 +70,25 @@
 </template>
 
 <script setup>
-import { NSpace, NButton } from "naive-ui";
-import { extractTaskData, getTaskDataList } from "@/api";
-import { useNow, useDateFormat } from "@vueuse/core";
+import { NSpace, NButton } from 'naive-ui';
+import { extractTaskData, getTaskDataList } from '@/api';
+import { useNow, useDateFormat } from '@vueuse/core';
 
-const formatted = useDateFormat(useNow(), "YYYY-MM-DD HH:mm:ss");
+const formatted = useDateFormat(useNow(), 'YYYY-MM-DD HH:mm:ss');
 
 const dialog = useDialog();
 
 const notification = useNotification();
 
-const task = window.sessionStorage.getItem("task")
-  ? JSON.parse(window.sessionStorage.getItem("task"))
+const task = window.sessionStorage.getItem('task')
+  ? JSON.parse(window.sessionStorage.getItem('task'))
   : {};
 
 // 查询数据
 const queryData = reactive({
   T_task_id: task.T_task_id,
-  T_sn: "",
-  T_id: "",
+  T_sn: '',
+  T_id: '',
   Time_start: null,
   Time_end: null,
   page: 1,
@@ -101,20 +101,20 @@ const taskList = ref([]);
 // 需要展示的列
 const columns = [
   {
-    title: "SN",
-    key: "T_sn",
+    title: 'SN',
+    key: 'T_sn',
   },
   {
-    title: "温度℃",
-    key: "T_t",
+    title: '温度℃',
+    key: 'T_t',
   },
   {
-    title: "湿度%",
-    key: "T_rh",
+    title: '湿度%',
+    key: 'T_rh',
   },
   {
-    title: "记录时间",
-    key: "T_time",
+    title: '记录时间',
+    key: 'T_time',
   },
 ];
 
@@ -135,8 +135,8 @@ const showModal = ref(false);
 
 //
 const handleSearch = () => {
-  queryData.T_id = "";
-  queryData.T_sn = "";
+  queryData.T_id = '';
+  queryData.T_sn = '';
   showModal.value = false;
   extractTask();
 };
@@ -144,10 +144,10 @@ const handleSearch = () => {
 // 重置
 const handleReset = () => {
   dialog.warning({
-    title: "警告",
-    content: "是否确认重置数据?",
-    positiveText: "确认",
-    negativeText: "取消",
+    title: '警告',
+    content: '是否确认重置数据?',
+    positiveText: '确认',
+    negativeText: '取消',
     onPositiveClick: () => {
       showModal.value = true;
     },
@@ -159,12 +159,12 @@ const extractTask = async () => {
   try {
     const { data: res } = await extractTaskData({
       T_task_id: queryData.T_task_id,
-      Time_start: queryData.Time_start !== null ? queryData.Time_start : "",
-      Time_end: queryData.Time_end !== null ? queryData.Time_end : "",
+      Time_start: queryData.Time_start !== null ? queryData.Time_start : '',
+      Time_end: queryData.Time_end !== null ? queryData.Time_end : '',
     });
     if (res.Code === 200) {
       notification.info({
-        title: "数据采集完成",
+        title: '数据采集完成',
         description: `${queryData.Time_start} 至 ${queryData.Time_end}`,
         meta: `当前时间:${formatted.value}`,
         duration: 2500,
@@ -182,8 +182,8 @@ const getDataList = async () => {
   try {
     const { data: res } = await getTaskDataList({
       ...queryData,
-      Time_start: queryData.Time_start !== null ? queryData.Time_start : "",
-      Time_end: queryData.Time_end !== null ? queryData.Time_end : "",
+      Time_start: queryData.Time_start !== null ? queryData.Time_start : '',
+      Time_end: queryData.Time_end !== null ? queryData.Time_end : '',
     });
     pagination.itemCount = res.Data.Num;
     if (!res.Data.List) {

+ 77 - 84
src/views/project/index.vue

@@ -11,24 +11,17 @@
 </template>
 
 <script setup>
-import { h } from "vue";
-import {
-  NButton,
-  NSpace,
-  NCard,
-  NTag,
-  NIcon,
-  NTooltip,
-} from "naive-ui";
-import { getTaskList } from "@/api";
-import { ArrowRightOutlined as ArrowRightIcon } from "@vicons/antd";
+import { h } from 'vue';
+import { NButton, NSpace, NCard, NTag, NIcon, NTooltip } from 'naive-ui';
+import { getTaskList } from '@/api';
+import { ArrowRightOutlined as ArrowRightIcon } from '@vicons/antd';
 
 const router = useRouter();
 
 // 查询参数
 const queryData = reactive({
-  T_uuid: "",
-  T_name: "",
+  T_uuid: '',
+  T_name: '',
   page: 1,
   page_z: 10,
 });
@@ -46,24 +39,24 @@ const renderTooltip = (trigger, content) => {
 // 需要展示的列
 const columns = [
   {
-    title: "公司名称",
-    key: "T_user_name",
+    title: '公司名称',
+    key: 'T_user_name',
     width: 180,
   },
   {
-    title: "报告名称",
-    key: "T_name",
+    title: '报告名称',
+    key: 'T_name',
     width: 180,
   },
   {
-    title: "截止时间",
-    key: "T_deadline",
+    title: '截止时间',
+    key: 'T_deadline',
     width: 180,
   },
   {
     title() {
       return renderTooltip(
-        "流程(?)",
+        '流程(?)',
         [0, 1, 2, 3].map((item) =>
           h(
             NTag,
@@ -71,23 +64,23 @@ const columns = [
               bordered: false,
               type:
                 item === 0
-                  ? "error"
+                  ? 'error'
                   : item === 1
-                  ? "success"
+                  ? 'success'
                   : item === 2
-                  ? "warning"
-                  : "default",
+                  ? 'warning'
+                  : 'default',
             },
             {
               default: () => {
                 if (item === 0) {
-                  return "未完成";
+                  return '未完成';
                 } else if (item === 1) {
-                  return "已完成";
+                  return '已完成';
                 } else if (item === 2) {
-                  return "处理中";
+                  return '处理中';
                 } else {
-                  return "已采集-无数据";
+                  return '已采集-无数据';
                 }
               },
             }
@@ -95,13 +88,13 @@ const columns = [
         )
       );
     },
-    key: "T_task_id",
+    key: 'T_task_id',
     width: 460,
     render(row) {
       return h(
         NSpace,
         {
-          align: "center",
+          align: 'center',
         },
         {
           default: () => [
@@ -109,11 +102,11 @@ const columns = [
               NCard,
               {
                 style: {
-                  width: "70px",
-                  height: "50px",
+                  width: '70px',
+                  height: '50px',
                 },
                 contentStyle: {
-                  textAlign: "center",
+                  textAlign: 'center',
                   padding: 0,
                 },
               },
@@ -123,26 +116,26 @@ const columns = [
                   h(
                     NTag,
                     {
-                      class: "w-full",
-                      type: row.T_scheme_state === 0 ? "error" : "success",
+                      class: 'w-full',
+                      type: row.T_scheme_state === 0 ? 'error' : 'success',
                       bordered: false,
                     },
                     {
-                      default: () => "实施方案",
+                      default: () => '实施方案',
                     }
                   ),
               }
             ),
             h(
               NIcon,
-              { size: 25, component: ArrowRightIcon, color: "#0e7a0d" },
+              { size: 25, component: ArrowRightIcon, color: '#0e7a0d' },
               {}
             ),
             h(
               NCard,
               {
                 contentStyle: {
-                  textAlign: "center",
+                  textAlign: 'center',
                   padding: 0,
                 },
               },
@@ -152,33 +145,33 @@ const columns = [
                   h(
                     NTag,
                     {
-                      class: "w-full",
+                      class: 'w-full',
                       type:
                         row.T_collection_state === 0
-                          ? "error"
+                          ? 'error'
                           : row.T_collection_state === 1
-                          ? "success"
+                          ? 'success'
                           : row.T_collection_state === 2
-                          ? "warning"
-                          : "default",
+                          ? 'warning'
+                          : 'default',
                       bordered: false,
                     },
                     {
-                      default: () => "数据采集",
+                      default: () => '数据采集',
                     }
                   ),
               }
             ),
             h(
               NIcon,
-              { size: 25, component: ArrowRightIcon, color: "#0e7a0d" },
+              { size: 25, component: ArrowRightIcon, color: '#0e7a0d' },
               {}
             ),
             h(
               NCard,
               {
                 contentStyle: {
-                  textAlign: "center",
+                  textAlign: 'center',
                   padding: 0,
                 },
               },
@@ -188,26 +181,26 @@ const columns = [
                   h(
                     NTag,
                     {
-                      class: "w-full",
-                      type: row.T_reporting_state === 0 ? "error" : "success",
+                      class: 'w-full',
+                      type: row.T_reporting_state === 0 ? 'error' : 'success',
                       bordered: false,
                     },
                     {
-                      default: () => "报告编写",
+                      default: () => '报告编写',
                     }
                   ),
               }
             ),
             h(
               NIcon,
-              { size: 25, component: ArrowRightIcon, color: "#0e7a0d" },
+              { size: 25, component: ArrowRightIcon, color: '#0e7a0d' },
               {}
             ),
             h(
               NCard,
               {
                 contentStyle: {
-                  textAlign: "center",
+                  textAlign: 'center',
                   padding: 0,
                 },
               },
@@ -217,17 +210,17 @@ const columns = [
                   h(
                     NTag,
                     {
-                      class: "w-full",
+                      class: 'w-full',
                       type:
                         row.T_delivery_state === 0
-                          ? "error"
+                          ? 'error'
                           : row.T_delivery_state === 1
-                          ? "success"
-                          : "warning",
+                          ? 'success'
+                          : 'warning',
                       bordered: false,
                     },
                     {
-                      default: () => "交付审核",
+                      default: () => '交付审核',
                     }
                   ),
               }
@@ -238,44 +231,44 @@ const columns = [
     },
   },
   {
-    title: "操作",
-    key: "actions",
+    title: '操作',
+    key: 'actions',
     render(row) {
       return h(NSpace, null, {
         default: () =>
           [
-            "实施方案",
-            "校准证书",
-            "设备管理",
-            "数据来源",
-            "数据编辑",
-            "数据校验",
-            "报告生成",
-            "报告审核",
+            '实施方案',
+            '校准证书',
+            '设备管理',
+            '数据来源',
+            '数据编辑',
+            '数据校验',
+            '报告生成',
+            '报告审核',
           ].map((item) =>
             h(
               NButton,
               {
-                type: "primary",
-                size: "small",
+                type: 'primary',
+                size: 'small',
                 onClick: () => {
-                  window.sessionStorage.setItem("task", JSON.stringify(row));
-                  if (item === "实施方案") {
-                    router.push("/scheme");
-                  } else if (item === "校准证书") {
-                    router.push("/certificate");
-                  } else if (item === "设备管理") {
-                    router.push("/equipment");
-                  } else if (item === "数据来源") {
-                    router.push("/data_source");
-                  } else if (item === "数据编辑") {
-                    router.push("/data_edit");
-                  } else if (item === "数据校验") {
-                    router.push("/data_checkout");
-                  } else if (item === "报告生成") {
-                    router.push("/report_create");
+                  window.sessionStorage.setItem('task', JSON.stringify(row));
+                  if (item === '实施方案') {
+                    router.push('/scheme');
+                  } else if (item === '校准证书') {
+                    router.push('/certificate');
+                  } else if (item === '设备管理') {
+                    router.push('/equipment');
+                  } else if (item === '数据来源') {
+                    router.push('/data_source');
+                  } else if (item === '数据编辑') {
+                    router.push('/data_edit');
+                  } else if (item === '数据校验') {
+                    router.push('/data_checkout');
+                  } else if (item === '报告生成') {
+                    router.push('/report_create');
                   } else {
-                    router.push("/report_audit");
+                    router.push('/report_audit');
                   }
                 },
               },

+ 257 - 172
src/views/report/create/index.vue

@@ -9,157 +9,162 @@
         </n-space>
       </template>
     </n-page-header>
-    <n-form
-      label-placement="left"
-      label-width="auto"
-      size="large"
-      show-require-mark
-      class="w-2/5 mx-auto"
-    >
-      <template
-        v-for="(item, i) of templateList"
-        :key="item.T_VerifyTemplateMap_id"
+    <n-scrollbar :style="{ maxHeight: `${height - 200}px` }" trigger="none">
+      <n-form
+        label-placement="left"
+        label-width="auto"
+        size="large"
+        show-require-mark
+        class="w-2/5 mx-auto"
       >
-        <n-form-item :label="item.T_name" v-if="item.T_label === 1">
-          <n-input v-model:value="item.T_value" />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 2">
-          <n-input v-model:value="item.T_value" />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 3">
-          <n-select
-            v-model:value="item.T_value"
-            multiple
-            label-field="T_sn"
-            value-field="T_sn"
-            max-tag-count="responsive"
-            :options="classList"
-          >
-            <template #action>
-              <n-space>
-                <n-button class="underline" text @click="handleSelectAll(i)"
-                  >全选</n-button
-                >
-                <n-button class="underline" text @click="handleSelectReverse(i)"
-                  >反选</n-button
-                >
-              </n-space>
-            </template>
-          </n-select>
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 4">
-          <n-select
-            label-field="T_sn"
-            value-field="T_sn"
-            v-model:value="item.T_value"
-            :options="classList"
-          />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-divider v-else-if="item.T_label === 5" />
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 7">
-          <n-date-picker
-            v-model:formatted-value="item.T_value"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            type="datetime"
-            clearable
-            class="w-full"
-          />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 9">
-          <n-date-picker
-            v-model:formatted-value="item.T_value"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            type="datetimerange"
-            clearable
-            class="w-full"
-          />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 10">
-          <n-image class="mr-5" width="100" :src="item.T_value" />
-          <n-upload
-            @change="(options) => handleChangeByIndex(options, i)"
-            :default-upload="false"
-            :max="1"
-          >
-            <n-button>{{ item.T_value ? "重新上传" : "点击上传" }}</n-button>
-          </n-upload>
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 11">
-          <n-image class="mr-5" width="100" :src="item.T_value" />
-          <n-upload
-            @change="(options) => handleChangeByIndex(options, i)"
-            :default-upload="false"
-            :max="1"
-          >
-            <n-button>{{ item.T_value ? "重新上传" : "点击上传" }}</n-button>
-          </n-upload>
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-      </template>
-    </n-form>
+        <template
+          v-for="(item, i) of templateList"
+          :key="item.T_VerifyTemplateMap_id"
+        >
+          <n-form-item :label="item.T_name" v-if="item.T_label === 1">
+            <n-input v-model:value="item.T_value" />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 2">
+            <n-input v-model:value="item.T_value" />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 3">
+            <n-select
+              v-model:value="item.T_value"
+              multiple
+              label-field="T_sn"
+              value-field="T_sn"
+              max-tag-count="responsive"
+              :options="classList"
+            >
+              <template #action>
+                <n-space>
+                  <n-button class="underline" text @click="handleSelectAll(i)"
+                    >全选</n-button
+                  >
+                  <n-button
+                    class="underline"
+                    text
+                    @click="handleSelectReverse(i)"
+                    >反选</n-button
+                  >
+                </n-space>
+              </template>
+            </n-select>
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 4">
+            <n-select
+              label-field="T_sn"
+              value-field="T_sn"
+              v-model:value="item.T_value"
+              :options="classList"
+            />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-divider v-else-if="item.T_label === 5" />
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 7">
+            <n-date-picker
+              v-model:formatted-value="item.T_value"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              type="datetime"
+              clearable
+              class="w-full"
+            />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 9">
+            <n-date-picker
+              v-model:formatted-value="item.T_value"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              type="datetimerange"
+              clearable
+              class="w-full"
+            />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 10">
+            <n-image class="mr-5" width="100" :src="item.T_value" />
+            <n-upload
+              @change="(options) => handleChangeByIndex(options, i)"
+              :default-upload="false"
+              :max="1"
+            >
+              <n-button>{{ item.T_value ? '重新上传' : '点击上传' }}</n-button>
+            </n-upload>
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 11">
+            <n-image class="mr-5" width="100" :src="item.T_value" />
+            <n-upload
+              @change="(options) => handleChangeByIndex(options, i)"
+              :default-upload="false"
+              :max="1"
+            >
+              <n-button>{{ item.T_value ? '重新上传' : '点击上传' }}</n-button>
+            </n-upload>
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+        </template>
+      </n-form>
+    </n-scrollbar>
   </div>
   <n-modal
     v-model:show="modal.showModal"
@@ -182,22 +187,30 @@ import {
   editTask,
   getTaskDataClassList,
   getVerifyTemplateMapDataList,
-} from "@/api";
-import * as qiniu from "qiniu-js";
-import { getToken } from "@/utils/storage/sessionToken";
-import { getFileToken } from "@/common";
-import { InformationCircleOutline } from "@vicons/ionicons5";
+  generateReport,
+  generateKey,
+} from '@/api';
+import * as qiniu from 'qiniu-js';
+import { getToken } from '@/utils/storage/sessionToken';
+import { getFileToken } from '@/common';
+import { InformationCircleOutline } from '@vicons/ionicons5';
+import { useWindowSize } from '@vueuse/core';
+import { NButton } from 'naive-ui';
+
+const { height } = useWindowSize();
 
 const message = useMessage();
 
 const dialog = useDialog();
 
-const task = window.sessionStorage.getItem("task")
-  ? JSON.parse(window.sessionStorage.getItem("task"))
+const notification = useNotification();
+
+const task = window.sessionStorage.getItem('task')
+  ? JSON.parse(window.sessionStorage.getItem('task'))
   : {};
 
 // 获取表项中收集到的值的对象
-const pdf2 = ref("");
+const pdf2 = ref('');
 
 // 查询数据
 const queryData = reactive({
@@ -218,7 +231,7 @@ const modal = reactive({
 });
 
 const handleChangeByIndex = async ({ file }, i) => {
-  const token = await getFileToken(file.name.split(".")[1]);
+  const token = await getFileToken(file.name.split('.')[1]);
   const observable = qiniu.upload(
     file.file,
     file.name,
@@ -234,7 +247,7 @@ const handleChangeByIndex = async ({ file }, i) => {
       console.warn(result);
     },
     error: () => {
-      message.error("上传失败");
+      message.error('上传失败');
     },
     complete: (res) => {
       templateList.value[i].T_value = res.key;
@@ -244,7 +257,7 @@ const handleChangeByIndex = async ({ file }, i) => {
 
 //
 const handleChange = async ({ file }) => {
-  const token = await getFileToken(file.name.split("/")[1]);
+  const token = await getFileToken(file.name.split('/')[1]);
   const observable = qiniu.upload(
     file.file,
     file.name,
@@ -260,7 +273,7 @@ const handleChange = async ({ file }) => {
       console.warn(result);
     },
     error: () => {
-      message.error("上传失败");
+      message.error('上传失败');
     },
     complete: (res) => {
       pdf2.value = res.key;
@@ -286,7 +299,7 @@ const handleSelectReverse = (i) => {
 
 //
 const showUploadModal = () => {
-  modal.title = "上传验证";
+  modal.title = '上传验证';
   modal.showModal = true;
 };
 
@@ -308,16 +321,77 @@ const editTaskInfo = async () => {
 //
 const showCreateDialog = async () => {
   dialog.info({
-    title: "提示",
-    content: "确认生成报告?",
-    positiveText: "确定",
-    negativeText: "取消",
+    title: '提示',
+    content: '确认生成报告?',
+    positiveText: '确定',
+    negativeText: '取消',
     onPositiveClick: () => {
       putTemplateData();
     },
   });
 };
 
+const reportKey = ref('');
+
+/**
+ * 生成报告
+ * @returns {Promise<void>}
+ */
+const generateReportInfo = async (obj) => {
+  const { data: res } = await generateReport({
+    T_task_id: task.T_task_id,
+    T_VerifyTemplate_id: task.T_VerifyTemplate_id,
+    ...obj,
+  });
+  if (res.Code === 200) {
+    reportKey.value = res.Data;
+    generateKeyInfo();
+  }
+};
+
+let timer = 0;
+const generateKeyInfo = async () => {
+  const { data: res } = await generateKey({
+    key: reportKey.value,
+  });
+  const items = res.Item.split('\n').filter((item) => item);
+  if (res.Code === 200) {
+    timer = setTimeout(() => {
+      generateKeyInfo();
+    }, 3000);
+    notification.warning({
+      title: res.Msg,
+      description: `进度:${res.Schedule}%`,
+      content: res.Msg,
+      duration: 3000,
+      keepAliveOnHover: true,
+    });
+  } else if (res.Code === 201) {
+    clearTimeout(timer);
+    notification.success({
+      title: res.Msg,
+      description: `进度:${res.Schedule}%`,
+      content: items.map((item, index) =>
+        h('p', {}, { default: () => `${index + 1} ${item}` })
+      ),
+      meta: h(
+        NButton,
+        { onclick: () => (window.location.href = res.Data) },
+        { default: () => '下载文件' }
+      ),
+    });
+  } else if (res.Code === 202) {
+    clearTimeout(timer);
+    notification.error({
+      title: res.Msg,
+      description: `进度:${res.Schedule}%`,
+      content: items.map((item, index) =>
+        h('p', {}, { default: () => `${index + 1} ${item}` })
+      ),
+    });
+  }
+};
+
 /**
  *
  */
@@ -328,7 +402,7 @@ const putTemplateData = async () => {
       if (item.T_label === 3 || item.T_label === 9) {
         return {
           T_VerifyTemplateMap_id: item.T_VerifyTemplateMap_id,
-          T_value: item.T_value.join("|"),
+          T_value: item.T_value.join('|'),
           T_source: item.T_source,
           T_flow_sort: item.T_flow_sort,
           T_max_time: item.T_max_time,
@@ -337,7 +411,7 @@ const putTemplateData = async () => {
       } else {
         return {
           T_VerifyTemplateMap_id: item.T_VerifyTemplateMap_id,
-          T_value: item.T_value + "",
+          T_value: item.T_value + '',
           T_source: item.T_source,
           T_flow_sort: item.T_flow_sort,
           T_max_time: item.T_max_time,
@@ -353,7 +427,18 @@ const putTemplateData = async () => {
       T_VerifyTemplate_id: queryData.T_VerifyTemplate_id,
       VerifyTemplateMapData,
     });
-    message.success(res.Msg);
+    if (res.Code === 200) {
+      message.success(res.Msg);
+      const arr = toRaw(templateList.value);
+      const obj = {};
+      for (let i of arr) {
+        if (i.T_label === 3 || i.T_label === 9) {
+          i.T_value = i.T_value.join('|');
+        }
+        obj[i.T_name] = i.T_value;
+      }
+      generateReportInfo(obj);
+    }
   } catch (e) {
     console.log(e);
   }
@@ -380,9 +465,9 @@ const getTemplateList = async () => {
       if (item.T_label === 7) {
         item.T_value = item.T_value ? item.T_value : null;
       } else if (item.T_label === 9) {
-        item.T_value = item.T_value ? item.T_value.split("|") : null;
+        item.T_value = item.T_value ? item.T_value.split('|') : null;
       } else if (item.T_label === 3) {
-        item.T_value = item.T_value ? item.T_value.split("|") : [];
+        item.T_value = item.T_value ? item.T_value.split('|') : [];
       }
     });
   } catch (e) {

+ 223 - 166
src/views/scheme/index.vue

@@ -9,157 +9,162 @@
         </n-space>
       </template>
     </n-page-header>
-    <n-form
-      label-placement="left"
-      label-width="auto"
-      size="large"
-      show-require-mark
-      class="w-2/5 mx-auto"
-    >
-      <template
-        v-for="(item, i) of templateList"
-        :key="item.T_VerifyTemplateMap_id"
+    <n-scrollbar :style="{ maxHeight: `${height - 200}px` }" trigger="none">
+      <n-form
+        label-placement="left"
+        label-width="auto"
+        size="large"
+        show-require-mark
+        class="w-2/5 mx-auto"
       >
-        <n-form-item :label="item.T_name" v-if="item.T_label === 1">
-          <n-input v-model:value="item.T_value" />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 2">
-          <n-input v-model:value="item.T_value" />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 3">
-          <n-select
-            v-model:value="item.T_value"
-            multiple
-            label-field="T_sn"
-            value-field="T_sn"
-            max-tag-count="responsive"
-            :options="classList"
-          >
-            <template #action>
-              <n-space>
-                <n-button class="underline" text @click="handleSelectAll(i)"
-                  >全选</n-button
-                >
-                <n-button class="underline" text @click="handleSelectReverse(i)"
-                  >反选</n-button
-                >
-              </n-space>
-            </template>
-          </n-select>
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 4">
-          <n-select
-            label-field="T_sn"
-            value-field="T_sn"
-            v-model:value="item.T_value"
-            :options="classList"
-          />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-divider v-else-if="item.T_label === 5" />
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 7">
-          <n-date-picker
-            v-model:formatted-value="item.T_value"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            type="datetime"
-            clearable
-            class="w-full"
-          />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 9">
-          <n-date-picker
-            v-model:formatted-value="item.T_value"
-            value-format="yyyy-MM-dd HH:mm:ss"
-            type="datetimerange"
-            clearable
-            class="w-full"
-          />
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 10">
-          <n-image class="mr-5" width="100" :src="item.T_value" />
-          <n-upload
-            @change="(options) => handleChangeByIndex(options, i)"
-            :default-upload="false"
-            :max="1"
-          >
-            <n-button>{{ item.T_value ? '重新上传' : '点击上传' }}</n-button>
-          </n-upload>
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-        <n-form-item :label="item.T_name" v-else-if="item.T_label === 11">
-          <n-image class="mr-5" width="100" :src="item.T_value" />
-          <n-upload
-            @change="(options) => handleChangeByIndex(options, i)"
-            :default-upload="false"
-            :max="1"
-          >
-            <n-button>{{ item.T_value ? '重新上传' : '点击上传' }}</n-button>
-          </n-upload>
-          <n-popover trigger="hover">
-            <template #trigger>
-              <n-icon size="24" class="ml-3">
-                <InformationCircleOutline />
-              </n-icon>
-            </template>
-            <n-image width="200" :src="item.T_text" />
-          </n-popover>
-        </n-form-item>
-      </template>
-    </n-form>
+        <template
+          v-for="(item, i) of templateList"
+          :key="item.T_VerifyTemplateMap_id"
+        >
+          <n-form-item :label="item.T_name" v-if="item.T_label === 1">
+            <n-input v-model:value="item.T_value" />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 2">
+            <n-input v-model:value="item.T_value" />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 3">
+            <n-select
+              v-model:value="item.T_value"
+              multiple
+              label-field="T_sn"
+              value-field="T_sn"
+              max-tag-count="responsive"
+              :options="classList"
+            >
+              <template #action>
+                <n-space>
+                  <n-button class="underline" text @click="handleSelectAll(i)"
+                    >全选</n-button
+                  >
+                  <n-button
+                    class="underline"
+                    text
+                    @click="handleSelectReverse(i)"
+                    >反选</n-button
+                  >
+                </n-space>
+              </template>
+            </n-select>
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 4">
+            <n-select
+              label-field="T_sn"
+              value-field="T_sn"
+              v-model:value="item.T_value"
+              :options="classList"
+            />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-divider v-else-if="item.T_label === 5" />
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 7">
+            <n-date-picker
+              v-model:formatted-value="item.T_value"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              type="datetime"
+              clearable
+              class="w-full"
+            />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 9">
+            <n-date-picker
+              v-model:formatted-value="item.T_value"
+              value-format="yyyy-MM-dd HH:mm:ss"
+              type="datetimerange"
+              clearable
+              class="w-full"
+            />
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 10">
+            <n-image class="mr-5" width="100" :src="item.T_value" />
+            <n-upload
+              @change="(options) => handleChangeByIndex(options, i)"
+              :default-upload="false"
+              :max="1"
+            >
+              <n-button>{{ item.T_value ? '重新上传' : '点击上传' }}</n-button>
+            </n-upload>
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+          <n-form-item :label="item.T_name" v-else-if="item.T_label === 11">
+            <n-image class="mr-5" width="100" :src="item.T_value" />
+            <n-upload
+              @change="(options) => handleChangeByIndex(options, i)"
+              :default-upload="false"
+              :max="1"
+            >
+              <n-button>{{ item.T_value ? '重新上传' : '点击上传' }}</n-button>
+            </n-upload>
+            <n-popover trigger="hover">
+              <template #trigger>
+                <n-icon size="24" class="ml-3">
+                  <InformationCircleOutline />
+                </n-icon>
+              </template>
+              <n-image width="200" :src="item.T_text" />
+            </n-popover>
+          </n-form-item>
+        </template>
+      </n-form>
+    </n-scrollbar>
   </div>
   <n-modal
     v-model:show="modal.showModal"
@@ -183,16 +188,23 @@ import {
   getTaskDataClassList,
   getVerifyTemplateMapDataList,
   generateScheme,
+  generateKey,
 } from '@/api';
 import * as qiniu from 'qiniu-js';
 import { getToken } from '@/utils/storage/sessionToken';
 import { getFileToken } from '@/common';
 import { InformationCircleOutline } from '@vicons/ionicons5';
+import { NButton } from 'naive-ui';
+import { useWindowSize } from '@vueuse/core';
+
+const { height } = useWindowSize();
 
 const message = useMessage();
 
 const dialog = useDialog();
 
+const notification = useNotification();
+
 const task = window.sessionStorage.getItem('task')
   ? JSON.parse(window.sessionStorage.getItem('task'))
   : {};
@@ -323,7 +335,6 @@ const editTaskInfo = async () => {
  * @returns {Promise<void>}
  */
 const showCreateDialog = () => {
-  console.log(templateList.value);
   dialog.info({
     title: '提示',
     content: '确认生成报告?',
@@ -335,30 +346,66 @@ const showCreateDialog = () => {
   });
 };
 
+const reportKey = ref('');
+
 /**
  * 生成报告
- * @param T_VerifyTemplateMap_id
  * @returns {Promise<void>}
  */
-const generateReport = async (T_VerifyTemplateMap_id) => {
+const generateSchemeInfo = async (obj) => {
   const { data: res } = await generateScheme({
     T_task_id: task.T_task_id,
     T_VerifyTemplate_id: task.T_VerifyTemplate_id,
-    T_VerifyTemplateMap_id,
+    ...obj,
   });
-  console.log(res);
   if (res.Code === 200) {
-    message.success(res.Msg);
+    reportKey.value = res.Data;
+    generateKeyInfo();
   }
 };
 
-// const generateReportKey = async () => {
-//   const { data: res } = await generateKey({});
-//   console.log(res);
-//   if (res.Code === 200) {
-//     message.success(res.Msg);
-//   }
-// };
+let timer = 0;
+const generateKeyInfo = async () => {
+  const { data: res } = await generateKey({
+    key: reportKey.value,
+  });
+  const items = res.Item.split('\n').filter((item) => item);
+  if (res.Code === 200) {
+    timer = setTimeout(() => {
+      generateKeyInfo();
+    }, 3000);
+    notification.warning({
+      title: res.Msg,
+      description: `进度:${res.Schedule}%`,
+      content: res.Msg,
+      duration: 3000,
+      keepAliveOnHover: true,
+    });
+  } else if (res.Code === 201) {
+    clearTimeout(timer);
+    notification.success({
+      title: res.Msg,
+      description: `进度:${res.Schedule}%`,
+      content: items.map((item, index) =>
+        h('p', {}, { default: () => `${index + 1} ${item}` })
+      ),
+      meta: h(
+        NButton,
+        { onclick: () => (window.location.href = res.Data) },
+        { default: () => '下载文件' }
+      ),
+    });
+  } else if (res.Code === 202) {
+    clearTimeout(timer);
+    notification.error({
+      title: res.Msg,
+      description: `进度:${res.Schedule}%`,
+      content: items.map((item, index) =>
+        h('p', {}, { default: () => `${index + 1} ${item}` })
+      ),
+    });
+  }
+};
 
 /**
  *
@@ -398,9 +445,15 @@ const putTemplateData = async () => {
     });
     if (res.Code === 200) {
       message.success(res.Msg);
-      templateList.value.forEach((item) => {
-        generateReport(item.T_VerifyTemplateMap_id);
-      });
+      const arr = toRaw(templateList.value);
+      const obj = {};
+      for (let i of arr) {
+        if (i.T_label === 3 || i.T_label === 9) {
+          i.T_value = i.T_value.join('|');
+        }
+        obj[i.T_name] = i.T_value;
+      }
+      generateSchemeInfo(obj);
     }
   } catch (e) {
     console.log(e);
@@ -444,6 +497,10 @@ const getTemplateList = async () => {
   }
 };
 
+onBeforeUnmount(() => {
+  clearTimeout(timer);
+});
+
 getClassList();
 getTemplateList();
 </script>

+ 23 - 26
vite.config.js

@@ -1,30 +1,27 @@
-import { fileURLToPath, URL } from "node:url";
-import { defineConfig } from "vite";
-import vue from "@vitejs/plugin-vue";
-import AutoImport from "unplugin-auto-import/vite";
-import Components from "unplugin-vue-components/vite";
-import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
-import WindiCSS from "vite-plugin-windicss";
+import { fileURLToPath, URL } from 'node:url';
+import { defineConfig } from 'vite';
+import vue from '@vitejs/plugin-vue';
+import AutoImport from 'unplugin-auto-import/vite';
+import Components from 'unplugin-vue-components/vite';
+import { NaiveUiResolver } from 'unplugin-vue-components/resolvers';
+import WindiCSS from 'vite-plugin-windicss';
 
 // https://vitejs.dev/config/
 export default defineConfig({
-  // server: {
-  //   host: true,
-  //   proxy: {
-  //     "/Api": {
-  //       target: "https://cold.coldbaozhida.com/api",
-  //       changeOrigin: true,
-  //       rewrite: (path) => path.replace(/^\/Api/, ""),
-  //     },
-  //   },
-  // },
   server: {
     cors: true,
+    proxy: {
+      '/api2': {
+        target: 'http://coldverifylocal.coldbaozhida.com',
+        changeOrigin: true,
+        rewrite: (path) => path.replace(/^\/api2/, ''),
+      },
+    },
   },
-  base: "./",
+  base: './',
   resolve: {
     alias: {
-      "@": fileURLToPath(new URL("./src", import.meta.url)),
+      '@': fileURLToPath(new URL('src', import.meta.url)),
     },
   },
   plugins: [
@@ -35,14 +32,14 @@ export default defineConfig({
         enabled: true,
       },
       imports: [
-        "vue",
-        "vue-router",
+        'vue',
+        'vue-router',
         {
-          "naive-ui": [
-            "useDialog",
-            "useMessage",
-            "useNotification",
-            "useLoadingBar",
+          'naive-ui': [
+            'useDialog',
+            'useMessage',
+            'useNotification',
+            'useLoadingBar',
           ],
         },
       ],

+ 1 - 1
windi.config.js

@@ -1,4 +1,4 @@
-import { defineConfig } from "windicss/helpers";
+import { defineConfig } from 'windicss/helpers';
 
 export default defineConfig({
   preflight: false,

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác