85 lines
3.6 KiB
Vue
85 lines
3.6 KiB
Vue
<template>
|
|
<view class="page-shell login-page">
|
|
<view class="ceremony-top">
|
|
<text class="seal-word">谱</text>
|
|
<text class="eyebrow">家脉绵延 · 生生不息</text>
|
|
<text class="brand-title">家谱</text>
|
|
<text class="brand-subtitle">为家族留存可传承的记忆</text>
|
|
</view>
|
|
|
|
<view class="login-paper">
|
|
<view class="section-title">登录家谱</view>
|
|
<text class="form-note">使用已注册手机号和密码登录。</text>
|
|
<text class="form-label">手机号</text>
|
|
<input v-model="phone" class="line-input" type="number" maxlength="11" placeholder="请输入手机号" placeholder-class="placeholder" />
|
|
<text class="form-label">密码</text>
|
|
<input v-model="password" class="line-input" password placeholder="请输入密码" placeholder-class="placeholder" />
|
|
<text v-if="errorMessage" class="error-message">{{ errorMessage }}</text>
|
|
<button class="primary-button login-button" :loading="isSubmitting" :disabled="isSubmitting" @click="login">进入家谱</button>
|
|
<text class="login-tip">短信登录将在验证码服务联调后开放。</text>
|
|
<text class="terms">登录即表示同意《用户协议》与《隐私政策》</text>
|
|
</view>
|
|
</view>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue'
|
|
import { appApi } from '@/utils/api.js'
|
|
import { calcMD5 } from '@/utils/md5.js'
|
|
|
|
const phone = ref('')
|
|
const password = ref('')
|
|
const isSubmitting = ref(false)
|
|
const errorMessage = ref('')
|
|
|
|
const login = async () => {
|
|
if (!/^1\d{10}$/.test(phone.value)) {
|
|
uni.showToast({ title: '请输入正确手机号', icon: 'none' })
|
|
return
|
|
}
|
|
if (!password.value) {
|
|
uni.showToast({ title: '请输入登录密码', icon: 'none' })
|
|
return
|
|
}
|
|
|
|
isSubmitting.value = true
|
|
errorMessage.value = ''
|
|
try {
|
|
await appApi.loginWithPassword({ phone: phone.value, passwordHash: calcMD5(password.value) })
|
|
uni.reLaunch({ url: '/pages/genealogy/index' })
|
|
} catch (error) {
|
|
errorMessage.value = error.message || '登录失败,请稍后重试'
|
|
} finally {
|
|
isSubmitting.value = false
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.login-page { padding-top: 108rpx; }
|
|
|
|
.ceremony-top {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
padding: 40rpx 40rpx 76rpx;
|
|
background: $brand-red;
|
|
color: #fff9ed;
|
|
}
|
|
|
|
.seal-word { display: flex; width: 66rpx; height: 66rpx; align-items: center; justify-content: center; box-sizing: border-box; border: 2rpx solid #f1d494; border-radius: 50%; color: #f5ddaa; font-family: serif; font-size: 37rpx; }
|
|
.eyebrow { margin-top: 24rpx; color: #f8dfad; font-size: 22rpx; letter-spacing: 5rpx; }
|
|
.brand-title { margin-top: 24rpx; font-family: serif; font-size: 68rpx; font-weight: 700; letter-spacing: 16rpx; }
|
|
.brand-subtitle { margin-top: 18rpx; color: #f5deae; font-size: 26rpx; letter-spacing: 3rpx; }
|
|
|
|
.login-paper { margin: -28rpx 28rpx 0; padding: 48rpx 42rpx; border: 1rpx solid $gold-soft; border-radius: 24rpx; background: $paper-white; }
|
|
.form-note { display: block; margin-top: 14rpx; color: $ink-muted; font-size: 23rpx; }
|
|
.form-label { display: block; margin-top: 40rpx; color: $ink-muted; font-size: 25rpx; }
|
|
.line-input { height: 78rpx; border-bottom: 1rpx solid $gold-soft; color: $ink; font-size: 30rpx; }
|
|
.placeholder { color: #b3a895; }
|
|
.error-message { display: block; margin-top: 22rpx; color: $brand-red; font-size: 23rpx; line-height: 1.5; }
|
|
.login-button { margin-top: 48rpx; }
|
|
.login-tip { display: block; margin-top: 24rpx; color: $ink-muted; font-size: 22rpx; text-align: center; }
|
|
.terms { display: block; margin-top: 16rpx; color: #a39785; font-size: 21rpx; text-align: center; }
|
|
</style>
|