2019-12-04 13:45:37 +08:00
|
|
|
|
<template>
|
2024-05-24 15:35:17 +08:00
|
|
|
|
<div class="login"
|
|
|
|
|
|
id="login-bgimg"
|
|
|
|
|
|
:style="`${nzDefaultConfig.showVideo ? 'background: none': ''}`"
|
|
|
|
|
|
>
|
|
|
|
|
|
<div class="video-box" v-if="nzDefaultConfig.showVideo">
|
2024-05-21 15:57:08 +08:00
|
|
|
|
<video class="video-background" preload="auto" loop="" playsinline="" autoplay="" src="/static/video/netsec-bg-video.mp4" tabindex="-1" muted="muted"></video>
|
2022-08-19 14:04:26 +08:00
|
|
|
|
</div>
|
2024-05-24 15:35:17 +08:00
|
|
|
|
<div class="model" v-if="!nzDefaultConfig.showVideo"></div>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<div class="login-main">
|
2022-12-21 14:05:37 +08:00
|
|
|
|
<div class="logo"><img :src="imageUrl"></div>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<div class='login-box'>
|
|
|
|
|
|
<div class="login-label"></div>
|
|
|
|
|
|
<div class="login-input" v-if="!verifyShow">
|
|
|
|
|
|
<i class="nz-icon nz-icon-user"></i>
|
2021-11-02 18:34:01 +08:00
|
|
|
|
<input id="usernameInput" v-model="loginData.username" autocomplete="on" name="userName" placeholder="Username" @keydown.enter="login"></input>
|
2020-02-19 15:16:38 +08:00
|
|
|
|
</div>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<div class="login-label"></div>
|
|
|
|
|
|
<div class="login-input" v-if="!verifyShow">
|
|
|
|
|
|
<i class="nz-icon nz-icon-password"></i>
|
2023-01-04 17:49:28 +08:00
|
|
|
|
<input v-model="loginData.pin" autocomplete="on" name="password" placeholder="Password" type="password" auto-complete="new-password" @keydown.enter="login"></input>
|
2019-12-05 16:48:23 +08:00
|
|
|
|
</div>
|
2022-06-16 15:58:17 +08:00
|
|
|
|
<div class="login-label" v-if="verifyShow">{{$t('profile.twoFactorAuthentication')}}</div>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<div class="login-input" v-if="verifyShow">
|
|
|
|
|
|
<i class="nz-icon nz-icon-yanzhengma"></i>
|
2021-08-13 14:43:39 +08:00
|
|
|
|
<input v-model="loginData.authCode" name="newPassword" autocomplete="off" :placeholder="$t('login.verifyPlaceholder')" @keydown.enter="verify"></input>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="login-label-foot" v-if="verifyShow">
|
|
|
|
|
|
{{$t('login.verifyContent')}}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="login-foot">
|
2022-04-13 11:21:56 +08:00
|
|
|
|
<button v-if="!verifyShow" id="login" v-my-loading="loading" :class="{'nz-btn-disabled': !license.valid}" class="login-btn" @click="login">{{$t("login.login")}}</button>
|
2022-03-25 15:40:05 +08:00
|
|
|
|
<button v-if="verifyShow" id="verify" v-my-loading="loading" :class="{'nz-btn-disabled': !license.valid}" class="login-btn" @click="verify">{{$t("login.verify")}}</button>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
</div>
|
2021-12-22 19:54:51 +08:00
|
|
|
|
<div class="license-warn" v-if="license.warnInfo">{{license.warnInfo}}</div>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<div class="login-license">
|
2021-12-13 17:15:32 +08:00
|
|
|
|
<!-- <div v-if="!license.valid" class="license-info">INSTALLATION ID: {{license.token}}</div>-->
|
2023-02-20 15:58:05 +08:00
|
|
|
|
<!-- <div v-if="!license.valid" class="license-upload">-->
|
|
|
|
|
|
<div class="license-upload" v-if="!license.valid">
|
2021-12-13 17:15:32 +08:00
|
|
|
|
<!-- <button type="button" class="login-btn" @click="downloadMib"><span style="margin-right: 5px"><i class="nz-icon nz-icon-download1"></i></span>{{$t('license.dowLicense')}}</button>-->
|
2024-05-21 17:11:40 +08:00
|
|
|
|
<button type="button" class="login-btn download-btn" @click="checkVisible = true"><span style="margin-right: 5px"><i class="nz-icon nz-icon-download1"></i></span>{{$t('license.downloadID')}}
|
2023-02-20 15:58:05 +08:00
|
|
|
|
</button>
|
|
|
|
|
|
<button class="license-left-footer-download login-btn download-btn" @click.stop="openQrcode" style="margin-left: -4px;display: inline-block">
|
|
|
|
|
|
<i class="nz-icon nz-icon-erweima"></i>
|
|
|
|
|
|
</button>
|
2021-12-13 17:15:32 +08:00
|
|
|
|
</div>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<div class="license-upload" v-if="!license.valid">
|
|
|
|
|
|
<el-upload
|
|
|
|
|
|
ref="upload"
|
|
|
|
|
|
accept=".xml"
|
|
|
|
|
|
action=""
|
|
|
|
|
|
:file-list="uploadFileList"
|
|
|
|
|
|
:auto-upload="false"
|
|
|
|
|
|
:on-change="handleChange"
|
2021-04-16 21:10:31 +08:00
|
|
|
|
>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<button type="button" class="login-btn" ><span style="margin-right: 5px"><i class="nz-icon nz-icon-upload"></i></span>{{$t('login.upload')}}</button>
|
|
|
|
|
|
</el-upload>
|
|
|
|
|
|
</div>
|
2021-04-16 21:10:31 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2020-12-16 13:02:53 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="login-foot-buildOn">
|
2020-12-16 14:09:44 +08:00
|
|
|
|
<span><a target="_blank" rel="noopener noreferrer" href='https://prometheus.io'>Build on Prometheus</a></span>
|
2019-12-04 13:45:37 +08:00
|
|
|
|
</div>
|
2022-03-09 11:01:17 +08:00
|
|
|
|
<el-dialog :visible.sync="authBindShow" :title="$t('login.verifyDialogTitle')" :modal-append-to-body='false'
|
2021-08-12 09:38:23 +08:00
|
|
|
|
:show-close="true" width="620px" class="nz-dialog" >
|
|
|
|
|
|
|
2022-03-25 15:40:05 +08:00
|
|
|
|
<div v-my-loading="dialogLoading">
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<div class="login-dialog-title" v-if="lang=== 'en'">
|
|
|
|
|
|
1. Download your preferred authenticator app to your phone (any will work). If you don't
|
2021-08-12 09:38:23 +08:00
|
|
|
|
have a preferred app, we recommend using <span @click="jumpDlw" class="verify-link">Google Authenticator.</span>
|
|
|
|
|
|
</div>
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<div class="login-dialog-title" v-else-if="lang=== 'zh'">
|
|
|
|
|
|
1. 将您喜欢的验证器应用程序下载到您的手机上(任何应用程序都可以)。
|
|
|
|
|
|
如果您没有首选应用程序,我们建议您使用 <span @click="jumpDlw" class="verify-link">Google Authenticator.</span>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="login-dialog-title" v-if="lang=== 'en'">
|
|
|
|
|
|
2. Use your app to take a photo of the QR code.
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="login-dialog-title" v-else-if="lang=== 'zh'">
|
|
|
|
|
|
2. 使用您的应用程序为二维码拍照。
|
2021-08-12 09:38:23 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div class="qrCode-box">
|
|
|
|
|
|
<div id="qrCode" ref="qrCodeDiv" class="qrCode-content"></div>
|
|
|
|
|
|
<div class="qrCode-text">
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<div v-if="lang=== 'en'">Type this code down if you can't take a photo.</div>
|
|
|
|
|
|
<div v-else-if="lang=== 'zh'">如果你不能拍照,请键入此代码。</div>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<div class="qrCode-authKey">{{authKey}}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<div class="login-dialog-title" v-if="lang=== 'en'">
|
2021-08-12 09:38:23 +08:00
|
|
|
|
3. Enter the 6-digit code provided by your app and then verify.
|
|
|
|
|
|
</div>
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<div class="login-dialog-title" v-else-if="lang=== 'zh'">
|
|
|
|
|
|
3. 输入应用程序提供的6位数代码,然后进行验证。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="enter-code" v-if="lang=== 'en'">Enter Code</div>
|
|
|
|
|
|
<div class="enter-code" v-else-if="lang=== 'zh'">输入代码</div>
|
2021-08-19 17:00:57 +08:00
|
|
|
|
<el-input v-model="bindAuthCode" size="small" style="width: 50%" @keydown.enter="bindCode"></el-input>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
<div slot="footer" class="footer">
|
|
|
|
|
|
<button id="asset-edit-cancel" @click="closeDialog" class="footer__btn footer__btn--light">
|
|
|
|
|
|
<span>{{$t('overall.cancel')}}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
<button id="asset-edit-save" :class="{'footer__btn--disabled': prevent_opt.save}" :disabled="prevent_opt.save" class="footer__btn" @click="bindCode">
|
|
|
|
|
|
<span style="text-transform:capitalize">{{$t('login.verify')}}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-dialog>
|
2022-03-09 11:01:17 +08:00
|
|
|
|
<el-dialog :visible.sync="fileShow" :title="$t('login.verifyDialogTitle')" :modal-append-to-body='false'
|
2021-08-12 09:38:23 +08:00
|
|
|
|
:show-close="true" width="620px" class="nz-dialog" >
|
|
|
|
|
|
|
|
|
|
|
|
<div>
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<div class="login-dialog-title" v-if="lang=== 'en'">
|
2021-08-12 09:38:23 +08:00
|
|
|
|
Should you ever lose your phone or access to your one time password secret, each of these recovery codes can be used one time each to regain access to your account.
|
|
|
|
|
|
Please save them in a safe place, or you will lose access to your account.
|
|
|
|
|
|
</div>
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<div class="login-dialog-title" v-else-if="lang=== 'zh'">
|
|
|
|
|
|
如果您丢失了您的手机或一次性密码密码,每个恢复代码都可以使用一次,以重新访问您的帐户。
|
|
|
|
|
|
请将它们保存在安全的地方,否则您将无法访问您的帐户。
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="login-dialog-title2" >
|
2021-08-12 09:38:23 +08:00
|
|
|
|
<div class="login-dialog-recover">
|
2021-08-19 17:00:57 +08:00
|
|
|
|
<div v-for="(item, index) in recoveryCode" :key="index" style="color: #999999;">
|
2021-08-12 17:13:11 +08:00
|
|
|
|
<span class="circle"></span>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
{{item}}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2022-07-01 09:39:20 +08:00
|
|
|
|
<span class="copy-value-content" :title="$t('overall.duplicate')"> <i class="nz-icon nz-icon-override" @click="copyValue"></i></span>
|
2021-08-12 09:38:23 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div slot="footer" class="footer">
|
|
|
|
|
|
<button id="asset-edit-download" :class="{'footer__btn--disabled': prevent_opt.save}" :disabled="prevent_opt.save" class="footer__btn" @click="downloadTxt">
|
|
|
|
|
|
<span style="text-transform:capitalize">{{$t('overall.download')}}</span>
|
|
|
|
|
|
</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-dialog>
|
2023-02-20 15:58:05 +08:00
|
|
|
|
<el-dialog :modal-append-to-body='false' :fullscreen="dialogQrType === 'all'" :show-close="true" :visible.sync="qrCodeShow" @close="closeQrCode" :title="'QR code'" class="nz-dialog overview" width="650px">
|
|
|
|
|
|
<div slot="title">
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<span class="el-dialog__header-title" v-if="lang=== 'en'">
|
2023-02-20 15:58:05 +08:00
|
|
|
|
QR code
|
|
|
|
|
|
</span>
|
2023-08-24 16:40:33 +08:00
|
|
|
|
<span class="el-dialog__header-title" v-else-if="lang=== 'zh'">
|
|
|
|
|
|
二维码
|
|
|
|
|
|
</span>
|
2023-02-20 15:58:05 +08:00
|
|
|
|
<div style="float: right; margin-right: 25px">
|
|
|
|
|
|
<el-button-group>
|
|
|
|
|
|
<el-button class="top-tool-btn" :class="{active: dialogQrType == 'item' }" size="small" @click="dialogQrType = 'item'"><i class="nz-icon nz-icon-dangemoshi"/></el-button>
|
|
|
|
|
|
<el-button class="top-tool-btn" :class="{active: dialogQrType == 'all' }" size="small" @click="dialogQrType = 'all'"><i class="nz-icon nz-icon-duogemoshi"/></el-button>
|
|
|
|
|
|
</el-button-group>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-show="dialogQrType === 'item'">
|
|
|
|
|
|
<el-carousel arrow="never" :autoplay="false" :height="'500px'" ref="carousel" v-my-loading="qrloading">
|
|
|
|
|
|
<el-carousel-item v-for="(item, index) in qrCodeNum" :key="index" :name="'qr-' + index" style="width: 100%;height: 100%">
|
|
|
|
|
|
<!-- :logo-src="getSrc(index)"-->
|
|
|
|
|
|
<div v-my-loading="item">
|
|
|
|
|
|
<vueQr
|
|
|
|
|
|
style="width: 500px;height: 500px"
|
|
|
|
|
|
:text="qrCodeArr[index] || String(index)"
|
|
|
|
|
|
:size="2000"
|
|
|
|
|
|
:margin="50"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-carousel-item>
|
|
|
|
|
|
</el-carousel>
|
|
|
|
|
|
<div class="nz-license-footer">
|
|
|
|
|
|
<el-pagination
|
|
|
|
|
|
@current-change="setActiveItem"
|
|
|
|
|
|
small
|
|
|
|
|
|
:page-size="1"
|
|
|
|
|
|
:current-page.sync="currentPage"
|
|
|
|
|
|
layout="prev, pager, next"
|
|
|
|
|
|
:total="qrCodeNum.length">
|
|
|
|
|
|
</el-pagination>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div v-show="dialogQrType === 'all'" :style="{
|
|
|
|
|
|
'padding-left': paddingLeft + 'px'
|
|
|
|
|
|
}" v-my-loading="qrloading">
|
|
|
|
|
|
<div v-for="(item, index) in qrCodeNum"
|
|
|
|
|
|
:key="index"
|
|
|
|
|
|
:name="'qr-' + index"
|
|
|
|
|
|
:style="{
|
|
|
|
|
|
width: qrWidth + 'px',
|
|
|
|
|
|
height: qrWidth + 'px',
|
|
|
|
|
|
'text-align': 'center',
|
|
|
|
|
|
display: 'inline-block'
|
|
|
|
|
|
}"
|
|
|
|
|
|
v-my-loading="item"
|
|
|
|
|
|
>
|
|
|
|
|
|
<!-- :logo-src="getSrc(index)"-->
|
|
|
|
|
|
<vueQr
|
|
|
|
|
|
:style="{
|
|
|
|
|
|
width: qrWidth - 32 + 'px',
|
|
|
|
|
|
height: qrWidth - 32 + 'px'
|
|
|
|
|
|
}"
|
|
|
|
|
|
:text="qrCodeArr[index] || String(index)"
|
|
|
|
|
|
:size="2000"
|
|
|
|
|
|
:margin="10"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<div style="text-align:center;margin-right:32px;"> {{index+1}} / {{qrCodeNum.length}}</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-dialog>
|
2024-06-18 09:29:59 +08:00
|
|
|
|
|
2024-05-21 17:11:40 +08:00
|
|
|
|
<el-dialog
|
|
|
|
|
|
class="nz-dialog c2vDialog"
|
|
|
|
|
|
:title="$t('license.downloadID')"
|
|
|
|
|
|
:show-close="true"
|
|
|
|
|
|
:visible.sync="checkVisible"
|
2024-06-18 09:29:59 +08:00
|
|
|
|
width="580px"
|
2024-05-21 17:11:40 +08:00
|
|
|
|
@close="closeCheckDialog"
|
2024-06-18 09:29:59 +08:00
|
|
|
|
>
|
|
|
|
|
|
<p class="check-tip">
|
|
|
|
|
|
<i class="nz-icon nz-icon-jinggao"></i>
|
|
|
|
|
|
{{$t('license.check')}}
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<div class="check-content">
|
|
|
|
|
|
<p class="check-tip">{{$t('license.check1')}}</p>
|
|
|
|
|
|
<p class="check-tip">{{$t('license.check2')}}</p>
|
|
|
|
|
|
<p class="check-tip">{{$t('license.check3')}}</p>
|
|
|
|
|
|
<p class="check-tip">{{$t('license.check4')}}</p>
|
|
|
|
|
|
</div>
|
2024-05-21 17:11:40 +08:00
|
|
|
|
<p class="check-tip isCheck">
|
|
|
|
|
|
<el-checkbox v-model="checkCompleted">{{$t('license.checkCompleted')}}</el-checkbox>
|
|
|
|
|
|
</p>
|
|
|
|
|
|
<div slot="footer">
|
2024-06-18 09:29:59 +08:00
|
|
|
|
<button @click="checkVisible = false" class="nz-btn nz-btn-size-normal nz-btn-style-light margin-r-10">{{$t("overall.cancel")}}</button>
|
2024-05-21 17:11:40 +08:00
|
|
|
|
<button @click="downloadLicense" class="nz-btn nz-btn-size-normal nz-btn-style-normal" :class="{'nz-btn-disabled': (downLoading || !checkCompleted)}" :disabled="(downLoading || !checkCompleted)">{{$t('overall.download')}}</button>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</el-dialog>
|
2019-12-26 16:31:53 +08:00
|
|
|
|
</div>
|
2019-12-04 13:45:37 +08:00
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
2021-03-19 18:52:19 +08:00
|
|
|
|
import { mapActions } from 'vuex'
|
2021-08-12 09:38:23 +08:00
|
|
|
|
import QRCode from 'qrcodejs2'
|
2021-08-19 12:51:49 +08:00
|
|
|
|
import bus from '@/libs/bus.js'
|
2022-08-19 14:04:26 +08:00
|
|
|
|
import { SVG } from '@svgdotjs/svg.js'
|
2022-08-22 15:41:59 +08:00
|
|
|
|
import { coordinatePoint } from '@/components/common/js/common'
|
2022-12-21 14:05:37 +08:00
|
|
|
|
import imageUrl from '@/assets/img/logo-big.png'
|
2023-02-20 15:58:05 +08:00
|
|
|
|
import VueQr from '@/components/common/vueQR/packages/vue-qr'
|
2021-11-04 09:29:01 +08:00
|
|
|
|
import { get } from '@/http'
|
2023-02-20 15:58:05 +08:00
|
|
|
|
import SparkMD5 from 'spark-md5'
|
2019-12-04 13:45:37 +08:00
|
|
|
|
export default {
|
2021-03-19 18:52:19 +08:00
|
|
|
|
name: 'login',
|
2023-02-20 15:58:05 +08:00
|
|
|
|
components: {
|
|
|
|
|
|
VueQr
|
|
|
|
|
|
},
|
2021-03-19 18:52:19 +08:00
|
|
|
|
data () {
|
2019-12-04 13:45:37 +08:00
|
|
|
|
return {
|
2022-12-21 14:05:37 +08:00
|
|
|
|
imageUrl,
|
2019-12-04 13:45:37 +08:00
|
|
|
|
loginData: {
|
|
|
|
|
|
username: '',
|
2021-03-25 09:46:59 +08:00
|
|
|
|
pin: '',
|
2021-08-12 09:38:23 +08:00
|
|
|
|
remember: false,
|
|
|
|
|
|
authCode: ''
|
2019-12-04 13:45:37 +08:00
|
|
|
|
},
|
2021-04-16 21:10:31 +08:00
|
|
|
|
license: {
|
|
|
|
|
|
warnInfo: '',
|
|
|
|
|
|
token: '',
|
2021-11-11 17:01:04 +08:00
|
|
|
|
valid: true
|
2021-04-16 21:10:31 +08:00
|
|
|
|
},
|
2022-04-13 11:21:56 +08:00
|
|
|
|
lang: this.$store.getters.getLanguage || 'en',
|
2021-04-16 21:10:31 +08:00
|
|
|
|
uploadFileList: [],
|
|
|
|
|
|
uploadFile: { file: '', path: '', uuid: '' },
|
2020-12-08 21:53:37 +08:00
|
|
|
|
loading: false,
|
2021-08-12 09:38:23 +08:00
|
|
|
|
verifyShow: false,
|
2021-12-02 10:44:21 +08:00
|
|
|
|
theme: 1,
|
2021-08-12 09:38:23 +08:00
|
|
|
|
authBindShow: false,
|
|
|
|
|
|
authToken: '',
|
|
|
|
|
|
QRCode: '',
|
|
|
|
|
|
bindAuthCode: '',
|
2021-08-13 13:47:12 +08:00
|
|
|
|
authKey: '',
|
2021-08-12 09:38:23 +08:00
|
|
|
|
dialogLoading: false,
|
|
|
|
|
|
fileShow: false,
|
|
|
|
|
|
fileContent: '',
|
2021-11-24 15:55:18 +08:00
|
|
|
|
recoveryCode: [],
|
2022-03-23 17:33:11 +08:00
|
|
|
|
userInfo: {},
|
2022-08-22 15:41:59 +08:00
|
|
|
|
zoom: 0.75,
|
|
|
|
|
|
circleStar: [],
|
|
|
|
|
|
starTimer: '',
|
|
|
|
|
|
starTimerIndex: 0,
|
2022-08-24 09:57:40 +08:00
|
|
|
|
bgImg: '', // 背景图
|
|
|
|
|
|
constellation: [],
|
|
|
|
|
|
requestAnimationFrame: '',
|
2023-02-20 15:58:05 +08:00
|
|
|
|
speed: [-1.3, -1, -0.6, -0.3, 0.3, 0.6, 1, 1.3],
|
|
|
|
|
|
stateItem: '',
|
|
|
|
|
|
endItem: '',
|
|
|
|
|
|
qrCodeShow: false,
|
|
|
|
|
|
qrCodeArr: [],
|
|
|
|
|
|
qrCodeNum: [], // 逐个加载 qr
|
|
|
|
|
|
totalQrCode: 10,
|
|
|
|
|
|
currentPage: 1,
|
|
|
|
|
|
qrloading: false,
|
|
|
|
|
|
dialogQrType: 'item',
|
|
|
|
|
|
boxWidth: '',
|
|
|
|
|
|
boxHeight: '',
|
|
|
|
|
|
qrWidth: 10,
|
2024-05-21 17:11:40 +08:00
|
|
|
|
paddingLeft: 0,
|
|
|
|
|
|
checkVisible: false,
|
|
|
|
|
|
downLoading: false,
|
|
|
|
|
|
checkCompleted: false
|
2019-12-04 13:45:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
methods: {
|
2021-03-19 18:52:19 +08:00
|
|
|
|
...mapActions(['loginSuccess']),
|
2024-05-21 17:11:40 +08:00
|
|
|
|
closeCheckDialog () {
|
|
|
|
|
|
this.checkCompleted = false
|
|
|
|
|
|
},
|
2021-03-19 18:52:19 +08:00
|
|
|
|
login () {
|
2021-12-20 18:02:48 +08:00
|
|
|
|
if (this.loading || !this.license.valid) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2021-04-26 21:42:15 +08:00
|
|
|
|
if (this.validateLogin() && (this.$route.path == '/' || this.$route.path == '/login')) {
|
2021-03-19 18:52:19 +08:00
|
|
|
|
this.loading = true
|
2021-08-13 13:47:12 +08:00
|
|
|
|
this.$post('/sys/login', this.loginData).then(res => {
|
2020-02-19 15:16:38 +08:00
|
|
|
|
if (res.code == 200) {
|
2021-03-19 18:52:19 +08:00
|
|
|
|
// 登录成功,记录用户名、token和lang
|
2021-08-13 13:47:12 +08:00
|
|
|
|
this.authToken = res.data.authToken
|
2021-11-24 15:55:18 +08:00
|
|
|
|
this.lang = res.data.user.lang || localStorage.getItem('nz-language')
|
2021-10-13 09:17:51 +08:00
|
|
|
|
this.$i18n.locale = this.lang
|
2021-12-02 10:44:21 +08:00
|
|
|
|
this.theme = res.data.user.theme
|
2022-03-23 17:33:11 +08:00
|
|
|
|
this.userInfo = res.data.user
|
2021-11-26 18:47:00 +08:00
|
|
|
|
localStorage.setItem('nz-token', res.data.authToken)
|
2024-05-21 17:11:40 +08:00
|
|
|
|
localStorage.setItem('nz-userInfo', JSON.stringify(this.userInfo))
|
2021-08-12 09:38:23 +08:00
|
|
|
|
if (res.data.authFlag === 1) {
|
|
|
|
|
|
if (res.data.authBind === 0) {
|
|
|
|
|
|
this.verifyShow = true
|
|
|
|
|
|
} else if (res.data.authBind === 1) {
|
|
|
|
|
|
this.authBindShow = true
|
|
|
|
|
|
this.dialogLoading = true
|
2021-08-13 13:47:12 +08:00
|
|
|
|
this.$post('/mfa/genkey', { authToken: this.authToken }).then(res => {
|
|
|
|
|
|
this.dialogLoading = false
|
|
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
this.authToken = res.data.authToken
|
|
|
|
|
|
this.authKey = res.data.authKey
|
|
|
|
|
|
this.bindQRCode(res.data.otpauth)
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.authBindShow = false
|
|
|
|
|
|
this.$message.error(res.message)
|
|
|
|
|
|
}
|
2021-08-12 09:38:23 +08:00
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
} else {
|
2021-11-26 18:47:00 +08:00
|
|
|
|
localStorage.setItem('nz-username', this.loginData.username)
|
2021-08-12 09:38:23 +08:00
|
|
|
|
localStorage.setItem('nz-username', this.loginData.username)
|
|
|
|
|
|
localStorage.setItem('nz-prometheus-federation-enabled', res.data.prometheusFederationEnabled)
|
|
|
|
|
|
localStorage.setItem('nz-language', this.lang)
|
2023-06-27 14:27:53 +08:00
|
|
|
|
this.$store.commit('setLanguage', this.lang)
|
2021-08-12 09:38:23 +08:00
|
|
|
|
this.loginSuccess(res)
|
|
|
|
|
|
}
|
2020-02-19 15:16:38 +08:00
|
|
|
|
} else {
|
2021-03-19 18:52:19 +08:00
|
|
|
|
this.$message.error(res.msg)
|
2020-02-19 15:16:38 +08:00
|
|
|
|
}
|
2020-12-08 21:53:37 +08:00
|
|
|
|
}).finally(() => {
|
2021-03-19 18:52:19 +08:00
|
|
|
|
this.loading = false
|
|
|
|
|
|
})
|
2020-02-19 15:16:38 +08:00
|
|
|
|
}
|
2019-12-04 13:45:37 +08:00
|
|
|
|
},
|
2021-08-12 09:38:23 +08:00
|
|
|
|
verify () {
|
|
|
|
|
|
const params = {
|
|
|
|
|
|
authToken: this.authToken,
|
|
|
|
|
|
authCode: this.loginData.authCode
|
|
|
|
|
|
}
|
2021-08-13 13:47:12 +08:00
|
|
|
|
this.$post('/mfa/verify', params).then(res => {
|
2021-08-12 15:52:48 +08:00
|
|
|
|
if (res.code === 200) {
|
2021-11-26 18:47:00 +08:00
|
|
|
|
localStorage.setItem('nz-username', this.loginData.username)
|
2021-08-12 15:52:48 +08:00
|
|
|
|
localStorage.setItem('nz-username', this.loginData.username)
|
|
|
|
|
|
localStorage.setItem('nz-prometheus-federation-enabled', res.data.prometheusFederationEnabled)
|
2021-10-14 13:40:13 +08:00
|
|
|
|
localStorage.setItem('nz-language', this.lang)
|
2023-06-27 14:27:53 +08:00
|
|
|
|
this.$store.commit('setLanguage', this.lang)
|
2021-11-15 11:18:07 +08:00
|
|
|
|
res.data.user = {
|
2022-03-23 17:33:11 +08:00
|
|
|
|
...this.userInfo
|
2021-11-15 11:18:07 +08:00
|
|
|
|
}
|
2021-08-12 15:52:48 +08:00
|
|
|
|
this.loginSuccess(res)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.authToken = res.data.authToken
|
2021-08-13 14:29:17 +08:00
|
|
|
|
this.$message.error(res.msg)
|
2021-08-12 15:52:48 +08:00
|
|
|
|
}
|
2021-08-12 09:38:23 +08:00
|
|
|
|
})
|
|
|
|
|
|
},
|
2021-03-19 18:52:19 +08:00
|
|
|
|
validateLogin () {
|
2021-03-25 09:46:59 +08:00
|
|
|
|
if (!this.loginData.username || !this.loginData.pin) {
|
2021-03-19 18:52:19 +08:00
|
|
|
|
this.$message.error('Empty username or password')
|
|
|
|
|
|
return false
|
2019-12-26 16:31:53 +08:00
|
|
|
|
} else {
|
2021-03-19 18:52:19 +08:00
|
|
|
|
return true
|
2020-02-19 15:16:38 +08:00
|
|
|
|
}
|
2021-04-16 21:10:31 +08:00
|
|
|
|
},
|
2021-05-12 11:43:43 +08:00
|
|
|
|
licenseStat () {
|
2021-12-15 17:29:55 +08:00
|
|
|
|
this.$get('/sys/license/status').then(response => {
|
2021-05-12 11:43:43 +08:00
|
|
|
|
if (response.code && response.code === 200) {
|
2021-04-16 21:10:31 +08:00
|
|
|
|
this.license.warnInfo = ''
|
|
|
|
|
|
this.license.valid = true
|
|
|
|
|
|
} else {
|
2021-04-21 18:24:25 +08:00
|
|
|
|
this.license.valid = false
|
2021-04-16 21:10:31 +08:00
|
|
|
|
this.license.warnInfo = response.msg
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
2021-05-12 11:43:43 +08:00
|
|
|
|
handleChange (file, fileList) {
|
2021-04-16 21:10:31 +08:00
|
|
|
|
if (fileList.length > 0) {
|
|
|
|
|
|
this.uploadFileList = [fileList[fileList.length - 1]]
|
|
|
|
|
|
}
|
|
|
|
|
|
this.uploadFile.file = this.uploadFileList[0]
|
|
|
|
|
|
this.upload()
|
|
|
|
|
|
},
|
|
|
|
|
|
upload () {
|
|
|
|
|
|
const form = new FormData()
|
|
|
|
|
|
form.append('file', this.uploadFile.file.raw)
|
2021-12-10 18:12:37 +08:00
|
|
|
|
this.$post('/sys/license/upload', form).then(res => {
|
2021-04-16 21:10:31 +08:00
|
|
|
|
if (res.code == 200) {
|
|
|
|
|
|
this.licenseStat()
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.$message.error(res.msg)
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
2021-08-12 09:38:23 +08:00
|
|
|
|
},
|
2024-05-21 17:11:40 +08:00
|
|
|
|
downloadLicense () {
|
|
|
|
|
|
this.downLoading = true
|
2021-12-13 17:15:32 +08:00
|
|
|
|
this.$get('/sys/license/token').then(res => {
|
2024-05-21 17:11:40 +08:00
|
|
|
|
this.downLoading = false
|
|
|
|
|
|
this.checkVisible = false
|
2022-03-18 10:26:36 +08:00
|
|
|
|
let fileName = ''
|
2022-03-14 13:47:37 +08:00
|
|
|
|
const resFileName = res.headers['content-disposition'].split('=')[1]
|
|
|
|
|
|
if (resFileName) {
|
|
|
|
|
|
fileName = resFileName
|
|
|
|
|
|
}
|
2021-12-13 17:15:32 +08:00
|
|
|
|
if (window.navigator.msSaveOrOpenBlob) {
|
|
|
|
|
|
// 兼容ie11
|
2022-03-14 13:47:37 +08:00
|
|
|
|
const blobObject = new Blob([res.data])
|
2021-12-13 17:15:32 +08:00
|
|
|
|
window.navigator.msSaveOrOpenBlob(blobObject, fileName)
|
|
|
|
|
|
} else {
|
2022-03-14 13:47:37 +08:00
|
|
|
|
const url = URL.createObjectURL(new Blob([res.data]))
|
2021-12-13 17:15:32 +08:00
|
|
|
|
const a = document.createElement('a')
|
|
|
|
|
|
document.body.appendChild(a) // 此处增加了将创建的添加到body当中
|
|
|
|
|
|
a.href = url
|
|
|
|
|
|
a.download = fileName
|
|
|
|
|
|
a.target = '_blank'
|
|
|
|
|
|
a.click()
|
|
|
|
|
|
a.remove() // 将a标签移除
|
|
|
|
|
|
}
|
|
|
|
|
|
}, error => {
|
2024-05-21 17:11:40 +08:00
|
|
|
|
this.downLoading = false
|
2021-12-13 17:15:32 +08:00
|
|
|
|
const $self = this
|
|
|
|
|
|
const reader = new FileReader()
|
|
|
|
|
|
reader.onload = function (event) {
|
|
|
|
|
|
const responseText = reader.result
|
|
|
|
|
|
const exception = JSON.parse(responseText)
|
|
|
|
|
|
if (exception.message) {
|
|
|
|
|
|
$self.$message.error(exception.message)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.error(error)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
reader.readAsText(error.response.data)
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
getTimeString () {
|
|
|
|
|
|
const split = '-'
|
|
|
|
|
|
const date = new Date()
|
|
|
|
|
|
const year = date.getFullYear()
|
|
|
|
|
|
const month = this.formatNum(date.getMonth() + 1)
|
|
|
|
|
|
const day = this.formatNum(date.getDate())
|
|
|
|
|
|
const hours = this.formatNum(date.getHours())
|
|
|
|
|
|
const minutes = this.formatNum(date.getMinutes())
|
|
|
|
|
|
const seconds = this.formatNum(date.getSeconds())
|
|
|
|
|
|
return year + split + month + split + day + ' ' + hours + split + minutes + split + seconds
|
|
|
|
|
|
},
|
|
|
|
|
|
formatNum (num) {
|
|
|
|
|
|
return num > 9 ? num : '0' + num
|
|
|
|
|
|
},
|
2021-08-12 09:38:23 +08:00
|
|
|
|
bindQRCode: function (text) {
|
|
|
|
|
|
text = text || 'https://www.baidu.com'
|
|
|
|
|
|
if (!this.QRCode) {
|
|
|
|
|
|
this.QRCode = new QRCode(this.$refs.qrCodeDiv, {
|
|
|
|
|
|
text: text,
|
|
|
|
|
|
width: 124,
|
|
|
|
|
|
height: 124,
|
|
|
|
|
|
colorDark: '#333333', // 二维码颜色
|
|
|
|
|
|
colorLight: '#ffffff', // 二维码背景色
|
|
|
|
|
|
correctLevel: QRCode.CorrectLevel.L// 容错率,L/M/H
|
|
|
|
|
|
})
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.QRCode.makeCode(text)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
closeDialog () {
|
|
|
|
|
|
this.authBindShow = false
|
|
|
|
|
|
this.bindAuthCode = ''
|
|
|
|
|
|
},
|
|
|
|
|
|
bindCode () {
|
|
|
|
|
|
this.prevent_opt.save = true
|
2021-08-13 13:47:12 +08:00
|
|
|
|
this.$post('/mfa/bind', { authToken: this.authToken, authCode: this.bindAuthCode }).then(res => {
|
2021-08-12 15:52:48 +08:00
|
|
|
|
this.prevent_opt.save = false
|
2021-08-12 09:38:23 +08:00
|
|
|
|
if (res.code === 200) {
|
|
|
|
|
|
this.authBindShow = false
|
|
|
|
|
|
this.bindAuthCode = ''
|
2021-08-12 17:13:11 +08:00
|
|
|
|
this.recoveryCode = res.data.recoveryCode
|
2021-08-12 09:38:23 +08:00
|
|
|
|
this.fileContent = this.recoveryCode.join(' \n ')
|
|
|
|
|
|
this.fileShow = true
|
|
|
|
|
|
} else {
|
2021-08-13 13:47:12 +08:00
|
|
|
|
this.authToken = res.data.authToken
|
2021-08-12 09:38:23 +08:00
|
|
|
|
this.$message.error(this.$t('login.bindFail'))
|
|
|
|
|
|
}
|
|
|
|
|
|
})
|
|
|
|
|
|
},
|
|
|
|
|
|
jumpDlw () {
|
|
|
|
|
|
window.open('https://google-authenticator.en.softonic.com/android')
|
|
|
|
|
|
},
|
|
|
|
|
|
downloadTxt () {
|
|
|
|
|
|
const element = document.createElement('a')
|
2021-12-17 09:47:50 +08:00
|
|
|
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(this.fileContent))
|
2021-08-13 14:29:17 +08:00
|
|
|
|
element.setAttribute('download', 'Nezha recovery codes')
|
2021-08-12 09:38:23 +08:00
|
|
|
|
element.style.display = 'none'
|
|
|
|
|
|
element.click()
|
|
|
|
|
|
},
|
|
|
|
|
|
copyValue () {
|
2022-11-02 14:38:28 +08:00
|
|
|
|
this.$copyText(this.fileContent).then(() => {
|
|
|
|
|
|
this.$message.success({ message: this.$t('overall.copySuccess') })
|
|
|
|
|
|
})
|
2021-08-19 12:51:49 +08:00
|
|
|
|
},
|
|
|
|
|
|
initEvent () {
|
|
|
|
|
|
bus.$on('profile-dialog', () => {
|
|
|
|
|
|
this.authBindShow = true
|
|
|
|
|
|
})
|
2022-08-19 14:04:26 +08:00
|
|
|
|
},
|
|
|
|
|
|
initStar () {
|
2022-08-24 09:57:40 +08:00
|
|
|
|
const self = this
|
2022-08-22 15:41:59 +08:00
|
|
|
|
this.circleStar = [[], [], [], []]
|
2022-08-19 14:04:26 +08:00
|
|
|
|
document.getElementById('login-bgimg').style['background-image'] = 'url()'
|
|
|
|
|
|
const box = document.getElementById('stars-wrapper')
|
|
|
|
|
|
for (let i = 0; i < 3; i++) {
|
|
|
|
|
|
const svg = SVG().addTo(box).size('100%', '100%')
|
2022-08-22 15:41:59 +08:00
|
|
|
|
svg.attr('class', 'stars' + (i + 1))
|
2022-08-19 14:04:26 +08:00
|
|
|
|
svg.attr('width', '100%')
|
|
|
|
|
|
svg.attr('height', '100%')
|
|
|
|
|
|
svg.attr('preserveAspectRatio', 'none')
|
2022-08-22 15:41:59 +08:00
|
|
|
|
for (let j = 0; j < 50; j++) {
|
2022-08-24 09:57:40 +08:00
|
|
|
|
const circle = svg.circle(self.r(0.5, 2))
|
2022-08-19 14:04:26 +08:00
|
|
|
|
circle.attr('class', 'star')
|
2022-08-24 09:57:40 +08:00
|
|
|
|
circle.attr('cx', self.r(0, 100) + '%')
|
|
|
|
|
|
circle.attr('cy', self.r(0, 100) + '%')
|
2022-08-22 15:41:59 +08:00
|
|
|
|
this.circleStar[i].push(circle)
|
2022-08-19 14:04:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2022-08-22 15:41:59 +08:00
|
|
|
|
Object.keys(coordinatePoint).forEach((key, index) => {
|
|
|
|
|
|
const group = SVG().addTo(box).attr('id', key).size('255', '305')
|
|
|
|
|
|
group.attr('width', '265')
|
|
|
|
|
|
group.attr('height', '305')
|
2022-08-24 09:57:40 +08:00
|
|
|
|
group.attr('style', `left: ${coordinatePoint[key].offsetX};top:${coordinatePoint[key].offsetY};transform:scale(${this.zoom});`)
|
2022-08-24 15:41:36 +08:00
|
|
|
|
group.attr('class', `constellation constellation${Math.round(self.r(0, 4))}`)
|
2022-08-24 09:57:40 +08:00
|
|
|
|
group.data({
|
|
|
|
|
|
id: key,
|
|
|
|
|
|
speedX: self.r(-1, 1, 0.3),
|
|
|
|
|
|
speedY: self.r(-1, 1, 0.3)
|
|
|
|
|
|
})
|
2022-08-22 15:41:59 +08:00
|
|
|
|
const polyline = group.polyline(coordinatePoint[key].point.map(item => [item.x, item.y])) // 先将所有点 用直线链接
|
|
|
|
|
|
polyline.fill('none')
|
|
|
|
|
|
polyline.stroke({ color: '#868096', width: 4, linecap: 'round', linejoin: 'round' })
|
|
|
|
|
|
if (coordinatePoint[key].dot && coordinatePoint[key].dot.length) { // 再用虚线 覆盖原本直线
|
|
|
|
|
|
coordinatePoint[key].dot.forEach(point => {
|
|
|
|
|
|
group.line(point).fill('none').stroke({ color: '#07011D', width: 4, linecap: 'round', linejoin: 'round', dasharray: coordinatePoint[key].dasharray || '10 15' })
|
|
|
|
|
|
})
|
|
|
|
|
|
// const polyline1 = group.polyline([[165, 210], [250, 240]])
|
|
|
|
|
|
// polyline1.fill('none')
|
|
|
|
|
|
// polyline1.stroke({ color: '#07011D', width: 3, linecap: 'round', linejoin: 'round', dasharray: '8 8' })
|
|
|
|
|
|
}
|
|
|
|
|
|
coordinatePoint[key].point.forEach(item => { // 最后添加所有点
|
2022-08-24 09:57:40 +08:00
|
|
|
|
const width = group.data('width') || item.x
|
|
|
|
|
|
const height = group.data('height') || item.y
|
|
|
|
|
|
group.data('width', (width >= item.x ? width : item.x))
|
|
|
|
|
|
group.data('height', (height >= item.y ? height : item.y))
|
2022-08-22 15:41:59 +08:00
|
|
|
|
if (item.disabled) return
|
|
|
|
|
|
group.circle(14)
|
|
|
|
|
|
.fill('#868096')
|
|
|
|
|
|
.attr('cx', item.x)
|
|
|
|
|
|
.attr('cy', item.y)
|
|
|
|
|
|
})
|
2022-08-24 09:57:40 +08:00
|
|
|
|
group.data('width', group.data('width') - 50)
|
|
|
|
|
|
group.data('height', group.data('height') - 50)
|
|
|
|
|
|
this.constellation.push(group)
|
2022-08-22 15:41:59 +08:00
|
|
|
|
})
|
|
|
|
|
|
this.starTimer = setInterval(() => {
|
|
|
|
|
|
this.starTimerIndex++
|
|
|
|
|
|
let index = 0
|
|
|
|
|
|
if (this.starTimerIndex === 1) return
|
|
|
|
|
|
if (this.starTimerIndex === 2) index = 2
|
2022-08-24 09:57:40 +08:00
|
|
|
|
if (this.starTimerIndex === 3) {
|
|
|
|
|
|
index = 1
|
|
|
|
|
|
clearInterval(this.starTimer)
|
|
|
|
|
|
}
|
2022-08-22 15:41:59 +08:00
|
|
|
|
if (this.starTimerIndex === 0) index = 0
|
|
|
|
|
|
this.starTimerIndex = this.starTimerIndex === 3 ? -1 : this.starTimerIndex
|
|
|
|
|
|
this.circleStar[index] && this.circleStar[index].forEach(circle => {
|
2022-08-24 09:57:40 +08:00
|
|
|
|
circle.radius(self.r(0.5, 2))
|
|
|
|
|
|
circle.attr('cx', self.r(0, 100) + '%')
|
|
|
|
|
|
circle.attr('cy', self.r(0, 100) + '%')
|
2022-08-22 15:41:59 +08:00
|
|
|
|
})
|
|
|
|
|
|
}, 1000)
|
2022-08-24 09:57:40 +08:00
|
|
|
|
this.requestAnimationFrame = requestAnimationFrame(this.constellationAnimation)
|
|
|
|
|
|
},
|
|
|
|
|
|
r (m, n, minSpeed) {
|
|
|
|
|
|
if (!minSpeed) {
|
2022-08-19 14:04:26 +08:00
|
|
|
|
return (Math.random() * (n - m) + m).toFixed(2)
|
2022-08-24 09:57:40 +08:00
|
|
|
|
} else {
|
|
|
|
|
|
let random = (Math.random() * (n - m) + m)
|
|
|
|
|
|
if (random > 0) {
|
|
|
|
|
|
random += minSpeed * 1
|
|
|
|
|
|
} else if (random < 0) {
|
|
|
|
|
|
random += minSpeed * -1
|
|
|
|
|
|
}
|
|
|
|
|
|
return random.toFixed(2)
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
constellationAnimation () {
|
|
|
|
|
|
for (let i = 0; i < this.constellation.length; i++) { // 循环遍历 判断碰撞
|
|
|
|
|
|
for (let j = i + 1; j < this.constellation.length; j++) {
|
|
|
|
|
|
if (this.impact(this.constellation[i], this.constellation[j])) {
|
2022-08-24 15:41:36 +08:00
|
|
|
|
const iSpeedX = this.constellation[i].data('speedX')
|
|
|
|
|
|
const iSpeedY = this.constellation[i].data('speedY')
|
|
|
|
|
|
const jSpeedX = this.constellation[j].data('speedX')
|
|
|
|
|
|
const jSpeedY = this.constellation[j].data('speedY')
|
2022-08-24 11:49:18 +08:00
|
|
|
|
this.constellation[i].data('speedX', jSpeedX)
|
|
|
|
|
|
this.constellation[i].data('speedY', jSpeedY)
|
2022-08-24 09:57:40 +08:00
|
|
|
|
this.constellation[j].data('speedX', iSpeedX)
|
|
|
|
|
|
this.constellation[j].data('speedY', iSpeedY)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
this.constellation.forEach(item => {
|
|
|
|
|
|
const position = item.node.getBoundingClientRect()
|
|
|
|
|
|
if (item.data('speedX') === 0) {
|
|
|
|
|
|
item.data('speedX', this.r(-1, 1, 0.3))
|
|
|
|
|
|
}
|
|
|
|
|
|
if (item.data('speedY') === 0) {
|
|
|
|
|
|
item.data('speedY', this.r(-1, 1, 0.3))
|
|
|
|
|
|
}
|
|
|
|
|
|
// 变速运动
|
|
|
|
|
|
// item.data('speedX', item.data('speedX') > 0 ? this.r(0, 1) : this.r(-1, 0))
|
|
|
|
|
|
// item.data('speedY', item.data('speedY') > 0 ? this.r(0, 1) : this.r(-1, 0))
|
|
|
|
|
|
// 处理边界问题
|
|
|
|
|
|
if (position.left + item.data('width') >= window.innerWidth) { // 向右移動 改为向左
|
|
|
|
|
|
item.data('speedX', this.r(-1, 0, 0.3))
|
|
|
|
|
|
}
|
|
|
|
|
|
if (position.left + item.data('speedX') < 0) { // 向左移動 改为向右
|
|
|
|
|
|
item.data('speedX', this.r(0, 1, 0.3))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (position.top + item.data('height') >= window.innerHeight) { // 向下移動 改为向上
|
|
|
|
|
|
item.data('speedY', this.r(-1, 0, 0.3))
|
|
|
|
|
|
}
|
|
|
|
|
|
if (position.top + item.data('speedY') < 0) { // 向上移動 改为向下
|
|
|
|
|
|
item.data('speedY', this.r(0, 1, 0.3))
|
|
|
|
|
|
}
|
|
|
|
|
|
const left = position.left + item.data('speedX')
|
|
|
|
|
|
const top = position.top + item.data('speedY')
|
|
|
|
|
|
item.attr('style', `left: ${left}px;top:${top}px;transform:scale(${this.zoom});`)
|
|
|
|
|
|
})
|
|
|
|
|
|
this.requestAnimationFrame = requestAnimationFrame(this.constellationAnimation)
|
|
|
|
|
|
},
|
|
|
|
|
|
impact (obj, dobj) {
|
|
|
|
|
|
const position = obj.node.getBoundingClientRect()
|
|
|
|
|
|
const o = {
|
2022-08-24 11:49:18 +08:00
|
|
|
|
x: position.left - 10,
|
|
|
|
|
|
y: position.top - 10,
|
2022-08-24 09:57:40 +08:00
|
|
|
|
w: obj.data('width'),
|
|
|
|
|
|
h: obj.data('height')
|
|
|
|
|
|
}
|
|
|
|
|
|
const position2 = dobj.node.getBoundingClientRect()
|
|
|
|
|
|
const d = {
|
2022-08-24 11:49:18 +08:00
|
|
|
|
x: position2.left - 10,
|
|
|
|
|
|
y: position2.top - 10,
|
2022-08-24 09:57:40 +08:00
|
|
|
|
w: dobj.data('width'),
|
|
|
|
|
|
h: dobj.data('height')
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const px = o.x <= d.x ? d.x : o.x
|
|
|
|
|
|
const py = o.y <= d.y ? d.y : o.y
|
|
|
|
|
|
|
|
|
|
|
|
// 判断点是否都在两个对象中
|
|
|
|
|
|
if (px >= o.x && px <= o.x + o.w && py >= o.y && py <= o.y + o.h && px >= d.x && px <= d.x + d.w && py >= d.y && py <= d.y + d.h) {
|
|
|
|
|
|
return true
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return false
|
2022-08-19 14:04:26 +08:00
|
|
|
|
}
|
2023-02-20 15:58:05 +08:00
|
|
|
|
},
|
|
|
|
|
|
closeQrCode () {
|
|
|
|
|
|
this.qrCodeShow = false
|
|
|
|
|
|
},
|
|
|
|
|
|
openQrcode () {
|
|
|
|
|
|
this.qrCodeArr = []
|
|
|
|
|
|
this.qrCodeNum = []
|
|
|
|
|
|
this.qrCodeShow = true
|
|
|
|
|
|
this.qrloading = true
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
this.$get('/sys/license/token').then(res => {
|
|
|
|
|
|
this.totalQrCode = Math.ceil(res.data.length / (1024 + 512))
|
|
|
|
|
|
if (this.totalQrCode < 1) {
|
|
|
|
|
|
this.totalQrCode = 1
|
|
|
|
|
|
}
|
|
|
|
|
|
const total = this.totalQrCode < 10 ? ('0' + this.totalQrCode) : this.totalQrCode
|
|
|
|
|
|
const totalMD5 = SparkMD5.hashBinary(res.data).slice(0, 8)
|
|
|
|
|
|
const arr = []
|
|
|
|
|
|
for (let i = 0; i < this.totalQrCode; i++) {
|
|
|
|
|
|
const num = (1024 + 512)
|
|
|
|
|
|
let str1 = res.data.slice(num * i, num * (i + 1))
|
|
|
|
|
|
const index = i < 10 ? ('0' + (i + 1)) : (i + 1)
|
|
|
|
|
|
const md5 = SparkMD5.hashBinary(str1).slice(0, 8)
|
|
|
|
|
|
str1 = total + '' + index + totalMD5 + md5 + '' + str1
|
|
|
|
|
|
arr.push(str1)
|
|
|
|
|
|
}
|
|
|
|
|
|
this.qrCodeArr = []
|
|
|
|
|
|
this.qrCodeNum = arr.map(() => {
|
|
|
|
|
|
return true
|
|
|
|
|
|
})
|
|
|
|
|
|
arr.forEach((item, index) => {
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
|
|
this.qrCodeArr.push(item)
|
|
|
|
|
|
this.qrCodeNum[index] = false
|
|
|
|
|
|
}, index * 100)
|
|
|
|
|
|
})
|
|
|
|
|
|
this.getLayout(arr)
|
|
|
|
|
|
this.qrloading = false
|
|
|
|
|
|
}, error => {
|
|
|
|
|
|
const $self = this
|
|
|
|
|
|
const reader = new FileReader()
|
|
|
|
|
|
reader.onload = function (event) {
|
|
|
|
|
|
const responseText = reader.result
|
|
|
|
|
|
const exception = JSON.parse(responseText)
|
|
|
|
|
|
if (exception.message) {
|
|
|
|
|
|
$self.$message.error(exception.message)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
console.error(error)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
reader.readAsText(error.response.data)
|
|
|
|
|
|
})
|
|
|
|
|
|
}, 100)
|
|
|
|
|
|
},
|
|
|
|
|
|
getSrc (index) {
|
|
|
|
|
|
const cas = document.createElement('canvas')
|
|
|
|
|
|
const ctx = cas.getContext('2d')
|
|
|
|
|
|
|
|
|
|
|
|
cas.width = 100
|
|
|
|
|
|
cas.height = 100
|
|
|
|
|
|
ctx.font = 'normal bold 40px Roboto-Regular'
|
|
|
|
|
|
let text = index + 1 + ''
|
|
|
|
|
|
if (text.length < 2) {
|
|
|
|
|
|
text = '0' + text
|
|
|
|
|
|
}
|
|
|
|
|
|
ctx.fillText(text, 25, 65)
|
|
|
|
|
|
// 把画布的内容转换为base64编码格式的图片
|
|
|
|
|
|
const data = cas.toDataURL('image/png', 1)
|
|
|
|
|
|
return data
|
|
|
|
|
|
},
|
|
|
|
|
|
setActiveItem (currentPage) {
|
|
|
|
|
|
this.$refs.carousel.setActiveItem('qr-' + (currentPage - 1))
|
|
|
|
|
|
},
|
|
|
|
|
|
getLayout () {
|
|
|
|
|
|
try {
|
|
|
|
|
|
this.boxWidth = document.body.offsetWidth - 30 - 40
|
|
|
|
|
|
this.boxHeight = document.body.offsetHeight - 104 - 50
|
|
|
|
|
|
} catch (error) {}
|
|
|
|
|
|
return new Promise(resolve => {
|
|
|
|
|
|
let rateMax = 0
|
|
|
|
|
|
let col = 0
|
|
|
|
|
|
let row = 0
|
|
|
|
|
|
for (let i = 1; i <= this.qrCodeNum.length; i++) {
|
|
|
|
|
|
const cols = Math.ceil(this.qrCodeNum.length / i)
|
|
|
|
|
|
const w = this.boxWidth / i
|
|
|
|
|
|
const h = this.boxHeight / cols
|
|
|
|
|
|
const rate = w > h ? h / w : w / h
|
|
|
|
|
|
if (rate > rateMax) {
|
|
|
|
|
|
rateMax = rate
|
|
|
|
|
|
col = cols
|
|
|
|
|
|
row = i
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if (this.qrCodeNum.length) {
|
|
|
|
|
|
while (col * row >= this.qrCodeNum.length) { // 避免出现空白
|
|
|
|
|
|
row--
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
row++
|
|
|
|
|
|
if (col === 1 || row === 1) { // 行 或 列有一个为1时 需要调换位置
|
|
|
|
|
|
const temp = col
|
|
|
|
|
|
col = row
|
|
|
|
|
|
row = temp
|
|
|
|
|
|
}
|
|
|
|
|
|
this.qrWidth = 10
|
|
|
|
|
|
if (this.boxHeight / col < this.boxWidth / row) {
|
|
|
|
|
|
this.qrWidth = this.boxHeight / col
|
|
|
|
|
|
} else {
|
|
|
|
|
|
this.qrWidth = this.boxWidth / row
|
|
|
|
|
|
}
|
|
|
|
|
|
this.paddingLeft = (this.boxWidth - row * this.qrWidth) / 2
|
|
|
|
|
|
resolve({ col, row })
|
|
|
|
|
|
})
|
2020-02-19 15:16:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
},
|
2022-04-13 11:21:56 +08:00
|
|
|
|
watch: {
|
|
|
|
|
|
lang (n) {
|
|
|
|
|
|
this.$i18n.locale = this.lang
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
2021-03-19 18:52:19 +08:00
|
|
|
|
mounted () {
|
|
|
|
|
|
this.$i18n.locale = this.lang
|
|
|
|
|
|
document.getElementById('usernameInput').focus()
|
2021-04-16 21:10:31 +08:00
|
|
|
|
this.licenseStat()
|
2021-08-19 12:51:49 +08:00
|
|
|
|
this.initEvent()
|
2021-11-24 15:55:18 +08:00
|
|
|
|
this.bgImg = localStorage.getItem('nz-sys-bgImg')
|
|
|
|
|
|
if (this.bgImg) {
|
2024-05-21 15:57:08 +08:00
|
|
|
|
// document.getElementById('login-bgimg').style['background-image'] = `url(${this.bgImg})`
|
2022-08-19 14:04:26 +08:00
|
|
|
|
} else {
|
2022-09-05 16:57:38 +08:00
|
|
|
|
// this.initStar()
|
2021-11-24 15:55:18 +08:00
|
|
|
|
}
|
2023-03-14 10:15:18 +08:00
|
|
|
|
|
|
|
|
|
|
if (sessionStorage.getItem('nz-is-logout')) {
|
|
|
|
|
|
sessionStorage.removeItem('nz-previous-page')
|
|
|
|
|
|
sessionStorage.removeItem('nz-is-logout')
|
|
|
|
|
|
}
|
2022-08-22 15:41:59 +08:00
|
|
|
|
},
|
|
|
|
|
|
beforeDestroy () {
|
2022-08-24 09:57:40 +08:00
|
|
|
|
cancelAnimationFrame(this.constellationAnimation)
|
2022-08-22 15:41:59 +08:00
|
|
|
|
clearInterval(this.starTimer)
|
|
|
|
|
|
this.starTimer = null
|
2019-12-04 13:45:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</script>
|