|
- <template>
- <view class="login">
- <view class="logo-section">
- <image
- class="logo-img"
- src="https://cdn.aionline.cc/logo/logo_aionline.svg"
- mode="widthFix"
- ></image>
- <text class="login-tip">登录后同步作品、点数和创作记录</text>
- </view>
-
- <view class="login-actions">
- <button class="login-btn wechat" hover-class="login-btn-hover" :loading="postLoading" @click="onLoginClick">
- <up-icon class="btn-icon" name="weixin-fill" size="24" color="#ffffff"></up-icon>
- <text>微信登录</text>
- </button>
-
- <!-- #ifdef MP-WEIXIN -->
- <button
- class="login-btn phone"
- hover-class="login-btn-hover"
- :open-type="agree ? 'getPhoneNumber' : ''"
- @getphonenumber="getPhoneNumber"
- @click="onPhoneLoginClick"
- >
- <up-icon class="btn-icon" name="phone-fill" size="24" color="#46bb36"></up-icon>
- <text>手机号登录</text>
- </button>
- <!-- #endif -->
-
- <!-- #ifndef MP-WEIXIN -->
- <button class="login-btn phone" hover-class="login-btn-hover" @click="onPhoneLoginClick">
- <up-icon class="btn-icon" name="phone-fill" size="24" color="#46bb36"></up-icon>
- <text>手机号登录</text>
- </button>
- <!-- #endif -->
-
- <!-- #ifdef APP-PLUS -->
- <view v-if="isIOS" class="more-actions">
- <button class="mini-login-btn apple" hover-class="mini-login-btn-hover" :loading="postLoading" @click="onAppleLoginClick">
- <up-icon name="apple-fill" size="20" color="#172033"></up-icon>
- <text>Apple 登录</text>
- </button>
- <button class="mini-login-btn visitor" hover-class="mini-login-btn-hover" :loading="postLoading" @click="onVisitorLoginClick">
- <up-icon name="account-fill" size="20" color="#172033"></up-icon>
- <text>游客登录</text>
- </button>
- </view>
- <!-- #endif -->
- </view>
-
- <view class="agreement" @click="agree = !agree">
- <view class="checkbox" :class="{ checked: agree }">
- <up-icon v-if="agree" name="checkbox-mark" size="14" color="#ffffff"></up-icon>
- </view>
- <view class="agreement-text">
- <text>请阅读并同意</text>
- <text class="link" @click.stop="onAgreementClick('service')">《服务条款》</text>
- <text class="link" @click.stop="onAgreementClick('privacy')">《隐私政策》</text>
- </view>
- </view>
- </view>
- </template>
-
- <script setup>
- import { ref } from 'vue'
- import { onLoad } from '@dcloudio/uni-app'
- import { userApi } from '@/api/index.js'
- import { useUserStore } from '@/store/user.js'
- import { useApp } from '@/utils/useApp.js'
- import { isInWechat } from '@/utils/util.js'
- import CONFIG from '@/utils/config.js'
-
- const userStore = useUserStore()
- const { toast, showLoading, hideLoading } = useApp()
-
- const postLoading = ref(false)
- const agree = ref(false)
- const type = ref('1')
- const source = ref('')
-
- // 平台标识
- let isIOS = false
- // #ifdef APP-PLUS
- isIOS = uni.getSystemInfoSync().platform === 'ios'
- // #endif
-
- onLoad((options = {}) => {
- type.value = options.type || '1'
- source.value = options.source || ''
- const redirect = options.redirect || options.url || ''
-
- // #ifdef H5
- if (redirect) uni.setStorageSync('login_redirect', decodeURIComponent(redirect))
- if (options.code) postLogin(options.code) // 公众号授权回跳
- // #endif
-
- // #ifdef MP-WEIXIN
- if (options.source === 'scheme') {
- // 深度链接进入,自动登录
- if (userStore.isLogin) {
- uni.switchTab({ url: '/pages/toolbox/toolbox' })
- } else {
- agree.value = true
- onLoginClick()
- }
- }
- // #endif
- })
-
- function checkAgree() {
- if (!agree.value) {
- toast('请阅读并同意服务政策')
- return false
- }
- return true
- }
-
- function onAgreementClick(key) {
- uni.navigateTo({ url: `/pages/agreement/agreement?key=${key}` })
- }
-
- /* ============ 微信登录 ============ */
- function onLoginClick() {
- // #ifndef H5
- if (!checkAgree()) return
- // #endif
-
- // #ifdef APP-PLUS
- wechatLogin()
- // #endif
-
- // #ifdef MP-WEIXIN
- uni.login({
- success: (res) => postLogin(res.code)
- })
- // #endif
-
- // #ifdef H5
- if (isInWechat()) {
- location.replace(getH5AuthUrl())
- } else {
- getMiniScheme()
- }
- // #endif
- }
-
- function wechatLogin() {
- uni.login({
- provider: 'weixin',
- onlyAuthorize: true,
- success: (event) => postLogin(event.code)
- })
- }
-
- function getH5AuthUrl() {
- const mUrl = CONFIG.M_URL
- const appid = CONFIG.WX_MP_APPID
- return `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${appid}&redirect_uri=${mUrl}/pages/login/login&response_type=code&scope=snsapi_userinfo&state=23_4_${appid}#wechat_redirect`
- }
-
- async function getMiniScheme() {
- try {
- showLoading('加载中...')
- const res = await userApi.getMiniScheme({})
- hideLoading()
- location.href = res.data.openlink
- } catch (e) {
- hideLoading()
- toast(e.msg || '登录失败,请重试')
- }
- }
-
- /* ============ 手机号登录 ============ */
- function onPhoneLoginClick() {
- if (!checkAgree()) return
- // #ifndef MP-WEIXIN
- // 非小程序端跳验证码登录页
- uni.navigateTo({ url: '/pages/login/phone' })
- // #endif
- // 小程序端由 button open-type=getPhoneNumber 触发 getPhoneNumber
- }
-
- function getPhoneNumber(event) {
- if (event.detail.errMsg !== 'getPhoneNumber:ok') {
- toast('已取消')
- return
- }
- loginByPhoneCode(event.detail.code)
- }
-
- async function loginByPhoneCode(code) {
- try {
- postLoading.value = true
- const res = await userApi.loginByPhoneMp({ code })
- afterLogin(res)
- } catch (e) {
- toast(e.msg || '登录失败,请重试!')
- } finally {
- postLoading.value = false
- }
- }
-
- /* ============ Apple / 游客登录 ============ */
- function onAppleLoginClick() {
- if (!checkAgree()) return
- uni.login({
- provider: 'apple',
- success: (res) => {
- const open_id = res.appleInfo.user
- let user_name = ''
- if (res.appleInfo.fullName) {
- user_name = `${res.appleInfo.fullName.familyName || ''}${res.appleInfo.fullName.givenName || ''}`
- }
- signWithApple({ open_id, user_name })
- }
- })
- }
-
- function onVisitorLoginClick() {
- if (!checkAgree()) return
- const open_id = uni.getSystemInfoSync().deviceId
- signWithApple({ open_id, user_name: '', is_visitor: 1 })
- }
-
- async function signWithApple(params) {
- try {
- postLoading.value = true
- const res = await userApi.signWithApple(params)
- afterLogin(res)
- } catch (e) {
- toast(e.msg || '登录失败,请重试!')
- } finally {
- postLoading.value = false
- }
- }
-
- /* ============ 通用登录处理 ============ */
- async function postLogin(code) {
- try {
- postLoading.value = true
- const res = await userApi.loginByCode({ code })
- afterLogin(res)
- } catch (e) {
- toast(e.msg || '登录失败,请重试!')
- } finally {
- postLoading.value = false
- }
- }
-
- function afterLogin(res) {
- const inviteCode = uni.getStorageSync('invite_code')
- userStore.setLogin({ token: res.data.token, userInfo: res.data })
-
- if (res.data.is_register) {
- toast(inviteCode ? '登录并领取成功!' : '登录成功!')
- } else {
- toast('登录成功!')
- }
-
- if (inviteCode) uni.removeStorageSync('invite_code')
-
- // 统一跳回首页
- setTimeout(() => {
- uni.switchTab({ url: '/pages/toolbox/toolbox' })
- }, 1200)
- }
- </script>
-
- <style lang="scss" scoped>
- .login {
- min-height: 100vh;
- padding: 0 48rpx calc(46rpx + env(safe-area-inset-bottom));
- box-sizing: border-box;
- background: #ffffff;
- text-align: center;
- }
-
- .logo-section {
- padding-top: 12vh;
- display: flex;
- flex-direction: column;
- align-items: center;
- }
-
- .logo-img {
- width: 300rpx;
- height: auto;
- display: block;
- }
-
- .login-tip {
- margin-top: 24rpx;
- color: #7f8896;
- font-size: 26rpx;
- line-height: 1.4;
- }
-
- .login-actions {
- margin-top: 92rpx;
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 30rpx;
- }
-
- .login-btn {
- width: 100%;
- max-width: 560rpx;
- height: 92rpx;
- margin: 0;
- padding: 0 28rpx;
- border-radius: 48rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- box-sizing: border-box;
- font-size: 30rpx;
- font-weight: 600;
- line-height: 1;
-
- &::after {
- border: none;
- }
-
- .btn-icon {
- margin-right: 14rpx;
- }
-
- &.wechat {
- color: #fff;
- background: #46bb36;
- box-shadow: 0 14rpx 28rpx rgba(70, 187, 54, 0.18);
- }
-
- &.phone {
- color: #46bb36;
- background: #ffffff;
- border: 2rpx solid rgba(70, 187, 54, 0.55);
- }
- }
-
- .login-btn-hover,
- .mini-login-btn-hover {
- opacity: 0.86;
- }
-
- .more-actions {
- width: 100%;
- max-width: 560rpx;
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 16rpx;
- }
-
- .mini-login-btn {
- height: 82rpx;
- margin: 0;
- padding: 0;
- border-radius: 42rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- gap: 10rpx;
- color: #172033;
- font-size: 26rpx;
- font-weight: 700;
- line-height: 1;
- background: #ffffff;
- border: 1rpx solid rgba(89, 105, 128, 0.12);
-
- &::after {
- border: none;
- }
- }
-
- .agreement {
- margin-top: 60rpx;
- padding: 0 6rpx;
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 24rpx;
- line-height: 1.45;
- color: #7f8896;
-
- .checkbox {
- width: 32rpx;
- height: 32rpx;
- margin-right: 12rpx;
- border-radius: 50%;
- border: 2rpx solid #b8c2d1;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-shrink: 0;
-
- &.checked {
- background: #46bb36;
- border-color: #46bb36;
- }
- }
-
- .agreement-text {
- min-width: 0;
- display: flex;
- align-items: center;
- justify-content: center;
- flex-wrap: wrap;
- }
-
- .link {
- color: #0b8cff;
- font-weight: 600;
- }
- }
- </style>
|