diff --git a/nezha-fronted/src/assets/css/components/common/login.scss b/nezha-fronted/src/assets/css/components/common/login.scss
index 0bd129072..a7c6d5b13 100644
--- a/nezha-fronted/src/assets/css/components/common/login.scss
+++ b/nezha-fronted/src/assets/css/components/common/login.scss
@@ -303,4 +303,62 @@
background: #CECECE;
margin-right: 10px;
}
+ .el-carousel__item{
+ text-align: center;
+ }
+ .nz-license-footer{
+ text-align: center;
+ margin-top: 30px;
+ margin-bottom: 15px;
+ .el-pagination{
+ font-size: 14px;
+ .btn-prev, .btn-next{
+ color: $--color-text-regular;
+ font-size: 14px;
+ margin: 0 5px;
+ border: none;
+ background-color: $--background-color-base !important;
+ border-radius: 50%;
+ height: 24px;
+ width: 24px;
+ }
+ .number {
+ font-size: 14px;
+ margin: 0px;
+ border: none;
+ background-color: transparent !important;
+ }
+ .number.active{
+ color: #FA901C;
+ }
+ }
+ }
+ .el-carousel__indicators.el-carousel__indicators--horizontal{
+ display: none;
+ }
+ .el-dialog__header {
+ border-bottom: 1px solid $--border-color-light;
+ height: 32px;
+ line-height: 32px;
+ .el-dialog__header-title {
+ font-weight: 600;
+ }
+ .top-tool-btn{
+ height: 32px;
+ width: 36px;
+ padding: 0;
+ }
+ .el-dialog__headerbtn{
+ line-height: 32px;
+ }
+ }
+ .el-dialog__body{
+
+ }
+ .el-button{
+ //background-color: $--background-color-1 !important;
+ background: $--background-color-empty;
+ border: 1px solid $--border-color-light;
+ border-color: $--border-color-light;
+ }
}
diff --git a/nezha-fronted/src/components/common/login.vue b/nezha-fronted/src/components/common/login.vue
index 7cf48f8be..cc03c9a2a 100644
--- a/nezha-fronted/src/components/common/login.vue
+++ b/nezha-fronted/src/components/common/login.vue
@@ -55,9 +55,14 @@
-
+
+
-
+
+
+
+
+
+
+
+
+
+
{{index+1}} / {{qrCodeNum.length}}
+
+
+
@@ -144,9 +214,14 @@ import QRCode from 'qrcodejs2'
import bus from '@/libs/bus.js'
import { SVG } from '@svgdotjs/svg.js'
import { coordinatePoint } from '@/components/common/js/common'
+import VueQr from '@/components/common/vueQR/packages/vue-qr'
import { get } from '@/http'
+import SparkMD5 from 'spark-md5'
export default {
name: 'login',
+ components: {
+ VueQr
+ },
data () {
return {
loginData: {
@@ -183,7 +258,20 @@ export default {
bgImg: '', // 背景图
constellation: [],
requestAnimationFrame: '',
- speed: [-1.3, -1, -0.6, -0.3, 0.3, 0.6, 1, 1.3]
+ 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,
+ paddingLeft: 0,
}
},
methods: {
@@ -561,6 +649,119 @@ export default {
} else {
return false
}
+ },
+ 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 })
+ })
}
},
watch: {