ny
22 小时以前 282fbc6488f4e8ceb5fda759f963ee88fbf7b999
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<script lang="ts" setup>
import { nextTick, onMounted, onUnmounted, reactive, toRefs } from 'vue';
import { useRouter } from 'vue-router';
 
import { preferences } from '@vben/preferences';
import { useAccessStore } from '@vben/stores';
 
import { CheckOutlined, ExclamationOutlined } from '@ant-design/icons-vue';
import { QRCode } from 'ant-design-vue';
 
import { getCodeCertificate, getCodeCertificateStatus, setCodeCertificateStatus } from '#/api/core/user';
import { $t } from '#/locales';
 
interface State {
  qrCodeText: string;
  qrCodeStatus: string;
  ticket: string;
  timer: any;
}
 
const accessStore = useAccessStore();
const router = useRouter();
const state = reactive<State>({
  qrCodeText: '',
  // active/expired/scanned/loading
  qrCodeStatus: 'loading',
  ticket: '',
  timer: null,
});
const { qrCodeText, qrCodeStatus } = toRefs(state);
 
function reset() {
  clearTimer();
  state.ticket = '';
  state.qrCodeStatus = 'loading';
  getCodeCertificate().then((res) => {
    state.ticket = res?.data || '';
    if (!res?.data) return;
    const data = { t: 'login', id: res.data };
    state.qrCodeText = JSON.stringify(data);
    state.qrCodeStatus = 'active';
    state.timer = setInterval(() => {
      handleGetStatus();
    }, 1000);
  });
}
function handleGetStatus() {
  getCodeCertificateStatus(state.ticket).then((res) => {
    if (res.data.status === 0) return;
    if (res.data.status === 1) {
      state.qrCodeStatus = 'scanned';
      return;
    }
    clearTimer();
    if (res.data.status === -1) {
      state.qrCodeStatus = 'expired';
      return;
    }
    // 登录成功
    if (res.data.status === 2) {
      accessStore.setAccessToken(res.data.value);
      nextTick(() => {
        router.push(preferences.app.defaultHomePath);
      });
    }
  });
}
function goBack() {
  setCodeCertificateStatus(state.ticket, '-1').then(() => {
    reset();
  });
}
function clearTimer() {
  if (!state.timer) return;
  clearInterval(state.timer);
  state.timer = null;
}
 
onMounted(() => {
  reset();
});
onUnmounted(() => {
  clearTimer();
});
</script>
<template>
  <div class="qrcode-form enter-x">
    <div class="qrcode-title">{{ $t('sys.login.qrCodeTip') }}</div>
    <div class="qrcode-content">
      <QRCode :value="qrCodeText" :size="240" :bordered="false" bg-color="#ffffff" color="#000" />
      <div class="qrcode-mask" v-if="qrCodeStatus !== 'active'">
        <div class="qrcode-mask-main" v-loading="qrCodeStatus === 'loading'">
          <div class="qrcode-scanned" v-if="qrCodeStatus === 'scanned'">
            <div class="qrcode-icon">
              <CheckOutlined />
            </div>
            <p class="qrcode-tip">{{ $t('sys.login.scanSuccessful') }}</p>
            <p class="qrcode-tip">{{ $t('sys.login.confirmLogin') }}</p>
          </div>
          <div class="qrcode-expired" v-if="qrCodeStatus === 'expired'">
            <div class="qrcode-icon expired-icon">
              <ExclamationOutlined />
            </div>
            <p class="qrcode-tip">{{ $t('sys.login.expired') }}</p>
            <p class="qrcode-tip link-text" @click="reset">{{ $t('sys.login.refreshCode') }}</p>
          </div>
        </div>
      </div>
      <div class="qrcode-bottom" v-if="qrCodeStatus === 'scanned'">
        <span class="link-text" @click="goBack">{{ $t('sys.login.recoverCode') }}</span>
      </div>
    </div>
  </div>
</template>