初步完成merchant和admin不同role的展示内容逻辑2
This commit is contained in:
@@ -26,7 +26,7 @@ export function checkConnection() {
|
||||
}
|
||||
|
||||
// 兼容 supaReady Promise
|
||||
export const supaReady = Promise.resolve(true)
|
||||
export const supaReady = supaInstance.hydrateSessionFromStorage()
|
||||
|
||||
// 如果有其他需要导出的函数,可以这样导出:
|
||||
export function initializeSupabase(url: string, key: string) {
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
<template>
|
||||
<view class="layout-root">
|
||||
<view v-if="!isAuthReady" class="auth-loading-overlay" style="flex: 1; display: flex; align-items: center; justify-content: center; height: 100vh; background-color: #f5f5f5;">
|
||||
<text style="color: #666; font-size: 16px;">身份鉴权中...</text>
|
||||
</view>
|
||||
<template v-else>
|
||||
<!-- 统一遮罩层 (复刻 CRMEB: 用于所有 Overlay 状态) -->
|
||||
<view
|
||||
class="mobile-mask"
|
||||
@@ -70,6 +74,7 @@
|
||||
<AdminFooter></AdminFooter>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@@ -131,6 +136,7 @@ const SUB_W = 200
|
||||
|
||||
// 页面加载状态
|
||||
const isPageLoading = ref(false)
|
||||
const isAuthReady = ref(false)
|
||||
|
||||
const hasAccess = computed<boolean>(() => {
|
||||
|
||||
@@ -391,6 +397,7 @@ let resizeTid: any = null
|
||||
|
||||
onMounted(async () => {
|
||||
await refreshAdminRole()
|
||||
isAuthReady.value = true
|
||||
initNavState()
|
||||
if (props.currentPage != '') {
|
||||
openRoute(props.currentPage as string)
|
||||
|
||||
@@ -62,10 +62,18 @@ import {
|
||||
openRoute
|
||||
} from '@/layouts/admin/store/adminNavStore.uts'
|
||||
import { state, logout } from '@/utils/store.uts'
|
||||
import { clearAdminRoleCache } from '@/layouts/admin/utils/role.uts'
|
||||
import { clearAdminRoleCache, getCurrentAdminRole } from '@/layouts/admin/utils/role.uts'
|
||||
|
||||
const showUserMenu = ref(false)
|
||||
const userName = computed((): string => state.userProfile.username || state.userProfile.email || 'admin')
|
||||
const userName = computed((): string => {
|
||||
if (state.userProfile?.username != null && state.userProfile!.username != '') return state.userProfile!.username as string
|
||||
if (state.authUser != null) {
|
||||
if (state.authUser!.getString('email') != null && state.authUser!.getString('email') != '') return state.authUser!.getString('email') as string
|
||||
if (state.authUser!.getString('phone') != null && state.authUser!.getString('phone') != '') return state.authUser!.getString('phone') as string
|
||||
if (state.authUser!.getString('id') != null && state.authUser!.getString('id') != '') return (state.authUser!.getString('id') as string).substring(0, 8)
|
||||
}
|
||||
return '未知用户'
|
||||
})
|
||||
|
||||
let hideMenuTimer: number | null = null
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { state, getCurrentUser } from '@/utils/store.uts'
|
||||
import { state, getCurrentUser } from '@/utils/store.uts'
|
||||
import supa from '@/components/supadb/aksupainstance.uts'
|
||||
|
||||
/**
|
||||
@@ -38,26 +38,18 @@ export function getCurrentAdminRole(): string {
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 缓存兜底:为了刷新页面时立刻渲染,读取最新的 adminRole 缓存
|
||||
const cachedRole = uni.getStorageSync('adminRole')
|
||||
if (cachedRole != null && cachedRole != '') {
|
||||
const normCached = normalizeRole(cachedRole)
|
||||
if (normCached === 'admin' || normCached === 'merchant') {
|
||||
return normCached
|
||||
// 2. Auth Session兜底获取(Tab 隔离):
|
||||
const sessionUser = supa.getSession().user
|
||||
if (sessionUser != null) {
|
||||
const meta = sessionUser.get("user_metadata") as UTSJSONObject | null
|
||||
if (meta != null && meta.getString("role") != null) {
|
||||
const metaRole = normalizeRole(meta.getString("role"))
|
||||
if (metaRole === "admin" || metaRole === "merchant") return metaRole
|
||||
}
|
||||
}
|
||||
|
||||
// 兼容旧的缓存字段以防万一
|
||||
const oldCached = uni.getStorageSync('admin_role')
|
||||
if (oldCached != null && oldCached != '') {
|
||||
const normOld = normalizeRole(oldCached)
|
||||
if (normOld === 'admin' || normOld === 'merchant') {
|
||||
return normOld
|
||||
}
|
||||
}
|
||||
|
||||
console.warn('[AdminRole] 未能获取到有效的管理端角色,准备安全降级...')
|
||||
return 'unknown'
|
||||
|
||||
console.warn("[AdminRole] 未能获取到有效的管理端角色,准备安全降级...")
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,6 +59,7 @@ export function clearAdminRoleCache(): void {
|
||||
// 清理 admin 专属
|
||||
uni.removeStorageSync('adminRole')
|
||||
uni.removeStorageSync('admin_role')
|
||||
uni.removeStorageSync('merchant_id')
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +85,7 @@ export async function refreshAdminRole(): Promise<string> {
|
||||
}
|
||||
|
||||
if (finalRole !== 'unknown') {
|
||||
uni.setStorageSync('adminRole', finalRole)
|
||||
// uni.setStorageSync('adminRole', finalRole) // 移除缓存耦合,强制按单例会话状态刷新
|
||||
if (state.userProfile != null) {
|
||||
state.userProfile!.role = finalRole
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<view class="product-edit-page">
|
||||
<view class="page-header">
|
||||
<view class="back-link" @click="goBack">
|
||||
@@ -186,7 +186,7 @@ const categoryName = ref('')
|
||||
|
||||
onMounted(async () => {
|
||||
await ensureSupabaseReady()
|
||||
const mId = uni.getStorageSync('merchant_id') as string | null
|
||||
const mId = supa.getSession().user?.id as string | null
|
||||
if (!mId) {
|
||||
uni.showToast({ title: '商家未获取到信息,请重新登录', icon: 'none' })
|
||||
return
|
||||
@@ -346,7 +346,7 @@ async function doSaveProduct(targetStatus: number) {
|
||||
|
||||
// 必须获取正确的 merchant_id,并且存在
|
||||
if (!formData.value.merchant_id || formData.value.merchant_id.startsWith('merchant_123')) {
|
||||
const mId = uni.getStorageSync('merchant_id') as string | null
|
||||
const mId = supa.getSession().user?.id as string | null
|
||||
if (!mId) {
|
||||
uni.showToast({ title: '未获取到商家信息,请重新登录', icon: 'none' })
|
||||
return
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<template>
|
||||
<template>
|
||||
<view class="product-list-page">
|
||||
<!-- 1. 搜索表单 -->
|
||||
<view class="search-card">
|
||||
@@ -197,7 +197,7 @@ async function fetchProducts() {
|
||||
await ensureSupabaseReady()
|
||||
|
||||
// 从本地缓存获取 current merchant_id
|
||||
const currentMerchantId = uni.getStorageSync('merchant_id') as string | null
|
||||
const currentMerchantId = supa.getSession().user?.id as string | null
|
||||
|
||||
if (!currentMerchantId) {
|
||||
uni.showToast({ title: '未获取到商家信息,请重新登录', icon: 'none' })
|
||||
|
||||
@@ -398,10 +398,10 @@ const handleLogin = async () => {
|
||||
|
||||
const currRole = accessData.getString('role')
|
||||
const currId = accessData.getString('id')
|
||||
uni.setStorageSync('adminRole', currRole)
|
||||
// uni.setStorageSync('adminRole', currRole) // 移除本地缓存依赖,强制按单例会话状态
|
||||
|
||||
if (currRole === 'merchant') {
|
||||
uni.setStorageSync('merchant_id', currId)
|
||||
// uni.setStorageSync('merchant_id', currId) // 移除本地缓存依赖,强制按单例会话状态
|
||||
} else {
|
||||
uni.removeStorageSync('merchant_id')
|
||||
}
|
||||
|
||||
35
process.py
Normal file
35
process.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import re
|
||||
|
||||
with open(r'c:\Users\黄镇堡\AppData\Roaming\Code\User\workspaceStorage\51c4c3615fa7807ba1c5a788ca077b83\GitHub.copilot-chat\chat-session-resources\18954447-db08-4bea-a5c4-72e8c9aaf171\call_MHxIMm13YmUwWkdUcjI5b3pueHM__vscode-1773276031647\content.txt', 'r', encoding='utf-8') as f:
|
||||
text = f.read()
|
||||
|
||||
auth_lines = []
|
||||
bz_lines = []
|
||||
|
||||
auth_kw = ['token', 'user', 'role', 'merchant', 'admin', 'auth', 'id']
|
||||
|
||||
for line in text.split('\n'):
|
||||
if not line.strip(): continue
|
||||
|
||||
match = re.match(r'^([a-zA-Z]:\\.*?):(\d+):\s*(.*)$', line)
|
||||
if match:
|
||||
path = match.group(1)
|
||||
lineno = match.group(2)
|
||||
content = match.group(3)
|
||||
fname = path.split(r'\\')[-1]
|
||||
|
||||
is_auth = any(k in content.lower() for k in auth_kw)
|
||||
output = f'{fname}:{lineno}: {content}'
|
||||
if is_auth:
|
||||
auth_lines.append(output)
|
||||
else:
|
||||
bz_lines.append(output)
|
||||
|
||||
print(f'=== AUTH CACHE USAGES ===')
|
||||
for l in auth_lines:
|
||||
if 'ak-req.uts' not in l and 'aksupa.uts' not in l:
|
||||
print(l[:100])
|
||||
|
||||
print(f'\n=== BZ CACHE USAGES (first 20) ===')
|
||||
for l in bz_lines[:20]:
|
||||
print(l[:100])
|
||||
14
search_user_id.py
Normal file
14
search_user_id.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import os
|
||||
for root, dirs, files in os.walk(r'd:\骅锋\mall'):
|
||||
if 'node_modules' in root or '.git' in root or 'unpackage' in root: continue
|
||||
for f in files:
|
||||
if f.endswith(('.uts', '.uvue')):
|
||||
path = os.path.join(root, f)
|
||||
with open(path, 'r', encoding='utf-8') as file:
|
||||
try:
|
||||
lines = file.readlines()
|
||||
for i, l in enumerate(lines):
|
||||
if 'setStorageSync' in l and 'user_id' in l:
|
||||
print(f'{path}:{i+1}: {l.strip()}')
|
||||
except:
|
||||
pass
|
||||
@@ -7,6 +7,29 @@ const REFRESH_TOKEN_KEY = 'akreq_refresh_token';
|
||||
const EXPIRES_AT_KEY = 'akreq_expires_at';
|
||||
|
||||
// 优化:用静态变量缓存 token,只有 set/clear 时同步 storage
|
||||
|
||||
// Web 端(H5)由于多账号联调需要,开启单 Tab 隔离的储流(sessionStorage)
|
||||
function setAuthStore(key : string, value : any) {
|
||||
// #ifdef H5
|
||||
sessionStorage.setItem(key, String(value));
|
||||
return;
|
||||
// #endif
|
||||
uni.setStorageSync(key, value);
|
||||
}
|
||||
function getAuthStore(key : string) : any | null {
|
||||
// #ifdef H5
|
||||
return sessionStorage.getItem(key);
|
||||
// #endif
|
||||
return uni.getStorageSync(key);
|
||||
}
|
||||
function removeAuthStore(key : string) {
|
||||
// #ifdef H5
|
||||
sessionStorage.removeItem(key);
|
||||
return;
|
||||
// #endif
|
||||
uni.removeStorageSync(key);
|
||||
}
|
||||
|
||||
let _accessToken : string | null = null;
|
||||
let _refreshToken : string | null = null;
|
||||
let _expiresAt : number | null = null;
|
||||
@@ -16,25 +39,25 @@ export class AkReq {
|
||||
_accessToken = token;
|
||||
_refreshToken = refreshToken;
|
||||
_expiresAt = expiresAt;
|
||||
uni.setStorageSync(ACCESS_TOKEN_KEY, token);
|
||||
uni.setStorageSync(REFRESH_TOKEN_KEY, refreshToken);
|
||||
uni.setStorageSync(EXPIRES_AT_KEY, expiresAt);
|
||||
setAuthStore(ACCESS_TOKEN_KEY, token);
|
||||
setAuthStore(REFRESH_TOKEN_KEY, refreshToken);
|
||||
setAuthStore(EXPIRES_AT_KEY, expiresAt);
|
||||
}
|
||||
static getToken() : string | null {
|
||||
if (_accessToken != null) return _accessToken;
|
||||
const t = uni.getStorageSync(ACCESS_TOKEN_KEY) as string | null;
|
||||
const t = getAuthStore(ACCESS_TOKEN_KEY) as string | null;
|
||||
_accessToken = t;
|
||||
return t;
|
||||
}
|
||||
static getRefreshToken() : string | null {
|
||||
if (_refreshToken != null) return _refreshToken;
|
||||
const t = uni.getStorageSync(REFRESH_TOKEN_KEY) as string | null;
|
||||
const t = getAuthStore(REFRESH_TOKEN_KEY) as string | null;
|
||||
_refreshToken = t;
|
||||
return t;
|
||||
} static getExpiresAt() : number | null {
|
||||
const val = _expiresAt;
|
||||
if (val != null) return val;
|
||||
const t = uni.getStorageSync(EXPIRES_AT_KEY) as number | null;
|
||||
const t = getAuthStore(EXPIRES_AT_KEY) as number | null;
|
||||
_expiresAt = t;
|
||||
return t;
|
||||
}
|
||||
@@ -42,9 +65,9 @@ export class AkReq {
|
||||
_accessToken = null;
|
||||
_refreshToken = null;
|
||||
_expiresAt = null;
|
||||
uni.removeStorageSync(ACCESS_TOKEN_KEY);
|
||||
uni.removeStorageSync(REFRESH_TOKEN_KEY);
|
||||
uni.removeStorageSync(EXPIRES_AT_KEY);
|
||||
removeAuthStore(ACCESS_TOKEN_KEY);
|
||||
removeAuthStore(REFRESH_TOKEN_KEY);
|
||||
removeAuthStore(EXPIRES_AT_KEY);
|
||||
} // 判断 token 是否即将过期(提前5分钟刷新)
|
||||
static isTokenExpiring() : boolean {
|
||||
const expiresAt = this.getExpiresAt();
|
||||
|
||||
@@ -17,6 +17,7 @@ export type DeviceState = {
|
||||
export type State = {
|
||||
globalNum : number
|
||||
userProfile ?: UserProfile
|
||||
authUser ?: UTSJSONObject
|
||||
isLoggedIn : boolean // 新增字段
|
||||
deviceState : DeviceState // 新增设备状态
|
||||
// 如有需要,可增加更多属性
|
||||
@@ -26,6 +27,7 @@ export type State = {
|
||||
export const state = reactive({
|
||||
globalNum: 0,
|
||||
userProfile: { username: '', email: '' },
|
||||
authUser: null,
|
||||
isLoggedIn: false,
|
||||
deviceState: {
|
||||
devices: [],
|
||||
@@ -54,6 +56,7 @@ export async function getCurrentUser() : Promise<UserProfile | null> {
|
||||
} catch (_) {}
|
||||
|
||||
const sessionInfo = supa.getSession()
|
||||
state.authUser = sessionInfo.user
|
||||
if (sessionInfo.user == null) {
|
||||
state.userProfile = { username: '', email: '' }
|
||||
state.isLoggedIn = false // 未登录
|
||||
@@ -174,6 +177,7 @@ export function getUserStore() {
|
||||
return {
|
||||
getUserId() : string | null {
|
||||
const sessionInfo = supa.getSession()
|
||||
state.authUser = sessionInfo.user
|
||||
return sessionInfo.user?.getString("id") ?? null
|
||||
},
|
||||
|
||||
@@ -184,6 +188,7 @@ export function getUserStore() {
|
||||
getUserRole() : string | null {
|
||||
// Default role logic - can be enhanced based on your needs
|
||||
const sessionInfo = supa.getSession()
|
||||
state.authUser = sessionInfo.user
|
||||
if (sessionInfo.user == null) return null
|
||||
|
||||
// You can add role detection logic here
|
||||
|
||||
Reference in New Issue
Block a user