黄琪勇 1 年之前
父節點
當前提交
4f50dc62a0

+ 7 - 0
src/api/user.api.ts

@@ -46,6 +46,13 @@ export const logout_gym = () => {
       }
    })
 }
+// 安全证书
+export const mutualTLSQuery_gym = () => {
+   return httpAxios_gym.axioseRquest({
+      method: "get",
+      url: "/api-auth/open/mutualTLS/query?isLogin=true" // 后面跟参数来区分是不是登录511
+   })
+}
 
 /** 管乐团*/
 

二進制
src/hooks/useSecureAnth/img/bg.png


二進制
src/hooks/useSecureAnth/img/btn.png


二進制
src/hooks/useSecureAnth/img/mac1.png


二進制
src/hooks/useSecureAnth/img/mac2.png


二進制
src/hooks/useSecureAnth/img/mac3.png


二進制
src/hooks/useSecureAnth/img/mac4.png


二進制
src/hooks/useSecureAnth/img/mac5.png


二進制
src/hooks/useSecureAnth/img/mac6.png


二進制
src/hooks/useSecureAnth/img/star.png


二進制
src/hooks/useSecureAnth/img/win1.png


二進制
src/hooks/useSecureAnth/img/win2.png


二進制
src/hooks/useSecureAnth/img/win3.png


二進制
src/hooks/useSecureAnth/img/win4.png


二進制
src/hooks/useSecureAnth/img/win5.png


二進制
src/hooks/useSecureAnth/img/win6.png


二進制
src/hooks/useSecureAnth/img/win7.png


二進制
src/hooks/useSecureAnth/img/win8.png


二進制
src/hooks/useSecureAnth/img/xiazai.png


+ 28 - 0
src/hooks/useSecureAnth/index.ts

@@ -0,0 +1,28 @@
+/*
+   安全证书
+ */
+
+import modalFrame from "@/plugin/modalFrame"
+import secureAnth from "./secureAnth.vue"
+
+/**
+ * @param obj
+ *  text :文字
+ *  btnShow:控制确认按钮显示
+ *  headImg:头部图片
+ */
+type objType = {
+   onCancel?: (...nargs: any[]) => void
+   onOk?: (...nargs: any[]) => void
+}
+export default (obj?: objType) => {
+   modalFrame({
+      template: secureAnth,
+      width: 920,
+      height: 860,
+      btnShow: [],
+      className: "useSecureAnth",
+      onCancel: obj?.onCancel,
+      onOk: obj?.onCancel
+   })
+}

+ 424 - 0
src/hooks/useSecureAnth/secureAnth.vue

@@ -0,0 +1,424 @@
+<!--
+* @FileDescription: 安全证书
+* @Author: 黄琪勇
+* @Date:2024-04-09 14:01:56
+-->
+<template>
+   <div class="secureAnth">
+      <img class="star" src="./img/star.png" />
+      <ElScrollbar ref="elScrollbarDom" class="elScrollbar">
+         <template v-if="isMac">
+            <div class="stepCon" v-if="stepNum === 1">
+               <div class="titleBox">
+                  <div class="stepNum">01</div>
+                  <div class="titleCon">点击下方【下载证书】按钮,下载数据安全证书安装包</div>
+               </div>
+               <div class="contentBox">
+                  <img @click="handleDownload" class="xiazaiImg" src="./img/xiazai.png" />
+               </div>
+               <div class="titleBox">
+                  <div class="stepNum">02</div>
+                  <div class="titleCon">
+                     双击
+                     <span class="colorOne">《安全证书.p12》</span>
+                     ,输入钥匙串密码,点击
+                     <span class="colorOne">【修改钥匙串】</span>
+                     <span class="colorThree">(若无此步骤则忽略)</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="mac1Img" src="./img/mac1.png" />
+                  <img class="mac2Img" src="./img/mac2.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 2">
+               <div class="titleBox">
+                  <div class="stepNum">03</div>
+                  <div class="titleCon">
+                     输入证书密码:
+                     <span class="colorTwo">lexiaoya.cn</span>
+                     ,点击
+                     <span class="colorOne">【好】</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="mac3Img" src="./img/mac3.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 3">
+               <div class="titleBox alignTop">
+                  <div class="stepNum">04</div>
+                  <div class="titleCon">
+                     <span class="colorTwo">重启浏览器</span>
+                     (在电脑屏幕左上方选择当前浏览器并点击
+                     <span class="colorOne">【退出】</span>
+                     ),再重新打开乐教通网址
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="mac4Img" src="./img/mac4.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 4">
+               <div class="titleBox alignTop">
+                  <div class="stepNum">05</div>
+                  <div class="titleCon">
+                     在【选择证书】弹窗中点击
+                     <span class="colorOne">【确定】</span>
+                     按钮
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="mac5Img" src="./img/mac5.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 5">
+               <div class="titleBox">
+                  <div class="stepNum">06</div>
+                  <div class="titleCon">
+                     输入您的电脑密码,点击
+                     <span class="colorOne">【始终允许】</span>
+                     <span class="colorThree">(若无此步骤则忽略)</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="mac6Img" src="./img/mac6.png" />
+               </div>
+               <div class="titleBox">
+                  <div class="stepNum">07</div>
+                  <div class="titleCon">证书安装完成,开始使用乐教通吧!</div>
+               </div>
+            </div>
+         </template>
+         <template v-else>
+            <div class="stepCon" v-if="stepNum === 1">
+               <div class="titleBox">
+                  <div class="stepNum">01</div>
+                  <div class="titleCon">点击下方【下载证书】按钮,下载数据安全证书安装包</div>
+               </div>
+               <div class="contentBox">
+                  <img @click="handleDownload" class="xiazaiImg" src="./img/xiazai.png" />
+               </div>
+               <div class="titleBox">
+                  <div class="stepNum">02</div>
+                  <div class="titleCon">
+                     双击
+                     <span class="colorOne">《安全证书.pfx》</span>
+                     ,出现弹窗后点击
+                     <span class="colorOne">【下一步】</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="win1Img" src="./img/win1.png" />
+                  <img class="win2Img" src="./img/win2.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 2">
+               <div class="titleBox">
+                  <div class="stepNum">03</div>
+                  <div class="titleCon">
+                     点击
+                     <span class="colorOne">【下一步】</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="win3Img" src="./img/win3.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 3">
+               <div class="titleBox">
+                  <div class="stepNum">04</div>
+                  <div class="titleCon">
+                     点击
+                     <span class="colorOne">【下一步】</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="win3Img" src="./img/win4.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 4">
+               <div class="titleBox">
+                  <div class="stepNum">05</div>
+                  <div class="titleCon">
+                     点击
+                     <span class="colorOne">【下一步】</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="win3Img" src="./img/win5.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 5">
+               <div class="titleBox">
+                  <div class="stepNum">06</div>
+                  <div class="titleCon">
+                     点击
+                     <span class="colorOne">【下一步】</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="win3Img" src="./img/win6.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 6">
+               <div class="titleBox">
+                  <div class="stepNum">07</div>
+                  <div class="titleCon">
+                     点击
+                     <span class="colorOne">【确定】</span>
+                  </div>
+               </div>
+               <div class="contentBox">
+                  <img class="win7Img" src="./img/win7.png" />
+               </div>
+            </div>
+            <div class="stepCon" v-if="stepNum === 7">
+               <div class="titleBox mb">
+                  <div class="stepNum">08</div>
+                  <div class="titleCon">
+                     <span class="colorTwo">重启浏览器</span>
+                     ,打开乐教通网址
+                  </div>
+               </div>
+               <div class="titleBox">
+                  <div class="stepNum">09</div>
+                  <div class="titleCon">在【选择证书】弹窗中点击【确定】按钮,证书安装完成,开始使用乐教通吧!</div>
+               </div>
+               <div class="contentBox">
+                  <img class="win8Img" src="./img/win8.png" />
+               </div>
+            </div>
+         </template>
+      </ElScrollbar>
+      <div class="stepBtn">
+         <div class="btn" v-if="stepNum > 1" @click="handleStep(-1)">上一步</div>
+         <div class="btn" v-if="stepNum <= maxStep" @click="handleStep(1)">{{ stepNum < maxStep ? "下一步" : "完成" }}</div>
+      </div>
+   </div>
+</template>
+
+<script setup lang="ts">
+import { ref } from "vue"
+import { ElScrollbar } from "element-plus"
+
+const emits = defineEmits<{
+   (e: "onCancel"): void
+}>()
+
+const isMac = (function () {
+   return /macintosh|mac os x/i.test(navigator.userAgent)
+})()
+
+const maxStep = isMac ? 5 : 7
+const stepNum = ref(1)
+const elScrollbarDom = ref<InstanceType<typeof ElScrollbar>>()
+
+// 下载证书
+function handleDownload() {
+   if (isMac) {
+      window.open("https://oss.dayaedu.com/https-ssl/安全证书.p12")
+   } else {
+      window.open("https://oss.dayaedu.com/https-ssl/安全证书.pfx")
+   }
+}
+// 步骤
+function handleStep(num: -1 | 1) {
+   if (num === 1 && stepNum.value === maxStep) {
+      emits("onCancel")
+      return
+   }
+   if (num === -1) {
+      stepNum.value > 1 && (stepNum.value += num)
+   } else {
+      stepNum.value < maxStep && (stepNum.value += num)
+   }
+   elScrollbarDom.value?.setScrollTop(0)
+}
+</script>
+
+<style lang="scss" scoped>
+.secureAnth {
+   width: 100%;
+   height: 100%;
+   padding: 210px 36px 0 50px;
+   position: relative;
+   > :deep(.elScrollbar) {
+      width: 100%;
+      height: 546px;
+      background: linear-gradient(180deg, rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0.7) 36%, rgba(255, 234, 224, 0.7) 98%, #fff9ed 100%);
+      border-radius: 23px;
+      border: 1px solid #ffffff;
+      .el-scrollbar__wrap {
+         overflow-x: hidden;
+      }
+   }
+   .star {
+      position: absolute;
+      top: 214px;
+      right: 23px;
+      z-index: 10;
+      width: 22px;
+      height: 22px;
+   }
+   .stepCon {
+      padding: 24px 34px 16px;
+      .titleBox {
+         display: flex;
+         align-items: center;
+         &.alignTop {
+            align-items: initial;
+         }
+         &.mb {
+            margin-bottom: 34px;
+         }
+         .stepNum {
+            width: 34px;
+            height: 34px;
+            background: #ffdac2;
+            border: 1px solid #ffffff;
+            border-radius: 50%;
+            font-weight: 600;
+            font-size: 17px;
+            color: #131415;
+            text-align: center;
+            line-height: 34px;
+         }
+         .titleCon {
+            margin-left: 14px;
+            font-weight: 600;
+            font-size: 18px;
+            color: #000000;
+            line-height: 30px;
+            .colorOne {
+               color: #df6117;
+               flex-shrink: 0;
+            }
+            .colorTwo {
+               color: #e80000;
+               flex-shrink: 0;
+            }
+            .colorThree {
+               color: #777777;
+               flex-shrink: 0;
+            }
+         }
+      }
+      .contentBox {
+         display: flex;
+         overflow: hidden;
+         margin-bottom: 18px;
+         &:last-child {
+            margin-bottom: 0;
+         }
+         .xiazaiImg {
+            margin-top: 22px;
+            margin-left: 43px;
+            width: 179px;
+            height: 47px;
+            cursor: pointer;
+            &:hover {
+               opacity: $opacity-hover;
+            }
+         }
+         .win1Img {
+            margin: 14px 0 0 48px;
+            width: 90px;
+            height: 98px;
+         }
+         .win2Img {
+            margin: 14px 0 0 50px;
+            width: 519px;
+            height: 512px;
+         }
+         .win3Img {
+            margin: 14px 0 0 47px;
+            width: 415px;
+            height: 427px;
+         }
+         .win7Img {
+            margin: 14px 0 0 47px;
+            width: 336px;
+            height: 375px;
+         }
+         .win8Img {
+            margin: 14px 0 0 47px;
+            width: 680px;
+            height: 388px;
+         }
+         .mac1Img {
+            margin: 14px 0 0 48px;
+            width: 90px;
+            height: 98px;
+         }
+         .mac2Img {
+            margin: 14px 0 0 33px;
+            width: 299px;
+            height: 335px;
+         }
+         .mac3Img {
+            margin: 14px 0 0 48px;
+            width: 663px;
+            height: 269px;
+         }
+         .mac4Img {
+            margin: 14px 0 0 48px;
+            width: 357px;
+            height: 420px;
+         }
+         .mac5Img {
+            margin: 14px 0 0 48px;
+            width: 681px;
+            height: 381px;
+         }
+         .mac6Img {
+            margin: 14px 0 0 48px;
+            width: 681px;
+            height: 310px;
+         }
+      }
+   }
+   .stepBtn {
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      margin-top: 25px;
+      .btn {
+         width: 179px;
+         height: 47px;
+         background: url("./img/btn.png") no-repeat;
+         background-size: 100% 100%;
+         cursor: pointer;
+         font-family: AlimamaFangYuanTiVF, AlimamaFangYuanTiVF;
+         font-weight: bold;
+         font-size: 20px;
+         color: #ffffff;
+         text-align: center;
+         line-height: 47px;
+         user-select: none;
+         &:hover {
+            opacity: $opacity-hover;
+         }
+         &:last-child {
+            margin-left: 17px;
+         }
+      }
+   }
+}
+</style>
+<style lang="scss">
+.h-modalFrame.useSecureAnth {
+   /* prettier-ignore */
+   --modalFrameTitHeight: 0PX;
+   .modalFrameBox {
+      box-shadow: initial;
+      border-radius: initial;
+      position: relative;
+      background: url("./img/bg.png") no-repeat;
+      background-size: 100% 100%;
+      .modalFrameTitle {
+         display: none;
+      }
+   }
+}
+</style>

+ 12 - 0
src/libs/axios.ts

@@ -4,6 +4,7 @@ import Nprogress from "@/plugin/nprogress"
 import { ElMessage } from "element-plus"
 import { TokenInvalidFlag, CODE401, CODE_ERR_CANCELED } from "@/libs/auth"
 import userStore from "@/store/modules/user"
+import useSecureAnth from "@/hooks/useSecureAnth"
 
 //重写 axios 传参
 interface AxiosConfigType extends AxiosRequestConfig {
@@ -74,6 +75,17 @@ class HttpAsynAxios {
             //         case 401:
             //     }
             // }
+            if (error.response?.status === 511) {
+               // isLogin=true 带有这个是登录时候的判断弹窗验证证书  其他的走正常弹窗
+               if (/isLogin=true/.test(error.request?.responseURL)) {
+                  return Promise.reject({
+                     code: 511,
+                     message: "没有安装证书",
+                     data: null
+                  })
+               }
+               useSecureAnth()
+            }
             const rejectData: apiResDataType =
                error.code === CODE_ERR_CANCELED
                   ? {

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

@@ -39,6 +39,9 @@ import QrcodeVue from "qrcode.vue"
 import { ref, computed } from "vue"
 import userStore from "@/store/modules/user"
 import { useRouter } from "vue-router"
+import useSecureAnth from "@/hooks/useSecureAnth"
+import { mutualTLSQuery_gym } from "@/api/user.api"
+import { httpAjaxLoading } from "@/plugin/httpAjax"
 
 const userStoreHook = userStore()
 const router = useRouter()
@@ -66,7 +69,17 @@ function handleQrcodeStatus() {
          if (status === "FINISH") {
             // 登录成功
             userStoreHook.login(res.data).then(() => {
-               router.push({ path: "/" })
+               httpAjaxLoading(mutualTLSQuery_gym).then(res => {
+                  if (res.code === 511) {
+                     useSecureAnth({
+                        onCancel() {
+                           router.push({ path: "/" })
+                        }
+                     })
+                  } else {
+                     router.push({ path: "/" })
+                  }
+               })
             })
             return
          }

+ 1 - 1
vue.config.js

@@ -22,7 +22,7 @@ module.exports = defineConfig({
                         if (file.includes("normalize")) {
                            return true
                         }
-                        return true
+                        return false
                      }
                   })
                ]