shuisheng 2 vuotta sitten
vanhempi
sitoutus
a48523363f

+ 0 - 1
src/App.vue

@@ -35,7 +35,6 @@ onMounted(() => {
   cacheStore.setVolume(0);
   const token = getToken();
   if (token) {
-    userStore.setToken(token);
     userStore.getUserInfo();
   }
 

+ 2 - 2
src/api/qqUser.ts

@@ -1,10 +1,10 @@
 import request from '@/utils/request';
 
 // qq登录
-export function fetchQQLogin(code: any) {
+export function fetchQQLogin({ code, exp }) {
   return request.instance({
     url: `/qq_user/login`,
     method: 'post',
-    data: { code },
+    data: { code, exp },
   });
 }

+ 1 - 1
src/api/user.ts

@@ -22,7 +22,7 @@ export function fetchQrcodeLoginStatus({ platform, login_id }) {
     platform: any;
     isLogin: boolean;
     token: string;
-  }>('/user/qrcode_login', {
+  }>('/user/qrcode_login_status', {
     // eslint-disable-next-line
     params: { platform, login_id },
   });

+ 7 - 2
src/api/wechatUser.ts

@@ -1,10 +1,15 @@
 import request from '@/utils/request';
 
 // qq登录
-export function fetchWechatLogin(code: any) {
+export function fetchWechatLogin(data: {
+  code: any;
+  platform: string;
+  exp: number;
+  login_id: string;
+}) {
   return request.instance({
     url: `/wechat_user/login`,
     method: 'post',
-    data: { code },
+    data,
   });
 }

+ 50 - 11
src/components/LoginModal/index.vue

@@ -125,9 +125,9 @@
 <script lang="ts" setup>
 import { LockClosedOutline, PersonOutline } from '@vicons/ionicons5';
 import QRCode from 'qrcode';
-import { ref } from 'vue';
+import { onUnmounted, reactive, ref } from 'vue';
 
-import { fetchQrcodeLogin } from '@/api/user';
+import { fetchQrcodeLogin, fetchQrcodeLoginStatus } from '@/api/user';
 import { QRCODE_LOGIN_URI } from '@/constant';
 import { useQQLogin } from '@/hooks/use-login';
 import { useAppStore } from '@/store/app';
@@ -145,12 +145,21 @@ const loginForm = ref({
   id: '',
   password: '',
 });
+const qrcodeParams = reactive({
+  platform: 'wechat',
+  exp: 24,
+  loginId: '',
+});
 const base64 = ref('');
 const loginFormRef = ref(null);
-const currentTab = ref('qrcodelogin'); // qrcodelogin,pwdlogin
-
+const currentTab = ref('pwdlogin'); // qrcodelogin,pwdlogin
+const loopTimer = ref();
 const emits = defineEmits(['close']);
 
+onUnmounted(() => {
+  clearInterval(loopTimer.value);
+});
+
 async function generateQR(text) {
   let base64 = '';
   try {
@@ -168,24 +177,53 @@ function handleGithubLogin() {
 }
 
 function handleQQLogin() {
-  useQQLogin();
+  useQQLogin({ exp: 24 });
 }
 
 async function handleWechatLogin() {
-  const params = {
-    platform: 'wechat',
-    exp: 24,
-  };
-  const res = await fetchQrcodeLogin(params);
+  const res = await fetchQrcodeLogin({
+    platform: qrcodeParams.platform,
+    exp: qrcodeParams.exp,
+  });
   if (res.code === 200) {
+    qrcodeParams.loginId = res.data.login_id;
     base64.value = await generateQR(
-      `${QRCODE_LOGIN_URI}?platform=${params.platform}&exp=${params.exp}&login_id=${res.data.login_id}`
+      `${QRCODE_LOGIN_URI}?platform=${qrcodeParams.platform}&exp=${qrcodeParams.exp}&loginId=${qrcodeParams.loginId}`
     );
+    handleLoopQrcodeLoginStatus();
   } else {
     window.$message.error(res.message);
   }
 }
 
+function handleLoopQrcodeLoginStatus() {
+  clearInterval(loopTimer.value);
+  async function loopFn() {
+    try {
+      const res = await fetchQrcodeLoginStatus({
+        platform: qrcodeParams.platform,
+        login_id: qrcodeParams.loginId,
+      });
+      if (res.code === 200) {
+        if (res.data.isLogin && res.data.token) {
+          userStore.setToken(res.data.token, res.data.exp);
+          userStore.getUserInfo();
+          appStore.showLoginModal = false;
+          clearInterval(loopTimer.value);
+        }
+      } else {
+        window.$message.error(res.message);
+      }
+    } catch (error) {
+      console.log(error);
+    }
+  }
+
+  loopTimer.value = setInterval(() => {
+    loopFn();
+  }, 1000);
+}
+
 function handleClose() {
   appStore.showLoginModal = false;
   emits('close');
@@ -218,6 +256,7 @@ const handleLoginSubmit = (e) => {
 };
 const tabChange = (v) => {
   currentTab.value = v;
+  clearInterval(loopTimer.value);
   if (currentTab.value === 'qrcodelogin') {
     handleWechatLogin();
   }

+ 1 - 34
src/constant.ts

@@ -64,7 +64,7 @@ export const QINIU_LIVE = {
 
 // 全局的cookie的key
 export const COOKIE_KEY = {
-  loginInfo: 'loginInfo',
+  thirdLoginInfo: 'thirdLoginInfo',
 };
 
 export const lsKeyPrefix = 'billd_live___';
@@ -86,39 +86,6 @@ export const mediaTypeEnumMap = {
   [MediaTypeEnum.stopwatch]: '秒表',
 };
 
-export const sliderList2 = [
-  {
-    img: 'https://resource.hsslive.cn/billd-live/image/a4039f86e5352bcfccaddecc4b72a1df.webp',
-    txt: 'https://resource.hsslive.cn/billd-live/image',
-    link: 'https://ossrs.net',
-  },
-  // {
-  //   img: 'https://resource.hsslive.cn/billd-live/image/a4039f86e5352bcfccaddecc4b72a1df.webp',
-  //   txt: 'SRS',
-  //   link: 'https://ossrs.net',
-  // },
-  {
-    img: 'https://resource.hsslive.cn/image/c3c342f6852706e0b70d011e8753d2d6.webp',
-    txt: 'FFmpeg',
-    link: 'https://ffmpeg.org',
-  },
-  {
-    img: 'https://resource.hsslive.cn/image/0214acde5f5f5e3caf278ce446cc4414.webp',
-    txt: 'WebRTC',
-    link: 'https://github.com/webrtc',
-  },
-  // {
-  //   img: 'https://resource.hsslive.cn/billd-live/image/1277df4371045310acbc4bf2fc0811b8.webp',
-  //   txt: 'Vue3',
-  //   link: 'https://vuejs.org',
-  // },
-  // {
-  //   img: 'https://resource.hsslive.cn/image/dd907463af7fdec395e5f6d088b0308b.webp',
-  //   txt: 'Pinia',
-  //   link: 'https://pinia.vuejs.org',
-  // },
-];
-
 export const sliderList = [
   {
     img: 'https://resource.hsslive.cn/billd-live/image/a4039f86e5352bcfccaddecc4b72a1df.webp',

+ 2 - 2
src/hooks/modal/index.vue

@@ -89,8 +89,8 @@ export default defineComponent({
         font-size: 14px;
       }
       &.next {
-        background-color: #fbab7e;
-        background-image: linear-gradient(62deg, #fbab7e 0%, #f7ce68 100%);
+        background-color: white;
+        background-image: $theme-color-gold;
         color: white;
         font-weight: 700;
         font-size: 16px;

+ 17 - 21
src/hooks/use-login.ts

@@ -1,4 +1,4 @@
-import { hrefToTarget, isMobile, isWechat } from 'billd-utils';
+import { hrefToTarget, isMobile } from 'billd-utils';
 import { createApp } from 'vue';
 
 import { fetchQQLogin } from '@/api/qqUser';
@@ -15,7 +15,7 @@ import LoginModalCpt from '@/hooks/loginModal/index.vue';
 import { PlatformEnum } from '@/interface';
 import { useAppStore } from '@/store/app';
 import { useUserStore } from '@/store/user';
-import { clearLoginInfo, setLoginInfo } from '@/utils/cookie';
+import { clearThirdLoginInfo, setThirdLoginInfo } from '@/utils/cookie';
 import { getToken } from '@/utils/localStorage/user';
 
 const app = createApp(LoginModalCpt);
@@ -38,14 +38,14 @@ export async function handleQQLogin(e) {
   try {
     switch (type) {
       case PlatformEnum.qqLogin: {
-        const res = await fetchQQLogin(data);
+        const res = await fetchQQLogin({ code: data.code, exp: data.qqExp });
         if (res.code === 200) {
           window.$message.success('登录成功!');
           fullLoading({
             loading: false,
           });
         }
-        userStore.setToken(res.data);
+        userStore.setToken(res.data, data.qqExp);
         userStore.getUserInfo();
         appStore.showLoginModal = false;
         break;
@@ -54,7 +54,7 @@ export async function handleQQLogin(e) {
   } catch (error) {
     console.log(error);
   } finally {
-    clearLoginInfo();
+    clearThirdLoginInfo();
   }
 }
 
@@ -75,52 +75,48 @@ export function loginMessage() {
   window.addEventListener('message', handleQQLogin);
 }
 
-export function useQQLogin() {
+export function useQQLogin(data: { exp }) {
   fullLoading({
     loading: true,
     showMask: true,
     content: 'qq登录...',
     style: { color: 'white' },
   });
-  const url = (state: string) =>
+  const handleUrl = (state: string) =>
     `${QQ_OAUTH_URL}/authorize?response_type=code&client_id=${QQ_CLIENT_ID}&redirect_uri=${QQ_REDIRECT_URI}&scope=get_user_info,get_vip_info,get_vip_rich_info&state=${state}`;
   let loginInfo = JSON.stringify({
     isMobile: false,
     createTime: +new Date(),
     env: 'qq',
     dev: process.env.NODE_ENV === 'development',
+    qqExp: data.exp,
   });
   if (isMobile()) {
     loginInfo = JSON.stringify({ ...JSON.parse(loginInfo), isMobile: true });
-    setLoginInfo(loginInfo);
-    hrefToTarget(url(window.btoa(loginInfo)));
+    setThirdLoginInfo(loginInfo);
+    hrefToTarget(handleUrl(window.btoa(loginInfo)));
   } else {
-    setLoginInfo(loginInfo);
+    setThirdLoginInfo(loginInfo);
     window.open(
-      url(window.btoa(loginInfo)),
+      handleUrl(window.btoa(loginInfo)),
       'qq_login_window',
       'toolbar=yes,location=no,directories=no,status=no,menubar=no,scrollbars=no,titlebar=no,toolbar=no,resizable=no,copyhistory=yes, width=918, height=609,top=250,left=400'
     );
   }
 }
 
-export const useWechatLogin = (qrData: { platform; exp; login_id }) => {
+export const useWechatLogin = (qrData: { platform; exp; loginId }) => {
   const redirectUri = encodeURIComponent(WECHAT_REDIRECT_URI);
-  const flag = isWechat();
-  if (flag) {
-    window.$message.error('请在微信打开!');
-    return;
-  }
   const loginInfo = JSON.stringify({
     isMobile: false,
     createTime: +new Date(),
     env: 'wechat',
     dev: process.env.NODE_ENV === 'development',
-    qr_platform: qrData.platform,
-    qr_exp: qrData.exp,
-    qr_login_id: qrData.login_id,
+    qrcodePlatform: qrData.platform,
+    qrcodeExp: qrData.exp,
+    qrcodeLoginId: qrData.loginId,
   });
-  setLoginInfo(loginInfo);
+  setThirdLoginInfo(loginInfo);
   const stateRes = window.btoa(loginInfo);
   // https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
   const url = `${WECHAT_GZH_OAUTH_URL}appid=${WECHAT_GZH_APPID}&redirect_uri=${redirectUri}&scope=snsapi_userinfo&response_type=code&state=${stateRes}`;

+ 3 - 31
src/store/user/index.ts

@@ -1,6 +1,5 @@
 import { defineStore } from 'pinia';
 
-import { fetchEmailCodeLogin, fetchRegister } from '@/api/emailUser';
 import { fetchLogin, fetchUserInfo } from '@/api/user';
 import { IRole, IUser } from '@/interface';
 import cache from '@/utils/cache';
@@ -23,8 +22,8 @@ export const useUserStore = defineStore('user', {
     setUserInfo(res) {
       this.userInfo = res;
     },
-    setToken(res) {
-      cache.setStorageExp('token', res, 24);
+    setToken(res, exp: number) {
+      cache.setStorageExp('token', res, exp);
       this.token = res;
     },
     setRoles(res) {
@@ -42,40 +41,13 @@ export const useUserStore = defineStore('user', {
           id,
           password,
         });
-        this.setToken(token);
+        this.setToken(token, 24);
         return token;
       } catch (error: any) {
         // 错误返回401,全局的响应拦截会打印报错信息
         return null;
       }
     },
-    async codeLogin({ email, code }) {
-      try {
-        const { data: token } = await fetchEmailCodeLogin({
-          email,
-          code,
-        });
-        this.setToken(token);
-        return token;
-      } catch (error: any) {
-        // 错误返回401,全局的响应拦截会打印报错信息
-        return null;
-      }
-    },
-    async register({ email, code }) {
-      try {
-        // @ts-ignore
-        const { data: token } = await fetchRegister({
-          email,
-          code,
-        });
-        this.setToken(token);
-        return { token };
-      } catch (error: any) {
-        window.$message.error(error.message);
-        return error;
-      }
-    },
     async getUserInfo() {
       try {
         const { code, data }: any = await fetchUserInfo();

+ 1 - 1
src/utils/cookie/index.ts

@@ -1 +1 @@
-export * from './loginEnv';
+export * from './thirdLogin';

+ 0 - 17
src/utils/cookie/loginEnv.ts

@@ -1,17 +0,0 @@
-import cookies from 'js-cookie';
-
-import { COOKIE_DOMAIN, COOKIE_KEY } from '@/constant';
-
-export const getLoginInfo = () => {
-  return cookies.get(COOKIE_KEY.loginInfo);
-};
-
-export const setLoginInfo = (val) => {
-  cookies.set(COOKIE_KEY.loginInfo, val, {
-    domain: COOKIE_DOMAIN,
-  });
-};
-
-export const clearLoginInfo = () => {
-  cookies.remove(COOKIE_KEY.loginInfo);
-};

+ 17 - 0
src/utils/cookie/thirdLogin.ts

@@ -0,0 +1,17 @@
+import cookies from 'js-cookie';
+
+import { COOKIE_DOMAIN, COOKIE_KEY } from '@/constant';
+
+export const getThirdLoginInfo = () => {
+  return cookies.get(COOKIE_KEY.thirdLoginInfo);
+};
+
+export const setThirdLoginInfo = (val) => {
+  cookies.set(COOKIE_KEY.thirdLoginInfo, val, {
+    domain: COOKIE_DOMAIN,
+  });
+};
+
+export const clearThirdLoginInfo = () => {
+  cookies.remove(COOKIE_KEY.thirdLoginInfo);
+};

+ 1 - 0
src/views/account/index.vue

@@ -14,6 +14,7 @@
       <span>直播间信息:</span>
       <span
         v-if="!userInfo?.live_rooms?.length"
+        class="link"
         @click="openLiveRoom"
       >
         未开通

+ 26 - 16
src/views/oauth/index.vue

@@ -7,10 +7,10 @@
 import { onMounted, ref } from 'vue';
 import { useRoute } from 'vue-router';
 
-import { fetchQrcodeLoginStatus } from '@/api/user';
+import { fetchWechatLogin } from '@/api/wechatUser';
 import { handleQQLogin } from '@/hooks/use-login';
 import { PlatformEnum } from '@/interface';
-import { clearLoginInfo, getLoginInfo } from '@/utils/cookie';
+import { clearThirdLoginInfo, getThirdLoginInfo } from '@/utils/cookie';
 
 const route = useRoute();
 
@@ -34,9 +34,10 @@ onMounted(async () => {
 
   try {
     const res = JSON.parse(atobStateRes);
+    // 在第三方登录的时候,会往cookie里记录环境,因此这里直接读取
+    // 如果不是dev环境,则读取cookie
     if (!res.dev) {
-      // 在第三方登录的时候,都会往cookie里记录环境,因此这里直接读取
-      loginInfo = getLoginInfo();
+      loginInfo = getThirdLoginInfo();
       if (!loginInfo) {
         errMsg.value = 'cookie缺少登录信息';
         return;
@@ -50,7 +51,7 @@ onMounted(async () => {
       loginInfo = atobStateRes;
     }
   } catch (error) {
-    errMsg.value = 'state非法';
+    errMsg.value = '校验state错误';
     return;
   }
 
@@ -59,15 +60,17 @@ onMounted(async () => {
       currentOauth.value = 'QQ';
       break;
     case PlatformEnum.wechatLogin:
-      currentOauth.value = 'Wechat';
+      currentOauth.value = '微信';
       break;
   }
 
   try {
-    const { isMobile, env } = JSON.parse(loginInfo);
+    // eslint-disable-next-line
+    const { isMobile, env, qrcodePlatform, qrcodeExp, qrcodeLoginId, qqExp } =
+      JSON.parse(loginInfo);
 
     if (env === 'qq') {
-      const info = { type: PlatformEnum.qqLogin, data: code };
+      const info = { type: PlatformEnum.qqLogin, data: { code, qqExp } };
       if (isMobile) {
         try {
           await handleQQLogin({
@@ -82,18 +85,25 @@ onMounted(async () => {
       }
     } else if (env === 'wechat') {
       // eslint-disable-next-line
-      const { qr_platform, qr_login_id } = JSON.parse(loginInfo);
-      console.log(qr_platform, qr_login_id, '====');
-      await fetchQrcodeLoginStatus({
-        // eslint-disable-next-line
-        platform: qr_platform,
-        // eslint-disable-next-line
-        login_id: qr_login_id,
+      if (!qrcodePlatform || !qrcodeLoginId || !qrcodeExp) {
+        window.$message.error('参数缺失!');
+        return;
+      }
+      const res = await fetchWechatLogin({
+        code,
+        platform: qrcodePlatform,
+        login_id: qrcodeLoginId,
+        exp: qrcodeExp,
       });
+      if (res.code === 200) {
+        window.$message.success('登录成功!');
+      } else {
+        window.$message.error(res.message);
+      }
     }
   } catch (error) {
     console.log(error);
-    clearLoginInfo();
+    clearThirdLoginInfo();
   }
 });
 </script>

+ 33 - 6
src/views/push/index.vue

@@ -910,6 +910,29 @@ function handleMoving({
   });
 }
 
+async function handleUserMedia({ video, audio }) {
+  try {
+    const event = await navigator.mediaDevices.getUserMedia({
+      video,
+      audio,
+    });
+    return event;
+  } catch (error) {
+    console.log(error);
+  }
+}
+async function handleDisplayMedia({ video, audio }) {
+  try {
+    const event = await navigator.mediaDevices.getDisplayMedia({
+      video,
+      audio,
+    });
+    return event;
+  } catch (error) {
+    console.log(error);
+  }
+}
+
 async function handleCache() {
   const res: AppRootState['allTrack'] = [];
   const err: string[] = [];
@@ -1027,10 +1050,11 @@ async function handleCache() {
 
     async function handleScreen() {
       try {
-        const event = await navigator.mediaDevices.getDisplayMedia({
+        const event = await handleDisplayMedia({
           video: true,
           audio: true,
         });
+        if (!event) return;
         const videoEl = createVideo({ appendChild: true });
         bodyAppendChildElArr.value.push(videoEl);
         videoEl.setAttribute('videoid', obj.id);
@@ -1072,10 +1096,11 @@ async function handleCache() {
     }
 
     async function handleMicrophone() {
-      const event = await navigator.mediaDevices.getUserMedia({
+      const event = await handleUserMedia({
         video: false,
         audio: { deviceId: obj.deviceId },
       });
+      if (!event) return;
       const videoEl = createVideo({ appendChild: true, muted: false });
       bodyAppendChildElArr.value.push(videoEl);
       videoEl.setAttribute('videoid', obj.id);
@@ -1237,14 +1262,14 @@ function setScaleInfo({ track, canvasDom, scale = 1 }) {
 async function addMediaOk(val: AppRootState['allTrack'][0]) {
   showMediaModalCpt.value = false;
   if (val.type === MediaTypeEnum.screen) {
-    const event = await navigator.mediaDevices.getDisplayMedia({
+    const event = await handleDisplayMedia({
       video: {
         deviceId: val.deviceId,
         // displaySurface: 'monitor', // browser默认标签页;window默认窗口;monitor默认整个屏幕
       },
       audio: true,
     });
-
+    if (!event) return;
     const videoTrack: AppRootState['allTrack'][0] = {
       id: getRandomEnglishString(8),
       audio: 2,
@@ -1301,12 +1326,13 @@ async function addMediaOk(val: AppRootState['allTrack'][0]) {
 
     console.log('获取窗口成功');
   } else if (val.type === MediaTypeEnum.camera) {
-    const event = await navigator.mediaDevices.getUserMedia({
+    const event = await handleUserMedia({
       video: {
         deviceId: val.deviceId,
       },
       audio: false,
     });
+    if (!event) return;
     const videoTrack: AppRootState['allTrack'][0] = {
       id: getRandomEnglishString(8),
       deviceId: val.deviceId,
@@ -1337,10 +1363,11 @@ async function addMediaOk(val: AppRootState['allTrack'][0]) {
     // @ts-ignore
     console.log('获取摄像头成功');
   } else if (val.type === MediaTypeEnum.microphone) {
-    const event = await navigator.mediaDevices.getUserMedia({
+    const event = await handleUserMedia({
       video: false,
       audio: { deviceId: val.deviceId },
     });
+    if (!event) return;
     const microphoneVideoTrack: AppRootState['allTrack'][0] = {
       id: getRandomEnglishString(8),
       deviceId: val.deviceId,

+ 3 - 5
src/views/qrcodeLogin/index.vue

@@ -18,15 +18,13 @@ const route = useRoute();
 
 function handleClick() {
   // eslint-disable-next-line
-  const { platform, exp, login_id } = route.query;
-  // eslint-disable-next-line
-  if (!platform || !exp || !login_id) {
+  const { platform, loginId, exp } = route.query;
+  if (!platform || !loginId || !exp) {
     window.$message.error('参数缺失!');
     return;
   }
   if (platform === 'wechat') {
-    // eslint-disable-next-line
-    useWechatLogin({ platform, exp, login_id });
+    useWechatLogin({ platform, exp, loginId });
   } else {
     window.$message.error('platform错误!');
   }