import supa from '@/components/supadb/aksupainstance.uts' // ───────────────────────────────────────────────────────────── // akUserMapping - Supabase Auth ID 到业务用户 ID 的映射管理 // // 核心概念: // - authUserId: Supabase Auth 用户 ID(session.user.id) // - akUserId: 业务用户 ID(ak_users.id) // - 所有业务表(ec_care_tasks.assigned_to、hc_dispatch_assignments.worker_id 等) // 都使用 akUserId,不是 authUserId // ───────────────────────────────────────────────────────────── const AUTH_USER_ID_KEY = 'auth_user_id' // Supabase Auth ID const AK_USER_ID_KEY = 'ak_user_id' // 业务用户 ID const AK_USER_PROFILE_KEY = 'current_ak_user' // 完整业务用户信息 export type AkUserProfile = { id: string // ak_users.id(业务用户 ID) auth_id: string // ak_users.auth_id(Supabase Auth ID) username: string email: string role: string user_type: string status: string } /** * 加载当前登录用户的业务账号信息 * 查询顺序: * 1. auth_id = session.user.id * 2. id = uni.getStorageSync('user_id') * 3. email = 当前登录邮箱 * 4. 最后才失败 */ export async function loadCurrentAkUser(): Promise { // 1. 获取当前 Supabase Auth 用户 const session = supa.getSession() if (session == null || session.user == null) { throw new Error('未登录或登录状态失效') } const authUserId = session.user.getString('id') ?? '' if (authUserId == '') { throw new Error('未获取到 Supabase Auth 用户 ID') } // 2. 查询 ak_users 表,通过 auth_id 匹配 console.log('[akUserMapping] 尝试通过 auth_id 查询:', authUserId) let { data: profiles, error } = await supa .from('ak_users') .select('id, auth_id, username, email, role, user_type, status') .eq('auth_id', authUserId) .single() if (error == null && profiles != null) { console.log('[akUserMapping] 通过 auth_id 查询成功') } else { console.warn('[akUserMapping] auth_id 查询失败:', error?.message ?? '未知错误') // 3. 尝试通过 user_id 缓存查询 const cachedUserId = uni.getStorageSync('user_id') if (cachedUserId != null && String(cachedUserId).length > 0) { console.log('[akUserMapping] 尝试通过 user_id 缓存查询:', cachedUserId) const { data: profilesById, error: errorById } = await supa .from('ak_users') .select('id, auth_id, username, email, role, user_type, status') .eq('id', cachedUserId) .single() if (errorById == null && profilesById != null) { profiles = profilesById error = null console.log('[akUserMapping] 通过 user_id 缓存查询成功') } else { console.warn('[akUserMapping] user_id 缓存查询失败:', errorById?.message ?? '未知错误') } } // 4. 尝试通过 session 中的 email 查询 if (profiles == null) { const userEmail = session.user.getString('email') ?? '' if (userEmail != '') { console.log('[akUserMapping] 尝试通过 email 查询:', userEmail) const { data: profilesByEmail, error: errorByEmail } = await supa .from('ak_users') .select('id, auth_id, username, email, role, user_type, status') .eq('email', userEmail) .single() if (errorByEmail == null && profilesByEmail != null) { profiles = profilesByEmail error = null console.log('[akUserMapping] 通过 email 查询成功') } else { console.warn('[akUserMapping] email 查询失败:', errorByEmail?.message ?? '未知错误') } } } } if (error != null || profiles == null) { console.error('[akUserMapping] ❌ 所有查询方式都失败') console.error('[akUserMapping] authUserId:', authUserId) console.error('[akUserMapping] user_id 缓存:', uni.getStorageSync('user_id')) console.error('[akUserMapping] session email:', session.user?.getString('email')) throw new Error('未找到当前用户的业务账号,请联系管理员绑定 ak_users.auth_id') } // 5. 存储到本地 const profile: AkUserProfile = { id: profiles.getString('id') ?? '', auth_id: profiles.getString('auth_id') ?? '', username: profiles.getString('username') ?? '', email: profiles.getString('email') ?? '', role: profiles.getString('role') ?? '', user_type: profiles.getString('user_type') ?? '', status: profiles.getString('status') ?? '' } uni.setStorageSync(AUTH_USER_ID_KEY, profile.auth_id) uni.setStorageSync(AK_USER_ID_KEY, profile.id) uni.setStorageSync(AK_USER_PROFILE_KEY, JSON.stringify(profile)) console.log('[akUserMapping] 加载业务用户成功:', { authUserId: profile.auth_id, akUserId: profile.id, username: profile.username, role: profile.role }) return profile } /** * 获取当前业务用户 ID(ak_users.id) * 优先级: * 1. uni.getStorageSync('ak_user_id') * 2. uni.getStorageSync('current_ak_user').id * 3. uni.getStorageSync('user_info').id * 4. uni.getStorageSync('userInfo').id * 5. uni.getStorageSync('user').id * 6. uni.getStorageSync('uid') * 7. uni.getStorageSync('user_id') * 8. uni.getStorageSync('auth_user_id') * 9. 最后再请求 ak_users 表或 RPC resolve_ak_user_id */ export async function getCurrentAkUserId(): Promise { // 1. 尝试从 ak_user_id 缓存读取 const cachedAkUserId = uni.getStorageSync(AK_USER_ID_KEY) if (cachedAkUserId != null && String(cachedAkUserId).length > 0) { const result = String(cachedAkUserId) console.log('[akUserMapping] getCurrentAkUserId: 从 ak_user_id 缓存读取:', result) return result } // 2. 尝试从 current_ak_user 缓存读取 const cachedProfile = uni.getStorageSync(AK_USER_PROFILE_KEY) if (cachedProfile != null && String(cachedProfile).length > 0) { try { const profile = JSON.parse(cachedProfile) as AkUserProfile if (profile.id != null && profile.id !== '') { const result = profile.id console.log('[akUserMapping] getCurrentAkUserId: 从 current_ak_user 缓存读取:', result) return result } } catch (e) { console.warn('[akUserMapping] getCurrentAkUserId: 解析 current_ak_user 失败:', e) } } // 3. 尝试从 user_info 缓存读取 try { const cachedUserInfo = uni.getStorageSync('user_info') if (cachedUserInfo != null && String(cachedUserInfo).length > 0) { try { const userInfo = JSON.parse(cachedUserInfo) as any if (userInfo != null && userInfo.id != null && String(userInfo.id).length > 0) { const result = String(userInfo.id) console.log('[akUserMapping] getCurrentAkUserId: 从 user_info 缓存读取:', result) return result } } catch (e) { console.warn('[akUserMapping] getCurrentAkUserId: 解析 user_info 失败:', e) } } } catch (e) { console.warn('[akUserMapping] getCurrentAkUserId: user_info 读取失败:', e) } // 4. 尝试从 userInfo 缓存读取 try { const cachedUserInfo = uni.getStorageSync('userInfo') if (cachedUserInfo != null && String(cachedUserInfo).length > 0) { try { const userInfo = JSON.parse(cachedUserInfo) as any if (userInfo != null && userInfo.id != null && String(userInfo.id).length > 0) { const result = String(userInfo.id) console.log('[akUserMapping] getCurrentAkUserId: 从 userInfo 缓存读取:', result) return result } } catch (e) { console.warn('[akUserMapping] getCurrentAkUserId: 解析 userInfo 失败:', e) } } } catch (e) { console.warn('[akUserMapping] getCurrentAkUserId: userInfo 读取失败:', e) } // 5. 尝试从 user 缓存读取 try { const cachedUser = uni.getStorageSync('user') if (cachedUser != null && String(cachedUser).length > 0) { try { const user = JSON.parse(cachedUser) as any if (user != null && user.id != null && String(user.id).length > 0) { const result = String(user.id) console.log('[akUserMapping] getCurrentAkUserId: 从 user 缓存读取:', result) return result } } catch (e) { console.warn('[akUserMapping] getCurrentAkUserId: 解析 user 失败:', e) } } } catch (e) { console.warn('[akUserMapping] getCurrentAkUserId: user 读取失败:', e) } // 6. 尝试从 uid 缓存读取 const cachedUid = uni.getStorageSync('uid') if (cachedUid != null && String(cachedUid).length > 0) { const result = String(cachedUid) console.log('[akUserMapping] getCurrentAkUserId: 从 uid 缓存读取:', result) return result } // 7. 尝试从 user_id 缓存读取 const cachedUserId = uni.getStorageSync('user_id') if (cachedUserId != null && String(cachedUserId).length > 0) { const result = String(cachedUserId) console.log('[akUserMapping] getCurrentAkUserId: 从 user_id 缓存读取:', result) return result } // 8. 尝试从 auth_user_id 缓存读取(可能是 Supabase Auth ID,需要转换) const cachedAuthUserId = uni.getStorageSync(AUTH_USER_ID_KEY) if (cachedAuthUserId != null && String(cachedAuthUserId).length > 0) { const authId = String(cachedAuthUserId) console.log('[akUserMapping] getCurrentAkUserId: 从 auth_user_id 缓存读取到 Auth ID:', authId) // 禁止直接返回 auth_user_id,必须通过 RPC 或 ak_users 表转换 console.log('[akUserMapping] 尝试通过 RPC resolve_ak_user_id 转换 Auth ID') try { const rpcParams = { p_auth_user_id: authId } as UTSJSONObject const { data: resolvedData, error: resolveError } = await supa .rpc('resolve_ak_user_id', rpcParams) if (resolveError == null && resolvedData != null) { const akUserId = String(resolvedData) if (akUserId != '' && akUserId != 'null') { console.log('[akUserMapping] RPC 转换成功,akUserId:', akUserId) // 缓存 akUserId uni.setStorageSync(AK_USER_ID_KEY, akUserId) return akUserId } } console.warn('[akUserMapping] RPC 转换失败:', resolveError?.message ?? '未知错误') } catch (rpcErr) { console.warn('[akUserMapping] RPC 转换异常:', rpcErr) } // 如果 RPC 失败,尝试通过 ak_users 表查询 console.log('[akUserMapping] 尝试通过 ak_users 表查询 auth_id 映射') const { data: profiles, error } = await supa .from('ak_users') .select('id') .eq('auth_id', authId) .single() if (error == null && profiles != null) { const akUserId = profiles.getString('id') ?? '' if (akUserId != '') { console.log('[akUserMapping] ak_users 表查询成功,akUserId:', akUserId) uni.setStorageSync(AK_USER_ID_KEY, akUserId) return akUserId } } console.warn('[akUserMapping] ak_users 表查询也失败') } // 9. 最后尝试从 Supabase session 查询 ak_users try { const session = supa.getSession() if (session != null && session.user != null) { const authUserId = session.user.getString('id') ?? '' if (authUserId != '') { console.log('[akUserMapping] getCurrentAkUserId: 尝试从 Supabase session 查询 ak_users, authUserId:', authUserId) const { data: profiles, error } = await supa .from('ak_users') .select('id') .eq('auth_id', authUserId) .single() if (error == null && profiles != null) { const akUserId = profiles.getString('id') ?? '' if (akUserId != '') { console.log('[akUserMapping] getCurrentAkUserId: Supabase 查询成功:', akUserId) // 缓存结果 uni.setStorageSync(AK_USER_ID_KEY, akUserId) return akUserId } } console.warn('[akUserMapping] getCurrentAkUserId: Supabase 查询未找到 ak_users 记录') } } } catch (e) { console.warn('[akUserMapping] getCurrentAkUserId: Supabase 查询失败:', e) } // 10. 全部失败,返回空字符串(不 throw) console.warn('[akUserMapping] getCurrentAkUserId: 所有降级策略失败,返回空字符串') return '' } /** * 获取当前业务用户完整信息 */ export async function getCurrentAkUser(): Promise { // 1. 尝试从缓存读取 const cached = uni.getStorageSync(AK_USER_PROFILE_KEY) if (cached != null && String(cached).length > 0) { try { return JSON.parse(cached) as AkUserProfile } catch (e) { // 解析失败,重新加载 } } // 2. 缓存不存在,自动加载 try { return await loadCurrentAkUser() } catch (e) { return null } } /** * 获取当前 Supabase Auth 用户 ID */ export function getCurrentAuthUserId(): string { const cached = uni.getStorageSync(AUTH_USER_ID_KEY) if (cached != null && String(cached).length > 0) { return String(cached) } // 尝试从 session 获取 try { const session = supa.getSession() if (session != null && session.user != null) { return session.user.getString('id') ?? '' } } catch (e) {} return '' } /** * 清除本地存储的 ak_user 信息 */ export function clearAkUserCache(): void { uni.removeStorageSync(AUTH_USER_ID_KEY) uni.removeStorageSync(AK_USER_ID_KEY) uni.removeStorageSync(AK_USER_PROFILE_KEY) } /** * 调试输出:打印当前用户信息 */ export function debugCurrentUser(): void { console.log('[akUserMapping] ========== 当前用户调试信息 ==========') console.log('[akUserMapping] authUserId:', uni.getStorageSync(AUTH_USER_ID_KEY)) console.log('[akUserMapping] akUserId:', uni.getStorageSync(AK_USER_ID_KEY)) const profileRaw = uni.getStorageSync(AK_USER_PROFILE_KEY) if (profileRaw != null && String(profileRaw).length > 0) { try { const profile = JSON.parse(profileRaw) as AkUserProfile console.log('[akUserMapping] profile:', profile) } catch (e) { console.log('[akUserMapping] profile (raw):', profileRaw) } } else { console.log('[akUserMapping] profile: (未缓存)') } console.log('[akUserMapping] ======================================') }