refactor: 重构移动端页面布局与资源路径,优化打包配置
1. 新增layout.uts统一管理页面尺寸与安全区计算 2. 修正图片资源路径到static/mobile目录 3. 调整App.vue与AppIcon组件样式适配多端 4. 为微信小程序配置打包忽略规则减少包体积 5. 修复API请求错误抛出类型,完善类型定义 6. 补充README文档说明项目运行与维护规范 7. 优化多个页面的样式与生命周期逻辑
This commit is contained in:
+31
-23
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view class="login-page page-white">
|
||||
<view class="status-space"></view>
|
||||
<view class="login-page page-white" :style="pageStyle()">
|
||||
<view class="status-space" :style="statusStyle(90)"></view>
|
||||
<view class="login-content">
|
||||
<BrandLogo />
|
||||
<text class="welcome">欢迎登录 AI融资</text>
|
||||
@@ -8,11 +8,11 @@
|
||||
<view :class="mode == 'phone' ? 'login-tab selected' : 'login-tab'" @click="switchMode('phone')"><text>手机号登录</text></view>
|
||||
<view :class="mode == 'password' ? 'login-tab selected' : 'login-tab'" @click="switchMode('password')"><text>密码登录</text></view>
|
||||
</view>
|
||||
<view class="input-box"><text class="input-prefix">+86</text><input v-model="phone" type="number" maxlength="11" placeholder="请输入手机号" /></view>
|
||||
<view v-if="mode == 'password'" class="input-box"><text class="input-prefix">密码</text><input v-model="password" password placeholder="请输入登录密码" /></view>
|
||||
<view v-if="mode == 'phone' && smsSent" class="input-box"><text class="input-prefix">验证码</text><input v-model="smsCode" type="number" maxlength="6" placeholder="请输入 6 位验证码" /><text class="countdown" @click="resendSms">{{ countdown > 0 ? countdown.toString() + 's' : '重新获取' }}</text></view>
|
||||
<view class="input-box"><text class="input-prefix">+86</text><input v-model="phone" type="number" maxlength="11" placeholder="请输入手机号" class="input-box-input" /></view>
|
||||
<view v-if="mode == 'password'" class="input-box"><text class="input-prefix">密码</text><input v-model="password" password placeholder="请输入登录密码" class="input-box-input" /></view>
|
||||
<view v-if="mode == 'phone' && smsSent" class="input-box"><text class="input-prefix">验证码</text><input v-model="smsCode" type="number" maxlength="6" placeholder="请输入 6 位验证码" class="input-box-input" /><text class="countdown" @click="resendSms">{{ countdown > 0 ? countdown.toString() + 's' : '重新获取' }}</text></view>
|
||||
<text v-if="errorMessage.length > 0" class="error-message">{{ errorMessage }}</text>
|
||||
<button class="login-button" :disabled="loading" @click="login">{{ loading ? '处理中...' : (mode == 'phone' ? (smsSent ? '登录' : '获取验证码') : '登录') }}</button>
|
||||
<button class="login-button" :disabled="loading" @click="login" :class="loading ? 'login-disabled' : ''">{{ loading ? '处理中...' : (mode == 'phone' ? (smsSent ? '登录' : '获取验证码') : '登录') }}</button>
|
||||
<view class="other-login"><view class="line"></view><text>其他登录方式</text><view class="line"></view></view>
|
||||
<view class="social-row">
|
||||
<view class="social wechat"><AppIcon name="message" :size="38" /></view><view class="social apple"><AppIcon name="lock" :size="38" /></view><view class="social phone"><AppIcon name="user" :size="38" /></view>
|
||||
@@ -23,6 +23,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="uts">
|
||||
import { usePageLayout } from '@/services/layout.uts'
|
||||
const { statusStyle, pageStyle } = usePageLayout()
|
||||
import BrandLogo from '@/components/BrandLogo.uvue'
|
||||
import AppIcon from '@/components/AppIcon.uvue'
|
||||
import { requestSmsCode, loginWithSms, loginWithPassword, saveSession } from '@/services/api.uts'
|
||||
@@ -35,7 +37,7 @@
|
||||
const loading = ref(false)
|
||||
const errorMessage = ref('')
|
||||
const agreed = ref(true)
|
||||
let countdownTimer: number | null = null
|
||||
let countdownTimer = 0
|
||||
|
||||
const switchMode = (nextMode: string) => {
|
||||
mode.value = nextMode
|
||||
@@ -50,12 +52,12 @@
|
||||
}
|
||||
const startCountdown = () => {
|
||||
countdown.value = 60
|
||||
if (countdownTimer != null) clearInterval(countdownTimer)
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = setInterval(() => {
|
||||
if (countdown.value <= 1) {
|
||||
countdown.value = 0
|
||||
if (countdownTimer != null) clearInterval(countdownTimer)
|
||||
countdownTimer = null
|
||||
clearInterval(countdownTimer)
|
||||
countdownTimer = 0
|
||||
} else {
|
||||
countdown.value -= 1
|
||||
}
|
||||
@@ -70,11 +72,11 @@
|
||||
loading.value = true
|
||||
errorMessage.value = ''
|
||||
try {
|
||||
if (!(await requestSmsCode(phone.value))) throw '验证码发送失败,请稍后重试'
|
||||
if (!(await requestSmsCode(phone.value))) throw new Error('验证码发送失败,请稍后重试')
|
||||
startCountdown()
|
||||
uni.showToast({ title: '验证码已重新发送', icon: 'none' })
|
||||
} catch (error) {
|
||||
errorMessage.value = error == null ? '验证码发送失败,请稍后重试' : error.toString()
|
||||
errorMessage.value = error instanceof Error ? error.message : '验证码发送失败,请稍后重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@@ -90,30 +92,30 @@
|
||||
if (!smsSent.value) {
|
||||
if (countdown.value > 0) return
|
||||
const sent = await requestSmsCode(phone.value)
|
||||
if (!sent) throw '验证码发送失败,请稍后重试'
|
||||
if (!sent) throw new Error('验证码发送失败,请稍后重试')
|
||||
smsSent.value = true
|
||||
startCountdown()
|
||||
uni.showToast({ title: '验证码已发送', icon: 'none' })
|
||||
} else {
|
||||
if (!/^[0-9]{6}$/.test(smsCode.value)) throw '请输入 6 位数字验证码'
|
||||
if (!/^[0-9]{6}$/.test(smsCode.value)) throw new Error('请输入 6 位数字验证码')
|
||||
finishLogin(await loginWithSms(phone.value, smsCode.value))
|
||||
}
|
||||
} else {
|
||||
if (password.value.length < 6) throw '密码至少需要 6 位'
|
||||
if (password.value.length < 6) throw new Error('密码至少需要 6 位')
|
||||
finishLogin(await loginWithPassword(phone.value, password.value))
|
||||
}
|
||||
} catch (error) {
|
||||
errorMessage.value = error == null ? '登录失败,请稍后重试' : error.toString()
|
||||
errorMessage.value = error instanceof Error ? error.message : '登录失败,请稍后重试'
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
onUnmounted(() => { if (countdownTimer != null) clearInterval(countdownTimer) })
|
||||
onUnmounted(() => { clearInterval(countdownTimer) })
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.login-page { min-height: 100vh; }
|
||||
.status-space { height: calc(var(--status-bar-height) + 90rpx); }
|
||||
.login-page { }
|
||||
.status-space { }
|
||||
.login-content { padding: 0 54rpx; }
|
||||
.welcome { font-size: 48rpx; line-height: 70rpx; font-weight: 800; margin-top: 60rpx; color: #122347; }
|
||||
.login-tabs { flex-direction: row; margin-top: 52rpx; border-bottom: 2rpx solid #eaf0f7; }
|
||||
@@ -121,16 +123,22 @@
|
||||
.login-tab.selected { color: #0868f7; font-weight: 700; border-bottom: 5rpx solid #0868f7; }
|
||||
.input-box { height: 96rpx; margin-top: 28rpx; border: 2rpx solid #dfe7f2; border-radius: 14rpx; padding: 0 24rpx; flex-direction: row; align-items: center; background-color: #fbfdff; }
|
||||
.input-prefix { font-size: 25rpx; color: #3c4a61; margin-right: 24rpx; }
|
||||
.input-box input { flex: 1; font-size: 28rpx; color: #17243c; }
|
||||
.input-box-input { flex: 1; font-size: 28rpx; color: #17243c; }
|
||||
.countdown { min-width: 90rpx; text-align: right; color: #0868f7; font-size: 24rpx; }
|
||||
.error-message { display: block; margin-top: 16rpx; color: #e55353; font-size: 23rpx; }
|
||||
.error-message {
|
||||
/* #ifndef APP */
|
||||
display: block;
|
||||
/* #endif */
|
||||
margin-top: 16rpx; color: #e55353; font-size: 23rpx; }
|
||||
.login-button { height: 92rpx; line-height: 92rpx; margin-top: 32rpx; border-radius: 14rpx; color: white; font-size: 29rpx; font-weight: 700; background-color: #0868f7; box-shadow: 0 16rpx 30rpx rgba(8, 104, 247, .2); }
|
||||
.login-button[disabled] { opacity: .6; }
|
||||
.login-disabled { opacity: .6; }
|
||||
.other-login { margin-top: 62rpx; flex-direction: row; align-items: center; justify-content: center; color: #a0a9b7; font-size: 22rpx; }
|
||||
.line { height: 1rpx; background-color: #e5eaf1; width: 120rpx; margin: 0 20rpx; }
|
||||
.social-row { flex-direction: row; justify-content: center; margin-top: 40rpx; }
|
||||
.social { width: 84rpx; height: 84rpx; border-radius: 50%; align-items: center; justify-content: center; margin: 0 25rpx; font-size: 28rpx; font-weight: 800; }
|
||||
.wechat { background-color: #e9f8ef; color: #12ad58; }.apple { background-color: #f2f4f7; color: #111; }.phone { background-color: #fff0ea; color: #ff6530; }
|
||||
.wechat { background-color: #e9f8ef; color: #12ad58; }
|
||||
.apple { background-color: #f2f4f7; color: #111; }
|
||||
.phone { background-color: #fff0ea; color: #ff6530; }
|
||||
.agreement { margin-top: 62rpx; flex-direction: row; align-items: center; justify-content: center; color: #8793a8; font-size: 21rpx; }
|
||||
.check { width: 28rpx; height: 28rpx; border: 2rpx solid #aeb8c7; border-radius: 6rpx; align-items: center; justify-content: center; margin-right: 10rpx; }
|
||||
.checked { color: white; background-color: #0868f7; border-color: #0868f7; }
|
||||
|
||||
Reference in New Issue
Block a user