Files
blind-select/frontend-app/pages/login/login.vue
T
admin 06488f0237 Initial commit: 帮我选盲选应用
功能:
- Go后端 (Gin + GORM + PostgreSQL)
- UniApp用户端 (iOS/Android/小程序)
- DaisyUI5后台管理
- JWT认证 + 微信登录
- 盲选加权算法
- 会员系统 + 优惠券
- 打分评价 + 偏好学习
2026-06-08 20:18:31 +00:00

215 lines
4.9 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
小程序登录引导页
微信小程序只能用 wx.login() 获取 code不能收集密码
流程: wx.login() 后端 code2session 自动注册/登录 返回 JWT
-->
<template>
<view class="login-page">
<view class="login-hero">
<text class="logo">🎲</text>
<text class="app-name">帮我选</text>
<text class="app-desc">每一次选择都是惊喜</text>
</view>
<view class="login-body">
<!-- 方式一: 微信一键登录 (小程序) -->
<button class="login-btn primary" @click="wechatLogin" :loading="logining">
<text class="login-icon">💬</text>
<text>微信一键登录</text>
</button>
<text class="login-hint">登录即同意用户协议隐私政策</text>
<!-- 方式二: 手机号登录 (备选) -->
<view class="divider">
<text></text>
</view>
<button class="login-btn secondary" @click="phoneLogin">
<text class="login-icon">📱</text>
<text>手机号快捷登录</text>
</button>
</view>
<view class="login-footer">
<text class="feature-item">🎲 盲选吃喝玩乐</text>
<text class="feature-item">🤖 AI 智能推荐</text>
<text class="feature-item">🎁 优惠券联动</text>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import { authApi } from '@/api/index.js'
import { useUserStore } from '@/store/user.js'
const logining = ref(false)
const userStore = useUserStore()
// ─── 微信一键登录 ───
async function wechatLogin() {
logining.value = true
// 1. 获取微信 code
try {
const loginRes = await new Promise((resolve, reject) => {
wx.login({
success: resolve,
fail: reject
})
})
const code = loginRes.code
if (!code) {
uni.showToast({ title: '获取登录凭证失败', icon: 'none' })
logining.value = false
return
}
// 2. 发送到后端换取 JWT
const data = await authApi.wechatLogin({ code })
// 3. 保存 token + 用户信息
uni.setStorageSync('token', data.token)
uni.setStorageSync('refresh_token', data.refresh_token)
uni.setStorageSync('userInfo', data.user)
userStore.setUserInfo(data.user)
userStore.setHasMember(data.has_member || false)
uni.showToast({ title: '登录成功', icon: 'success' })
// 4. 跳转首页
setTimeout(() => {
uni.switchTab({ url: '/pages/index/index' })
}, 500)
} catch (e) {
console.error('wechat login failed:', e)
uni.showToast({ title: '登录失败,请重试', icon: 'none' })
logining.value = false
}
}
// ─── 手机号登录 (小程序需要用户授权手机号) ───
function phoneLogin() {
// 小程序的 getPhoneNumber 需要 <button open-type="getPhoneNumber">
// 这里提示用户使用微信登录,因为手机号登录需要后端支持
uni.showToast({
title: '请使用微信一键登录',
icon: 'none',
duration: 2000
})
}
// ─── 检查是否已有token (自动登录) ───
onLoad(() => {
const token = uni.getStorageSync('token')
if (token) {
// 有 token → 直接进首页
uni.switchTab({ url: '/pages/index/index' })
}
})
</script>
<style lang="scss" scoped>
.login-page {
min-height: 100vh;
background: linear-gradient(180deg, #FF6B35 0%, #FF8C42 60%, #F5F5F5 100%);
display: flex;
flex-direction: column;
}
.login-hero {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding-top: 100rpx;
.logo {
font-size: 140rpx;
display: block;
margin-bottom: 20rpx;
}
.app-name {
font-size: 56rpx;
font-weight: 800;
color: #fff;
display: block;
margin-bottom: 12rpx;
}
.app-desc {
font-size: 28rpx;
color: rgba(255,255,255,0.8);
display: block;
}
}
.login-body {
background: #fff;
border-radius: 40rpx 40rpx 0 0;
padding: 60rpx 50rpx;
min-height: 400rpx;
.login-btn {
width: 100%;
height: 90rpx;
border-radius: 45rpx;
border: none;
display: flex;
align-items: center;
justify-content: center;
gap: 16rpx;
font-size: 32rpx;
font-weight: 600;
margin-bottom: 24rpx;
&.primary {
background: linear-gradient(135deg, #FF6B35, #FF8C42);
color: #fff;
box-shadow: 0 8rpx 24rpx rgba(255,107,53,0.3);
}
&.secondary {
background: #fff;
color: #333;
border: 2rpx solid #eee;
}
.login-icon {
font-size: 36rpx;
}
}
.login-hint {
display: block;
text-align: center;
font-size: 22rpx;
color: #999;
margin: 30rpx 0;
}
.divider {
text-align: center;
color: #ccc;
font-size: 24rpx;
margin: 20rpx 0;
}
}
.login-footer {
background: #fff;
padding: 40rpx;
display: flex;
flex-wrap: wrap;
gap: 20rpx;
justify-content: center;
.feature-item {
font-size: 22rpx;
color: #666;
}
}
</style>