factory_mp/pages/auth/login.vue

571 lines
13 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="login-page">
<!-- 顶部渐变区域 -->
<view class="login-header">
<image src="/static/banner_c.png" mode="widthFix" class="login-banner"></image>
<view class="login-welcome">
<text class="login-title">欢迎回来</text>
<text class="login-subtitle">登录您的账号以继续</text>
</view>
</view>
<!-- 登录卡片 -->
<view class="login-card">
<view class="login-tabs">
<view class="login-tab" :class="{active: current===0}" @click="onClickItem({currentIndex:0})">密码登录</view>
<view class="login-tab" :class="{active: current===1}" @click="onClickItem({currentIndex:1})">验证码登录</view>
<view class="login-tab-indicator" :style="{left: current===0?'0%':'50%'}"></view>
</view>
<view class="login-form-wrap">
<view v-if="current==0">
<uni-forms ref="form1" :modelValue="formData" label-position="left" :rules="rules1">
<uni-forms-item required label="用户名" name="username">
<uni-easyinput type="text" v-model="formData.username" placeholder="请输入用户名" />
</uni-forms-item>
<uni-forms-item required label="密码" name="password">
<uni-easyinput type="password" v-model="formData.password" placeholder="请输入密码" />
</uni-forms-item>
</uni-forms>
</view>
<view v-if="current==1">
<uni-forms ref="form2" :modelValue="formData2" label-position="left" :rules="rules2">
<uni-forms-item label="手机号" name="phone" required>
<uni-easyinput type="number" v-model="formData2.phone" placeholder="请输入手机号" />
</uni-forms-item>
<uni-forms-item label="验证码" name="code" required>
<view class="code-row">
<view class="code-input">
<uni-easyinput type="number" v-model="formData2.code" placeholder="请输入验证码" />
</view>
<view class="code-btn" @click="getCode">
<text class="code-btn-text">{{content}}</text>
</view>
</view>
</uni-forms-item>
</uni-forms>
</view>
</view>
<button class="login-btn" @click="login(current)">登 录</button>
</view>
<!-- 下载进度弹窗 -->
<view v-show="dShow" class="download-mask">
<view class="download-dialog">
<view class="download-icon">⬇</view>
<text class="download-text">下载中 请勿退出</text>
<view class="download-progress-bar">
<view class="download-progress-fill" :style="{width: percentVal+'%'}"></view>
</view>
<text class="download-percent">{{percentVal}}%</text>
</view>
</view>
</view>
</template>
<script>
import config from '/utils/config';
import { auth } from '@/utils/auth.js'
export default {
data() {
return {
current: 0,
items: ['密码登录', '验证码登录'],
content: '获取验证码',
formData: {},
formData2: {},
timer: null,
time: 30,
rules1: {
username: {
rules: [{
required: true,
errorMessage: '请填写',
}]
},
password: {
rules: [{
required: true,
errorMessage: '请填写',
}]
}
},
rules2: {
phone: {
rules: [{
required: true,
errorMessage: '请填写',
}]
},
code: {
rules: [{
required: true,
errorMessage: '请填写',
}]
}
},
wxmp_openid: null,
dShow: false,
percentVal: 0
}
},
onLoad(options) {
var that = this
var autoLoading = options.autoLoading;
that.checkVersion();
if (autoLoading != 'no') {
// #ifdef APP-PLUS || H5
that.appLogin()
// #endif
// #ifdef MP-WEIXIN
that.wxmpLogin()
// #endif
}
},
onUnload() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
onShow() {
// #ifdef MP-WEIXIN
uni.hideHomeButton()
// #endif
},
methods: {
checkVersion() {
let that = this;
uni.getSystemInfo({
success(res) {
uni.setStorageSync("vuex_version", res.appVersion)
// #ifdef APP-PLUS
if (res.platform == 'android') {
that.$api.apkCheck().then(res1 => {
if (res.appWgtVersion != res1.version) {
uni.showModal({
title: "版本更新",
content: '有新的版本发布, 请下载新版本',
confirmText: '立即更新',
cancelText: '稍后进行',
success: function(res2) {
if (res2.confirm) {
let fullurl = res1.file
if (res1.file.indexOf("http") == -1) {
fullurl = config.baseUrl + res1.file
}
that.dShow =
true // show变量控制一个下载进度弹框这个UI样式自己写即可
uni.hideTabBar()
// 创建一个下载任务并根据后端返回的apk静态资源地址filePath进行下载
var dtask = plus.downloader.createDownload(
fullurl, {},
function(d, status) {
// 下载完成
if (status == 200) {
that.dShow =
false // 下载完成再把下载进度弹框关闭即可
uni.showTabBar();
plus.runtime.install(plus.io
.convertLocalFileSystemURL(
d
.filename), {}, {},
function(error) {
uni.showToast({
title: '安装失败',
duration: 1500
});
})
} else {
uni.showToast({
title: '更新失败',
duration: 1500
});
}
});
function onStateChanged(download, status) {
if (status == 200) {
const totalSize = download.totalSize
let nowSize = download.downloadedSize
that.percentVal = nowSize / 17700000 *
100 > 99 ? 99 : (nowSize /
17700000 * 100).toFixed(0)
}
}
dtask.addEventListener("statechanged",
onStateChanged, false);
dtask.start();
} else {
}
}
});
}
})
}
// #endif
}
})
},
wxmpLogin() {
var that = this;
uni.showLoading({
title: '自动登录中...',
mask: true
})
uni.login({
provider: 'weixin',
success: (loginRes) => {
that.$api.wxmpLogin({
code: loginRes.code
}).then(res => {
uni.setStorageSync('access', res.access)
that.$api.getUserInfo().then(res => {
uni.setStorageSync('userInfo', res)
auth.setPermissions(Object.keys(res.perms))
uni.reLaunch({
url: '/pages/index/index'
})
})
}).catch(e => {
this.wxmp_openid = e.data.wxmp_openid
})
},
complete: function() {
uni.hideLoading();
},
})
},
appLogin() {
var that = this;
// App自动登录
uni.showLoading({
title: '自动登录中...',
mask: true
})
uni.getStorage({
key: 'mySecret',
success: function(res) {
let secret = res.data
if (secret) {
that.$api.loginSecret(JSON.parse(secret)).then(res => {
uni.setStorageSync('access', res.access)
that.$api.getUserInfo().then(res => {
uni.setStorageSync('userInfo', res)
auth.setPermissions(Object.keys(res.perms))
uni.reLaunch({
url: '/pages/index/index'
})
})
})
}
},
complete: function() {
uni.hideLoading();
},
});
},
onClickItem(e) {
if (this.current !== e.currentIndex) {
this.current = e.currentIndex
}
},
countDown() {
var that = this;
if (that.time >= 0) {
that.content = that.time.toString() + '秒';
--that.time
} else {
clearInterval(that.timer)
that.timer = null
that.content = '获取验证码'
}
},
getCode() {
var that = this
if (that.content == '获取验证码') {
if (that.$check.mobile(that.formData2.phone)) {
that.$api.getCode({
phone: that.formData2.phone
}).then(res => {
uni.showToast({
icon: "none",
title: '验证码已发送'
})
setInterval(that.countDown, 1000)
})
} else {
uni.showToast({
icon: "none",
title: '手机号格式有误'
})
}
}
},
login() {
var that = this;
if (that.current == 1) {
that.$refs.form2.validate().then(res0 => {
that.$api.codeLogin(res0).then(res => {
uni.setStorageSync('access', res.access)
that.$api.getUserInfo().then(res => {
uni.setStorageSync('userInfo', res)
auth.setPermissions(Object.keys(res.perms))
that.bindXX()
uni.reLaunch({
url: '/pages/index/index'
})
})
})
}).catch(err => {
console.log('表单错误信息:', err);
})
} else if (that.current == 0) {
that.$refs.form1.validate().then(res0 => {
that.$api.login(res0).then(res => {
uni.setStorageSync('access', res.access)
that.bindXX()
that.$api.getUserInfo().then(res => {
uni.setStorageSync('userInfo', res)
auth.setPermissions(Object.keys(res.perms))
uni.reLaunch({
url: '/pages/index/index'
})
})
})
}).catch(err => {
console.log('表单错误信息:', err);
})
}
},
ranStr(e) {
//形参e,需要产生随机字符串的长度
//如果没有传参默认生成32位长度随机字符串
e = e || 32;
//模拟随机字符串库
var t = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz0123456789",
a = t.length, //字符串t的长度随机数生成最大值
n = "";
for (let i = 0; i < e; i++) {
//随机生成长度为e的随机字符串拼接
n += t.charAt(Math.floor(Math.random() * a));
}
//返回随机组合字符串
return n
},
bindXX() {
let that = this;
// #ifdef APP-PLUS || H5
let userInfo = uni.getStorageSync("userInfo")
let secret = that.ranStr(12)
let mySecret = {
'username': userInfo.username,
'secret': secret
}
this.$api.bindSecret({
secret: secret
}).then(res => {
uni.setStorageSync('mySecret', JSON.stringify(mySecret))
}).catch(e => {})
// #endif
// #ifdef MP-WEIXIN
if (this.wxmp_openid != null) {
this.$api.bindWxmp({
"openid": this.wxmp_openid
}).then(res => {
})
}
// #endif
}
}
}
</script>
<style lang="scss" scoped>
.login-page {
min-height: 100vh;
background: linear-gradient(180deg, #14694A 0%, #1F8C5E 35%, #F5FAF7 40%);
padding: 0;
}
.login-header {
position: relative;
overflow: hidden;
}
.login-banner {
width: 100%;
display: block;
opacity: 0.08;
}
.login-welcome {
position: absolute;
bottom: 60rpx;
left: 48rpx;
}
.login-title {
display: block;
font-size: 48rpx;
font-weight: 800;
color: #FFFFFF;
letter-spacing: 6rpx;
}
.login-subtitle {
display: block;
font-size: 26rpx;
color: rgba(255, 255, 255, 0.6);
margin-top: 12rpx;
}
.login-card {
margin: -40rpx 32rpx 0;
background: #FFFFFF;
border-radius: 16rpx;
padding: 44rpx 32rpx;
box-shadow: 0 12rpx 40rpx rgba(25, 27, 35, 0.06);
position: relative;
z-index: 2;
}
.login-tabs {
display: flex;
position: relative;
margin-bottom: 40rpx;
border-bottom: 2rpx solid #C4C6D0;
padding-bottom: 0;
}
.login-tab {
flex: 1;
text-align: center;
font-size: 30rpx;
color: #74777F;
padding-bottom: 20rpx;
transition: color 0.3s;
&.active {
color: #2BA471;
font-weight: 600;
}
}
.login-tab-indicator {
position: absolute;
bottom: 0;
width: 50%;
height: 5rpx;
background: linear-gradient(90deg, #2BA471, #2BA471);
border-radius: 4rpx;
transition: left 0.3s ease;
}
.login-form-wrap {
margin-bottom: 32rpx;
}
.code-row {
display: flex;
align-items: center;
gap: 16rpx;
}
.code-input {
flex: 1;
}
.code-btn {
min-width: 180rpx;
height: 72rpx;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #2BA471, #1F8C5E);
border-radius: 12rpx;
padding: 0 20rpx;
}
.code-btn-text {
color: #FFFFFF;
font-size: 24rpx;
white-space: nowrap;
}
.login-btn {
width: 100% !important;
height: 92rpx;
line-height: 92rpx;
background: linear-gradient(135deg, #2BA471, #1F8C5E) !important;
color: #FFFFFF !important;
font-size: 33rpx;
font-weight: 700;
letter-spacing: 8rpx;
border: none !important;
border-radius: 16rpx !important;
box-shadow: 0 8rpx 24rpx rgba(43, 164, 113, 0.2);
margin-top: 16rpx;
&:active {
opacity: 0.85;
transform: scale(0.98);
}
}
.download-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 999;
display: flex;
align-items: center;
justify-content: center;
}
.download-dialog {
background: #fff;
border-radius: 24rpx;
padding: 48rpx 40rpx;
width: 560rpx;
text-align: center;
box-shadow: 0 16rpx 48rpx rgba(0, 0, 0, 0.15);
}
.download-icon {
font-size: 64rpx;
margin-bottom: 20rpx;
}
.download-text {
display: block;
font-size: 30rpx;
color: #191B23;
margin-bottom: 24rpx;
}
.download-progress-bar {
height: 12rpx;
background: #C4C6D0;
border-radius: 6rpx;
overflow: hidden;
margin-bottom: 16rpx;
}
.download-progress-fill {
height: 100%;
background: linear-gradient(90deg, #2BA471, #1F8C5E);
border-radius: 6rpx;
transition: width 0.3s;
}
.download-percent {
font-size: 28rpx;
color: #2BA471;
font-weight: 600;
}
</style>