wechat-login.tsx 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import { View, Text } from '@tarojs/components'
  2. import { useState, useEffect } from 'react'
  3. import Taro from '@tarojs/taro'
  4. import { cn } from '@/utils/cn'
  5. import Navbar from '@/components/ui/navbar'
  6. import { isWeapp } from '@/utils/platform'
  7. import { Button } from '@/components/ui/button'
  8. export default function WechatLogin() {
  9. const [loading, setLoading] = useState(false)
  10. const [isWechatEnv, setIsWechatEnv] = useState(true)
  11. // 设置导航栏标题并检查平台
  12. useEffect(() => {
  13. Taro.setNavigationBarTitle({
  14. title: '微信登录'
  15. })
  16. // 检查是否为微信小程序环境
  17. const wechatEnv = isWeapp()
  18. setIsWechatEnv(wechatEnv)
  19. // 如果不是微信小程序,显示提示并延迟跳转
  20. if (!wechatEnv) {
  21. Taro.showModal({
  22. title: '提示',
  23. content: '微信登录功能仅支持在微信小程序中使用',
  24. showCancel: false,
  25. confirmText: '返回',
  26. success: () => {
  27. setTimeout(() => {
  28. Taro.navigateBack()
  29. }, 500)
  30. }
  31. })
  32. }
  33. }, [])
  34. const handleWechatLogin = async () => {
  35. setLoading(true)
  36. try {
  37. Taro.showLoading({
  38. title: '登录中...',
  39. mask: true
  40. })
  41. // 1. 获取用户信息授权
  42. const userProfile = await Taro.getUserProfile({
  43. desc: '用于完善用户资料'
  44. }).catch(err => {
  45. if (err.errMsg.includes('deny') || err.errMsg.includes('cancel')) {
  46. throw new Error('用户拒绝授权')
  47. }
  48. throw err
  49. })
  50. // 2. 获取登录code
  51. const loginRes = await Taro.login()
  52. if (!loginRes.code) {
  53. throw new Error('获取登录凭证失败')
  54. }
  55. // 3. 调用后端小程序登录API
  56. const response = await Taro.request({
  57. url: `${process.env.API_BASE_URL || ''}/api/v1/auth/mini-login`,
  58. method: 'POST',
  59. data: {
  60. code: loginRes.code,
  61. userInfo: userProfile.userInfo
  62. },
  63. header: {
  64. 'Content-Type': 'application/json'
  65. }
  66. })
  67. Taro.hideLoading()
  68. if (response.statusCode === 200) {
  69. const { token, user, isNewUser } = response.data
  70. // 4. 保存token和用户信息
  71. Taro.setStorageSync('token', token)
  72. Taro.setStorageSync('userInfo', user)
  73. Taro.showToast({
  74. title: isNewUser ? '注册成功' : '登录成功',
  75. icon: 'success',
  76. duration: 1500
  77. })
  78. // 跳转到首页
  79. setTimeout(() => {
  80. Taro.switchTab({ url: '/pages/index/index' })
  81. }, 1500)
  82. } else {
  83. throw new Error(response.data.message || '登录失败')
  84. }
  85. } catch (error: any) {
  86. Taro.hideLoading()
  87. const errorMessage = error.message || '登录失败'
  88. if (errorMessage.includes('用户拒绝授权')) {
  89. Taro.showModal({
  90. title: '提示',
  91. content: '需要授权才能使用小程序的全部功能',
  92. showCancel: false,
  93. confirmText: '知道了'
  94. })
  95. } else if (errorMessage.includes('网络')) {
  96. Taro.showModal({
  97. title: '网络错误',
  98. content: '请检查网络连接后重试',
  99. showCancel: false,
  100. confirmText: '确定'
  101. })
  102. } else {
  103. Taro.showToast({
  104. title: errorMessage,
  105. icon: 'none',
  106. duration: 3000
  107. })
  108. }
  109. } finally {
  110. setLoading(false)
  111. }
  112. }
  113. const goToAccountLogin = () => {
  114. Taro.navigateBack()
  115. }
  116. return (
  117. <View className="min-h-screen bg-gradient-to-br from-green-50 via-white to-blue-50">
  118. <Navbar
  119. title="微信登录"
  120. backgroundColor="bg-transparent"
  121. textColor="text-gray-900"
  122. border={false}
  123. />
  124. {!isWechatEnv ? (
  125. <View className="flex-1 flex items-center justify-center px-6">
  126. <View className="flex flex-col items-center">
  127. <View className="i-heroicons-exclamation-triangle-20-solid w-16 h-16 text-orange-500 mx-auto mb-4" />
  128. <Text className="text-lg font-semibold text-gray-900 mb-2">当前环境不支持</Text>
  129. <Text className="text-sm text-gray-600 mb-6">
  130. 微信登录功能仅支持在微信小程序中使用
  131. </Text>
  132. <Button
  133. className="w-full max-w-xs"
  134. size="lg"
  135. variant="default"
  136. onClick={goToAccountLogin}
  137. >
  138. <View className="i-heroicons-arrow-left-20-solid w-4 h-4 mr-2" />
  139. 返回账号登录
  140. </Button>
  141. </View>
  142. </View>
  143. ) : (
  144. <View className="flex-1 px-6 py-12">
  145. {/* Logo区域 */}
  146. <View className="flex flex-col items-center mb-10">
  147. <View className="w-20 h-20 mb-4 rounded-full bg-green-100 flex items-center justify-center">
  148. <View className="i-heroicons-chat-bubble-left-right-20-solid w-12 h-12 text-green-500" />
  149. </View>
  150. <Text className="text-2xl font-bold text-gray-900 mb-2">微信一键登录</Text>
  151. <Text className="text-gray-600 text-sm">便捷登录,无需输入账号密码</Text>
  152. </View>
  153. {/* 功能介绍 */}
  154. <View className="bg-white rounded-2xl shadow-sm p-6 mb-8">
  155. <Text className="text-lg font-semibold text-gray-900 mb-4">登录后您将享受</Text>
  156. <View className="space-y-3">
  157. <View className="flex items-center">
  158. <View className="w-2 h-2 bg-green-500 rounded-full mr-3" />
  159. <Text className="text-sm text-gray-700">数据云端同步</Text>
  160. </View>
  161. <View className="flex items-center">
  162. <View className="w-2 h-2 bg-green-500 rounded-full mr-3" />
  163. <Text className="text-sm text-gray-700">个性化推荐</Text>
  164. </View>
  165. <View className="flex items-center">
  166. <View className="w-2 h-2 bg-green-500 rounded-full mr-3" />
  167. <Text className="text-sm text-gray-700">多端数据共享</Text>
  168. </View>
  169. <View className="flex items-center">
  170. <View className="w-2 h-2 bg-green-500 rounded-full mr-3" />
  171. <Text className="text-sm text-gray-700">专属会员权益</Text>
  172. </View>
  173. </View>
  174. </View>
  175. {/* 微信登录按钮 */}
  176. <View className="space-y-4">
  177. <Button
  178. className={cn(
  179. "w-full",
  180. "bg-green-500 text-white hover:bg-green-600",
  181. "border-none"
  182. )}
  183. size="lg"
  184. variant="default"
  185. onClick={handleWechatLogin}
  186. disabled={loading || !isWechatEnv}
  187. loading={loading}
  188. >
  189. <View className="i-heroicons-chat-bubble-left-right-20-solid w-5 h-5 mr-2" />
  190. {loading ? '登录中...' : '微信一键登录'}
  191. </Button>
  192. <Button
  193. className="w-full"
  194. size="lg"
  195. variant="outline"
  196. onClick={goToAccountLogin}
  197. >
  198. <View className="i-heroicons-arrow-left-20-solid w-4 h-4 mr-2" />
  199. 使用账号密码登录
  200. </Button>
  201. </View>
  202. {/* 隐私声明 */}
  203. <View className="mt-8 text-center">
  204. <Text className="text-xs text-gray-500 leading-relaxed">
  205. 点击"微信一键登录"即表示您同意
  206. <Text className="text-blue-500">《用户协议》</Text>
  207. <Text className="text-blue-500">《隐私政策》</Text>
  208. </Text>
  209. <Text className="text-xs text-gray-400 mt-2">
  210. 我们将严格保护您的个人信息安全
  211. </Text>
  212. </View>
  213. </View>
  214. )}
  215. </View>
  216. )
  217. }