<template>
|
<cl-page background-color="#fff">
|
<cl-topbar :border="false" background-color="transparent" />
|
|
<view class="page-login">
|
<!-- Logo -->
|
<view class="logo">
|
<image src="/static/logo.png" mode="aspectFill" />
|
<text>{{ app.info.name }}</text>
|
</view>
|
|
<div class="container">
|
<!-- 登录方式 -->
|
<view class="mode" :class="[`is-${mode}`]">
|
<!-- 手机号 -->
|
<template v-if="mode == 'phone'">
|
<text class="label">手机号登录</text>
|
|
<view class="phone">
|
<text>+86</text>
|
<cl-input
|
v-model="phone"
|
type="number"
|
placeholder="请填写手机号码"
|
:border="false"
|
:maxlength="11"
|
:font-size="30"
|
background-color="transparent"
|
/>
|
</view>
|
|
<sms-btn
|
:ref="setRefs('smsBtn')"
|
:phone="phone"
|
@success="phoneLogin(false)"
|
>
|
<template #default="{ disabled, btnText }">
|
<cl-button
|
fill
|
type="primary"
|
:height="90"
|
:font-size="30"
|
:disabled="disabled"
|
@tap="phoneLogin"
|
>
|
{{ btnText }}
|
</cl-button>
|
</template>
|
</sms-btn>
|
</template>
|
|
<!-- 微信登录 -->
|
<template v-else-if="mode == 'wx'">
|
<cl-button
|
type="primary"
|
fill
|
:height="90"
|
:font-size="30"
|
:loading="loading"
|
@tap="wxLogin"
|
>
|
微信一键登录
|
</cl-button>
|
</template>
|
|
<!-- 协议 -->
|
<view class="agree">
|
<agree-btn :ref="setRefs('agreeBtn')" />
|
</view>
|
</view>
|
</div>
|
|
<!-- 其他登录方式 -->
|
<view class="other" v-if="!isEmpty(platformsEnv)">
|
<cl-divider width="400rpx" background-color="#ffffff">
|
<cl-text color="#ccc" value="其他登录方式" />
|
</cl-divider>
|
|
<view class="platform">
|
<view
|
class="platform__item"
|
v-for="(item, index) in platformsEnv"
|
:key="index"
|
@tap="changeMode(item)"
|
>
|
<image :src="item.icon" mode="aspectFit" v-if="item.icon" />
|
<text>{{ item.label }}</text>
|
</view>
|
</view>
|
</view>
|
</view>
|
</cl-page>
|
</template>
|
|
<script lang="ts" setup>
|
import { computed, reactive, ref } from "vue";
|
import { onReady } from "@dcloudio/uni-app";
|
import { useApp, useCool, useStore, useWx } from "/@/cool";
|
import { useUi } from "/$/cool-ui";
|
import SmsBtn from "/@/components/sms-btn.vue";
|
import AgreeBtn from "/@/components/agree-btn.vue";
|
import { config } from "/@/config";
|
import { ctx } from "virtual:ctx";
|
import { cloneDeep, isEmpty } from "lodash-es";
|
|
interface Platform {
|
label: string;
|
value: any;
|
icon?: string;
|
hidden?: boolean;
|
onClick?: () => void;
|
}
|
|
const { service, router, refs, setRefs, storage } = useCool();
|
const { user } = useStore();
|
const app = useApp();
|
const ui = useUi();
|
const wx = useWx();
|
|
// 登录中
|
const loading = ref(false);
|
|
// 手机号
|
const phone = ref(storage.get("phone") || "");
|
|
// 登录方式
|
const mode = ref();
|
|
// 登录平台
|
const platforms = ref<Platform[]>([
|
{
|
label: "通过手机登录",
|
value: "phone",
|
icon: "/pages/user/static/icon/phone.png",
|
hidden: false,
|
},
|
{
|
label: "通过微信登录",
|
value: "wx",
|
icon: "/pages/user/static/icon/wx.png",
|
hidden: true,
|
},
|
]);
|
|
// 环境校验
|
const platformsEnv = computed(() => {
|
let arr = cloneDeep(platforms.value);
|
|
// #ifdef H5
|
if (wx.isWxBrowser()) {
|
arr[1].hidden = false;
|
}
|
// #endif
|
|
// #ifdef MP-WEIXIN
|
arr[1].hidden = false;
|
// #endif
|
|
// 过滤隐藏的
|
arr = arr.filter((e) => !e.hidden);
|
|
// 默认第一个登录方式
|
if (!mode.value) {
|
mode.value = arr[0]?.value;
|
}
|
|
// 过滤不是当前登录方式
|
return arr.filter((e) => e.value != mode.value);
|
});
|
|
// 切换模式
|
function changeMode(item: Platform) {
|
if (item.onClick) {
|
item.onClick();
|
} else {
|
mode.value = item.value;
|
}
|
}
|
|
// 登录请求
|
async function nextLogin(key: "mini" | "mp" | "uniPhone", data: any) {
|
return service.user.login[key](data)
|
.then(async (res) => {
|
// 设置token
|
user.setToken(res);
|
|
// 获取用户信息
|
await user.get();
|
|
// 登录跳转
|
router.nextLogin(key);
|
})
|
.catch((err) => {
|
ui.showTips(err.message);
|
});
|
}
|
|
// 短信登录
|
function phoneLogin(sms?: boolean) {
|
if (sms) {
|
check(() => {
|
refs.smsBtn.open();
|
});
|
} else {
|
storage.set("phone", phone.value);
|
|
router.push({
|
path: "/pages/user/captcha",
|
query: {
|
phone: phone.value,
|
},
|
});
|
}
|
}
|
|
// 微信登录
|
function wxLogin() {
|
check(async () => {
|
// #ifdef APP
|
if (wx.hasApp()) {
|
wx.appLogin().then((code) => {
|
//
|
});
|
} else {
|
ui.showConfirm({
|
title: "温馨提示",
|
message: "您还未安装微信~",
|
showCancelButton: false,
|
confirmButtonText: "去下载",
|
callback(action) {
|
if (action == "confirm") {
|
wx.downloadApp();
|
}
|
},
|
});
|
}
|
// #endif
|
|
// #ifdef MP-WEIXIN
|
loading.value = true;
|
|
await wx
|
.miniLogin()
|
.then(async (res) => {
|
await nextLogin("mini", res);
|
})
|
.catch((err) => {
|
ui.showToast(err.message);
|
});
|
|
loading.value = false;
|
// #endif
|
|
// #ifdef H5
|
wx.mpAuth();
|
// #endif
|
});
|
}
|
|
// 公众号登录
|
function mpLogin() {
|
// #ifdef H5
|
wx.mpLogin().then(async (code) => {
|
if (code) {
|
ui.showLoading();
|
await nextLogin("mp", { code });
|
ui.hideLoading();
|
}
|
});
|
// #endif
|
}
|
|
// 协议检测
|
function check(cb: () => void) {
|
if (refs.agreeBtn.check()) {
|
cb();
|
}
|
}
|
|
// 手机号一键登录
|
const univerify = reactive({
|
error: "",
|
|
check() {
|
// #ifdef APP
|
uni.preLogin({
|
provider: "univerify",
|
success() {
|
platforms.value.push({
|
label: "手机号一键登录",
|
value: "univerify",
|
onClick() {
|
univerify.login();
|
},
|
});
|
},
|
fail(err) {
|
univerify.error = err.metadata?.msg || "当前环境不支持一键登录,请切换至验证码登录";
|
},
|
});
|
// #endif
|
},
|
|
login() {
|
uni.login({
|
provider: "univerify",
|
univerifyStyle: {
|
authButton: {
|
normalColor: "#6b69f8",
|
highlightColor: "#6b69f8",
|
disabledColor: "#73aaf5",
|
textColor: "#ffffff",
|
title: "一键登录",
|
borderRadius: "12px",
|
},
|
privacyTerms: {
|
defaultCheckBoxState: true, // 条款勾选框初始状态
|
textColor: "#BBBBBB",
|
termsColor: "#5496E3",
|
prefix: "我已阅读并同意",
|
suffix: "并使用本机号码登录",
|
privacyItems: [
|
// 自定义协议条款,最大支持2个,需要同时设置url和title. 否则不生效
|
{
|
url: `${config.baseUrl}/app/base/comm/html?key=userAgreement`,
|
title: "用户协议",
|
},
|
{
|
url: `${config.baseUrl}/app/base/comm/html?key=privacyPolicy`,
|
title: "隐私政策",
|
},
|
],
|
},
|
},
|
async success(res: { authResult: any }) {
|
await nextLogin("uniPhone", {
|
appId: ctx.appid,
|
...res.authResult,
|
});
|
|
uni.closeAuthView();
|
},
|
fail() {
|
if (univerify.error) {
|
ui.showToast(univerify.error);
|
}
|
},
|
});
|
},
|
});
|
|
// 手机号一键登录环境检测
|
univerify.check();
|
|
onReady(() => {
|
// 公众号登录授权回调
|
mpLogin();
|
});
|
</script>
|
|
<style lang="scss" scoped>
|
.page-login {
|
.logo {
|
display: flex;
|
flex-direction: column;
|
justify-content: center;
|
align-items: center;
|
padding-top: 20%;
|
|
image {
|
display: block;
|
height: 150rpx;
|
width: 150rpx;
|
border-radius: 24rpx;
|
margin-bottom: 30rpx;
|
box-shadow: 0 25rpx 30rpx -25rpx #666666;
|
}
|
|
text {
|
font-size: 36rpx;
|
font-weight: bold;
|
letter-spacing: 1rpx;
|
color: #333;
|
}
|
}
|
|
.container {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
justify-content: center;
|
margin-top: 80rpx;
|
|
.mode {
|
width: 100%;
|
padding: 0 80rpx;
|
box-sizing: border-box;
|
|
.label {
|
display: block;
|
font-size: 36rpx;
|
font-weight: 500;
|
margin-bottom: 30rpx;
|
}
|
|
&.is-phone {
|
.phone {
|
display: flex;
|
align-items: center;
|
background-color: #eeeeee;
|
border-radius: 10rpx;
|
height: 90rpx;
|
margin-bottom: 30rpx;
|
font-size: 30rpx;
|
|
text {
|
display: inline-block;
|
padding: 0 40rpx;
|
border-right: $cl-border-width solid $cl-border-color;
|
font-weight: bold;
|
color: #404040;
|
}
|
|
input {
|
height: 100%;
|
flex: 1;
|
padding: 0 30rpx;
|
}
|
}
|
}
|
}
|
|
.agree {
|
text-align: center;
|
margin: 50rpx -60rpx 0 0;
|
}
|
}
|
|
.other {
|
margin-top: 100rpx;
|
|
.platform {
|
display: flex;
|
flex-direction: column;
|
align-items: center;
|
margin: 20rpx 0 60rpx 0;
|
|
&__item {
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
border: 1px solid #000000;
|
height: 30px;
|
width: 130px;
|
margin-bottom: 28rpx;
|
border-radius: 6px;
|
background-color: #ffffff;
|
|
image {
|
height: 32rpx;
|
width: 32rpx;
|
margin-right: 10rpx;
|
}
|
|
text {
|
font-size: 24rpx;
|
color: #000000;
|
}
|
}
|
}
|
}
|
}
|
</style>
|