فهرست منبع

弹窗 加退出

黄琪勇 1 سال پیش
والد
کامیت
1febbcca54

+ 2 - 2
.env.development

@@ -1,5 +1,5 @@
 # 开发环境  管乐团和管乐迷 接口需要跨域  所以代理了一下
 # 开发环境  管乐团和管乐迷 接口需要跨域  所以代理了一下
 
 
 VUE_APP_URL = "https://dev.resource.colexiu.com/cbs-app"
 VUE_APP_URL = "https://dev.resource.colexiu.com/cbs-app"
-VUE_APP_URL_GYM = "/gym/api-teacher"
-VUE_APP_URL_GYT = "/gyt/api-teacher"
+VUE_APP_URL_GYM = "/gym"
+VUE_APP_URL_GYT = "/gyt"

+ 21 - 10
src/api/user.api.ts

@@ -16,14 +16,6 @@ export const queryQrcodeStatusApi = (uuid: string) => {
    })
    })
 }
 }
 
 
-/** 退出登录 */
-export const logout = () => {
-   return httpAxios.axioseRquest({
-      method: "delete",
-      url: "/api/v1/logout"
-   })
-}
-
 /** 获取字典 */
 /** 获取字典 */
 export const getDictionary = (key: string) => {
 export const getDictionary = (key: string) => {
    return httpAxios.axioseRquest({
    return httpAxios.axioseRquest({
@@ -41,14 +33,33 @@ export const getDictionary = (key: string) => {
 export const queryUserInfo_gym = () => {
 export const queryUserInfo_gym = () => {
    return httpAxios_gym.axioseRquest({
    return httpAxios_gym.axioseRquest({
       method: "get",
       method: "get",
-      url: "/teacher/queryUserInfo"
+      url: "/api-teacher/teacher/queryUserInfo"
+   })
+}
+// 退出登录
+export const logout_gym = () => {
+   return httpAxios_gym.axioseRquest({
+      method: "post",
+      url: "/api-auth/exit",
+      headers: {
+         "Content-Type": "x-www-form-urlencoded"
+      }
    })
    })
 }
 }
+
 /** 管乐团*/
 /** 管乐团*/
+
 // 获取用户信息
 // 获取用户信息
 export const getUserInfo_gyt = () => {
 export const getUserInfo_gyt = () => {
    return httpAxios_gyt.axioseRquest({
    return httpAxios_gyt.axioseRquest({
       method: "get",
       method: "get",
-      url: "/user/getUserInfo"
+      url: "/api-teacher/user/getUserInfo"
+   })
+}
+// 退出登录
+export const logout_gyt = () => {
+   return httpAxios_gyt.axioseRquest({
+      method: "get",
+      url: "/api-teacher/user/logout"
    })
    })
 }
 }

+ 103 - 0
src/hooks/useDialogConfirm/dialogConfirm.vue

@@ -0,0 +1,103 @@
+<!--
+* @FileDescription: 提示确认类型弹窗
+* @Author: 黄琪勇
+* @Date:2024-03-20 19:18:13
+-->
+<template>
+   <div class="dialogConfirm">
+      <div class="close" @click="close">
+         <img src="@/img/useDialogConfirm/close.png" />
+      </div>
+      <img class="headImg" v-if="props.modalData.headImg" :src="props.modalData.headImg" />
+      <div class="textCon">
+         <div class="text">{{ props.modalData.text }}</div>
+      </div>
+      <div v-if="filterBtnShow" class="dialogBtn">
+         <img v-if="props.modalData.btnShow[1]" @click="cancel" src="@/img/useDialogConfirm/cancel.png" />
+         <img v-if="props.modalData.btnShow[0]" @click="ok" src="@/img/useDialogConfirm/ok.png" />
+      </div>
+   </div>
+</template>
+
+<script setup lang="ts">
+import { computed } from "vue"
+
+const props = defineProps<{
+   modalData: {
+      text: string
+      btnShow: [boolean?, boolean?]
+      headImg?: string
+   }
+}>()
+
+const emits = defineEmits<{
+   (e: "onClose"): void
+   (e: "onCancel"): void
+   (e: "onOk"): void
+}>()
+
+const filterBtnShow = computed(() => {
+   const { btnShow } = props.modalData
+   return !!(btnShow[0] || btnShow[1])
+})
+function close() {
+   emits("onClose")
+}
+function cancel() {
+   emits("onCancel")
+}
+function ok() {
+   emits("onOk")
+}
+</script>
+
+<style lang="scss" scoped>
+.dialogConfirm {
+   padding-top: 36px;
+   padding-bottom: 22px;
+   width: 100%;
+   height: 100%;
+   display: flex;
+   flex-direction: column;
+   .close {
+      position: absolute;
+      top: -14px;
+      right: -16px;
+      width: 42px;
+      height: 44px;
+      cursor: pointer;
+   }
+   .headImg {
+      position: absolute;
+      left: 50%;
+      top: -13px;
+      transform: translate(-50%, 0);
+   }
+   .textCon {
+      flex-grow: 1;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      padding: 0 20px;
+      overflow: hidden;
+      .text {
+         font-size: 20px;
+         color: #a04d11;
+         line-height: 32px;
+      }
+   }
+   .dialogBtn {
+      flex-shrink: 0;
+      display: flex;
+      justify-content: center;
+      margin-top: 6px;
+      > img {
+         cursor: pointer;
+         margin-left: 12px;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+      }
+   }
+}
+</style>

+ 13 - 0
src/hooks/useDialogConfirm/index.scss

@@ -0,0 +1,13 @@
+.modalFrame.useDialogConfirm {
+   --modalFrameTitHeight: 0px;
+   .modalFrameTitle {
+      display: none !important;
+   }
+   .modalFrameBox {
+      background: linear-gradient(180deg, #fdfef2 0%, #fdf6de 100%);
+      box-shadow: 0px 7px 10px 0px #6e6e6e, 0px 5px 0px 0px #ca8e2d;
+      border-radius: 20px;
+      border: 8px solid #ffdd98;
+      position: relative;
+   }
+}

+ 39 - 0
src/hooks/useDialogConfirm/index.ts

@@ -0,0 +1,39 @@
+/*
+   提示确认类型弹窗
+ */
+
+import modalFrame from "@/plugin/modalFrame"
+import dialogConfirm from "./dialogConfirm.vue"
+import "./index.scss"
+
+/**
+ * @param obj
+ *  text :文字
+ *  btnShow:控制确认按钮显示
+ *  headImg:头部图片
+ */
+type objType = {
+   text: string
+   btnShow?: [boolean?, boolean?]
+   headImg?: string
+   onCancel?: (...nargs: any[]) => void
+   onOk?: (...nargs: any[]) => void
+   onClose?: (...nargs: any[]) => void
+}
+export default ({ text, onCancel, onOk, onClose, btnShow, headImg }: objType) => {
+   modalFrame({
+      template: dialogConfirm,
+      width: 478,
+      height: 248,
+      btnShow: [],
+      modalData: {
+         text,
+         btnShow: btnShow || [true, true],
+         headImg
+      },
+      className: "useDialogConfirm",
+      onCancel,
+      onOk,
+      onClose
+   })
+}

BIN
src/img/layout/logout.png


BIN
src/img/layout/tis.png


BIN
src/img/useDialogConfirm/cancel.png


BIN
src/img/useDialogConfirm/close.png


BIN
src/img/useDialogConfirm/ok.png


+ 2 - 2
src/plugin/modalFrame/modalFrame.vue

@@ -13,8 +13,8 @@
                   <el-icon class="icon" @click="close"><Close /></el-icon>
                   <el-icon class="icon" @click="close"><Close /></el-icon>
                </div>
                </div>
                <div class="frameBox" :class="{ frameBtnNone: !filterBtnShow }">
                <div class="frameBox" :class="{ frameBtnNone: !filterBtnShow }">
-                  <!-- 这里有个异常bug,系统默认上传文件取消时候,不知道为啥会触发cancel,所以这里将cancel,close,ok改为onCancel,OnClose,onOk -->
-                  <component :is="props.template" ref="templateModal" @onCancel="cancel" @OnClose="close" @onOk="ok" :modal-data="props.modalData" />
+                  <!-- 这里有个异常bug,系统默认上传文件取消时候,不知道为啥会触发cancel,所以这里将cancel,close,ok改为onCancel,onClose,onOk -->
+                  <component :is="props.template" ref="templateModal" @onCancel="cancel" @onClose="close" @onOk="ok" :modal-data="props.modalData" />
                </div>
                </div>
                <div v-if="filterBtnShow" class="frameBtn">
                <div v-if="filterBtnShow" class="frameBtn">
                   <el-button v-if="props.btnShow[1]" @click="cancel">
                   <el-button v-if="props.btnShow[1]" @click="cancel">

+ 3 - 2
src/store/modules/user.ts

@@ -1,7 +1,7 @@
 import { defineStore } from "pinia"
 import { defineStore } from "pinia"
 import { store } from "../index"
 import { store } from "../index"
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
-import { logout, getUserInfo_gyt, queryUserInfo_gym } from "@/api/user.api"
+import { logout_gym, logout_gyt, getUserInfo_gyt, queryUserInfo_gym } from "@/api/user.api"
 import { removeToken, setToken, setUserType, getUserType, removeUserType, setCODE401 } from "@/libs/auth"
 import { removeToken, setToken, setUserType, getUserType, removeUserType, setCODE401 } from "@/libs/auth"
 import router, { resetRouter } from "@/router"
 import router, { resetRouter } from "@/router"
 import { httpAjax } from "@/plugin/httpAjax"
 import { httpAjax } from "@/plugin/httpAjax"
@@ -56,7 +56,8 @@ const useStore = defineStore("user", {
       },
       },
       /** 退出登录 */
       /** 退出登录 */
       async loginOut() {
       async loginOut() {
-         const logoutRes = await httpAjax(logout)
+         // GYM 和 GYT 区分  区分退出登录
+         const logoutRes = await httpAjax(this.roles === "GYM" ? logout_gym : logout_gyt)
          if (logoutRes.code !== 200) {
          if (logoutRes.code !== 200) {
             return Promise.reject(logoutRes)
             return Promise.reject(logoutRes)
          }
          }

+ 88 - 7
src/viewsframe/layout/layout.vue

@@ -6,18 +6,28 @@
 <template>
 <template>
    <div class="layout">
    <div class="layout">
       <div class="head">
       <div class="head">
-         <el-dropdown class="avatar-con" trigger="click" @visible-change="visibleChange">
+         <el-dropdown :popper-options="{}" popper-class="headDropdown" class="avatar-con" trigger="click" @visible-change="visibleChange">
             <div class="avatar">
             <div class="avatar">
                <div class="imgCon"><img :src="userInfo.avatar" /></div>
                <div class="imgCon"><img :src="userInfo.avatar" /></div>
                <div class="name">{{ userInfo.username }}</div>
                <div class="name">{{ userInfo.username }}</div>
                <img class="horn" :class="{ isVisible: visible }" src="@/img/layout/horn.png" />
                <img class="horn" :class="{ isVisible: visible }" src="@/img/layout/horn.png" />
             </div>
             </div>
             <template #dropdown>
             <template #dropdown>
-               <el-dropdown-menu>
-                  <el-dropdown-item @click="logout">
-                     <span>退出登录</span>
-                  </el-dropdown-item>
-               </el-dropdown-menu>
+               <div class="dropdown">
+                  <div class="avatar-item">
+                     <img :src="userInfo.avatar" />
+                     <div class="userInfo">
+                        <div class="realName">{{ userInfo.realName }}</div>
+                        <div class="phone">{{ userInfo.phone }}</div>
+                     </div>
+                  </div>
+                  <div class="logout-item">
+                     <div class="logoutBtn" @click="handleLogout">
+                        <img src="@/img/layout/logout.png" />
+                        <div class="text">退出登录</div>
+                     </div>
+                  </div>
+               </div>
             </template>
             </template>
          </el-dropdown>
          </el-dropdown>
       </div>
       </div>
@@ -29,6 +39,7 @@
 import userStore from "@/store/modules/user"
 import userStore from "@/store/modules/user"
 import { computed } from "vue"
 import { computed } from "vue"
 import { ref } from "vue"
 import { ref } from "vue"
+import { ElMessage } from "element-plus"
 
 
 const userStoreHook = userStore()
 const userStoreHook = userStore()
 
 
@@ -40,7 +51,14 @@ const visible = ref(false)
 function visibleChange(value: boolean) {
 function visibleChange(value: boolean) {
    visible.value = value
    visible.value = value
 }
 }
-function logout() {}
+function handleLogout() {
+   userStore()
+      .loginOut()
+      .then()
+      .catch((err: apiResDataType) => {
+         ElMessage.error(err.message)
+      })
+}
 </script>
 </script>
 
 
 <style lang="scss" scoped>
 <style lang="scss" scoped>
@@ -99,4 +117,67 @@ function logout() {}
       }
       }
    }
    }
 }
 }
+:global(.headDropdown.el-dropdown__popper.el-popper) {
+   box-shadow: 0px 2px 17px 0px rgba(0, 0, 0, 0.08);
+   background: #ffffff;
+   border-radius: 16px;
+   inset: 84px 54px auto auto !important;
+}
+.dropdown {
+   width: 300px;
+   padding: 20px;
+   & > div {
+      border-bottom: 1px solid #f2f2f2;
+      &:last-child {
+         border-bottom: none;
+      }
+   }
+   .avatar-item {
+      display: flex;
+      padding-bottom: 16px;
+      > img {
+         width: 48px;
+         height: 48px;
+         border-radius: 50%;
+         flex-shrink: 0;
+      }
+      .userInfo {
+         margin-left: 16px;
+         .realName {
+            font-weight: 600;
+            font-size: 20px;
+            line-height: 28px;
+            color: #333333;
+         }
+         .phone {
+            font-weight: 400;
+            font-size: 16px;
+            color: #777777;
+            line-height: 22px;
+         }
+      }
+   }
+   .logout-item {
+      padding-top: 16px;
+      .logoutBtn {
+         cursor: pointer;
+         padding: 0 12px;
+         width: 100%;
+         height: 50px;
+         background: #f5f6fa;
+         border-radius: 10px;
+         display: flex;
+         align-items: center;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+         .text {
+            margin-left: 20px;
+            font-weight: 500;
+            font-size: 18px;
+            color: #333333;
+         }
+      }
+   }
+}
 </style>
 </style>

+ 0 - 1
src/viewsframe/login/login.vue

@@ -41,7 +41,6 @@ const router = useRouter()
 
 
 const uuid = ref<string>("")
 const uuid = ref<string>("")
 const qrcode = computed(() => {
 const qrcode = computed(() => {
-   console.log(JSON.stringify({ action: "login", uuid: uuid.value }))
    return JSON.stringify({ action: "login", uuid: uuid.value })
    return JSON.stringify({ action: "login", uuid: uuid.value })
 })
 })
 const qrcodeStatus = ref<1 | 2 | 3>(1) // 1 未扫码  2 扫码完成  3 二维码过期
 const qrcodeStatus = ref<1 | 2 | 3>(1) // 1 未扫码  2 扫码完成  3 二维码过期

+ 2 - 2
vue.config.js

@@ -12,13 +12,13 @@ module.exports = defineConfig({
    },
    },
    devServer: {
    devServer: {
       proxy: {
       proxy: {
-         "/gym/api-teacher": {
+         "/gym": {
             target: "https://dev.dayaedu.com",
             target: "https://dev.dayaedu.com",
             pathRewrite: {
             pathRewrite: {
                "^/gym": ""
                "^/gym": ""
             }
             }
          },
          },
-         "/gyt/api-teacher": {
+         "/gyt": {
             target: "https://dev.lexiaoya.cn",
             target: "https://dev.lexiaoya.cn",
             pathRewrite: {
             pathRewrite: {
                "^/gyt": ""
                "^/gyt": ""