Init applications
This commit is contained in:
37
apps/kid-coding-miniapp/src/pages/home.vue
Normal file
37
apps/kid-coding-miniapp/src/pages/home.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<view class="flex flex-col items-center justify-center space-y-4">
|
||||
Index123
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { auth } from '@/lib/nvwa'
|
||||
import { AUTH_REQUIRED } from '@/lib/config'
|
||||
import redirectToLogin from '@/custom/redirect-to-login'
|
||||
|
||||
onLoad(async () => {
|
||||
// 如果需要认证,检查登录状态
|
||||
if (AUTH_REQUIRED) {
|
||||
try {
|
||||
const userProfile = await auth.currentUser()
|
||||
if (!userProfile) {
|
||||
// 未登录,重定向到登录页
|
||||
await redirectToLogin()
|
||||
return
|
||||
}
|
||||
console.log("current user profile", userProfile)
|
||||
} catch (error) {
|
||||
// 获取用户信息失败,重定向到登录页
|
||||
await redirectToLogin()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// 不需要认证,可以尝试获取用户信息(但不强制)
|
||||
const userProfile = await auth.currentUser()
|
||||
console.log("current user profile", userProfile)
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
<style></style>
|
||||
214
apps/kid-coding-miniapp/src/pages/user/login.vue
Normal file
214
apps/kid-coding-miniapp/src/pages/user/login.vue
Normal file
@@ -0,0 +1,214 @@
|
||||
<template>
|
||||
<view class="flex flex-col items-center justify-center min-h-screen bg-gray-50 px-5">
|
||||
<view class="w-full max-w-md">
|
||||
<!-- Logo -->
|
||||
<view class="flex justify-center mb-10 mt-20">
|
||||
<image class="h-24 w-24" src="/static/logo.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
<!-- 登录方式切换 -->
|
||||
<view class="flex gap-2 mb-6">
|
||||
<button
|
||||
:class="loginType === 'username' ? 'bg-blue-500 text-white' : 'bg-white text-gray-700 border border-gray-300'"
|
||||
class="flex-1 py-2 rounded-full text-sm"
|
||||
@click="loginType = 'username'"
|
||||
>
|
||||
用户名登录
|
||||
</button>
|
||||
<button
|
||||
:class="loginType === 'phone' ? 'bg-blue-500 text-white' : 'bg-white text-gray-700 border border-gray-300'"
|
||||
class="flex-1 py-2 rounded-full text-sm"
|
||||
@click="loginType = 'phone'"
|
||||
>
|
||||
手机号登录
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<view v-if="loginType === 'username'" class="space-y-4">
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入用户名"
|
||||
border="surround"
|
||||
v-model="username"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入密码"
|
||||
type="password"
|
||||
border="surround"
|
||||
v-model="password"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view v-else class="space-y-4">
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入手机号"
|
||||
border="surround"
|
||||
v-model="phoneNumber"
|
||||
type="number"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入密码"
|
||||
type="password"
|
||||
border="surround"
|
||||
v-model="password"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
<view class="flex items-center" @click="rememberMe = !rememberMe">
|
||||
<uni-icons :type="rememberMe ? 'checkbox-filled' : 'circle'" size="20" :color="rememberMe ? '#007AFF' : '#999'"></uni-icons>
|
||||
<text class="ml-2 text-xs text-gray-600">记住我</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<view v-if="errorMessage" class="mt-4 p-3 bg-red-50 border border-red-200 rounded-lg">
|
||||
<text class="text-red-600 text-sm">{{ errorMessage }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 登录按钮 -->
|
||||
<button
|
||||
class="w-full rounded-full bg-blue-500 border border-blue-500 text-white py-3 mt-6"
|
||||
:disabled="isLoading"
|
||||
@click="handleLogin"
|
||||
>
|
||||
{{ isLoading ? '登录中...' : '登录' }}
|
||||
</button>
|
||||
|
||||
<!-- 注册链接 -->
|
||||
<view class="mt-6 text-center">
|
||||
<text class="text-gray-600 text-sm">还没有账户?</text>
|
||||
<text class="text-blue-500 text-sm ml-1" @click="goToRegister">立即注册</text>
|
||||
</view>
|
||||
|
||||
<!-- 其他登录方式 -->
|
||||
<view class="mt-10 text-center">
|
||||
<view class="text-gray-600 text-sm mb-5">其他登录方式</view>
|
||||
<view class="flex justify-center gap-4">
|
||||
<view class="p-2" @click="handleWechatLogin">
|
||||
<uni-icons type="weixin" size="40" color="#07C160"></uni-icons>
|
||||
</view>
|
||||
<view class="p-2" @click="handleQQLogin">
|
||||
<uni-icons type="qq" size="40" color="#12B7F5"></uni-icons>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { auth, localStorage } from '@/lib/nvwa'
|
||||
|
||||
const LOGIN_BACK_URL_KEY = "LOGIN_BACK_URL"
|
||||
|
||||
const loginType = ref<'username' | 'phone'>('username')
|
||||
const username = ref<string>('')
|
||||
const phoneNumber = ref<string>('')
|
||||
const password = ref<string>('')
|
||||
const rememberMe = ref<boolean>(false)
|
||||
const isLoading = ref<boolean>(false)
|
||||
const errorMessage = ref<string>('')
|
||||
|
||||
onLoad(async () => {
|
||||
// 检查是否已登录
|
||||
const user = await auth.currentUser()
|
||||
if (user) {
|
||||
const url = await localStorage.get(LOGIN_BACK_URL_KEY) || '/pages/home'
|
||||
uni.reLaunch({
|
||||
url
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const handleLogin = async () => {
|
||||
if (isLoading.value) return
|
||||
|
||||
// 验证输入
|
||||
if (!password.value || password.value.length < 6) {
|
||||
errorMessage.value = '密码至少需要6个字符'
|
||||
return
|
||||
}
|
||||
|
||||
if (loginType.value === 'username') {
|
||||
if (!username.value || username.value.trim().length === 0) {
|
||||
errorMessage.value = '请输入用户名'
|
||||
return
|
||||
}
|
||||
} else {
|
||||
if (!phoneNumber.value || phoneNumber.value.trim().length === 0) {
|
||||
errorMessage.value = '请输入手机号'
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
if (loginType.value === 'username') {
|
||||
await auth.signInWithUsername(username.value.trim(), password.value)
|
||||
} else {
|
||||
await auth.signInWithPhoneNumber(
|
||||
phoneNumber.value.trim(),
|
||||
password.value,
|
||||
rememberMe.value
|
||||
)
|
||||
}
|
||||
|
||||
// 登录成功,跳转
|
||||
const url = await localStorage.get(LOGIN_BACK_URL_KEY) || '/pages/home'
|
||||
await localStorage.remove(LOGIN_BACK_URL_KEY)
|
||||
uni.reLaunch({
|
||||
url
|
||||
})
|
||||
} catch (error: any) {
|
||||
errorMessage.value = error?.message || '登录失败,请重试'
|
||||
uni.showToast({
|
||||
title: errorMessage.value,
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const goToRegister = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/user/register'
|
||||
})
|
||||
}
|
||||
|
||||
const handleWechatLogin = () => {
|
||||
uni.showToast({
|
||||
title: '微信登录功能开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
|
||||
const handleQQLogin = () => {
|
||||
uni.showToast({
|
||||
title: 'QQ登录功能开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 使用 Tailwind CSS 类名,无需额外样式 */
|
||||
</style>
|
||||
213
apps/kid-coding-miniapp/src/pages/user/register.vue
Normal file
213
apps/kid-coding-miniapp/src/pages/user/register.vue
Normal file
@@ -0,0 +1,213 @@
|
||||
<template>
|
||||
<view class="flex flex-col items-center justify-center min-h-screen bg-gray-50 px-5">
|
||||
<view class="w-full max-w-md">
|
||||
<!-- Logo -->
|
||||
<view class="flex justify-center mb-10 mt-20">
|
||||
<image class="h-24 w-24" src="/static/logo.png" mode="aspectFit"></image>
|
||||
</view>
|
||||
|
||||
<!-- 注册标题 -->
|
||||
<view class="text-center mb-8">
|
||||
<text class="text-2xl font-bold text-gray-800">创建账户</text>
|
||||
</view>
|
||||
|
||||
<!-- 注册表单 -->
|
||||
<view class="space-y-4">
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入姓名"
|
||||
border="surround"
|
||||
v-model="name"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入用户名(至少3个字符)"
|
||||
border="surround"
|
||||
v-model="username"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入邮箱(可选)"
|
||||
border="surround"
|
||||
v-model="email"
|
||||
type="email"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入头像URL(可选)"
|
||||
border="surround"
|
||||
v-model="image"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请输入密码(至少6个字符)"
|
||||
type="password"
|
||||
border="surround"
|
||||
v-model="password"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
<view>
|
||||
<uni-easyinput
|
||||
shape="circle"
|
||||
placeholder="请再次输入密码"
|
||||
type="password"
|
||||
border="surround"
|
||||
v-model="confirmPassword"
|
||||
:clearable="true"
|
||||
></uni-easyinput>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 错误提示 -->
|
||||
<view v-if="errorMessage" class="mt-4 p-3 bg-red-50 border border-red-200 rounded-lg">
|
||||
<text class="text-red-600 text-sm">{{ errorMessage }}</text>
|
||||
</view>
|
||||
|
||||
<!-- 注册按钮 -->
|
||||
<button
|
||||
class="w-full rounded-full bg-blue-500 border border-blue-500 text-white py-3 mt-6"
|
||||
:disabled="isLoading"
|
||||
@click="handleRegister"
|
||||
>
|
||||
{{ isLoading ? '注册中...' : '注册' }}
|
||||
</button>
|
||||
|
||||
<!-- 登录链接 -->
|
||||
<view class="mt-6 text-center">
|
||||
<text class="text-gray-600 text-sm">已有账户?</text>
|
||||
<text class="text-blue-500 text-sm ml-1" @click="goToLogin">立即登录</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { onLoad } from '@dcloudio/uni-app'
|
||||
import { auth } from '@/lib/nvwa'
|
||||
|
||||
const name = ref<string>('')
|
||||
const username = ref<string>('')
|
||||
const email = ref<string>('')
|
||||
const image = ref<string>('')
|
||||
const password = ref<string>('')
|
||||
const confirmPassword = ref<string>('')
|
||||
const isLoading = ref<boolean>(false)
|
||||
const errorMessage = ref<string>('')
|
||||
|
||||
onLoad(async () => {
|
||||
// 检查是否已登录
|
||||
const user = await auth.currentUser()
|
||||
if (user) {
|
||||
uni.reLaunch({
|
||||
url: '/pages/home'
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const validateForm = (): boolean => {
|
||||
errorMessage.value = ''
|
||||
|
||||
if (!name.value || name.value.trim().length < 2) {
|
||||
errorMessage.value = '姓名至少需要2个字符'
|
||||
return false
|
||||
}
|
||||
|
||||
if (!username.value || username.value.trim().length < 3) {
|
||||
errorMessage.value = '用户名至少需要3个字符'
|
||||
return false
|
||||
}
|
||||
|
||||
if (!password.value || password.value.length < 6) {
|
||||
errorMessage.value = '密码至少需要6个字符'
|
||||
return false
|
||||
}
|
||||
|
||||
if (password.value !== confirmPassword.value) {
|
||||
errorMessage.value = '两次输入的密码不一致'
|
||||
return false
|
||||
}
|
||||
|
||||
if (email.value && !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.value)) {
|
||||
errorMessage.value = '请输入有效的邮箱地址'
|
||||
return false
|
||||
}
|
||||
|
||||
if (image.value && !/^https?:\/\/.+/.test(image.value)) {
|
||||
errorMessage.value = '请输入有效的图片URL'
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
const handleRegister = async () => {
|
||||
if (isLoading.value) return
|
||||
|
||||
if (!validateForm()) {
|
||||
uni.showToast({
|
||||
title: errorMessage.value,
|
||||
icon: 'none'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
isLoading.value = true
|
||||
errorMessage.value = ''
|
||||
|
||||
try {
|
||||
await auth.signUp({
|
||||
name: name.value.trim(),
|
||||
username: username.value.trim(),
|
||||
password: password.value,
|
||||
email: email.value.trim() || undefined,
|
||||
image: image.value.trim() || '',
|
||||
})
|
||||
|
||||
// 注册成功,跳转到首页
|
||||
uni.showToast({
|
||||
title: '注册成功',
|
||||
icon: 'success'
|
||||
})
|
||||
|
||||
setTimeout(() => {
|
||||
uni.reLaunch({
|
||||
url: '/pages/home'
|
||||
})
|
||||
}, 1500)
|
||||
} catch (error: any) {
|
||||
errorMessage.value = error?.message || '注册失败,请重试'
|
||||
uni.showToast({
|
||||
title: errorMessage.value,
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const goToLogin = () => {
|
||||
uni.navigateTo({
|
||||
url: '/pages/user/login'
|
||||
})
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
/* 使用 Tailwind CSS 类名,无需额外样式 */
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user