feat(pay): 新增小程序支付页面及相关隐私协议处理

- 新增支付页面组件,实现JSAPI支付流程和多状态页面展示
- 配置支付页面导航条样式和标题
- app.config.ts中添加支付页面路径
- app.tsx中新增微信隐私协议授权弹窗,拦截敏感API授权流程
- api/system/file中导出ensurePrivacyAuthorized用于隐私授权预检
- 登录页和注册页新增useDidShow钩子调用ensurePrivacyAuthorized预检隐私协议
- 登录和注册接口请求迁移至统一request封装,修正响应解构
- 支付流程中新增获取openid和自动登录逻辑,支持未注册用户跳转登录
- 支付成功后通知后端确认并自动跳转到已购产品页面
- 优化支付状态判断逻辑,正确识别支付和订单状态
- 添加错误处理和用户提示,提升支付体验安全性与稳定性
This commit is contained in:
2026-07-16 00:26:42 +08:00
parent 549e8258b6
commit ca78e73f51
7 changed files with 492 additions and 61 deletions

View File

@@ -1,11 +1,13 @@
import { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import Taro, { useDidShow } from '@tarojs/taro'
import { View, Image, Text, Button } from '@tarojs/components'
import { TenantId } from '@/config/app'
import { getWxOpenId } from '@/api/layout'
import { getUserInfo } from '@/api/layout'
import { saveStorageByLoginUser } from '@/utils/server'
import { saveStorageByLoginUser, SERVER_API_URL } from '@/utils/server'
import { isUserDisabled } from '@/utils/auth'
import request from '@/utils/request'
import { ensurePrivacyAuthorized } from '@/api/system/file'
import {
checkAndHandleInviteRelation,
hasPendingInvite,
@@ -72,22 +74,21 @@ async function ensureWxOpenIdSaved() {
}
}
/** 获取用户信息 */
/** 获取用户信息(使用临时 token避免本地 storage 尚未写入) */
async function fetchUserInfo(token: string) {
try {
const serverUrl = 'https://server.websoft.top'
const res: any = await Taro.request({
url: `${serverUrl}/api/auth/user`,
method: 'GET',
header: {
'Authorization': `Bearer ${token}`,
'content-type': 'application/json',
TenantId: String(TenantId),
},
})
if (res.data?.code === 0 && res.data?.data) {
return res.data.data
const res: any = await request.get(
`${SERVER_API_URL}/auth/user`,
{},
{
header: {
Authorization: `Bearer ${token}`,
},
showError: false,
}
)
if (res?.code === 0 && res?.data) {
return res.data
}
return null
} catch (e) {
@@ -109,6 +110,14 @@ const Login = () => {
setTimeout(() => setShowContent(true), 100)
}, [])
/** 页面显示时预检隐私协议,避免 getPhoneNumber 因未授权隐私协议而失败 */
useDidShow(() => {
if (!isWeapp) return
ensurePrivacyAuthorized().catch((e) => {
console.warn('登录页隐私协议预检失败:', e)
})
})
/** 解析 redirect 参数 */
const redirectUrl = (() => {
const raw = (router?.params as Record<string, string> | undefined)?.redirect
@@ -215,23 +224,21 @@ const Login = () => {
const inviteParams = parseInviteParams({ query: router?.params })
const refereeId = inviteParams?.inviter ? parseInt(inviteParams.inviter, 10) : 0
const serverUrl = 'https://server.websoft.top'
const res: any = await Taro.request({
url: `${serverUrl}/api/wx-login/loginByMpWxPhone`,
method: 'POST',
data: {
const res: any = await request.post(
`${SERVER_API_URL}/wx-login/loginByMpWxPhone`,
{
code: phoneCode,
notVerifyPhone: true,
refereeId,
sceneType: 'save_referee',
tenantId: Number(TenantId),
},
header: { 'content-type': 'application/json', TenantId: String(TenantId) },
})
{ showError: false }
)
if (res.data?.code === 0 && res.data?.data?.access_token) {
const token = res.data.data.access_token
let user = res.data.data.user
if (res?.code === 0 && res?.data?.access_token) {
const token = res.data.access_token
let user = res.data.user
// 获取最新的用户信息
const freshUserInfo = await fetchUserInfo(token)
@@ -262,7 +269,7 @@ const Login = () => {
Taro.showToast({ title: '登录成功', icon: 'success' })
setTimeout(() => navigateAfterLogin(), 800)
} else {
Taro.showToast({ title: res.data?.message || '登录失败', icon: 'none' })
Taro.showToast({ title: res?.message || '登录失败', icon: 'none' })
}
} catch (e: any) {
console.error('微信登录失败:', e)