Kaynağa Gözat

登录权限

CzRger 3 hafta önce
ebeveyn
işleme
766f0698f1

+ 7 - 3
.env.development

@@ -1,8 +1,12 @@
 # 本地环境
 NODE_ENV = development
-
 # 标题
 VITE_TITLE = 大模型智能应用开发及监测平台
-
+# 是否需要登录  Y/N
+VITE_LOGIN_MUST = Y
+# token标识
+VITE_TOKEN = bmwToken
 # 基础路径
-VITE_BASE = 'big-model-web'
+VITE_BASE = big-model-web
+# 基础路径
+VITE_BASE_API_PROXY = /bmw-api

+ 7 - 3
.env.production

@@ -1,8 +1,12 @@
 # 生产环境
 NODE_ENV = production
-
 # 标题
 VITE_TITLE = 大模型智能应用开发及监测平台
-
+# 是否需要登录  Y/N
+VITE_LOGIN_MUST = Y
+# token标识
+VITE_TOKEN = bmwToken
 # 基础路径
-VITE_BASE = 'big-model-web'
+VITE_BASE = big-model-web
+# 基础路径
+VITE_BASE_API_PROXY = /bmw-api

+ 0 - 3
.prettierignore

@@ -1,3 +0,0 @@
-# Ignore artifacts:
-build
-coverage

+ 1 - 1
README.md

@@ -1,4 +1,4 @@
-# nodejs: > 18.17.1
+# nodejs: > 22.17.0
 
 # 安装依赖: yarn
 

+ 0 - 55
src/api/index.ts

@@ -1,55 +0,0 @@
-import HttpService from './request'
-
-export const handle = ({
-  url,
-  params,
-  method,
-  config,
-  filName,
-  onProcess,
-}: any) => {
-  const httpService = new HttpService()
-  // @ts-ignore
-  return httpService[method.toLowerCase()]({
-    url,
-    params,
-    config,
-    filName,
-    onProcess,
-  })
-}
-
-// @ts-ignore
-const files = import.meta.glob('/src/api/modules/**/*.ts')
-const apiModule: any = {}
-const apiRepeatMap = new Map()
-let num1 = 0
-let num2 = 0
-
-for (const [key, value] of Object.entries(files)) {
-  num1++
-  // @ts-ignore
-  value().then((res) => {
-    for (const [apiKey, apiValue] of Object.entries(res)) {
-      if (apiKey !== '__tla') {
-        // 过滤掉内部属性,非业务
-        if (apiRepeatMap.has(apiKey)) {
-          apiRepeatMap.set(apiKey, [...apiRepeatMap.get(apiKey), key])
-        } else {
-          apiRepeatMap.set(apiKey, [key])
-        }
-      }
-    }
-    Object.assign(apiModule, res)
-    num2++
-    if (num1 === num2) {
-      apiRepeatMap.forEach((v, k) => {
-        if (v.length > 1) {
-          console.error(`检测到接口${k}重复定义,路径为:`, v)
-        }
-      })
-    }
-  })
-}
-
-export default apiModule

+ 17 - 21
src/api/interceptors.ts

@@ -1,5 +1,6 @@
 import axios from 'axios'
-import { ElMessage } from 'element-plus'
+import { ElMessage, ElNotification } from 'element-plus'
+
 // import {toLogin} from "@/utils/permissions";
 export class Interceptors {
   public instance: any
@@ -17,7 +18,6 @@ export class Interceptors {
   }
 
   public initInterceptors() {
-    // this.instance.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=utf-8'
     /**
      * 请求拦截器
      * 每次请求前,如果存在token则在请求头中携带token
@@ -25,7 +25,9 @@ export class Interceptors {
     this.instance.interceptors.request.use(
       (config: any) => {
         if (!config.headers.Authorization) {
-          const token = localStorage.getItem('__token')
+          const token = localStorage.getItem(
+            (import.meta as any).env.VITE_TOKEN,
+          )
           if (token) {
             config.headers.Authorization = token
           } else {
@@ -42,14 +44,7 @@ export class Interceptors {
     this.instance.interceptors.response.use(
       // 请求成功
       (res: any) => {
-        if (res.data.code === 200 || res.data.code == 0) {
-          return Promise.resolve(res.data)
-        } else if (res.data.code === 500) {
-          ElMessage.error(res.data?.msg)
-          return Promise.reject(res.data?.msg)
-        } else {
-          return Promise.resolve(res)
-        }
+        return Promise.resolve(res.data)
       },
       // 请求失败
       (error: { response: any }) => {
@@ -68,20 +63,21 @@ export class Interceptors {
   }
 
   private errorHandle(res: any) {
-    console.error('错误接口:' + res.data.path)
+    console.error('错误接口:' + res.request.responseURL)
     // 状态码判断
     switch (res.status) {
-      case 401:
-        ElMessage.warning(res.data.msg)
-        // toLogin()
-        break
-      case 403:
-        break
-      case 404:
-        ElMessage.error('请求的资源不存在')
+      case 400:
+        ElNotification({
+          title: res.data.message,
+          message: res.data.data,
+          type: 'error',
+        })
         break
       default:
-        ElMessage.warning('连接错误')
+        ElNotification({
+          title: '连接错误',
+          type: 'error',
+        })
     }
   }
 }

+ 7 - 0
src/api/modules/global/login.ts

@@ -0,0 +1,7 @@
+import { get, post } from '@/api/request'
+// 验证码
+export const loginCaptcha = () => get('/login/captcha', {}, {})
+// 登录
+export const loginSubmit = (params) => post('/login/submit', params, {})
+// 获取用户信息
+export const userInfo = () => get('/user/info', {}, {})

+ 4 - 0
src/api/modules/knowledge/index.ts

@@ -0,0 +1,4 @@
+import { get, post } from '@/api/request'
+
+export const datasetsGetAllByPage = (params) =>
+  post('/datasets/getAllByPage', params, {})

+ 36 - 140
src/api/request.ts

@@ -1,146 +1,42 @@
-import { Interceptors } from './interceptors'
-export class HttpRequest {
-  public axios: any
-  constructor() {
-    // 获取axios实例
-    this.axios = new Interceptors().getInterceptors()
-  }
-  public get({ url = '', params, config = {} }) {
-    return new Promise((resolve, reject) => {
-      let paramUrl = url
-      if (params) {
-        paramUrl += `?${params}`
-      }
-      this.axios
-        .get(paramUrl, {
-          ...config,
-        })
-        .then((res: any) => {
-          this.resultHandle(res, resolve, reject, url)
-        })
-        .catch((err: { message: any }) => {
-          console.log(err)
-          reject(err.message)
-        })
-    })
-  }
+import { Interceptors } from '@/api/interceptors'
 
-  public post({ url = '', params, config = {} }) {
-    return new Promise((resolve, reject) => {
-      this.axios
-        .post(url, params, {
-          ...config, //  导出添加的下载类型
-        })
-        .then((res: any) => {
-          this.resultHandle(res, resolve, reject, url)
-        })
-        .catch((err: { message: any }) => {
-          reject(err.message)
-        })
-    })
-  }
+const request: any = new Interceptors().getInterceptors()
 
-  public delete({ url = '', params, config = {} }) {
-    return new Promise((resolve, reject) => {
-      let paramUrl = url
-      if (params) {
-        paramUrl += `?${params}`
-      }
-      this.axios
-        .delete(paramUrl, {
-          ...config,
-        })
-        .then((res: any) => {
-          this.resultHandle(res, resolve, reject, url)
-        })
-        .catch((err: { message: any }) => {
-          console.log(err)
-          reject(err.message)
-        })
-    })
-  }
-  public put({ url = '', params, config = {} }) {
-    return new Promise((resolve, reject) => {
-      this.axios
-        .put(url, params, {
-          ...config, //  导出添加的下载类型
-        })
-        .then((res: any) => {
-          this.resultHandle(res, resolve, reject, url)
-        })
-        .catch((err: { message: any }) => {
-          reject(err.message)
-        })
-    })
-  }
-  public upload({ url, params, onProcess = (p) => {} }) {
-    return new Promise(async (resolve, reject) => {
-      this.axios
-        .post(url, params, {
-          headers: {
-            authorization:
-              'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6Ijg4NGJjMjQ5LTQ2ZTktNDhhYi1hNjAyLWIzMGYxZTUwNDMxMSJ9.KoDqMUYjxGk4obbaKYcGjYCbS891t9PCriBGbsBAlOdGfySdKvDeF3H8WrIO0DWG09Ew7sKStUUnXr4gqdlAaw',
-          },
-          onUploadProgress: (progressEvent) => {
-            const percent = Math.round(
-              (progressEvent.loaded / progressEvent.total) * 100,
-            )
-            // console.log(`上传进度: ${percent}%`);
-            onProcess(percent)
-          },
-        })
-        .then((res: any) => {
-          this.resultHandle(res, resolve, reject, url)
-        })
-        .catch((err: { message: any }) => {
-          reject(err.message)
-        })
-    })
-  }
+export const get = (url = '', params: any = {}, config: any = {}) => {
+  return new Promise((resolve, reject) => {
+    const rUrl = (import.meta as any).env.VITE_BASE_API_PROXY + url
+    request
+      .get(rUrl, {
+        params,
+        ...config,
+      })
+      .then((res: any) => {
+        resultHandle(res, resolve, reject, rUrl)
+      })
+      .catch((res: any) => {
+        resultHandle(res, resolve, reject, rUrl)
+      })
+  })
+}
+export const post = (url = '', params: any = {}, config: any = {}) => {
+  return new Promise((resolve, reject) => {
+    const rUrl = (import.meta as any).env.VITE_BASE_API_PROXY + url
+    request
+      .post(rUrl, params, {
+        ...config,
+      })
+      .then((res: any) => {
+        resultHandle(res, resolve, reject, rUrl)
+      })
+  })
+}
 
-  public resultHandle(
-    res: any,
-    resolve: {
-      (value: unknown): void
-      (value: unknown): void
-      (arg0: any): void
-    },
-    reject: {
-      (value: unknown): void
-      (value: unknown): void
-      (arg0: any): void
-    },
-    url: string,
-  ) {
-    if (res) {
-      if (res.code === 200 || (res.size > 0 && res.type)) {
-        //  增加blob文件判断
-        resolve(res)
-      } else {
-        resolve(res)
-        // this.errorHandle(res, reject, url);
-      }
-    }
-  }
-  public errorHandle(res: any, reject: any, url: string) {
-    console.error('错误接口:' + url)
-    if (res.hasOwnProperty('message')) {
-      // ElMessage.warning(res.message);  // 统一谈服务端提示,我们提示统一由服务端提供
-    } else if (res.hasOwnProperty('msg')) {
-      // ElMessage.warning(res.msg);  // 统一谈服务端提示,我们提示统一由服务端提供
-    }
-    // 状态码判断
-    if (res) {
-      switch (res.code) {
-        case -102:
-          break
-        case -152:
-          break
-        default:
-          reject(res)
-      }
+const resultHandle = (res: any, resolve: any, reject: any, url: string) => {
+  if (res) {
+    if (res.code === 200) {
+      resolve(res)
+    } else {
+      reject(res)
     }
   }
 }
-
-export default HttpRequest

BIN
src/assets/images/login/code.png


+ 1 - 1
src/main.ts

@@ -21,7 +21,7 @@ app.use(initDirectives)
 app.use(createPinia())
 await initProperties(app)
 initComponent(app)
-await beforeInit()
+// await beforeInit()
 app.use(router)
 app.use(ElementPlus)
 app.use(Antd)

+ 42 - 46
src/router/index.ts

@@ -5,7 +5,7 @@ import Temp404 from '@/views/global/temp/404.vue'
 import RouterView from '@/layout/router-view.vue'
 // @ts-ignore
 import Layout from '@/layout/index.vue'
-import { useMenuStore } from '@/stores'
+import { useAppStore } from '@/stores'
 const routes = [
   demoRouter,
   { path: '/:pathMatch(.*)*', name: 'NotFound', component: Temp404 },
@@ -33,58 +33,54 @@ const routes = [
     },
   },
 ]
-
+const hasLogin = (import.meta as any).env.VITE_LOGIN_MUST === 'Y'
 const router = createRouter({
   // @ts-ignore
   history: createWebHistory(import.meta.env.BASE_URL),
   routes,
 })
+const initUser = (next, isLogin = false) => {
+  const AppStore = useAppStore()
+  if (hasLogin) {
+    if (AppStore.userInfo) {
+      isLogin ? next({ name: 'root' }) : next()
+      AppStore.loadingEnd()
+    } else {
+      if (localStorage.getItem((import.meta as any).env.VITE_TOKEN)) {
+        AppStore.initUserInfo()
+          .then(() => {
+            isLogin ? next({ name: 'root' }) : next()
+          })
+          .catch((e) => {
+            localStorage.removeItem((import.meta as any).env.VITE_TOKEN)
+            next({ name: 'login' })
+          })
+          .finally(() => {
+            AppStore.loadingEnd()
+          })
+      } else {
+        next({ name: 'login' })
+        AppStore.loadingEnd()
+      }
+    }
+  } else {
+    next()
+    AppStore.loadingEnd()
+  }
+}
 router.beforeEach((to, from, next) => {
-  const loading = document.getElementById('loader')
-  if (to.meta?.noLoading && loading) {
-    loading.style.display = 'none'
+  if (to.name === 'login') {
+    initUser(next, true)
+  } else {
+    initUser(next)
   }
-  next()
 })
-// export const initRoutes = () => {
-//     const MenuStore = useMenuStore()
-//     return new Promise((resolve, reject) => {
-//         setTimeout(() => {
-//             MenuStore.initRoutes(MenuStore.mockApi)
-//             resolve(null)
-//         }, 1000)
-//     })
+// export const beforeInit = () => {
+//   const l = document.getElementById('loader')
+//   if (!hasLogin) {
+//     if (l) {
+//       l.style.display = 'none'
+//     }
+//   }
 // }
-export const beforeInit = () => {
-  const l = document.getElementById('loader')
-  if (l) {
-    l.style.display = 'none'
-  }
-  // if (location.pathname === (import.meta as any).env.BASE_URL + 'assistant') {
-  //     document.title = "“i口岸”通关小助理";
-  //     let link: any = document.querySelector("link[rel*='icon']") || document.createElement('link');
-  //     link.type = 'image/x-icon';
-  //     link.rel = 'shortcut icon';
-  //     link.href = chatLogo;
-  //     document.head.appendChild(link);
-  //     const loginData = {
-  //         email: 'guest@qq.com',
-  //         password: 'tj123456',
-  //         language: 'zh-Hans',
-  //         remember_me: true,
-  //         anonymous: true
-  //     }
-  //     login({
-  //         url: '/login',
-  //         body: loginData,
-  //     }).then((res: any) => {
-  //         localStorage.setItem('console_token', res.data.access_token)
-  //         localStorage.setItem('refresh_token', res.data.refresh_token)
-  //         const l = document.getElementById('loader')
-  //         if (l) {
-  //             l.style.display = 'none'
-  //         }
-  //     })
-  // }
-}
 export default router

+ 1 - 0
src/stores/index.ts

@@ -1,3 +1,4 @@
+export * from './modules/app'
 export * from './modules/dialog'
 export * from './modules/menu'
 export * from './modules/workflow'

+ 35 - 0
src/stores/modules/app.ts

@@ -0,0 +1,35 @@
+import { defineStore } from 'pinia'
+import { userInfo } from '@/api/modules/global/login'
+
+export const useAppStore = defineStore('app', {
+  state: () => ({
+    userInfo: null,
+  }),
+  getters: {},
+  actions: {
+    initUserInfo() {
+      return new Promise((resolve, reject) => {
+        userInfo()
+          .then((res: any) => {
+            this.userInfo = res.data
+            resolve(this.userInfo)
+          })
+          .catch((e) => {
+            reject(e)
+          })
+      })
+    },
+    loadingStart() {
+      const l = document.getElementById('loader')
+      if (l) {
+        l.style.display = 'unset'
+      }
+    },
+    loadingEnd() {
+      const l = document.getElementById('loader')
+      if (l) {
+        l.style.display = 'none'
+      }
+    },
+  },
+})

+ 1 - 1
src/style/index.scss

@@ -27,7 +27,7 @@ body,
 .loader {
   width: 100%;
   height: 100vh;
-  background-color: #000000;
+  background-color: #ffffff;
   display: flex;
   align-items: center;
   justify-content: center;

+ 62 - 9
src/views/global/login/index.vue

@@ -12,26 +12,51 @@
             <CzrFormColumn
               required
               width="100%"
+              label-width="0px"
               v-model:param="state.form.username"
               placeholder="请输入您的账号"
               default-error-msg="请输入您的账号"
               :prefix-icon="User"
+              size="large"
             />
           </div>
-          <div class="mt-4 w-full">
+          <div class="w-full">
             <CzrFormColumn
               required
+              label-width="0px"
               width="100%"
               v-model:param="state.form.password"
               type="password"
               placeholder="请输入您的密码"
               default-error-msg="请输入您的密码"
               :prefix-icon="Lock"
+              size="large"
             />
           </div>
+          <div class="flex w-full">
+            <div class="mr-2 flex-1">
+              <CzrFormColumn
+                label-width="0px"
+                width="100%"
+                v-model:param="state.form.captcha"
+                placeholder="请输入验证码"
+                default-error-msg="请输入验证码"
+                :prefix-icon="Clock"
+                size="large"
+              />
+            </div>
+            <div class="h-[38px]">
+              <img
+                class="h-full w-full"
+                v-if="state.codeImg"
+                :src="state.codeImg"
+                @click="initCode"
+              />
+            </div>
+          </div>
         </CzrForm>
         <div
-          class="__hover mt-8 flex h-[2.5rem] w-full items-center justify-center bg-[#3363DE] text-[0.88rem] text-[#ffffff]"
+          class="__hover mt-2 flex h-[2.5rem] w-full items-center justify-center bg-[#3363DE] text-[0.88rem] text-[#ffffff]"
           @click="onLogin"
           v-loading="state.loading"
         >
@@ -43,28 +68,44 @@
 </template>
 
 <script setup lang="ts">
-import { computed, getCurrentInstance, reactive, ref } from 'vue'
-import { User, Lock } from '@element-plus/icons-vue'
+import { computed, getCurrentInstance, reactive, ref, onMounted } from 'vue'
+import { User, Lock, Clock } from '@element-plus/icons-vue'
 import { ElMessage } from 'element-plus'
+import { loginCaptcha, loginSubmit } from '@/api/modules/global/login'
+import CzrForm from '@/components/czr-ui/CzrForm.vue'
 
 const emit = defineEmits([])
 const props = defineProps({})
 const { proxy }: any = getCurrentInstance()
 const state: any = reactive({
-  form: {},
+  form: {
+    username: 'super-admin',
+    password: 'Ai@2025',
+    captcha: '',
+    tenantId: 0,
+  },
   loading: false,
+  codeImg: '',
 })
 const ref_form = ref()
-const titleCpt = computed(() => import.meta.env.VITE_TITLE)
+const titleCpt = computed(() => (import.meta as any).env.VITE_TITLE)
 const onLogin = () => {
   if (!state.loading) {
     ref_form.value
       .submit()
       .then(() => {
         state.loading = true
-        ElMessage.success('登录成功!')
-        localStorage.setItem('bm_token', 'token')
-        window.location.replace(`/${import.meta.env.VITE_BASE}/`)
+        loginSubmit(state.form)
+          .then((res: any) => {
+            ElMessage.success('登录成功!')
+            localStorage.setItem((import.meta as any).env.VITE_TOKEN, res.data)
+            window.location.replace(`/${(import.meta as any).env.VITE_BASE}/`)
+            state.loading = false
+          })
+          .catch((e) => {
+            ElMessage.error(e.message)
+            state.loading = false
+          })
       })
       .catch((e) => {
         ElMessage({
@@ -75,6 +116,18 @@ const onLogin = () => {
       })
   }
 }
+const initCode = () => {
+  loginCaptcha().then((res: any) => {
+    if (res.code === 200) {
+      state.codeImg = res.data
+    } else {
+      ElMessage.error(res.message)
+    }
+  })
+}
+onMounted(() => {
+  initCode()
+})
 </script>
 
 <style lang="scss" scoped>

+ 2 - 0
src/views/manage/knowledge/index.vue

@@ -182,6 +182,7 @@ import { useDialogStore, useDictionaryStore } from '@/stores'
 import { ElMessage } from 'element-plus'
 import tagsSelect from './tags-select.vue'
 import detailCom from './detail.vue'
+import { datasetsGetAllByPage } from '@/api/modules/knowledge'
 
 const DialogStore = useDialogStore()
 const DictionaryStore = useDictionaryStore()
@@ -315,6 +316,7 @@ const initDictionary = () => {
   DictionaryStore.initKnowledgeGroups()
 }
 onMounted(() => {
+  datasetsGetAllByPage()
   initDictionary()
   onReset()
 })

+ 3 - 3
vite.config.ts

@@ -63,12 +63,12 @@ export default defineConfig(({ mode, command }) => {
             return path.replace(/^\/dify-api/, '')
           },
         },
-        '/cms-api': {
-          target: 'http://192.168.5.98:8090/',
+        '/bmw-api': {
+          target: 'http://1.95.78.201:18088/',
           // target: 'http://192.168.4.12:8090/',
           changeOrigin: true,
           rewrite: (path) => {
-            return path.replace(/^\/cms-api/, '')
+            return path.replace(/^\/bmw-api/, '')
           },
         },
       },