Browse Source

调整知识图谱构建

yangdr 1 day ago
parent
commit
23f8e6907e
8 changed files with 759 additions and 475 deletions
  1. 20 18
      src/components/LayoutHeader.vue
  2. 1 1
      src/main.ts
  3. 47 64
      src/router/index.ts
  4. 220 0
      src/router/index_.ts_
  5. 8 4
      src/utils/session.ts
  6. 16 298
      src/views/AppCopy.vue
  7. 90 90
      src/views/GraphView.vue
  8. 357 0
      src/views/Login/Login.vue

+ 20 - 18
src/components/LayoutHeader.vue

@@ -1,9 +1,9 @@
 <template>
   <div class="layout-header">
     <div class="logo"></div>
-    <div style="display: flex;align-items: center;margin-right: 10px;">
+    <!-- <div style="display: flex;align-items: center;margin-right: 10px;">
       <span class="knowledge-graph-icon" @click="router.push({ path: '/home' })"></span>
-    </div>
+    </div> -->
     <div class="menu">
       <el-menu :default-active="currentPath" class="el-menu-demo" mode="horizontal" router>
         <el-menu-item :index="item.path" v-for="item in routeList" :key="item.name">{{ item.title }}</el-menu-item>
@@ -11,15 +11,15 @@
     </div>
     <div style="align-self: center;">
       <el-dropdown style="margin-top:10px">
-            <div style="font-size:medium;font-weight: bold; color:#000">{{ user.full_name }}</div>
-            <template #dropdown>
-              <el-dropdown-menu>
-                <el-dropdown-item>用户资料</el-dropdown-item>
-                <el-dropdown-item>修改密码</el-dropdown-item>
-                <el-dropdown-item @click="handleLogout">登出</el-dropdown-item>
-              </el-dropdown-menu>
-            </template>
-          </el-dropdown>
+        <div style="font-size:medium;font-weight: bold; color:#000">{{ user.full_name }}</div>
+        <template #dropdown>
+          <el-dropdown-menu>
+            <el-dropdown-item>用户资料</el-dropdown-item>
+            <el-dropdown-item>修改密码</el-dropdown-item>
+            <el-dropdown-item @click="handleLogout">登出</el-dropdown-item>
+          </el-dropdown-menu>
+        </template>
+      </el-dropdown>
     </div>
   </div>
 </template>
@@ -29,7 +29,8 @@ import { ref } from 'vue'
 import { computed } from "vue";
 import { useMenuStore } from "@/stores/menu.js"
 import { useRoute, useRouter } from "vue-router";
-import {  getSessionVar } from '@/utils/session'
+import { getSessionVar, clearSessionVar } from '@/utils/session'
+
 const route = useRoute()
 const router = useRouter()
 // console.log('route', route)
@@ -39,11 +40,11 @@ const user = ref({
   full_name: 'John Doe',
   username: 'johndoe',
 })
-    user.value = {
-      id: getSessionVar('user_id') || "0",
-      full_name: getSessionVar('full_name') || 'John Doe',
-      username: getSessionVar('username') || 'johndoe',
-    }
+user.value = {
+  id: getSessionVar('user_id') || "0",
+  full_name: getSessionVar('full_name') || 'John Doe',
+  username: getSessionVar('username') || 'johndoe',
+}
 const currentPath = computed(() => {
   let temp = ""
   for (let i = 0; i < routeList.length; i++) {
@@ -59,7 +60,8 @@ const currentPath = computed(() => {
 })
 const handleLogout = () => {
   // 跳转到登录页面
-  router.push({ path: '/home',query: { logout: true } });
+  router.push({ path: '/login' });
+  clearSessionVar()
 }
 
 // console.log(menu.menu)

+ 1 - 1
src/main.ts

@@ -7,7 +7,7 @@ import 'element-plus/dist/index.css'
 import * as ElementPlusIconsVue from '@element-plus/icons-vue'
 import { createPinia } from 'pinia'
 import App from './App.vue'
-import router from '@/router/index'
+import router from '@/router/index.ts'
 import http from "@/utils/http.js"
 
 const app = createApp(App)

+ 47 - 64
src/router/index.ts

@@ -1,4 +1,5 @@
 import { createRouter, createWebHistory, isNavigationFailure } from "vue-router";
+import Login from "@/views/Login/Login.vue";
 import AppCopy from "@/views/AppCopy.vue";
 import HomeView from "@/views/HomeView.vue";
 import Layout from "@/views/KMPlatform/Layout.vue";
@@ -21,48 +22,17 @@ const router = createRouter({
   routes: [
     {
       path: "/",
-      component: AppCopy,
-      redirect: "/home",
-      children: [
-        {
-          path: "home",
-          name: "home",
-          component: HomeView,
-        },
-        {
-          path: "workspace",
-          name: "workspace",
-          component: () => import("@/views/WorkspaceView.vue"),
-          children: [
-            {
-              path: "queue/:id",
-              name: "queue",
-              component: () => import("@/views/QueueView.vue"),
-            },
-            {
-              path: "worker",
-              name: "worker",
-              component: () => import("@/views/WorkerView.vue"),
-            },
-            {
-              path: "graph",
-              name: "graph",
-              component: () => import("../views/GraphView.vue"),
-            },
-            {
-              path: "graph-mgr/:id",
-              name: "graph-mgr",
-              component: () => import("../views/GraphManagement.vue"),
-            },
-          ],
-        },
-        {
-          path: "about",
-          name: "about",
-          component: () => import("../views/AboutView.vue"),
-        },
-      ],
+      redirect: "/kmplatform/home",
     },
+    {
+      path: "/login",
+      name: "login",
+      component: Login,
+      meta: {
+
+      }
+    },
+
     {
       path: "/kmplatform",
       name: "kmplatform",
@@ -114,33 +84,46 @@ const router = createRouter({
           meta: {
             title: "知识图谱构建",
           },
-          redirect: "/kmplatform/kgbuilder/tm",
-          component: KGBuilder,
+          redirect: "/kmplatform/kgbuilder/home",
+          component: AppCopy,
           children: [
             {
-              path: "tm",
-              name: "kgb-tm",
-              meta: {
-                title: "术语管理",
-              },
-              component: TerminologyManagement,
+              path: "home",
+              name: "home",
+              component: HomeView,
             },
             {
-              path: 'etm',
-              name: 'kgb-etm',
-              meta: {
-                title: "实体类型管理",
-              },
-              component: EntityTypeManagement,
+              path: "workspace",
+              name: "workspace",
+              component: () => import("@/views/WorkspaceView.vue"),
+              children: [
+                {
+                  path: "queue/:id",
+                  name: "queue",
+                  component: () => import("@/views/QueueView.vue"),
+                },
+                {
+                  path: "worker",
+                  name: "worker",
+                  component: () => import("@/views/WorkerView.vue"),
+                },
+                {
+                  path: "graph",
+                  name: "graph",
+                  component: () => import("../views/GraphView.vue"),
+                },
+                {
+                  path: "graph-mgr/:id",
+                  name: "graph-mgr",
+                  component: () => import("../views/GraphManagement.vue"),
+                },
+              ],
             },
             {
-              path: 'krtm',
-              name: 'kgb-krtm',
-              meta: {
-                title: "实体关系类型管理"
-              },
-              component: EntityRelationshipTypeManagement,
-            }
+              path: "about",
+              name: "about",
+              component: () => import("../views/AboutView.vue"),
+            },
           ]
         },
         {
@@ -189,8 +172,8 @@ router.beforeEach((to, from, next) => {
     getSessionVar("session_id") == null &&
     getSessionVar("username") == null
   ) {
-    if (to.name !== "home") {
-      next({ name: "home" }); // 重定向到登录页面
+    if (to.name !== "login") {
+      next({ name: "login" }); // 重定向到登录页面
     } else {
       next(); // 确认转移
     }

+ 220 - 0
src/router/index_.ts_

@@ -0,0 +1,220 @@
+import { createRouter, createWebHistory, isNavigationFailure } from "vue-router";
+import Login from "@/views/Login/Login.vue";
+import AppCopy from "@/views/AppCopy.vue";
+import HomeView from "@/views/HomeView.vue";
+import Layout from "@/views/KMPlatform/Layout.vue";
+import Home from "@/views/KMPlatform/Home/Home.vue";
+import KGBuilder from "@/views/KMPlatform/KGBuilder/KGBuilder.vue";
+import KnowledgeBase from "@/views/KMPlatform/KnowledgeBase/KnowledgeBase.vue";
+import OpenPlatform from "@/views/KMPlatform/OpenPlatform/OpenPlatform.vue";
+import TerminologyManagement from "@/views/KMPlatform/KGBuilder/TM/TerminologyManagement.vue";
+import EntityTypeManagement from "@/views/KMPlatform/KGBuilder/ETM/EntityTypeManagement.vue";
+import KnowledgeBaseManagement from "@/views/KMPlatform/KnowledgeBase/KBM/KnowledgeBaseManagement.vue";
+import KnowledgeManagement from "@/views/KMPlatform/KnowledgeBase/KM/KnowledgeManagement.vue";
+import AccountManage from "@/views/KMPlatform/Permission/AccountManage.vue";
+import PermissionManage from "@/views/KMPlatform/Permission/permission.vue";
+import RoleManage from "@/views/KMPlatform/Permission/RoleManage.vue";
+import EntityRelationshipTypeManagement from '@/views/KMPlatform/KGBuilder/KRTM/EntityRelationshipTypeManagement.vue'
+import { getSessionVar, deleteSessionVar } from "@/utils/session";
+
+const router = createRouter({
+  history: createWebHistory(import.meta.env.BASE_URL),
+  routes: [
+    {
+      path: "/",
+      component: AppCopy,
+      redirect: "/home",
+      children: [
+        {
+          path: "home",
+          name: "home",
+          component: HomeView,
+        },
+        {
+          path: "workspace",
+          name: "workspace",
+          component: () => import("@/views/WorkspaceView.vue"),
+          children: [
+            {
+              path: "queue/:id",
+              name: "queue",
+              component: () => import("@/views/QueueView.vue"),
+            },
+            {
+              path: "worker",
+              name: "worker",
+              component: () => import("@/views/WorkerView.vue"),
+            },
+            {
+              path: "graph",
+              name: "graph",
+              component: () => import("../views/GraphView.vue"),
+            },
+            {
+              path: "graph-mgr/:id",
+              name: "graph-mgr",
+              component: () => import("../views/GraphManagement.vue"),
+            },
+          ],
+        },
+        {
+          path: "about",
+          name: "about",
+          component: () => import("../views/AboutView.vue"),
+        },
+      ],
+    },
+    {
+      path: "/login",
+      name: "login",
+      component: Login,
+      meta: {
+
+      }
+    },
+
+    {
+      path: "/kmplatform",
+      name: "kmplatform",
+      component: Layout,
+      redirect: "/kmplatform/home",
+      children: [
+        {
+          path: "home",
+          name: "kmplatform-home",
+          meta: {
+            title: "主页",
+          },
+          component: Home,
+          children: [],
+        },
+        {
+          path: "knowledgebase",
+          name: "knowledgebase",
+          meta: {
+            title: "知识库",
+            keepAlive: true,
+          },
+          component: KnowledgeBase,
+          redirect: "/kmplatform/knowledgebase/kbm",
+          children: [
+            {
+              path: "kbm",
+              name: "kbm",
+              meta: {
+                title: "知识库",
+                keepAlive: true,
+              },
+              component: KnowledgeBaseManagement,
+            },
+            {
+              path: "km/:kbId",
+              name: "km",
+              meta: {
+                title: "知识库",
+                keepAlive: false,
+              },
+              component: KnowledgeManagement,
+            },
+          ],
+        },
+        {
+          path: "kgbuilder",
+          name: "kgbuilder",
+          meta: {
+            title: "知识图谱构建",
+          },
+          redirect: "/kmplatform/kgbuilder/tm",
+          component: KGBuilder,
+          children: [
+            {
+              path: "tm",
+              name: "kgb-tm",
+              meta: {
+                title: "术语管理",
+              },
+              component: TerminologyManagement,
+            },
+            {
+              path: 'etm',
+              name: 'kgb-etm',
+              meta: {
+                title: "实体类型管理",
+              },
+              component: EntityTypeManagement,
+            },
+            {
+              path: 'krtm',
+              name: 'kgb-krtm',
+              meta: {
+                title: "实体关系类型管理"
+              },
+              component: EntityRelationshipTypeManagement,
+            }
+          ]
+        },
+        {
+          path: "openplatform",
+          name: "openplatform",
+          meta: {
+            title: "开放平台",
+          },
+          component: OpenPlatform,
+          children: [],
+        },
+        {
+          path: "kgpermission",
+          name: "kgpermission",
+          meta: {
+            title: "系统权限",
+          },
+          redirect: "/kmplatform/kgpermission/AccountManage",
+          component: PermissionManage,
+          children: [
+            {
+              path: "RoleManage",
+              name: "kgb-RoleManage",
+              meta: {
+                title: "角色管理",
+              },
+              component: RoleManage,
+            },
+            {
+              path: "AccountManage",
+              name: "kgb-AccountManage",
+              meta: {
+                title: "账号管理",
+              },
+              component: AccountManage,
+            },
+          ],
+        },
+      ],
+    },
+  ],
+});
+
+router.beforeEach((to, from, next) => {
+  if (
+    getSessionVar("session_id") == null &&
+    getSessionVar("username") == null
+  ) {
+    if (to.name !== "login") {
+      next({ name: "login" }); // 重定向到登录页面
+    } else {
+      next(); // 确认转移
+    }
+  } else {
+    next(); // 确认转移
+  }
+});
+
+router.afterEach((to, from, failure) => {
+  if (isNavigationFailure(failure)) {
+    console.log('failed navigation', failure)
+  } else {
+    to.meta.title ? (document.title = to.meta.title as string) : document.title = '知识图谱自动化构建平台'
+  }
+})
+
+export default router;

+ 8 - 4
src/utils/session.ts

@@ -1,13 +1,17 @@
-export function saveSessionVar(name: string, value:string) {
+export function saveSessionVar(name: string, value: string) {
 
     sessionStorage.setItem(name, value);
 }
 
-export function getSessionVar(name: string){
+export function getSessionVar(name: string) {
     return sessionStorage.getItem(name);
 }
 
 
-export function deleteSessionVar(name: string){
+export function deleteSessionVar(name: string) {
     return sessionStorage.removeItem(name);
-}
+}
+
+export function clearSessionVar(name: string) {
+    return sessionStorage.clear();
+}

+ 16 - 298
src/views/AppCopy.vue

@@ -1,86 +1,6 @@
 <template>
-  <el-container v-if="isLoggedIn == false" class="login-box">
-    <div style="width: 50%"></div>
-    <div class="login-container">
-      <div class="login-header">
-        <!-- <h1>知识图谱自动化构建平台</h1><br> -->
-        <h1>欢迎{{ isSignedIn ? '注册' : '登录' }}知识图谱自动化构建平台</h1>
-      </div>
 
-      <div v-if="isSignedIn == false">
-        <el-form v-model="loginForm">
-          <el-form-item label="用户名" :label-width="loginForm.formLabelWidth" size="large">
-            <el-input v-model="loginForm.username" name="username" placeholder="请输入用户名"></el-input>
-          </el-form-item>
-          <el-form-item label="密码" :label-width="loginForm.formLabelWidth" size="large">
-            <el-input v-model="loginForm.password" name="password" type="password" placeholder="请输入密码"></el-input>
-          </el-form-item>
-          <el-form-item label="" :label-width="loginForm.formLabelWidth">
-            <el-button type="primary" @click="handleLoginSubmit">登录</el-button>
-            <el-button type="success" @click="handleSignIn">注册</el-button>
-          </el-form-item>
-        </el-form>
-      </div>
-      <div v-if="isSignedIn == true">
-        <!-- <div>
-        <h1>注册</h1>
-      </div> -->
-
-        <el-form :model="loginForm" :rules="signinRules" ref="signinForm">
-          <el-form-item label="用户名" :label-width="loginForm.formLabelWidth" prop="username" size="large">
-            <el-input v-model="loginForm.username" name="username" placeholder="请输入用户名"></el-input>
-          </el-form-item>
-          <el-form-item label="显示姓名" :label-width="loginForm.formLabelWidth" prop="full_name" size="large">
-            <el-input v-model="loginForm.full_name" name="full_name" placeholder="请输入姓名"></el-input>
-          </el-form-item>
-          <el-form-item label="密码" :label-width="loginForm.formLabelWidth" prop="password" size="large">
-            <el-input v-model="loginForm.password" name="password" type="password" placeholder="请输入密码"></el-input>
-          </el-form-item>
-          <el-form-item lable="密码确认" :label-width="loginForm.formLabelWidth" prop="password2" size="large">
-            <el-input v-model="loginForm.password2" name="password2" type="password" placeholder="请再次输入密码"></el-input>
-          </el-form-item>
-          <el-form-item label="邮箱" :label-width="loginForm.formLabelWidth" prop="email" size="large">
-            <el-input v-model="loginForm.email" name="email" placeholder="请输入邮箱"></el-input>
-          </el-form-item>
-          <el-form-item label="" :label-width="loginForm.formLabelWidth">
-            <el-button type="primary" @click="handleSignInSubmit">注册</el-button>
-            <el-button type="success" @click="handleSignIn">登录</el-button>
-          </el-form-item>
-        </el-form>
-      </div>
-    </div>
-
-  </el-container>
-  <el-container class="main-container" v-if="isLoggedIn">
-    <el-header class="site_header">
-      <el-row>
-        <el-col :span="18">
-          <div style="margin-top: 8px; font-size: large; font-weight: bold">
-            <span style="vertical-align: middle">知识图谱自动化构建平台</span>
-            <span class="knowledge-base-icon" @click="goToKMPlatform"></span>
-          </div>
-        </el-col>
-        <el-col :span="6" style="
-            justify-content: flex-end;
-            display: flex;
-            flex-direction: row;
-            margin-top: 8px;
-          ">
-          <el-dropdown style="margin-top: 10px">
-            <div style="font-size: medium; font-weight: bold; color: #000">
-              {{ user.full_name }}
-            </div>
-            <template #dropdown>
-              <el-dropdown-menu>
-                <el-dropdown-item>用户资料</el-dropdown-item>
-                <el-dropdown-item>修改密码</el-dropdown-item>
-                <el-dropdown-item @click="handleLogout">登出</el-dropdown-item>
-              </el-dropdown-menu>
-            </template>
-          </el-dropdown>
-        </el-col>
-      </el-row>
-    </el-header>
+  <el-container class="main-container">
     <el-container>
       <el-aside class="main-aside">
         <SideMenu @selectQueue="onSelectQueue" @selectMenu="onSelectMenu"></SideMenu>
@@ -99,84 +19,10 @@ import { onMounted, ref, watch, watchEffect } from "vue";
 import { useRouter, useRoute } from "vue-router";
 import { RouterView } from "vue-router";
 import SideMenu from "@/components/SideMenu.vue";
-import { userLogin, userSignin } from "@/api/AgentApi";
-import {
-  deleteSessionVar,
-  getSessionVar,
-  saveSessionVar,
-} from "@/utils/session";
-import { ElNotification, ElMessageBox, ElMessage } from "element-plus";
 import { useMenuStore } from "@/stores/menu.js";
-const { updateRouteList } = useMenuStore();
-const router = useRouter();
-const route = useRoute();
-// console.log('router', router.getRoutes(), route)
-const isSignedIn = ref(false);
-const loginForm = ref({
-  username: "",
-  password: "",
-  full_name: "",
-  password2: "",
-  email: "",
-  formLabelWidth: 100,
-});
-const signinForm = ref();
 
-function goToKMPlatform() {
-  router.push({ name: "kmplatform" });
-}
-
-const validatePassword = (rule: any, value: any, callback: Function) => {
-  if (value === "") {
-    callback(new Error("请输入密码"));
-  } else {
-    if (loginForm.value.password2 !== "") {
-      signinForm.value.validateField("password2");
-    }
-    callback();
-  }
-};
-const validatePassword2 = (rule: Object, value: string, callback: Function) => {
-  if (value === "") {
-    callback(new Error("请再次输入密码"));
-  } else if (value !== loginForm.value.password) {
-    callback(new Error("两次输入密码不一致"));
-  } else {
-    callback();
-  }
-};
+const router = useRouter();
 
-const signinRules = ref({
-  username: [
-    { required: true, message: "请输入用户名", trigger: "blur" },
-    { min: 3, max: 20, message: "长度在 3 到 10 个字符", trigger: "blur" },
-  ],
-  full_name: [
-    { required: true, message: "请输入姓名", trigger: "blur" },
-    { min: 2, max: 50, message: "姓名长度为2到50个字符", trigger: "blur" },
-  ],
-  password: [
-    { required: true, validator: validatePassword, trigger: "blur" },
-    { min: 6, max: 32, message: "密码长度为6到32个字符", trigger: "blur" },
-  ],
-  password2: [
-    { required: true, validator: validatePassword2, trigger: "blur" },
-  ],
-  email: [
-    { required: true, message: "请输入邮箱", trigger: "blur" },
-    {
-      type: "email",
-      message: "请输入有效的邮箱地址",
-      trigger: ["blur", "change"],
-    },
-  ],
-});
-const isLoggedIn = ref(false);
-const user = ref({
-  id: "0",
-  full_name: "John Doe",
-  username: "johndoe",
-});
 //校验注册信息
 const onSelectQueue = (idData: any) => {
   // console.log(router.getRoutes());
@@ -184,149 +30,14 @@ const onSelectQueue = (idData: any) => {
   // 假设队列详情页的路由路径是 '/workspace/queue'
   // 可以使用 router.push 方法来实现路由跳转
 
-  router.push({ path: `/workspace/queue/${idData.id}` });
+  router.push({ name: 'queue', params: { id: idData.id } });
 };
 const onSelectMenu = (menuData: any) => {
   if (menuData.name == "graph") {
-    router.push({ path: `/workspace/graph` });
+    router.push({ name: 'graph' });
   }
 };
-const handleSignIn = () => {
-  loginForm.value.username = "";
-  loginForm.value.password = "";
-  isSignedIn.value = !isSignedIn.value;
-};
-
-const handleSignInSubmit = () => {
-  // console.log('submit', loginForm.value)
-  signinForm.value.validate((valid: boolean) => {
-    if (valid) {
-      userSignin({
-        username: loginForm.value.username,
-        password: loginForm.value.password,
-        full_name: loginForm.value.full_name,
-        email: loginForm.value.email,
-      })
-        .then((res: any) => {
-          loginForm.value.password = "";
-          loginForm.value.password2 = "";
-          loginForm.value.email = "";
-          loginForm.value.full_name = "";
-          loginForm.value.username = "";
-          ElNotification({
-            title: "成功",
-            message: res.message,
-            type: "success",
-            duration: 3000,
-          });
-          isSignedIn.value = !isSignedIn.value;
-        })
-        .catch((err: any) => {
-          ElNotification({
-            title: "错误",
-            message: err.message,
-            type: "error",
-            duration: 3000,
-          });
-        });
-    } else {
-      console.log("表单校验失败");
-    }
-  });
-};
 
-const handleLoginSubmit = () => {
-  // console.log('submit', loginForm.value)
-  userLogin({
-    username: loginForm.value.username,
-    password: loginForm.value.password,
-  }).then((res: any) => {
-    // console.log(res.records[0])
-    loginForm.value.password = "";
-    saveSessionVar("session_id", res.records[0].session.session_id);
-    saveSessionVar("user_id", res.records[0].session.user_id);
-    saveSessionVar("username", res.records[0].session.username);
-    saveSessionVar("full_name", res.records[0].session.full_name);
-    let knowledageSystem = '';
-    let routeList: any = [{
-      path: '/kmplatform/home',
-      name: 'kmplatform-home',
-      title: "主页",
-      children: []
-    }]
-    res.records[0].menu_permissions.sort((a: any, b: any) => {
-      return a.id - b.id;
-    });
-    res.records[0].menu_permissions.forEach((item: any) => {
-      if (item.menu_name == "知识更新管理") {
-        knowledageSystem = 'true';
-      }
-      if (item.menu_route) {
-        routeList.push({
-          path: item.menu_route,
-          name: item.menu_route.split("/")[2],
-          title: item.name,
-          children: item.children,
-        });
-      }
-    });
-    console.log("knowledageSystem", knowledageSystem);
-    saveSessionVar("knowledageSystem", knowledageSystem);
-    saveSessionVar('routeList', JSON.stringify(routeList))
-
-    updateRouteList(routeList);
-
-    user.value = {
-      id: getSessionVar("user_id") || "0",
-      full_name: getSessionVar("full_name") || "John Doe",
-      username: getSessionVar("username") || "johndoe",
-    };
-
-    isLoggedIn.value = true;
-    goToKMPlatform()
-  }).catch((err: any) => {
-    ElMessage({
-      message: err.message,
-      type: 'error'
-    })
-    console.log(err)
-  })
-}
-
-function handleLogout() {
-  deleteSessionVar("session_id");
-  deleteSessionVar("user_id");
-  deleteSessionVar("username");
-  deleteSessionVar("full_name");
-  updateRouteList([]);
-  deleteSessionVar("knowledageSystem");
-  isLoggedIn.value = false;
-}
-
-onMounted(() => {
-  // 模拟从后端获取数据
-  setTimeout(() => {
-    user.value = {
-      id: getSessionVar("user_id") || "0",
-      full_name: getSessionVar("full_name") || "John Doe",
-      username: getSessionVar("username") || "johndoe",
-    };
-    if (user.value.id != "0") {
-      isLoggedIn.value = true;
-    } else {
-      isLoggedIn.value = false;
-    }
-
-    router.push({ path: "/" });
-  });
-});
-watchEffect(() => {
-  // 监听路由变化
-  console.log("route changed", route);
-  if (route.query.logout) {
-    handleLogout()
-  }
-})
 </script>
 <style scoped>
 #app {
@@ -336,17 +47,22 @@ watchEffect(() => {
 }
 
 .main-container {
-  width: 100vw;
-  height: 100vh;
+  width: 100%;
+  height: 100%;
   overflow: hidden;
+  box-sizing: margin-box;
+  padding: 0px;
+  margin: 0px;
+  min-width: 0px;
 }
 
 .login-box {
-  width: 100vw;
-  height: 100vh;
+  width: 100%;
+  height: 100%;
   background-image: url("@/assets/images/loginBanar.png");
   background-repeat: no-repeat;
   background-size: cover;
+  box-sizing: margin-box;
 }
 
 .login-container {
@@ -371,7 +87,7 @@ watchEffect(() => {
 
 .content-area {
   padding: 20px;
-  width: calc(100vw - 300px);
+  width: calc(100% - 300px);
   overflow: auto;
 }
 
@@ -382,6 +98,8 @@ watchEffect(() => {
 }
 
 .site_header {
+  width: 100%;
+  box-sizing: border-box;
   /* background-color: #c5c5c5; */
   background-color: #eef6ff;
   padding: 0 20px;

+ 90 - 90
src/views/GraphView.vue

@@ -1,16 +1,18 @@
 <template>
 
 
-    <el-row>        
-    <span style="text-align: right;"> <h2>知识图谱</h2></span>
+    <el-row>
+        <span style="text-align: right;">
+            <h2>知识图谱</h2>
+        </span>
     </el-row>
     <el-row style="margin:15px;">
         <el-button @click="handleRefreshTable">刷新</el-button>
     </el-row>
 
-    <el-row >           
+    <el-row>
         <el-table :data="pageData.records" highlight-current-row @current-change="handleCurrentChange">
-            <el-table-column prop="id" label="ID" width="50" ></el-table-column>
+            <el-table-column prop="id" label="ID" width="50"></el-table-column>
             <el-table-column prop="job_category" label="工作类型" width="200"></el-table-column>
             <el-table-column prop="job_name" label="工作名称" width="200"></el-table-column>
             <el-table-column prop="job_creator" label="创建人" width="100"></el-table-column>
@@ -19,11 +21,11 @@
                     <el-tag :type="getJobStatusTag(scope.row.status)">{{ formatStatus(scope.row.status) }}</el-tag>
                 </template>
             </el-table-column>
-            <el-table-column  label="操作" width="500">
+            <el-table-column label="操作" width="500">
                 <template v-slot="scope">
-                    <el-menu  mode="horizontal">
-                        
-                        <el-sub-menu index="1">                            
+                    <el-menu mode="horizontal">
+
+                        <el-sub-menu index="1">
                             <template #title>操作</template>
                             <el-menu-item index="1-1" @click="handleViewJob(scope.row)">查看</el-menu-item>
                         </el-sub-menu>
@@ -34,47 +36,44 @@
         </el-table>
 
     </el-row>
-    <el-row  style="margin-top:30px;">
-        <el-pagination
-        background
-        layout="prev, pager, next"
-        :total="pageData.total"
-        :page-size="pageData.page_size"
-        @current-change="handleCurrentPageChange"
-        :current-page.sync="pageData.page"
-        >
+    <el-row style="margin-top:30px;">
+        <el-pagination background layout="prev, pager, next" :total="pageData.total" :page-size="pageData.page_size"
+            @current-change="handleCurrentPageChange" :current-page.sync="pageData.page">
         </el-pagination>
     </el-row>
-    <el-drawer
-        title="工作详情"
-        v-model="showDrawer"
-        :direction="showDrawerDirection"        
-        >        
+    <el-drawer title="工作详情" v-model="showDrawer" :direction="showDrawerDirection">
         <el-tabs type="border-card" v-model="jobDetailsActivateTab">
             <el-tab-pane label="基本信息" name="basic_info">
-                <div class="prop_header">任务类型</div><div>{{ currentJob.job_category }}</div>
-                <div class="prop_header">任务名称</div><div>{{ currentJob.job_name }}</div>
-                <div class="prop_header">创建人</div><div>{{ currentJob.job_creator }}</div>
-                <div class="prop_header">创建时间</div><div>{{ formatDate(currentJob.created) }}</div>
-                <div class="prop_header">更新时间</div><div>{{ formatDate(currentJob.updated) }}</div>
-                <div class="prop_header">日志</div><div><el-input type="textarea" v-model="currentJob.job_logs" :rows="20"></el-input></div>
+                <div class="prop_header">任务类型</div>
+                <div>{{ currentJob.job_category }}</div>
+                <div class="prop_header">任务名称</div>
+                <div>{{ currentJob.job_name }}</div>
+                <div class="prop_header">创建人</div>
+                <div>{{ currentJob.job_creator }}</div>
+                <div class="prop_header">创建时间</div>
+                <div>{{ formatDate(currentJob.created) }}</div>
+                <div class="prop_header">更新时间</div>
+                <div>{{ formatDate(currentJob.updated) }}</div>
+                <div class="prop_header">日志</div>
+                <div><el-input type="textarea" v-model="currentJob.job_logs" :rows="20"></el-input></div>
             </el-tab-pane>
-            <el-tab-pane label="文件夹" name="file_browse">                
-                <el-row >
-                        <el-col :span="4">
-                            <el-tree :data="jobFileData" :props="jobFileTree" @node-click="handleTreeNodeClick"></el-tree>             
-                        </el-col>
-                        <el-col :span="20">                    
-                            <el-table v-if="jobFileInDir.length > 0" :data="jobFileInDir" highlight-current-row style="width: 100%;">
-                                <el-table-column prop="type" label="类型" width="75" ></el-table-column>
-                                <el-table-column prop="name" label="名称" width="250"></el-table-column>
-                                <el-table-column prop="size" label="操作" width="100">
-                                    <template v-slot="scope">
-                                        <a  :href="'/api/file/download/'+currentJob?.id+'/'+scope.row.path">下载</a>
-                                    </template>
-                                </el-table-column>
-                            </el-table>
-                        </el-col>
+            <el-tab-pane label="文件夹" name="file_browse">
+                <el-row>
+                    <el-col :span="4">
+                        <el-tree :data="jobFileData" :props="jobFileTree" @node-click="handleTreeNodeClick"></el-tree>
+                    </el-col>
+                    <el-col :span="20">
+                        <el-table v-if="jobFileInDir.length > 0" :data="jobFileInDir" highlight-current-row
+                            style="width: 100%;">
+                            <el-table-column prop="type" label="类型" width="75"></el-table-column>
+                            <el-table-column prop="name" label="名称" width="250"></el-table-column>
+                            <el-table-column prop="size" label="操作" width="100">
+                                <template v-slot="scope">
+                                    <a :href="'/api/file/download/' + currentJob?.id + '/' + scope.row.path">下载</a>
+                                </template>
+                            </el-table-column>
+                        </el-table>
+                    </el-col>
                 </el-row>
             </el-tab-pane>
         </el-tabs>
@@ -89,21 +88,22 @@
 
 import { ref, onMounted, watch } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
-import { 
-    getJob, 
-    getJobs, 
-    getQueue, 
-    browseJobFile, 
-    getJobStatus, 
+import {
+    getJob,
+    getJobs,
+    getQueue,
+    browseJobFile,
+    getJobStatus,
     getJobStatusTag,
-    JobSatus, 
-    deleteJob, 
-    updateJob, 
-    updateJobStatus } from '@/api/AgentApi'
-import type { JobData,  } from '@/api/AgentApi'
+    JobSatus,
+    deleteJob,
+    updateJob,
+    updateJobStatus
+} from '@/api/AgentApi'
+import type { JobData, } from '@/api/AgentApi'
 import OCRDialog from '@/dialogs/OCRDialog.vue'
 import QueueSelectDialog from '@/dialogs/QueueSelectDialog.vue'
-import { ElNotification,ElMessageBox } from 'element-plus'
+import { ElNotification, ElMessageBox } from 'element-plus'
 import { formatTime } from 'element-plus/es/components/countdown/src/utils.mjs'
 import { formatDate } from '@/utils/misc'
 import { getSessionVar, saveSessionVar } from '@/utils/session'
@@ -113,30 +113,30 @@ const sessionId = ref("")
 const ocrDialog = ref()
 const queueSelectDialog = ref()
 const queueId = ref("")
-const queueData = ref({id:"0",  queue_category:"", queue_name:"", title:""})
+const queueData = ref({ id: "0", queue_category: "", queue_name: "", title: "" })
 const showDrawer = ref(false)
 const showDrawerDirection = ref('rtl')
 const jobDetailsActivateTab = ref('basic_info')
 const queueIdNameDict = ref([
-    {id: "0", name: "DEFAULT", category:'SYSTEM', title:"缺省队列", dialog: ocrDialog},
-    {id: "1", name: "OCR", category:'SYSTEM', title:"文档OCR", dialog: ocrDialog},
-    {id: "2", name: "OCR_RESULTS", title:"OCR结果校对", category:'SYSTEM', dialog: null},
-    {id: "3", name: "CHUNKS", title:"文本切片队列", category:'SYSTEM', dialog: null},
-    {id: "4", name: "KB_EXTRACT", title:"知识抽取", category:'SYSTEM', dialog: null},
-    {id: "5", name: "KB_BUILD", title:"图谱数据构建", category:'SYSTEM', dialog: null},
-    {id: "6", name: "WORD", title:"WORD文档抽取", category:'SYSTEM', dialog: ocrDialog},
+    { id: "0", name: "DEFAULT", category: 'SYSTEM', title: "缺省队列", dialog: ocrDialog },
+    { id: "1", name: "OCR", category: 'SYSTEM', title: "文档OCR", dialog: ocrDialog },
+    { id: "2", name: "OCR_RESULTS", title: "OCR结果校对", category: 'SYSTEM', dialog: null },
+    { id: "3", name: "CHUNKS", title: "文本切片队列", category: 'SYSTEM', dialog: null },
+    { id: "4", name: "KB_EXTRACT", title: "知识抽取", category: 'SYSTEM', dialog: null },
+    { id: "5", name: "KB_BUILD", title: "图谱数据构建", category: 'SYSTEM', dialog: null },
+    { id: "6", name: "WORD", title: "WORD文档抽取", category: 'SYSTEM', dialog: ocrDialog },
 ])
 
 const jobStatusList = ref(JobSatus)
 const jobFileTree = ref({
-          children: 'children',
-          label: 'label'
-        })
-const pageData = ref({page:1, pages:1, page_size:10, total:0, records:[]})
+    children: 'children',
+    label: 'label'
+})
+const pageData = ref({ page: 1, pages: 1, page_size: 10, total: 0, records: [] })
 const jobFileData = ref([])
 const jobFileInDir = ref([])
-const currentJob = ref({id:0,job_category:"USER",job_name:""})
-const currentActionJob = ref({id:0,job_category:"USER",job_name:""})
+const currentJob = ref({ id: 0, job_category: "USER", job_name: "" })
+const currentActionJob = ref({ id: 0, job_category: "USER", job_name: "" })
 
 const route = useRoute()
 const router = useRouter()
@@ -148,31 +148,31 @@ watch(route, (newValue, oldValue) => {
     console.log('route changed')
     queueId.value = para
     queueData.value.id = "0"
-    loadQueueData() 
+    loadQueueData()
 })
 
 const handleRefreshTable = () => {
-    loadQueueData() 
+    loadQueueData()
 }
 function formatStatus(status: number) {
-    return getJobStatus(status) 
+    return getJobStatus(status)
 }
 function loadQueueData() {
-   
+
     jobFileData.value = []
     jobFileInDir.value = []
-    currentJob.value = {id:0,job_category:"USER",job_name:""}
-    currentActionJob.value = {id:0,job_category:"USER",job_name:""}
+    currentJob.value = { id: 0, job_category: "USER", job_name: "" }
+    currentActionJob.value = { id: 0, job_category: "USER", job_name: "" }
     // 根据队列ID获取队列数据
     let queue_data = queueIdNameDict.value.find((item) => item.id == queueId.value)
 
     if (queue_data == undefined) {
-        queueData.value = {id:"999", queue_category: 'SYSTEM', queue_name: 'UNKNOWN', title:"未知队列"}
+        queueData.value = { id: "999", queue_category: 'SYSTEM', queue_name: 'UNKNOWN', title: "未知队列" }
         return
     }
     getQueue(queue_data.category, queue_data.name).then((res) => {
         if (res.records.length == 0) {
-            return 
+            return
         }
         queueData.value.id = res.records[0].id
         queueData.value.queue_category = res.records[0].queue_category
@@ -183,36 +183,36 @@ function loadQueueData() {
         pageData.value.page = res.meta.page
         pageData.value.pages = res.meta.pages
         pageData.value.total = res.meta.total
-        pageData.value.records = res.records 
-        
+        pageData.value.records = res.records
+
     })
 }
-function handleTreeNodeClick(data:any) {
-    if (data.type=='dir'){
-        browseJobFile({ job_id:currentJob.value.id, path:data.name}).then((res) => {
+function handleTreeNodeClick(data: any) {
+    if (data.type == 'dir') {
+        browseJobFile({ job_id: currentJob.value.id, path: data.name }).then((res) => {
             jobFileInDir.value = res.records
         })
     }
 }
-function handleCurrentPageChange(page:number) {
+function handleCurrentPageChange(page: number) {
     getJobs(queueData.value.queue_category, queueData.value.queue_name, page).then((res) => {
         pageData.value.page = res.meta.page
         pageData.value.pages = res.meta.pages
         pageData.value.total = res.meta.total
         pageData.value.records = res.records
-    }) 
+    })
 }
-function handleViewJob(job:JobData) {
+function handleViewJob(job: JobData) {
     if (job == null) {
         return
-    }    
-    router.push({ path: `/workspace/graph-mgr/${job.id}` })
+    }
+    router.push({ name: 'graph-mgr', params: { id: job.id } })
 }
-function handleCurrentChange(data:any) {
+function handleCurrentChange(data: any) {
     if (data == null) {
         return
     }
-    
+
     //currentJob.value = data
 }
 onMounted(() => {

+ 357 - 0
src/views/Login/Login.vue

@@ -0,0 +1,357 @@
+<template>
+
+  <el-container class="login-box">
+    <div style="width: 50%"></div>
+    <div class="login-container">
+      <div class="login-header">
+        <!-- <h1>知识图谱自动化构建平台</h1><br> -->
+        <h1>欢迎{{ isSignedIn ? '注册' : '登录' }}知识图谱自动化构建平台</h1>
+      </div>
+
+      <div v-if="isSignedIn == false">
+        <el-form v-model="loginForm">
+          <el-form-item label="用户名" :label-width="loginForm.formLabelWidth" size="large" required>
+            <el-input v-model="loginForm.username" autocomplete="username" name="username" placeholder="请输入用户名"
+              required></el-input>
+          </el-form-item>
+          <el-form-item label="密码" :label-width="loginForm.formLabelWidth" size="large" required>
+            <el-input v-model="loginForm.password" autocomplete="current-password" name="password" type="password"
+              required placeholder="请输入密码"></el-input>
+          </el-form-item>
+          <el-form-item label="" :label-width="loginForm.formLabelWidth">
+            <el-button type="primary" @click="handleLoginSubmit">登录</el-button>
+            <el-button type="success" @click="handleSignIn">注册</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+      <div v-if="isSignedIn == true">
+        <!-- <div>
+        <h1>注册</h1>
+      </div> -->
+
+        <el-form :model="loginForm" :rules="signinRules" ref="signinForm">
+          <el-form-item label="用户名" :label-width="loginForm.formLabelWidth" prop="username" size="large">
+            <el-input v-model="loginForm.username" name="username" placeholder="请输入用户名"></el-input>
+          </el-form-item>
+          <el-form-item label="显示姓名" :label-width="loginForm.formLabelWidth" prop="full_name" size="large">
+            <el-input v-model="loginForm.full_name" name="full_name" placeholder="请输入姓名"></el-input>
+          </el-form-item>
+          <el-form-item label="密码" :label-width="loginForm.formLabelWidth" prop="password" size="large">
+            <el-input v-model="loginForm.password" name="password" type="password" placeholder="请输入密码"></el-input>
+          </el-form-item>
+          <el-form-item lable="密码确认" :label-width="loginForm.formLabelWidth" prop="password2" size="large">
+            <el-input v-model="loginForm.password2" name="password2" type="password" placeholder="请再次输入密码"></el-input>
+          </el-form-item>
+          <el-form-item label="邮箱" :label-width="loginForm.formLabelWidth" prop="email" size="large">
+            <el-input v-model="loginForm.email" name="email" placeholder="请输入邮箱"></el-input>
+          </el-form-item>
+          <el-form-item label="" :label-width="loginForm.formLabelWidth">
+            <el-button type="primary" @click="handleSignInSubmit">注册</el-button>
+            <el-button type="success" @click="handleSignIn">登录</el-button>
+          </el-form-item>
+        </el-form>
+      </div>
+    </div>
+
+  </el-container>
+</template>
+
+<script setup lang="ts">
+import { onMounted, ref, watch, watchEffect } from "vue";
+import { useRouter, useRoute } from "vue-router";
+import { userLogin, userSignin } from "@/api/AgentApi";
+import {
+  deleteSessionVar,
+  getSessionVar,
+  saveSessionVar,
+} from "@/utils/session";
+import { ElNotification, ElMessageBox, ElMessage } from "element-plus";
+import { useMenuStore } from "@/stores/menu.js";
+const { updateRouteList } = useMenuStore();
+const router = useRouter();
+const route = useRoute();
+// console.log('router', router.getRoutes(), route)
+const isSignedIn = ref(false);
+const loginForm = ref({
+  username: "",
+  password: "",
+  full_name: "",
+  password2: "",
+  email: "",
+  formLabelWidth: 100,
+});
+const signinForm = ref();
+
+function goToKMPlatform() {
+  router.push({ name: "kmplatform" });
+}
+
+const validatePassword = (rule: any, value: any, callback: Function) => {
+  if (value === "") {
+    callback(new Error("请输入密码"));
+  } else {
+    if (loginForm.value.password2 !== "") {
+      signinForm.value.validateField("password2");
+    }
+    callback();
+  }
+};
+const validatePassword2 = (rule: Object, value: string, callback: Function) => {
+  if (value === "") {
+    callback(new Error("请再次输入密码"));
+  } else if (value !== loginForm.value.password) {
+    callback(new Error("两次输入密码不一致"));
+  } else {
+    callback();
+  }
+};
+
+const signinRules = ref({
+  username: [
+    { required: true, message: "请输入用户名", trigger: "blur" },
+    { min: 3, max: 20, message: "长度在 3 到 10 个字符", trigger: "blur" },
+  ],
+  full_name: [
+    { required: true, message: "请输入姓名", trigger: "blur" },
+    { min: 2, max: 50, message: "姓名长度为2到50个字符", trigger: "blur" },
+  ],
+  password: [
+    { required: true, validator: validatePassword, trigger: "blur" },
+    { min: 6, max: 32, message: "密码长度为6到32个字符", trigger: "blur" },
+  ],
+  password2: [
+    { required: true, validator: validatePassword2, trigger: "blur" },
+  ],
+  email: [
+    { required: true, message: "请输入邮箱", trigger: "blur" },
+    {
+      type: "email",
+      message: "请输入有效的邮箱地址",
+      trigger: ["blur", "change"],
+    },
+  ],
+});
+const isLoggedIn = ref(false);
+const user = ref({
+  id: "0",
+  full_name: "John Doe",
+  username: "johndoe",
+});
+//校验注册信息
+const onSelectQueue = (idData: any) => {
+  // console.log(router.getRoutes());
+  // 跳转到队列详情页并且传递队列ID作为查询参数
+  // 假设队列详情页的路由路径是 '/workspace/queue'
+  // 可以使用 router.push 方法来实现路由跳转
+
+  router.push({ path: `/workspace/queue/${idData.id}` });
+};
+const onSelectMenu = (menuData: any) => {
+  if (menuData.name == "graph") {
+    router.push({ path: `/workspace/graph` });
+  }
+};
+const handleSignIn = () => {
+  loginForm.value.username = "";
+  loginForm.value.password = "";
+  isSignedIn.value = !isSignedIn.value;
+};
+
+const handleSignInSubmit = () => {
+  // console.log('submit', loginForm.value)
+  signinForm.value.validate((valid: boolean) => {
+    if (valid) {
+      userSignin({
+        username: loginForm.value.username,
+        password: loginForm.value.password,
+        full_name: loginForm.value.full_name,
+        email: loginForm.value.email,
+      })
+        .then((res: any) => {
+          loginForm.value.password = "";
+          loginForm.value.password2 = "";
+          loginForm.value.email = "";
+          loginForm.value.full_name = "";
+          loginForm.value.username = "";
+          ElNotification({
+            title: "成功",
+            message: res.message,
+            type: "success",
+            duration: 3000,
+          });
+          isSignedIn.value = !isSignedIn.value;
+        })
+        .catch((err: any) => {
+          ElNotification({
+            title: "错误",
+            message: err.message,
+            type: "error",
+            duration: 3000,
+          });
+        });
+    } else {
+      console.log("表单校验失败");
+    }
+  });
+};
+
+const handleLoginSubmit = () => {
+  // console.log('submit', loginForm.value)
+  userLogin({
+    username: loginForm.value.username,
+    password: loginForm.value.password,
+  }).then((res: any) => {
+    // console.log(res.records[0])
+    loginForm.value.password = "";
+    saveSessionVar("session_id", res.records[0].session.session_id);
+    saveSessionVar("user_id", res.records[0].session.user_id);
+    saveSessionVar("username", res.records[0].session.username);
+    saveSessionVar("full_name", res.records[0].session.full_name);
+    let knowledageSystem = '';
+    let routeList: any = [{
+      path: '/kmplatform/home',
+      name: 'kmplatform-home',
+      title: "主页",
+      children: []
+    }]
+    res.records[0].menu_permissions.sort((a: any, b: any) => {
+      return a.id - b.id;
+    });
+    res.records[0].menu_permissions.forEach((item: any) => {
+      if (item.menu_name == "知识更新管理") {
+        knowledageSystem = 'true';
+      }
+      if (item.menu_route) {
+        routeList.push({
+          path: item.menu_route,
+          name: item.menu_route.split("/")[2],
+          title: item.name,
+          children: item.children,
+        });
+      }
+    });
+    console.log("knowledageSystem", knowledageSystem);
+    saveSessionVar("knowledageSystem", knowledageSystem);
+    saveSessionVar('routeList', JSON.stringify(routeList))
+
+    updateRouteList(routeList);
+
+    user.value = {
+      id: getSessionVar("user_id") || "0",
+      full_name: getSessionVar("full_name") || "John Doe",
+      username: getSessionVar("username") || "johndoe",
+    };
+
+    isLoggedIn.value = true;
+    goToKMPlatform()
+  }).catch((err: any) => {
+    ElMessage({
+      message: err.message,
+      type: 'error'
+    })
+    console.log(err)
+  })
+}
+
+function handleLogout() {
+  deleteSessionVar("session_id");
+  deleteSessionVar("user_id");
+  deleteSessionVar("username");
+  deleteSessionVar("full_name");
+  updateRouteList([]);
+  deleteSessionVar("knowledageSystem");
+  isLoggedIn.value = false;
+}
+
+onMounted(() => {
+  // 模拟从后端获取数据
+  setTimeout(() => {
+    user.value = {
+      id: getSessionVar("user_id") || "0",
+      full_name: getSessionVar("full_name") || "John Doe",
+      username: getSessionVar("username") || "johndoe",
+    };
+    if (user.value.id != "0") {
+      isLoggedIn.value = true;
+    } else {
+      isLoggedIn.value = false;
+    }
+
+    // router.push({ path: "/" });
+  });
+});
+watchEffect(() => {
+  // 监听路由变化
+  console.log("route changed", route);
+  if (route.query.logout) {
+    handleLogout()
+  }
+})
+</script>
+<style scoped>
+#app {
+  width: 100vw;
+  height: 100vh;
+  overflow: auto;
+}
+
+.main-container {
+  width: 100vw;
+  height: 100vh;
+  overflow: hidden;
+}
+
+.login-box {
+  width: 100vw;
+  height: 100vh;
+  background-image: url("@/assets/images/loginBanar.png");
+  background-repeat: no-repeat;
+  background-size: cover;
+}
+
+.login-container {
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
+  align-items: center;
+  margin: auto;
+  width: 500px;
+  /* width: 100vw; */
+  /* height: 100vh; */
+  padding: 50px;
+  background-color: #eef6ff;
+  border-radius: 12px 12px 12px 12px;
+}
+
+.login-header {
+  font-size: 26px;
+  font-weight: bold;
+  margin-bottom: 20px;
+}
+
+.content-area {
+  padding: 20px;
+  width: calc(100vw - 300px);
+  overflow: auto;
+}
+
+.main-aside {
+  width: 300px;
+  border-right: 0px solid #e4e7ed;
+  padding: 1px;
+}
+
+.site_header {
+  /* background-color: #c5c5c5; */
+  background-color: #eef6ff;
+  padding: 0 20px;
+  height: 50px;
+  /* border-bottom: 1px solid #e4e7ed; */
+}
+
+.knowledge-base-icon {
+  cursor: pointer;
+  vertical-align: middle;
+  margin-left: 10px;
+}
+</style>