import { myRequest } from './api.js'; // 权限列表的内存缓存。 // 首次成功读取后缓存在内存里,后续不再依赖每次渲染都同步读取存储, // 既避免了“数据还没写入存储就被读取”的偶发时序问题,也省去重复 JSON.parse。 var permissionList = null; // 正在进行的拉取请求,避免并发重复调用接口 var fetchingPromise = null; // 从本地存储同步读取并刷新缓存。 // 读到有效数据时返回解析后的数组;否则返回 null(缓存保持不变)。 function loadListFromStorage() { try { var raw = uni.getStorageSync('jurisdiction'); if (raw) { var parsed = JSON.parse(raw); if (Array.isArray(parsed)) { permissionList = parsed; return permissionList; } } } catch (e) { console.warn('[QueryPermission] 解析 jurisdiction 失败:', e); } return null; } // 从服务端拉取权限列表并写入存储 + 缓存。 // 幂等:已缓存且非强制刷新时直接返回;并发调用共享同一个请求。 // 用于“未经过首页”等无法依赖本地存储已写入的特殊场景。 function fetchPermissionList(options = {}) { const { force = false } = options; if (!force && permissionList && permissionList.length) { return Promise.resolve(permissionList); } if (fetchingPromise) { return fetchingPromise; } fetchingPromise = (async () => { try { const res = await myRequest({ url: '/api/api_gateway?method=user.login.user_login_info', data: { is_app: 1 }, }); const menuList = []; (res || []).forEach((item) => { if (item && item.children) { menuList.push(...item.children); } }); const children = []; menuList.forEach((item) => { if (item && item.children) { children.push(...item.children); } }); permissionList = children; // 同步落盘,保证其他读取 storage 的地方也能拿到 uni.setStorageSync('jurisdiction', JSON.stringify(children)); return children; } catch (e) { console.warn('[QueryPermission] 拉取权限列表失败:', e); return permissionList || []; } finally { fetchingPromise = null; } })(); return fetchingPromise; } // 重置权限数据:清空内存缓存,并默认清除本地存储中的权限列表。 // 用于退出登录、一键登录(切换账号)等场景,防止上一个用户的权限残留。 function resetPermissionList(options = {}) { const { keepStorage = false } = options; permissionList = null; fetchingPromise = null; if (!keepStorage) { try { uni.removeStorageSync('jurisdiction'); } catch (e) { console.warn('[QueryPermission] 清除 jurisdiction 存储失败:', e); } } } function QueryPermission(id) { // 优先使用内存缓存;缓存为空时尝试同步读取一次存储 // (覆盖“模块初始化时存储还没写入、但调用时已写入”的情况) var list = permissionList || loadListFromStorage() || []; for (var i = 0; i < list.length; i++) { if (list[i] && list[i].children) { var data = list[i].children; for (var j = 0; j < data.length; j++) { var item = data[j]; if (item && item.pur_id == id) { return true; } } } } return false; } function getUserPermission() { if (!permissionList) { loadListFromStorage(); } return permissionList || []; } function getPermissionById(node = getUserPermission(), id) { for (const child of node) { if (id == child.pur_id) { return child.children || []; } if (child.children) { let result = getPermissionById(child.children, id); if (result) { return result; } } } return null; } /** * 异步预加载权限列表,解决“数据未写入存储就执行 QueryPermission”的时序问题。 * 在依赖权限的详情页 onLoad 中 `await ensurePermissionLoaded()`, * 可保证页面渲染前权限数据已就绪: * - 缓存或本地存储里已有 -> 立即返回; * - 本地没有(未经过首页等特殊入口)-> 默认直接请求接口拉取; * - 也可设置 fromServer:false 仅轮询等待本地存储写入完成。 * @param {Object} options * @param {number} options.timeout 最长等待时间(ms),默认 8000(仅轮询模式生效) * @param {number} options.interval 轮询间隔(ms),默认 100(仅轮询模式生效) * @param {boolean} options.fromServer 本地无数据时是否请求接口拉取,默认 true * @returns {Promise} */ function ensurePermissionLoaded(options = {}) { const { timeout = 8000, interval = 100, fromServer = true } = options; // 已就绪:缓存或存储里有数据,直接返回 if (permissionList && permissionList.length) { return Promise.resolve(permissionList); } if (loadListFromStorage()) { return Promise.resolve(permissionList); } // 未经过首页等特殊情况:本地没有权限数据,默认直接请求接口拉取 if (fromServer) { return fetchPermissionList(); } // fromServer=false:仅轮询等待本地存储写入完成 return new Promise((resolve) => { const start = Date.now(); const timer = setInterval(() => { if (loadListFromStorage()) { clearInterval(timer); resolve(permissionList); } else if (Date.now() - start >= timeout) { clearInterval(timer); console.warn('[QueryPermission] 预加载超时,权限数据可能未就绪'); resolve([]); } }, interval); }); } export { QueryPermission, getPermissionById, getUserPermission, ensurePermissionLoaded, fetchPermissionList, resetPermissionList, };