瀏覽代碼

feat(all): update

HuCheng 2 年之前
父節點
當前提交
24917ad066

+ 2 - 0
.env.development

@@ -0,0 +1,2 @@
+VITE_API_BASE_URL = "http://coldverifylocal.coldbaozhida.com/api"
+VITE_API_BASE_URL_ONLINE = "https://coldverify.coldbaozhida.com/api"

+ 2 - 0
.env.production

@@ -0,0 +1,2 @@
+VITE_API_BASE_URL = "http://coldverifylocal.coldbaozhida.com/api"
+VITE_API_BASE_URL_ONLINE = "https://coldverify.coldbaozhida.com/api"

+ 2 - 0
package.json

@@ -18,12 +18,14 @@
     "axios": "^1.3.2",
     "highcharts": "^10.3.3",
     "highcharts-vue": "^1.4.0",
+    "md5": "^2.3.0",
     "vue": "^3.2.45",
     "vue-pdf-embed": "^1.1.5",
     "vue-router": "^4.1.6"
   },
   "devDependencies": {
     "@rushstack/eslint-patch": "^1.1.4",
+    "@vicons/antd": "^0.12.0",
     "@vitejs/plugin-vue": "^4.0.0",
     "@vue/eslint-config-prettier": "^7.0.0",
     "cz-git": "^1.4.1",

+ 28 - 0
pnpm-lock.yaml

@@ -2,6 +2,7 @@ lockfileVersion: 5.4
 
 specifiers:
   '@rushstack/eslint-patch': ^1.1.4
+  '@vicons/antd': ^0.12.0
   '@vitejs/plugin-vue': ^4.0.0
   '@vue/eslint-config-prettier': ^7.0.0
   axios: ^1.3.2
@@ -10,6 +11,7 @@ specifiers:
   eslint-plugin-vue: ^9.3.0
   highcharts: ^10.3.3
   highcharts-vue: ^1.4.0
+  md5: ^2.3.0
   naive-ui: ^2.34.3
   prettier: ^2.7.1
   sass: ^1.58.0
@@ -26,12 +28,14 @@ dependencies:
   axios: 1.3.2
   highcharts: 10.3.3
   highcharts-vue: 1.4.0_x2ttk5sq3pjxzxl7cjqodvt53e
+  md5: 2.3.0
   vue: 3.2.47
   vue-pdf-embed: 1.1.5_vue@3.2.47
   vue-router: 4.1.6_vue@3.2.47
 
 devDependencies:
   '@rushstack/eslint-patch': 1.2.0
+  '@vicons/antd': 0.12.0
   '@vitejs/plugin-vue': 4.0.0_vite@4.1.1+vue@3.2.47
   '@vue/eslint-config-prettier': 7.0.0_kcm2pbg4372aakdkvxabn7z2ri
   cz-git: 1.4.1
@@ -658,6 +662,10 @@ packages:
     resolution: {integrity: sha512-BdZ5BCCvho3EIXw6wUCXHe7rS53AIDPLE+JzwgT+OsJk53oBfbSmZZ7CX4VaRoN78N+TJpFi9QPlfIVNmJYWxQ==}
     dev: true
 
+  /@vicons/antd/0.12.0:
+    resolution: {integrity: sha512-C0p6aO1EmGG1QHrqgUWQS1No20934OdWSRQshM5NIDK5H1On6tC26U0hT6Rmp40KfUsvhvX5YW8BoWJdNFifPg==}
+    dev: true
+
   /@vitejs/plugin-vue/4.0.0_vite@4.1.1+vue@3.2.47:
     resolution: {integrity: sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==}
     engines: {node: ^14.18.0 || >=16.0.0}
@@ -948,6 +956,10 @@ packages:
       supports-color: 7.2.0
     dev: true
 
+  /charenc/0.0.2:
+    resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==}
+    dev: false
+
   /chokidar/3.5.3:
     resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
     engines: {node: '>= 8.10.0'}
@@ -1029,6 +1041,10 @@ packages:
       which: 2.0.2
     dev: true
 
+  /crypt/0.0.2:
+    resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==}
+    dev: false
+
   /css-render/0.15.12:
     resolution: {integrity: sha512-eWzS66patiGkTTik+ipO9qNGZ+uNuGyTmnz6/+EJIiFg8+3yZRpnMwgFo8YdXhQRsiePzehnusrxVvugNjXzbw==}
     dependencies:
@@ -1634,6 +1650,10 @@ packages:
       binary-extensions: 2.2.0
     dev: true
 
+  /is-buffer/1.1.6:
+    resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+    dev: false
+
   /is-core-module/2.11.0:
     resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
     dependencies:
@@ -1803,6 +1823,14 @@ packages:
       '@jridgewell/sourcemap-codec': 1.4.14
     dev: true
 
+  /md5/2.3.0:
+    resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==}
+    dependencies:
+      charenc: 0.0.2
+      crypt: 0.0.2
+      is-buffer: 1.1.6
+    dev: false
+
   /memory-fs/0.5.0:
     resolution: {integrity: sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==}
     engines: {node: '>=4.3.0 <5.0.0 || >=5.10'}

+ 5 - 11
src/App.vue

@@ -12,14 +12,6 @@ const themeOverrides = {
     primaryColorPressed: "#2d8cf0",
     primaryColorSuppl: "#2d8cf0",
   },
-  Menu: {
-    itemColorActive: "#2080f0",
-    itemColorActiveHover: "#2080f0",
-    itemTextColorActive: "#fff",
-    itemTextColor: "#bbb",
-    itemTextColorActiveHover: "#fff",
-    itemTextColorHoverHorizontalInverted: "#fff",
-  },
 };
 </script>
 
@@ -29,9 +21,11 @@ const themeOverrides = {
     :date-locale="dateZhCN"
     :theme-overrides="themeOverrides"
   >
-    <n-message-provider>
-      <RouterView />
-    </n-message-provider>
+    <n-loading-bar-provider>
+      <n-message-provider>
+        <RouterView />
+      </n-message-provider>
+    </n-loading-bar-provider>
   </n-config-provider>
 </template>
 

+ 56 - 0
src/api/index.js

@@ -0,0 +1,56 @@
+import service from "@/utils/axios";
+
+// 登录
+export const login = (data, role) => {
+  return service.request({
+    method: "POST",
+    url:
+      role === "管理员" ? "/Login_Admin_verification" : "/Login_verification",
+    data,
+  });
+};
+// 用户(列表)
+export const getUserData = (data) => {
+  return service.request({
+    method: "POST",
+    url: "/User/List",
+    data,
+  });
+};
+
+
+// 任务管理(列表)
+export const getTaskData = (data) => {
+  return service.request({
+    method: "POST",
+    url: "/Task/List",
+    data,
+  });
+};
+
+// 任务管理(添加)
+export const addTaskData = (data) => {
+  return service.request({
+    method: "POST",
+    url: "/Task/Add",
+    data,
+  });
+};
+
+// 任务管理(编辑)
+export const editTaskData = (data) => {
+  return service.request({
+    method: "POST",
+    url: "/Task/Up",
+    data,
+  });
+};
+
+// 任务管理(删除)
+export const deleteTaskData = (data) => {
+  return service.request({
+    method: "POST",
+    url: "/Task/Del",
+    data,
+  });
+};

+ 1 - 0
src/constant/index.js

@@ -0,0 +1 @@
+export const TOKEN = "User_tokey";

+ 96 - 81
src/layout/components/menu/index.vue

@@ -8,92 +8,107 @@
 </template>
 
 <script setup>
+import { h } from "vue";
 import { RouterLink } from "vue-router";
+import { NIcon } from "naive-ui";
+import { UnorderedListOutlined } from "@vicons/antd";
+
+function renderIcon(icon) {
+  return () => h(NIcon, null, { default: () => h(icon) });
+}
 
 // 菜单的数据
 const menuOptions = [
   {
-    label: "任务管理",
-    key: "1",
-    children: [
-      {
-        label: () =>
-          h(
-            RouterLink,
-            {
-              to: "/equipment",
-            },
-            { default: () => "设备管理" }
-          ),
-        key: "/equipment",
-      },
-      {
-        label: () =>
-          h(
-            RouterLink,
-            {
-              to: "/data_source",
-            },
-            { default: () => "数据来源" }
-          ),
-        key: "/data_source",
-      },
-      {
-        label: () =>
-          h(
-            RouterLink,
-            {
-              to: "/data_edit",
-            },
-            { default: () => "数据编辑" }
-          ),
-        key: "/data_edit",
-      },
-      {
-        label: () =>
-          h(
-            RouterLink,
-            {
-              to: "/data_checkout",
-            },
-            { default: () => "数据校验" }
-          ),
-        key: "/data_checkout",
-      },
-      {
-        label: () =>
-          h(
-            RouterLink,
-            {
-              to: "/report_create",
-            },
-            { default: () => "报告生成" }
-          ),
-        key: "/report_create",
-      },
-      {
-        label: () =>
-          h(
-            RouterLink,
-            {
-              to: "/report_edit",
-            },
-            { default: () => "报告编辑" }
-          ),
-        key: "/report_edit",
-      },
-      {
-        label: () =>
-          h(
-            RouterLink,
-            {
-              to: "/report_audit",
-            },
-            { default: () => "报告审核" }
-          ),
-        key: "/report_audit",
-      },
-    ],
+    label: () =>
+      h(
+        RouterLink,
+        {
+          to: "/project",
+        },
+        { default: () => "任务管理" }
+      ),
+    key: "/project",
+    icon: renderIcon(UnorderedListOutlined),
+    // children: [
+    //   {
+    //     label: () =>
+    //       h(
+    //         RouterLink,
+    //         {
+    //           to: "/equipment",
+    //         },
+    //         { default: () => "设备管理" }
+    //       ),
+    //     key: "/equipment",
+    //   },
+    //   {
+    //     label: () =>
+    //       h(
+    //         RouterLink,
+    //         {
+    //           to: "/data_source",
+    //         },
+    //         { default: () => "数据来源" }
+    //       ),
+    //     key: "/data_source",
+    //   },
+    //   {
+    //     label: () =>
+    //       h(
+    //         RouterLink,
+    //         {
+    //           to: "/data_edit",
+    //         },
+    //         { default: () => "数据编辑" }
+    //       ),
+    //     key: "/data_edit",
+    //   },
+    //   {
+    //     label: () =>
+    //       h(
+    //         RouterLink,
+    //         {
+    //           to: "/data_checkout",
+    //         },
+    //         { default: () => "数据校验" }
+    //       ),
+    //     key: "/data_checkout",
+    //   },
+    //   {
+    //     label: () =>
+    //       h(
+    //         RouterLink,
+    //         {
+    //           to: "/report_create",
+    //         },
+    //         { default: () => "报告生成" }
+    //       ),
+    //     key: "/report_create",
+    //   },
+    //   {
+    //     label: () =>
+    //       h(
+    //         RouterLink,
+    //         {
+    //           to: "/report_edit",
+    //         },
+    //         { default: () => "报告编辑" }
+    //       ),
+    //     key: "/report_edit",
+    //   },
+    //   {
+    //     label: () =>
+    //       h(
+    //         RouterLink,
+    //         {
+    //           to: "/report_audit",
+    //         },
+    //         { default: () => "报告审核" }
+    //       ),
+    //     key: "/report_audit",
+    //   },
+    // ],
   },
 ];
 </script>

+ 26 - 30
src/layout/index.vue

@@ -4,23 +4,20 @@
     position="absolute"
     style="top: 0; right: 0; bottom: 0; left: 0"
   >
-    <n-config-provider :theme="darkTheme">
-      <n-layout-sider
-        collapse-mode="transform"
-        :collapsed-width="0"
-        show-trigger="bar"
-        :native-scrollbar="false"
-        content-style="height: 100%"
-        class="h-full"
-      >
-        <h2 class="text-center leading-[64px]">冷链验证报告生成系统</h2>
-        <MenuComponent />
-      </n-layout-sider>
-    </n-config-provider>
+    <n-layout-sider
+      collapse-mode="transform"
+      :collapsed-width="0"
+      show-trigger="bar"
+      :native-scrollbar="false"
+      class="h-full shadow"
+    >
+      <h2 class="text-center leading-[64px]">冷链验证报告生成系统</h2>
+      <MenuComponent />
+    </n-layout-sider>
     <n-layout>
       <n-layout-header class="h-16 px-6 shadow">
         <n-space justify="end" align="center" class="h-full">
-          <n-dropdown trigger="hover" :options="options">
+          <n-dropdown trigger="hover" :options="options" @select="handleSelect">
             <n-avatar round class="cursor-pointer"> 用户名 </n-avatar>
           </n-dropdown>
         </n-space>
@@ -40,27 +37,26 @@
 
 <script setup>
 import MenuComponent from "@/layout/components/menu/index.vue";
-import { darkTheme } from "naive-ui";
+import { removeToken } from "@/utils/storage/sessionToken";
+
+const router = useRouter();
 
+const message = useMessage();
+
+// 下拉菜单传入的 options
 const options = [
   {
-    label: "滨海湾金沙,新加坡",
-    key: "marina bay sands",
-    disabled: true,
-  },
-  {
-    label: "布朗酒店,伦敦",
-    key: "brown's hotel, london",
-  },
-  {
-    label: "亚特兰蒂斯巴哈马,拿骚",
-    key: "atlantis nahamas, nassau",
-  },
-  {
-    label: "比佛利山庄酒店,洛杉矶",
-    key: "the beverly hills hotel, los angeles",
+    label: "退出登录",
+    key: "/login",
   },
 ];
+
+// select 选中时触发的回调函数
+const handleSelect = (key) => {
+  removeToken();
+  message.success("成功退出登录");
+  router.replace(key);
+};
 </script>
 
 <style scoped></style>

+ 86 - 21
src/login/index.vue

@@ -1,31 +1,47 @@
 <template>
-  <div class="h-full flex justify-center items-center">
-    <n-card
-      class="w-1/4"
-      title="冷链验证报告生成系统"
-      :header-style="{
-        textAlign: 'center',
-        fontSize: '25px',
-        fontWeight: 'bolder',
-      }"
-      hoverable
-    >
-      <n-form :model="model" size="large" label-placement="left">
+  <div
+    class="absolute top-0 right-0 bottom-0 left-0 bg-[#f5f7f9] flex justify-center items-center"
+  >
+    <n-card class="w-[500px] shadow rounded-lg" :bordered="false">
+      <template #header>
+        <h2 class="text-center">冷链验证报告生成系统</h2>
+      </template>
+      <n-form
+        ref="formRef"
+        :rules="rules"
+        :model="formValue"
+        size="large"
+        label-placement="left"
+      >
         <n-form-item path="username">
-          <n-input v-model:value="model.username" />
+          <n-input v-model:value="formValue.username" :maxlength="8" clearable>
+            <template #prefix>
+              <n-icon :component="UserOutlined" />
+            </template>
+          </n-input>
         </n-form-item>
         <n-form-item path="password">
-          <n-input v-model:value="model.password" />
+          <n-input
+            v-model:value="formValue.password"
+            type="password"
+            show-password-on="click"
+            :maxlength="8"
+            clearable
+          >
+            <template #prefix>
+              <n-icon :component="LockOutlined" />
+            </template>
+          </n-input>
         </n-form-item>
-        <n-form-item path="selectValue">
+        <n-form-item path="role">
           <n-select
-            v-model:value="model.selectValue"
-            placeholder="Select"
+            v-model:value="formValue.role"
             :options="generalOptions"
+            clearable
           />
         </n-form-item>
         <n-form-item>
-          <n-button type="primary" block>登录</n-button>
+          <n-button type="primary" block @click="handleSubmit">登录</n-button>
         </n-form-item>
       </n-form>
     </n-card>
@@ -33,15 +49,64 @@
 </template>
 
 <script setup>
-const model = reactive({
+import { UserOutlined, LockOutlined } from "@vicons/antd";
+import { login } from "@/api";
+import md5 from "md5";
+import { setToken } from "@/utils/storage/sessionToken";
+
+const loadingBar = useLoadingBar();
+
+const formRef = ref(null);
+
+const router = useRouter();
+
+const message = useMessage();
+
+// 验证表项的规则
+const rules = {
+  username: { required: true, message: "请输入用户名", trigger: "blur" },
+  password: { required: true, message: "请输入密码", trigger: "blur" },
+  role: { required: true, message: "请选择角色", trigger: ["blur", "change"] },
+};
+
+// 登录表单
+const formValue = reactive({
   username: "",
   password: "",
-  selectValue: "管理员登录",
+  role: "",
 });
-const generalOptions = ["管理员登录", "用户登录"].map((v) => ({
+
+// 角色列表
+const generalOptions = ["管理员", "用户"].map((v) => ({
   label: v,
   value: v,
 }));
+
+const handleSubmit = async () => {
+  formRef.value.validate(async (errors) => {
+    if (!errors) {
+      try {
+        loadingBar.start();
+        const { data: res } = await login(
+          {
+            bzd_username: formValue.username,
+            bzd_password: md5(formValue.password),
+          },
+          formValue.role
+        );
+        if (res.Code === 200) {
+          router.replace("/");
+          message.success(res.Msg);
+          setToken(res.Data);
+        }
+      } finally {
+        loadingBar.finish();
+      }
+    } else {
+      message.error("验证失败,请填写完整信息");
+    }
+  });
+};
 </script>
 
 <style lang="scss" scoped></style>

+ 33 - 9
src/router/index.js

@@ -1,41 +1,47 @@
-import { createRouter, createWebHistory } from "vue-router";
+import { createRouter, createWebHashHistory } from "vue-router";
 import LayoutView from "../layout/index.vue";
 import LoginView from "../login/index.vue";
+import { getToken } from "@/utils/storage/sessionToken";
 
 const router = createRouter({
-  history: createWebHistory(import.meta.env.BASE_URL),
+  history: createWebHashHistory(import.meta.env.BASE_URL),
   routes: [
     {
       path: "/",
       component: LayoutView,
+      redirect: "/project",
       children: [
         {
+          path: "/project",
+          component: () => import("@/views/project/index.vue"),
+        },
+        {
           path: "/equipment",
-          component: () => import("@/views/equipment/index.vue"),
+          component: () => import("@/views/project/equipment/index.vue"),
         },
         {
           path: "/data_source",
-          component: () => import("@/views/data/source/index.vue"),
+          component: () => import("@/views/project/data/source/index.vue"),
         },
         {
           path: "/data_edit",
-          component: () => import("@/views/data/edit/index.vue"),
+          component: () => import("@/views/project/data/edit/index.vue"),
         },
         {
           path: "/data_checkout",
-          component: () => import("@/views/data/checkout/index.vue"),
+          component: () => import("@/views/project/data/checkout/index.vue"),
         },
         {
           path: "/report_create",
-          component: () => import("@/views/report/create/index.vue"),
+          component: () => import("@/views/project/report/create/index.vue"),
         },
         {
           path: "/report_edit",
-          component: () => import("@/views/report/edit/index.vue"),
+          component: () => import("@/views/project/report/edit/index.vue"),
         },
         {
           path: "/report_audit",
-          component: () => import("@/views/report/audit/index.vue"),
+          component: () => import("@/views/project/report/audit/index.vue"),
         },
       ],
     },
@@ -46,4 +52,22 @@ const router = createRouter({
   ],
 });
 
+// 全局前置路由守卫
+router.beforeEach((to, from, next) => {
+  const token = getToken();
+  if (to.path === "/login") {
+    if (!token) {
+      next();
+    } else {
+      next("/");
+    }
+  } else {
+    if (!token) {
+      next("/login");
+    } else {
+      next();
+    }
+  }
+});
+
 export default router;

+ 23 - 3
src/utils/axios.js

@@ -1,15 +1,31 @@
 import axios from "axios";
+import { getToken } from "@/utils/storage/sessionToken";
+import { TOKEN } from "@/constant";
+import { createDiscreteApi } from "naive-ui";
+
+const { message } = createDiscreteApi(["message"]);
 
 const service = axios.create({
-  baseURL: "https://some-domain.com/api/",
-  timeout: 1000,
-  headers: { "X-Custom-Header": "foobar" },
+  baseURL: import.meta.env.VITE_API_BASE_URL_ONLINE,
+  timeout: 8000,
 });
 
 // 添加请求拦截器
 service.interceptors.request.use(
   function (config) {
     // 在发送请求之前做些什么
+    const formData = new FormData();
+    if (
+      config.url !== "/Login_Admin_verification" &&
+      config.url !== "/Login_verification"
+    ) {
+      const token = getToken();
+      formData.append(TOKEN, token);
+    }
+    Object.entries(config.data).forEach(([key, value]) => {
+      formData.append(key, value);
+    });
+    config.data = formData;
     return config;
   },
   function (error) {
@@ -23,6 +39,10 @@ service.interceptors.response.use(
   function (response) {
     // 2xx 范围内的状态码都会触发该函数。
     // 对响应数据做点什么
+    const { data: res } = response;
+    if (res.Code !== 200) {
+      return message.error(res.Msg);
+    }
     return response;
   },
   function (error) {

+ 14 - 0
src/utils/storage/sessionToken.js

@@ -0,0 +1,14 @@
+import { TOKEN } from "@/constant";
+
+export const getToken = () => {
+  const token = window.sessionStorage.getItem(TOKEN);
+  return !token ? "" : token;
+};
+
+export const setToken = (value) => {
+  return window.sessionStorage.setItem(TOKEN, value);
+};
+
+export const removeToken = () => {
+  return window.sessionStorage.removeItem(TOKEN);
+};

+ 0 - 0
src/views/data/checkout/index.vue → src/views/project/data/checkout/index.vue


+ 0 - 0
src/views/data/edit/index.vue → src/views/project/data/edit/index.vue


+ 0 - 0
src/views/data/source/index.vue → src/views/project/data/source/index.vue


+ 1 - 1
src/views/equipment/index.vue → src/views/project/equipment/index.vue

@@ -53,7 +53,7 @@
 import { h } from "vue";
 import { NButton, NSpace } from "naive-ui";
 
-const createColumns = ({ goToView }) => {
+const createColumns = () => {
   return [
     {
       title: "项目名称",

+ 245 - 0
src/views/project/index.vue

@@ -0,0 +1,245 @@
+<template>
+  <n-space vertical>
+    <n-space justify="end">
+      <n-button type="primary" @click="showAddModal">添加</n-button>
+    </n-space>
+    <n-data-table
+      :columns="columns"
+      :data="data"
+      :pagination="pagination"
+      :bordered="false"
+    />
+  </n-space>
+  <n-modal
+    style="width: 30%"
+    :show-icon="false"
+    v-model:show="modal.showModal"
+    preset="dialog"
+    :title="modal.title"
+    positive-text="提交"
+    negative-text="取消"
+    @positive-click="submitCallback"
+  >
+    <n-form
+      ref="formRef"
+      :model="formValue"
+      label-placement="left"
+      label-width="auto"
+      :rules="rules"
+    >
+      <n-form-item label="任务名称" path="T_name">
+        <n-input v-model:value="formValue.T_name" clearable />
+      </n-form-item>
+      <n-form-item label="用户" path="T_uuid">
+        <n-select
+          v-model:value="formValue.T_uuid"
+          :options="userList"
+          label-field="T_user"
+          value-field="T_uuid"
+          clearable
+        />
+      </n-form-item>
+      <n-form-item label="任务模板" path="T_name">
+        <n-input v-model:value="formValue.T_name" clearable />
+      </n-form-item>
+      <n-form-item label="截止时间" path="T_deadline">
+        <n-date-picker
+          v-model:formatted-value="formValue.T_deadline"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="datetime"
+          clearable
+          class="w-full"
+        />
+      </n-form-item>
+      <n-form-item label="数据采集负责人" path="T_name">
+        <n-input v-model:value="formValue.T_name" clearable />
+      </n-form-item>
+      <n-form-item label="报告编写负责人" path="T_name">
+        <n-input v-model:value="formValue.T_name" clearable />
+      </n-form-item>
+      <n-form-item label="交付审核负责人" path="T_name">
+        <n-input v-model:value="formValue.T_name" clearable />
+      </n-form-item>
+      <n-form-item label="实施方案负责人" path="T_name">
+        <n-input v-model:value="formValue.T_name" clearable />
+      </n-form-item>
+    </n-form>
+  </n-modal>
+</template>
+
+<script setup>
+import { h } from "vue";
+import { NButton, NSpace } from "naive-ui";
+import { getTaskData, getUserData } from "@/api";
+
+const formRef = ref(null);
+
+// 验证表项的规则
+const rules = {
+  T_name: { required: true, message: "请输入名称", trigger: "blur" },
+  T_text: { required: true, message: "请输入描述", trigger: "blur" },
+};
+
+// 查询参数
+const queryData = reactive({
+  T_uuid: "",
+  T_name: "",
+  page: 1,
+  page_z: 10,
+});
+
+// 任务列表
+const data = ref([]);
+
+// 用户列表
+const userList = ref([]);
+
+// 获取表项中收集到的值的对象
+const formValue = reactive({
+  T_name: null,
+  T_uuid: null,
+  T_VerifyTemplate_id: null,
+  T_deadline: null,
+  T_collection: null,
+  T_reporting: null,
+  T_delivery: null,
+  T_scheme: null,
+});
+
+// 模态框数据源
+const modal = reactive({
+  title: "",
+  showModal: false,
+});
+
+// 需要展示的列
+const columns = [
+  {
+    title: "公司名称",
+    key: "T_user_name",
+  },
+  {
+    title: "报告名称",
+    key: "T_name",
+  },
+  {
+    title: "截止时间",
+    key: "T_deadline",
+  },
+  {
+    title: "流程",
+    key: "length",
+    render() {
+      return ["数据采集", "报告编写", "交付审核"].map((item) =>
+        h(
+          "span",
+          {},
+          {
+            default: () => item,
+          }
+        )
+      );
+    },
+  },
+  {
+    title: "操作",
+    key: "actions",
+    render() {
+      return h(
+        NSpace,
+        {},
+        {
+          default: () =>
+            [
+              "设备管理",
+              "数据来源",
+              "数据编辑",
+              "数据校验",
+              "报告生成",
+              "报告编辑",
+              "报告审核",
+            ].map((item) =>
+              h(
+                NButton,
+                {
+                  type: "primary",
+                  size: "small",
+                  onClick: () => {},
+                },
+                { default: () => item }
+              )
+            ),
+        }
+      );
+    },
+  },
+];
+
+// 执行 positive 时执行的回调函数
+const submitCallback = () => {
+  if (modal.title === "添加") {
+    console.log("添加");
+  } else {
+    console.log("添加");
+  }
+};
+
+// 显示添加
+const showAddModal = () => {
+  modal.title = "添加";
+  modal.showModal = true;
+  Object.keys(formValue).forEach((key) => (formValue[key] = null));
+};
+
+// 添加
+// const addProject = () => {
+//   formRef.value.validate(async (errors) => {
+//     if (!errors) {
+//       try {
+//         const { data: res } = await addProjectData({
+//           T_name: formValue.T_name,
+//           T_text: formValue.T_text,
+//         });
+//         message.success(res.Msg);
+//         getProjectList();
+//       } finally {
+//         formRef.value.restoreValidation();
+//         Object.keys(formValue).forEach((key) => (formValue[key] = ""));
+//       }
+//     } else {
+//       modal.showModal = true;
+//       message.error("验证失败,请填写完整信息");
+//     }
+//   });
+// };
+
+// 分页数据源
+const pagination = reactive({
+  page: queryData.page,
+  pageSize: queryData.page_z,
+  itemCount: 0,
+  onChange: (page) => {
+    pagination.page = page;
+    queryData.page = page;
+    getDataList();
+  },
+});
+
+// 用户(列表)
+const getUserList = async () => {
+  const { data: res } = await getUserData({});
+  userList.value = res.Data.List;
+};
+
+// 任务管理(列表)
+const getDataList = async () => {
+  const { data: res } = await getTaskData(queryData);
+  pagination.itemCount = res.Data.Num;
+  data.value = res.Data.List;
+};
+
+getUserList();
+getDataList();
+</script>
+
+<style scoped></style>

+ 0 - 0
src/views/report/audit/index.vue → src/views/project/report/audit/index.vue


+ 0 - 0
src/views/report/create/index.vue → src/views/project/report/create/index.vue


+ 0 - 0
src/views/report/edit/index.vue → src/views/project/report/edit/index.vue


+ 3 - 0
vite.config.js

@@ -8,6 +8,9 @@ import WindiCSS from "vite-plugin-windicss";
 
 // https://vitejs.dev/config/
 export default defineConfig({
+  server: {
+    open: true
+  },
   plugins: [
     vue(),
     WindiCSS(),