20260809223428

This commit is contained in:
oneao committed 2026-08-09 22:34:28 +08:00
1 parent d72ca4193d
commit c4891538a7
466 files changed
+21000 -3339

No files matched your search

-144
View File
@@ -1,144 +0,0 @@
import { ref } from "vue";
import { defineStore } from "pinia";
import { loadDataApi } from "@/services/api";
const createDefaultVisitedTabs = () => [
{ key: "/dashboard", label: "工作台", i18nKey: "common.dashboard", closable: false },
];
export const useAppStore = defineStore(
"app",
() => {
const locale = ref("");
const languages = ref([]);
const languagesLoading = ref(false);
const translations = ref({});
const translationLoading = ref(false);
const sidebarCollapsed = ref(false);
const visitedTabs = ref(createDefaultVisitedTabs());
const contentMaximized = ref(false);
const routeRefreshKeys = ref({});
function toggleSidebar() {
sidebarCollapsed.value = !sidebarCollapsed.value;
}
function toggleContentMaximized() {
contentMaximized.value = !contentMaximized.value;
}
function refreshRoute(routeKey) {
const key = String(routeKey || "");
routeRefreshKeys.value[key] = (routeRefreshKeys.value[key] || 0) + 1;
}
function getRouteRefreshKey(routeKey) {
return routeRefreshKeys.value[String(routeKey || "")] || 0;
}
async function loadLanguages() {
if (languagesLoading.value) return;
languagesLoading.value = true;
try {
const response = await loadDataApi(
"b_i18n_type",
"b_canuse = 1",
"b_default DESC, b_xh ASC, b_id ASC",
[],
);
languages.value = response.data || [];
let selectedLanguage = languages.value.find(
(item) => String(item.b_code) === String(locale.value),
);
if (!selectedLanguage) {
const defaultLanguage = languages.value.find((item) => Number(item.b_default) === 1);
selectedLanguage = defaultLanguage || languages.value[0];
}
const code = String(selectedLanguage?.b_code || "");
await loadTranslations(code);
locale.value = code;
} finally {
languagesLoading.value = false;
}
}
async function loadTranslations(code) {
if (!code) {
translations.value = {};
return;
}
translationLoading.value = true;
try {
const escapedCode = String(code).replaceAll("'", "''");
const response = await loadDataApi(
"b_i18n",
`b_locale = N'${escapedCode}'`,
"b_key ASC",
[],
);
const values = {};
for (const item of response.data || []) {
if (item.b_key) values[item.b_key] = item.b_value;
}
translations.value = values;
} finally {
translationLoading.value = false;
}
}
async function setLocale(value) {
const code = String(value || "");
const exists = languages.value.some((item) => String(item.b_code) === code);
if (!exists) return;
await loadTranslations(code);
locale.value = code;
}
function t(key, fallback = "") {
const value = translations.value[String(key || "")];
if (value !== undefined && value !== null && value !== "") return value;
return fallback || String(key || "");
}
function addVisitedTab(tab) {
if (!visitedTabs.value.some((item) => item.key === tab.key)) {
visitedTabs.value.push(tab);
}
}
function removeVisitedTab(key) {
visitedTabs.value = visitedTabs.value.filter((item) => item.key !== key);
delete routeRefreshKeys.value[key];
}
return {
locale,
languages,
languagesLoading,
translations,
translationLoading,
sidebarCollapsed,
visitedTabs,
contentMaximized,
toggleSidebar,
toggleContentMaximized,
refreshRoute,
getRouteRefreshKey,
setLocale,
loadLanguages,
loadTranslations,
t,
addVisitedTab,
removeVisitedTab,
};
},
{
persist: {
key: "fms-app",
pick: ["locale"],
},
},
);
+143
View File
@@ -0,0 +1,143 @@
import { defineStore } from 'pinia'
import { computed, ref, watch } from 'vue'
export type ColorScheme = {
label: string
primary: string
primaryFg: string
ring: string
sidebarPrimary: string
sidebarRing: string
}
const colorSchemes: { light: ColorScheme; dark: ColorScheme }[] = [
{
light: { label: '#1a1a2e', primary: 'oklch(0.205 0 0)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.708 0 0)', sidebarPrimary: 'oklch(0.205 0 0)', sidebarRing: 'oklch(0.708 0 0)' },
dark: { label: '#1a1a2e', primary: 'oklch(0.922 0 0)', primaryFg: 'oklch(0.205 0 0)', ring: 'oklch(0.556 0 0)', sidebarPrimary: 'oklch(0.488 0.243 264.376)', sidebarRing: 'oklch(0.556 0 0)' },
},
{
light: { label: '#3b82f6', primary: 'oklch(0.546 0.245 262.881)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.546 0.245 262.881)', sidebarPrimary: 'oklch(0.546 0.245 262.881)', sidebarRing: 'oklch(0.546 0.245 262.881)' },
dark: { label: '#3b82f6', primary: 'oklch(0.623 0.214 259.815)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.623 0.214 259.815)', sidebarPrimary: 'oklch(0.623 0.214 259.815)', sidebarRing: 'oklch(0.623 0.214 259.815)' },
},
{
light: { label: '#22c55e', primary: 'oklch(0.527 0.154 150.069)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.527 0.154 150.069)', sidebarPrimary: 'oklch(0.527 0.154 150.069)', sidebarRing: 'oklch(0.527 0.154 150.069)' },
dark: { label: '#22c55e', primary: 'oklch(0.596 0.145 163.225)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.596 0.145 163.225)', sidebarPrimary: 'oklch(0.596 0.145 163.225)', sidebarRing: 'oklch(0.596 0.145 163.225)' },
},
{
light: { label: '#8b5cf6', primary: 'oklch(0.496 0.265 301.924)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.496 0.265 301.924)', sidebarPrimary: 'oklch(0.496 0.265 301.924)', sidebarRing: 'oklch(0.496 0.265 301.924)' },
dark: { label: '#8b5cf6', primary: 'oklch(0.558 0.238 301.358)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.558 0.238 301.358)', sidebarPrimary: 'oklch(0.558 0.238 301.358)', sidebarRing: 'oklch(0.558 0.238 301.358)' },
},
{
light: { label: '#f97316', primary: 'oklch(0.57 0.2 49.5)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.57 0.2 49.5)', sidebarPrimary: 'oklch(0.57 0.2 49.5)', sidebarRing: 'oklch(0.57 0.2 49.5)' },
dark: { label: '#f97316', primary: 'oklch(0.643 0.215 41.5)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.643 0.215 41.5)', sidebarPrimary: 'oklch(0.643 0.215 41.5)', sidebarRing: 'oklch(0.643 0.215 41.5)' },
},
{
light: { label: '#ef4444', primary: 'oklch(0.506 0.232 25.7)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.506 0.232 25.7)', sidebarPrimary: 'oklch(0.506 0.232 25.7)', sidebarRing: 'oklch(0.506 0.232 25.7)' },
dark: { label: '#ef4444', primary: 'oklch(0.577 0.245 27.325)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.577 0.245 27.325)', sidebarPrimary: 'oklch(0.577 0.245 27.325)', sidebarRing: 'oklch(0.577 0.245 27.325)' },
},
{
light: { label: '#ec4899', primary: 'oklch(0.523 0.214 349.4)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.523 0.214 349.4)', sidebarPrimary: 'oklch(0.523 0.214 349.4)', sidebarRing: 'oklch(0.523 0.214 349.4)' },
dark: { label: '#ec4899', primary: 'oklch(0.592 0.225 349.5)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.592 0.225 349.5)', sidebarPrimary: 'oklch(0.592 0.225 349.5)', sidebarRing: 'oklch(0.592 0.225 349.5)' },
},
{
light: { label: '#14b8a6', primary: 'oklch(0.563 0.144 180)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.563 0.144 180)', sidebarPrimary: 'oklch(0.563 0.144 180)', sidebarRing: 'oklch(0.563 0.144 180)' },
dark: { label: '#14b8a6', primary: 'oklch(0.627 0.124 180)', primaryFg: 'oklch(0.985 0 0)', ring: 'oklch(0.627 0.124 180)', sidebarPrimary: 'oklch(0.627 0.124 180)', sidebarRing: 'oklch(0.627 0.124 180)' },
},
]
function loadPersisted<T>(key: string, fallback: T): T {
try {
const raw = localStorage.getItem(key)
if (raw != null) return JSON.parse(raw) as T
} catch { /* ignore */ }
return fallback
}
function persist(key: string, value: unknown) {
try { localStorage.setItem(key, JSON.stringify(value)) } catch { /* ignore */ }
}
export type TabItem = {
key: string
label: string
closable: boolean
}
export const useAppStore = defineStore('app', () => {
// -- dark mode --
const isDark = ref(loadPersisted<boolean>('fms-dark', false))
function toggleTheme() {
isDark.value = !isDark.value
}
// Sync to DOM
watch(isDark, (v) => {
document.documentElement.classList.toggle('dark', v)
persist('fms-dark', v)
}, { immediate: true })
// -- color scheme & locale (persisted by pinia-plugin-persistedstate) --
const schemeIndex = ref(0)
const locale = ref('zh-CN')
// -- tabs --
const visitedTabs = ref<TabItem[]>([{ key: '/dashboard', label: '工作台', closable: false }])
const routeRefreshKeys = ref<Record<string, number>>({})
const schemeKeys = colorSchemes
const totalSchemes = colorSchemes.length
const currentScheme = computed<ColorScheme>(() => {
const entry = colorSchemes[schemeIndex.value] ?? colorSchemes[0]
return isDark.value ? entry.dark : entry.light
})
function selectColorScheme(index: number) {
schemeIndex.value = index
}
function toggleLocale() {
locale.value = locale.value === 'zh-CN' ? 'en-US' : 'zh-CN'
}
// -- tab management --
function addVisitedTab(tab: TabItem) {
const exists = visitedTabs.value.find(t => t.key === tab.key)
if (exists) return
visitedTabs.value.push(tab)
}
function removeVisitedTab(key: string) {
const index = visitedTabs.value.findIndex(t => t.key === key)
if (index >= 0) visitedTabs.value.splice(index, 1)
}
function getRouteRefreshKey(key: string) {
return routeRefreshKeys.value[key] ?? 0
}
function refreshRoute(key: string) {
routeRefreshKeys.value[key] = (routeRefreshKeys.value[key] ?? 0) + 1
}
return {
isDark,
toggleTheme,
schemeIndex,
locale,
visitedTabs,
routeRefreshKeys,
schemeKeys,
totalSchemes,
currentScheme,
selectColorScheme,
toggleLocale,
addVisitedTab,
removeVisitedTab,
getRouteRefreshKey,
refreshRoute,
}
}, {
persist: {
pick: ['schemeIndex', 'locale'],
},
})
-52
View File
@@ -1,52 +0,0 @@
import { computed, ref } from "vue";
import { defineStore } from "pinia";
const AUTH_STORAGE_KEY = "fms-auth";
try {
// Retain a session created before persistence moved from sessionStorage.
const session = sessionStorage.getItem(AUTH_STORAGE_KEY);
if (session && !localStorage.getItem(AUTH_STORAGE_KEY)) {
localStorage.setItem(AUTH_STORAGE_KEY, session);
}
} catch {
// Storage can be unavailable in restricted browser contexts.
}
export const useAuthStore = defineStore(
"auth",
() => {
const token = ref("");
const orgId = ref("");
const user = ref(null);
const isAuthenticated = computed(() => Boolean(token.value));
function setSession(session, organizationId) {
token.value = session.token ?? session.access_token ?? "";
orgId.value = session.orgid ?? organizationId;
user.value = session.user ?? session.user_info ?? null;
}
function clearSession() {
token.value = "";
orgId.value = "";
user.value = null;
}
return {
token,
orgId,
user,
isAuthenticated,
setSession,
clearSession,
};
},
{
persist: {
key: AUTH_STORAGE_KEY,
storage: localStorage,
pick: ["token", "orgId", "user"],
},
},
);
+65
View File
@@ -0,0 +1,65 @@
import { computed, ref } from 'vue'
import { defineStore } from 'pinia'
const AUTH_STORAGE_KEY = 'fms-auth'
try {
const session = sessionStorage.getItem(AUTH_STORAGE_KEY)
if (session && !localStorage.getItem(AUTH_STORAGE_KEY)) {
localStorage.setItem(AUTH_STORAGE_KEY, session)
}
} catch {
// Storage can be unavailable in restricted browser contexts.
}
interface UserInfo {
id: string
account?: string
name: string
}
interface SessionData {
token?: string
access_token?: string
orgid?: string
user?: UserInfo
user_info?: UserInfo
}
export const useAuthStore = defineStore(
'auth',
() => {
const token = ref('')
const orgId = ref('')
const user = ref<UserInfo | null>(null)
const isAuthenticated = computed(() => Boolean(token.value))
function setSession(session: SessionData, organizationId?: string) {
token.value = session.token ?? session.access_token ?? ''
orgId.value = session.orgid ?? organizationId ?? ''
user.value = session.user ?? session.user_info ?? null
}
function clearSession() {
token.value = ''
orgId.value = ''
user.value = null
}
return {
token,
orgId,
user,
isAuthenticated,
setSession,
clearSession,
}
},
{
persist: {
key: AUTH_STORAGE_KEY,
storage: localStorage,
pick: ['token', 'orgId', 'user'],
},
},
)
-164
View File
@@ -1,164 +0,0 @@
import { computed, ref, watch } from "vue";
import { defineStore } from "pinia";
import { loadDataApi } from "@/services/api";
import { useAuthStore } from "./auth";
export const usePermissionStore = defineStore("permissions", () => {
const authStore = useAuthStore();
const loadedPrincipalKey = ref("");
const modules = ref([]);
const grantedPageIds = ref([]);
const moduleCodes = ref([]);
const powerCodes = ref([]);
let loadingPromise = null;
let loadingPrincipalKey = "";
let loadVersion = 0;
const moduleByCode = computed(
() => new Map(modules.value.map((module) => [String(module.b_code || ""), module])),
);
const moduleById = computed(
() => new Map(modules.value.map((module) => [String(module.b_id || ""), module])),
);
const grantedPageSet = computed(() => new Set(grantedPageIds.value));
const powerSet = computed(() => new Set(powerCodes.value));
const isG3soft = computed(() => {
return (
String(authStore.user?.account || "")
.trim()
.toLowerCase() === "g3soft"
);
});
async function load() {
const userId = String(authStore.user?.id || "");
const principalKey = `${String(authStore.orgId || "")}:${userId}`;
if (isG3soft.value) {
const elevatedKey = `g3soft:${principalKey}`;
if (loadedPrincipalKey.value === elevatedKey) return;
loadingPromise = null;
loadingPrincipalKey = "";
// g3soft 也需要加载模块列表用于菜单渲染,权限检查直接返回 true
const requestVersion = ++loadVersion;
const request = loadDataApi("s_module", "b_canuse = 1", "b_id ASC")
.then((res) => {
if (requestVersion !== loadVersion) return;
modules.value = res.data || [];
grantedPageIds.value = [];
moduleCodes.value = [];
powerCodes.value = [];
loadedPrincipalKey.value = elevatedKey;
})
.finally(() => {
if (requestVersion !== loadVersion) return;
loadingPromise = null;
loadingPrincipalKey = "";
});
loadingPromise = request;
return request;
}
if (!/^\d+$/.test(userId)) throw new Error("登录用户 ID 无效,请重新登录");
if (loadedPrincipalKey.value === principalKey) return;
if (loadingPromise && loadingPrincipalKey === principalKey) return loadingPromise;
const requestVersion = ++loadVersion;
loadingPrincipalKey = principalKey;
const request = Promise.all([
loadDataApi("s_module", "b_canuse = 1", "b_id ASC"),
loadDataApi("b_user_module", `b_user_id = ${userId}`, "b_id ASC"),
loadDataApi("b_user_power", `b_user_id = ${userId}`, "b_id ASC"),
loadDataApi("s_module_power", "b_canuse = 1", "b_id ASC"),
])
.then(([moduleResponse, userModules, userPowers, powers]) => {
if (requestVersion !== loadVersion) return;
const activeModules = moduleResponse.data || [];
const moduleById = new Map(activeModules.map((module) => [String(module.b_id), module]));
const powerById = new Map(powers.data.map((power) => [String(power.b_id), power]));
const pageIds = userModules.data
.map((item) => String(item.b_module_id || ""))
.filter(Boolean);
modules.value = activeModules;
grantedPageIds.value = pageIds;
moduleCodes.value = userModules.data
.map((item) => moduleById.get(String(item.b_module_id))?.b_code)
.filter(Boolean);
powerCodes.value = userPowers.data
.map((item) => powerById.get(String(item.b_power_id)))
.filter(Boolean)
.map((power) => `${String(power.b_module_id)}.${power.b_code}`)
.filter(Boolean);
loadedPrincipalKey.value = principalKey;
})
.finally(() => {
if (requestVersion !== loadVersion) return;
loadingPromise = null;
loadingPrincipalKey = "";
});
loadingPromise = request;
return request;
}
function resolvePageId(code) {
let module = moduleByCode.value.get(String(code || ""));
const visited = new Set();
while (module) {
const moduleId = String(module.b_id || "");
if (!moduleId || visited.has(moduleId)) return "";
visited.add(moduleId);
if (module.b_module_type === "page") return moduleId;
const parentId = String(module.b_parent_id || "");
module = parentId ? moduleById.value.get(parentId) : null;
}
return "";
}
function canAccess(moduleCode) {
if (isG3soft.value || !moduleCode) return true;
const module = moduleByCode.value.get(String(moduleCode));
if (!module) return false;
const moduleId = String(module.b_id || "");
const pageId = resolvePageId(moduleCode);
return grantedPageSet.value.has(moduleId) || (!!pageId && grantedPageSet.value.has(pageId));
}
function canPower(scopeCode, powerCode) {
if (isG3soft.value) return true;
const module = moduleByCode.value.get(String(scopeCode || ""));
if (!module || !canAccess(scopeCode)) return false;
const moduleId = String(module.b_id || "");
const pageId = resolvePageId(scopeCode);
return (
powerSet.value.has(`${moduleId}.${powerCode}`) ||
(!!pageId && powerSet.value.has(`${pageId}.${powerCode}`))
);
}
function clear() {
loadVersion++;
loadingPromise = null;
loadingPrincipalKey = "";
loadedPrincipalKey.value = "";
modules.value = [];
grantedPageIds.value = [];
moduleCodes.value = [];
powerCodes.value = [];
}
watch(
() => [authStore.orgId, authStore.user?.id, authStore.user?.account, authStore.token],
clear,
);
return {
load,
canAccess,
canPower,
clear,
modules,
grantedPageIds,
moduleCodes,
powerCodes,
isG3soft,
};
});
+178
View File
@@ -0,0 +1,178 @@
import { computed, ref, watch } from 'vue'
import { defineStore } from 'pinia'
import { loadDataApi } from '@/services/api'
import { useAuthStore } from './auth'
interface Module {
b_id: number | string
b_code: string
b_module_type: string
b_parent_id?: number | string
[key: string]: unknown
}
interface UserModule {
b_module_id: number | string
[key: string]: unknown
}
interface ModulePower {
b_id: number | string
b_module_id: number | string
b_code: string
[key: string]: unknown
}
export const usePermissionStore = defineStore('permissions', () => {
const authStore = useAuthStore()
const loadedPrincipalKey = ref('')
const modules = ref<Module[]>([])
const grantedPageIds = ref<string[]>([])
const moduleCodes = ref<string[]>([])
const powerCodes = ref<string[]>([])
let loadingPromise: Promise<void> | null = null
let loadingPrincipalKey = ''
let loadVersion = 0
const moduleByCode = computed(
() => new Map(modules.value.map((m) => [String(m.b_code || ''), m])),
)
const moduleById = computed(
() => new Map(modules.value.map((m) => [String(m.b_id || ''), m])),
)
const grantedPageSet = computed(() => new Set(grantedPageIds.value))
const powerSet = computed(() => new Set(powerCodes.value))
const isG3soft = computed(() => {
return String(authStore.user?.account || '').trim().toLowerCase() === 'g3soft'
})
async function load(): Promise<void> {
const userId = String(authStore.user?.id || '')
const principalKey = `${String(authStore.orgId || '')}:${userId}`
if (isG3soft.value) {
const elevatedKey = `g3soft:${principalKey}`
if (loadedPrincipalKey.value === elevatedKey) return
loadingPromise = null
loadingPrincipalKey = ''
const requestVersion = ++loadVersion
const request = loadDataApi<Module[]>('s_module', 'b_canuse = 1', 'b_id ASC')
.then((res) => {
if (requestVersion !== loadVersion) return
modules.value = res.data || []
grantedPageIds.value = []
moduleCodes.value = []
powerCodes.value = []
loadedPrincipalKey.value = elevatedKey
})
.finally(() => {
if (requestVersion !== loadVersion) return
loadingPromise = null
loadingPrincipalKey = ''
})
loadingPromise = request
return request
}
if (!/^\d+$/.test(userId)) throw new Error('登录用户 ID 无效,请重新登录')
if (loadedPrincipalKey.value === principalKey) return
if (loadingPromise && loadingPrincipalKey === principalKey) return loadingPromise
const requestVersion = ++loadVersion
loadingPrincipalKey = principalKey
const request = Promise.all([
loadDataApi<Module[]>('s_module', 'b_canuse = 1', 'b_id ASC'),
loadDataApi<UserModule[]>('b_user_module', `b_user_id = ${userId}`, 'b_id ASC'),
loadDataApi<UserModule[]>('b_user_power', `b_user_id = ${userId}`, 'b_id ASC'),
loadDataApi<ModulePower[]>('s_module_power', 'b_canuse = 1', 'b_id ASC'),
])
.then(([moduleResponse, userModules, userPowers, powers]) => {
if (requestVersion !== loadVersion) return
const activeModules = moduleResponse.data || []
const mById = new Map(activeModules.map((m) => [String(m.b_id), m]))
const pById = new Map(powers.data.map((p) => [String(p.b_id), p]))
const pageIds = userModules.data.map((item) => String(item.b_module_id || '')).filter(Boolean)
modules.value = activeModules
grantedPageIds.value = pageIds
moduleCodes.value = userModules.data
.map((item) => mById.get(String(item.b_module_id))?.b_code)
.filter(Boolean) as string[]
powerCodes.value = userPowers.data
.map((item) => pById.get(String(item.b_power_id)))
.filter((p): p is ModulePower => Boolean(p))
.map((power) => `${String(power.b_module_id)}.${power.b_code}`)
loadedPrincipalKey.value = principalKey
})
.finally(() => {
if (requestVersion !== loadVersion) return
loadingPromise = null
loadingPrincipalKey = ''
})
loadingPromise = request
return request
}
function resolvePageId(code: string): string {
let module = moduleByCode.value.get(String(code || ''))
const visited = new Set<string>()
while (module) {
const moduleId = String(module.b_id || '')
if (!moduleId || visited.has(moduleId)) return ''
visited.add(moduleId)
if (module.b_module_type === 'page') return moduleId
const parentId = String(module.b_parent_id || '')
module = parentId ? moduleById.value.get(parentId) : undefined
}
return ''
}
function canAccess(moduleCode?: string): boolean {
if (isG3soft.value || !moduleCode) return true
const module = moduleByCode.value.get(String(moduleCode))
if (!module) return false
const moduleId = String(module.b_id || '')
const pageId = resolvePageId(moduleCode)
return grantedPageSet.value.has(moduleId) || (!!pageId && grantedPageSet.value.has(pageId))
}
function canPower(scopeCode?: string, powerCode?: string): boolean {
if (isG3soft.value) return true
const module = moduleByCode.value.get(String(scopeCode || ''))
if (!module || !canAccess(scopeCode)) return false
const moduleId = String(module.b_id || '')
const pageId = resolvePageId(scopeCode || '')
return (
powerSet.value.has(`${moduleId}.${powerCode}`) ||
(!!pageId && powerSet.value.has(`${pageId}.${powerCode}`))
)
}
function clear() {
loadVersion++
loadingPromise = null
loadingPrincipalKey = ''
loadedPrincipalKey.value = ''
modules.value = []
grantedPageIds.value = []
moduleCodes.value = []
powerCodes.value = []
}
watch(
() => [authStore.orgId, authStore.user?.id, authStore.user?.account, authStore.token],
clear,
)
return {
load,
canAccess,
canPower,
clear,
modules,
grantedPageIds,
moduleCodes,
powerCodes,
isG3soft,
}
})