Files
zkxw/mobile-h5/pages/login/index.vue
T

273 lines
7.8 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-brand">
<image
class="login-brand__logo"
src="/static/logo.png"
mode="widthFix"
/>
<view class="login-brand__sub">员工工作台登录</view>
</view>
<view class="login-card">
<view class="login-field">
<text class="login-field__label">账号</text>
<view
class="login-field__box"
:class="{ 'is-focus': focusUser, 'is-error': !!errors.username }"
>
<input
class="login-field__input"
type="text"
:value="username"
placeholder="请输入用户名 / 工号"
placeholder-class="login-ph"
@input="onUserInput"
@focus="focusUser = true"
@blur="focusUser = false"
/>
</view>
<view v-if="errors.username" class="login-field__error">{{ errors.username }}</view>
</view>
<view class="login-field">
<text class="login-field__label">密码</text>
<view
class="login-field__box"
:class="{ 'is-focus': focusPwd, 'is-error': !!errors.password }"
>
<input
class="login-field__input"
:password="!showPwd"
:value="password"
placeholder="请输入密码"
placeholder-class="login-ph"
@input="onPwdInput"
@focus="focusPwd = true"
@blur="focusPwd = false"
/>
<text class="login-field__action" @click="showPwd = !showPwd">
{{ showPwd ? '隐藏' : '显示' }}
</text>
</view>
<view v-if="errors.password" class="login-field__error">{{ errors.password }}</view>
</view>
<view
class="login-submit"
:class="{ 'is-disabled': loading }"
@click="onPasswordLogin"
>
{{ loading ? '登录中…' : '登录' }}
</view>
<view class="login-agree" @click="toggleAgree">
<view class="login-agree__box" :class="{ 'is-on': agreed }" />
<view class="login-agree__text">
已阅读并同意
<text class="login-agree__link" @click.stop="openProtocol('user')">《用户协议》</text>
和
<text class="login-agree__link" @click.stop="openProtocol('privacy')">《隐私政策》</text>
</view>
</view>
</view>
<view class="login-divider">或</view>
<button
v-if="agreed"
class="login-wechat"
:class="{ 'is-disabled': loading }"
open-type="getPhoneNumber"
:disabled="loading"
@getphonenumber="onGetPhoneNumber"
>
<image class="login-wechat__icon" src="/static/wechat-logo.png" mode="aspectFit" />
<text>微信授权登录</text>
</button>
<view
v-else
class="login-wechat"
:class="{ 'is-disabled': loading }"
@click="onWechatGate"
>
<image class="login-wechat__icon" src="/static/wechat-logo.png" mode="aspectFit" />
<text>微信授权登录</text>
</view>
<ConfirmDialog
:show="agreeDialogVisible"
title="请先同意协议"
cancel-text="取消"
confirm-text="同意并登录"
@update:show="agreeDialogVisible = $event"
@confirm="onAgreeConfirm"
@cancel="onAgreeCancel"
>
<text>登录前需阅读并同意</text>
<text class="confirm-dialog__link" @click.stop="openProtocol('user')">
《用户协议》
</text>
<text>和</text>
<text class="confirm-dialog__link" @click.stop="openProtocol('privacy')">
《隐私政策》
</text>
<text>。是否同意并继续登录?</text>
</ConfirmDialog>
</view>
</template>
<script>
import {
isLoggedIn,
passwordLogin,
wechatLogin,
clearLegacyMockSessionIfNeeded
} from '../../utils/auth.js'
import { validateCredentials } from '../../utils/validate-credentials.js'
import ConfirmDialog from '../../components/ConfirmDialog.vue'
export default {
components: {
ConfirmDialog
},
data() {
return {
username: '',
password: '',
showPwd: false,
agreed: false,
agreeDialogVisible: false,
loading: false,
focusUser: false,
focusPwd: false,
errors: {
username: '',
password: ''
}
}
},
onShow() {
clearLegacyMockSessionIfNeeded()
if (isLoggedIn()) {
uni.reLaunch({ url: '/pages/index/index' })
}
},
methods: {
onUserInput(e) {
this.username = e.detail.value
this.errors.username = ''
},
onPwdInput(e) {
this.password = e.detail.value
this.errors.password = ''
},
toggleAgree() {
this.agreed = !this.agreed
},
ensureAgree() {
if (this.agreed) return Promise.resolve(true)
this.agreeDialogVisible = true
return new Promise((resolve) => {
this._agreeResolver = resolve
})
},
onAgreeConfirm() {
this.agreed = true
this.agreeDialogVisible = false
if (this._agreeResolver) {
this._agreeResolver(true)
this._agreeResolver = null
}
},
onAgreeCancel() {
this.agreeDialogVisible = false
if (this._agreeResolver) {
this._agreeResolver(false)
this._agreeResolver = null
}
},
openProtocol(type) {
uni.navigateTo({ url: `/pages/protocol/index?type=${type}` })
},
goHome() {
uni.reLaunch({ url: '/pages/index/index' })
},
async onPasswordLogin() {
if (this.loading) return
this.errors = { username: '', password: '' }
const v = validateCredentials(this.username, this.password)
if (!v.ok) {
if (v.code === 'EMPTY_USERNAME') this.errors.username = v.message
if (v.code === 'EMPTY_PASSWORD') this.errors.password = v.message
return
}
if (!(await this.ensureAgree())) return
this.loading = true
try {
await passwordLogin({
username: this.username,
password: this.password
})
uni.showToast({ title: '登录成功', icon: 'success' })
setTimeout(() => this.goHome(), 400)
} catch (e) {
uni.showToast({ title: e.message || '登录失败', icon: 'none' })
} finally {
this.loading = false
}
},
async onWechatGate() {
if (this.loading) return
await this.ensureAgree()
},
async onGetPhoneNumber(e) {
if (this.loading) return
if (!(await this.ensureAgree())) return
const detail = (e && e.detail) || {}
const errMsg = detail.errMsg || ''
if (errMsg && errMsg.indexOf('ok') === -1) {
uni.showToast({
title: '需要授权手机号,或请使用账号密码登录',
icon: 'none'
})
return
}
const phoneCode = detail.code
if (!phoneCode) {
uni.showToast({
title: '需要授权手机号,或请使用账号密码登录',
icon: 'none'
})
return
}
this.loading = true
try {
const loginRes = await new Promise((resolve, reject) => {
uni.login({ provider: 'weixin', success: resolve, fail: reject })
})
await wechatLogin({
loginCode: loginRes.code,
phoneCode
})
uni.showToast({ title: '登录成功', icon: 'success' })
setTimeout(() => this.goHome(), 400)
} catch (err) {
uni.showToast({
title: (err && err.message) || '登录失败',
icon: 'none'
})
} finally {
this.loading = false
}
}
}
}
</script>
<style scoped>
.login-ph {
color: #9aaba3;
}
</style>