Files
medical-mall/utils/sapi.uts
2026-03-18 20:34:55 +08:00

181 lines
6.7 KiB
Plaintext
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.
import supabase, { supaReady } from '@/components/supadb/aksupainstance.uts'
import type { UserProfile } from '@/types/mall-types.uts'
/**
* 确保用户资料存在,如果不存在则创建基础资料
* @param sessionUser 会话用户对象 (UTSJSONObject)
* @returns 创建的用户资料,如果创建失败则返回 null
*/
export async function ensureUserProfile(sessionUser: UTSJSONObject): Promise<UserProfile | null> {
try {
await supaReady
// 从 sessionUser 中获取用户ID和邮箱
const userId = sessionUser.getString('id')
const email = sessionUser.getString('email') ?? ''
if (userId == null || userId === '') {
console.error('无法获取用户ID')
return null
}
// 检查用户是否已存在ak_users 通过 id 或 auth_id 关联 auth.users.id
const checkRes = await supabase.from('ak_users')
.select('*', {})
.or('id.eq.' + userId + ',auth_id.eq.' + userId)
.execute()
console.log('ensureUserProfile check ak_users:', {
status: checkRes.status,
hasData: checkRes.data != null
})
const dataList = checkRes.data
if (checkRes.status >= 200 && checkRes.status < 300 && dataList != null && (dataList as any[]).length > 0) {
// 用户已存在返回现有资料H5 下 checkRes.data 可能是 plain object不一定是 UTSJSONObject
let existingUser: UTSJSONObject
const firstItem = (dataList as any[])[0]
if (firstItem instanceof UTSJSONObject) {
existingUser = firstItem
} else {
existingUser = new UTSJSONObject(firstItem)
}
const currentRole = existingUser.getString('role')
const currentAuthId = existingUser.getString('auth_id')
// 【强力修复逻辑】如果 role 是 student 或者 auth_id 为空,进行 upsert 修复
if (currentRole == 'student' || currentAuthId == null || currentAuthId == '') {
console.log('检测到旧数据异常正在修复角色或关联ID...')
const updateData = new UTSJSONObject()
// updateData.set('id', userId) // update 场景不需要传 ID 在 body 里,通常作为 filter
updateData.set('auth_id', userId)
updateData.set('role', 'consumer')
await supabase.from('ak_users')
.update(updateData)
.eq('id', userId)
.execute()
// 同步 Auth 元数据
try {
const meta = new UTSJSONObject()
meta.set('user_role', 'consumer')
await supabase.updateUserMetadata(meta)
} catch (e) {
console.warn('同步 Auth 元数据失败:', e)
}
// 返回修复后的对象
return {
id: userId,
username: existingUser.getString('username') ?? email.split('@')[0],
email: existingUser.getString('email') ?? email,
role: 'consumer'
} as UserProfile
}
return {
id: userId, // 始终返回 auth.users.id 作为 Profile ID
username: existingUser.getString('username') ?? '',
email: existingUser.getString('email') ?? email,
gender: existingUser.getString('gender'),
birthday: existingUser.getString('birthday'),
height_cm: existingUser.getNumber('height_cm'),
weight_kg: existingUser.getNumber('weight_kg'),
bio: existingUser.getString('bio'),
avatar_url: existingUser.getString('avatar_url'),
preferred_language: existingUser.getString('preferred_language'),
role: existingUser.getString('role') ?? 'consumer',
created_at: existingUser.getString('created_at'),
updated_at: existingUser.getString('updated_at')
} as UserProfile
}
// 用户不存在,创建新用户资料
// 权威字段映射ak_users.auth_id = auth.uid(),业务主键 id 由数据库自动生成
const newUserData = new UTSJSONObject()
newUserData.set('id', userId)
newUserData.set('auth_id', userId) // 确保 auth_id 被存储,解决登录查不到 Profile 的问题
newUserData.set('email', email)
newUserData.set('username', email.split('@')[0] ?? 'user') // 默认用户名为邮箱前缀
//hzb
newUserData.set('role', 'consumer')
// 获取注册时带入的 meta_data 角色信息,在这个端(商家端/管理端)找不到则默认为 merchant
let userRole = 'merchant'
const metadata = sessionUser.getJSON('user_metadata') ?? sessionUser.getJSON('raw_user_meta_data')
if (metadata != null) {
const metaRole = metadata.getString('user_role')
if (metaRole != null && metaRole.trim() !== '') {
userRole = metaRole
}
}
newUserData.set('role', userRole)
//cyh
// newUserData.set('role', 'consumer') // 强制设置为消费者角色
// newUserData.set('created_at', new Date().toISOString()) // 手动设置创建时间
// // 尝试同步更新 Auth 元数据,确保以后登录生成的 JWT 中角色也为 consumer
// try {
// const meta = new UTSJSONObject()
// meta.set('user_role', 'consumer')
// await supabase.updateUserMetadata(meta)
// } catch (e) {
// console.warn('同步 Auth 元数据失败 (非致命):', e)
// }
// console.log('准备插入 ak_users, 目标 ID:', userId)
// console.log('正在执行 insert 资料:', JSON.stringify(newUserData))
const insertRes = await supabase.from('ak_users')
.insert(newUserData)
.select('*', {})
.execute()
console.log('ensureUserProfile insert ak_users 完整结果:', JSON.stringify(insertRes))
if (insertRes.status >= 200 && insertRes.status < 300) {
const dataList = (insertRes.data != null) ? (insertRes.data as any[]) : []
const rawData = dataList.length > 0 ? dataList[0] : null
if (rawData == null) {
console.log('ensureUserProfile: 资料插入操作已完成(200),但未返回数据(可能是 RLS 限制)');
return {
id: userId,
username: email.split('@')[0] ?? 'user',
email: email,
role: 'consumer',
created_at: newUserData.getString('created_at')
} as UserProfile
}
const newUser = (rawData instanceof UTSJSONObject)
? (rawData as UTSJSONObject)
: new UTSJSONObject(rawData)
return {
id: newUser.getString('id') ?? userId,
username: newUser.getString('username') ?? email.split('@')[0],
email: newUser.getString('email') ?? email,
gender: newUser.getString('gender'),
birthday: newUser.getString('birthday'),
height_cm: newUser.getNumber('height_cm'),
weight_kg: newUser.getNumber('weight_kg'),
bio: newUser.getString('bio'),
avatar_url: newUser.getString('avatar_url'),
preferred_language: newUser.getString('preferred_language'),
role: newUser.getString('role') ?? userRole,
created_at: newUser.getString('created_at'),
updated_at: newUser.getString('updated_at')
} as UserProfile
} else {
console.error('创建用户资料失败:', insertRes.status)
return null
}
} catch (error) {
console.error('ensureUserProfile 异常:', error)
return null
}
}