20260203
This commit is contained in:
62
utils/authRedirect.uts
Normal file
62
utils/authRedirect.uts
Normal file
@@ -0,0 +1,62 @@
|
||||
export type AuthRedirectOptions = {
|
||||
loginPath?: string
|
||||
registerPath?: string
|
||||
fallbackUrl?: string
|
||||
}
|
||||
|
||||
function normalizePath(path: string): string {
|
||||
if (!path) return ''
|
||||
return path.startsWith('/') ? path : `/${path}`
|
||||
}
|
||||
|
||||
function safeEncode(url: string): string {
|
||||
try {
|
||||
return encodeURIComponent(url)
|
||||
} catch (_) {
|
||||
return url
|
||||
}
|
||||
}
|
||||
|
||||
export function getCurrentPageUrlWithQuery(): string {
|
||||
const pages = getCurrentPages() as any[]
|
||||
const currentPage = pages.length > 0 ? pages[pages.length - 1] : null
|
||||
if (!currentPage) return ''
|
||||
|
||||
const route = currentPage.route as string | null
|
||||
const options = (currentPage.options ?? {}) as Record<string, any>
|
||||
if (!route) return ''
|
||||
|
||||
const path = normalizePath(route)
|
||||
const keys = Object.keys(options)
|
||||
if (keys.length === 0) return path
|
||||
|
||||
const query = keys
|
||||
.filter((k) => options[k] != null)
|
||||
.map((k) => `${k}=${encodeURIComponent(String(options[k]))}`)
|
||||
.join('&')
|
||||
return query.length > 0 ? `${path}?${query}` : path
|
||||
}
|
||||
|
||||
export function toLoginWithRedirect(redirectUrl?: string, opts?: AuthRedirectOptions) {
|
||||
const loginPath = opts?.loginPath ?? '/pages/user/login'
|
||||
const fallback = opts?.fallbackUrl ?? '/pages/mall/consumer/index'
|
||||
const target = (redirectUrl != null && redirectUrl.length > 0)
|
||||
? redirectUrl
|
||||
: (getCurrentPageUrlWithQuery() || fallback)
|
||||
|
||||
uni.navigateTo({
|
||||
url: `${loginPath}?redirect=${safeEncode(target)}`
|
||||
})
|
||||
}
|
||||
|
||||
export function toRegisterWithRedirect(redirectUrl?: string, opts?: AuthRedirectOptions) {
|
||||
const registerPath = opts?.registerPath ?? '/pages/user/register'
|
||||
const fallback = opts?.fallbackUrl ?? '/pages/mall/consumer/index'
|
||||
const target = (redirectUrl != null && redirectUrl.length > 0)
|
||||
? redirectUrl
|
||||
: (getCurrentPageUrlWithQuery() || fallback)
|
||||
|
||||
uni.navigateTo({
|
||||
url: `${registerPath}?redirect=${safeEncode(target)}`
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { supabase, ensureSupabaseReady } from '@/components/supadb/aksupainstance.uts'
|
||||
import supabase, { supaReady } from '@/components/supadb/aksupainstance.uts'
|
||||
import type { UserProfile } from '@/types/mall-types.uts'
|
||||
|
||||
/**
|
||||
@@ -8,8 +8,8 @@ import type { UserProfile } from '@/types/mall-types.uts'
|
||||
*/
|
||||
export async function ensureUserProfile(sessionUser: UTSJSONObject): Promise<UserProfile | null> {
|
||||
try {
|
||||
await ensureSupabaseReady()
|
||||
|
||||
await supaReady
|
||||
|
||||
// 从 sessionUser 中获取用户ID和邮箱
|
||||
const userId = sessionUser.getString('id')
|
||||
const email = sessionUser.getString('email') ?? ''
|
||||
@@ -19,16 +19,25 @@ export async function ensureUserProfile(sessionUser: UTSJSONObject): Promise<Use
|
||||
return null
|
||||
}
|
||||
|
||||
// 检查用户是否已存在
|
||||
// 检查用户是否已存在(ak_users 通过 auth_id 关联 auth.users.id)
|
||||
const checkRes = await supabase.from('ak_users')
|
||||
.select('*', {})
|
||||
.eq('id', userId)
|
||||
.eq('auth_id', userId)
|
||||
.single()
|
||||
.execute()
|
||||
|
||||
console.log('ensureUserProfile check ak_users:', {
|
||||
status: checkRes.status,
|
||||
hasData: checkRes.data != null,
|
||||
hasError: (checkRes as any).error != null,
|
||||
error: (checkRes as any).error
|
||||
})
|
||||
|
||||
if (checkRes.status >= 200 && checkRes.status < 300 && checkRes.data != null) {
|
||||
// 用户已存在,返回现有资料
|
||||
const existingUser = checkRes.data as UTSJSONObject
|
||||
// 用户已存在,返回现有资料(H5 下 checkRes.data 可能是 plain object,不一定是 UTSJSONObject)
|
||||
const existingUser = (typeof (checkRes.data as any).getString === 'function')
|
||||
? (checkRes.data as UTSJSONObject)
|
||||
: new UTSJSONObject(checkRes.data as any)
|
||||
return {
|
||||
id: existingUser.getString('id') ?? '',
|
||||
username: existingUser.getString('username') ?? '',
|
||||
@@ -58,8 +67,17 @@ export async function ensureUserProfile(sessionUser: UTSJSONObject): Promise<Use
|
||||
.single()
|
||||
.execute()
|
||||
|
||||
console.log('ensureUserProfile insert ak_users:', {
|
||||
status: insertRes.status,
|
||||
hasData: insertRes.data != null,
|
||||
hasError: (insertRes as any).error != null,
|
||||
error: (insertRes as any).error
|
||||
})
|
||||
|
||||
if (insertRes.status >= 200 && insertRes.status < 300 && insertRes.data != null) {
|
||||
const newUser = insertRes.data as UTSJSONObject
|
||||
const newUser = (typeof (insertRes.data as any).getString === 'function')
|
||||
? (insertRes.data as UTSJSONObject)
|
||||
: new UTSJSONObject(insertRes.data as any)
|
||||
return {
|
||||
id: newUser.getString('id') ?? '',
|
||||
username: newUser.getString('username') ?? '',
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { supabase as supa, ensureSupabaseReady } from '@/components/supadb/aksupainstance.uts'
|
||||
import supa, { supaReady } from '@/components/supadb/aksupainstance.uts'
|
||||
import type { UserProfile, UserStats } from '@/pages/user/types.uts'
|
||||
import type { DeviceInfo } from '@/pages/sense/types.uts'
|
||||
import { SenseDataService, type DeviceParams } from '@/pages/sense/senseDataService.uts'
|
||||
@@ -50,7 +50,7 @@ export const setUserProfile = (profile : UserProfile) => {
|
||||
// 获取当前用户信息(含补全 profile)
|
||||
export async function getCurrentUser() : Promise<UserProfile | null> {
|
||||
try {
|
||||
await ensureSupabaseReady()
|
||||
await supaReady
|
||||
} catch (_) {}
|
||||
|
||||
const sessionInfo = supa.getSession()
|
||||
|
||||
@@ -149,6 +149,20 @@ export function responsiveState() {
|
||||
}
|
||||
}
|
||||
|
||||
export function goToLogin(redirectUrl?: string | null) {
|
||||
try {
|
||||
const target = redirectUrl != null && redirectUrl.length > 0 ? redirectUrl : ''
|
||||
if (target.length > 0) {
|
||||
const redirect = encodeURIComponent(target)
|
||||
uni.navigateTo({ url: `/pages/user/login?redirect=${redirect}` })
|
||||
} else {
|
||||
uni.navigateTo({ url: '/pages/user/login' })
|
||||
}
|
||||
} catch (e) {
|
||||
uni.navigateTo({ url: '/pages/user/login' })
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容 UTS Android 的剪贴板写入
|
||||
* @param text 要写入剪贴板的文本
|
||||
@@ -159,3 +173,29 @@ export function setClipboard(text: string): void {
|
||||
// #endif
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间,显示为相对时间(如:刚刚,几小时前)
|
||||
* @param dateStr ISO 格式的日期字符串
|
||||
* @returns 格式化后的相对时间字符串
|
||||
*/
|
||||
export function formatTime(dateStr: string): string {
|
||||
if (!dateStr) return ''
|
||||
try {
|
||||
const date = new Date(dateStr)
|
||||
const now = new Date()
|
||||
const diff = now.getTime() - date.getTime()
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60))
|
||||
|
||||
if (hours < 1) {
|
||||
return '刚刚'
|
||||
} else if (hours < 24) {
|
||||
return `${hours}小时前`
|
||||
} else {
|
||||
return `${Math.floor(hours / 24)}天前`
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('formatTime error:', e)
|
||||
return dateStr.replace('T', ' ').split('.')[0]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user