From 102882e3fdef6074c9cb58348a71216dffd4f4d3 Mon Sep 17 00:00:00 2001 From: hb Date: Sat, 2 Aug 2025 10:47:16 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9D=83=E9=99=90=E8=B0=83=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/base/notice.ts | 17 ++ src/pages/base/home/index.vue | 85 ++++++- src/pages/system/launchPage/launchPage.vue | 43 ++-- src/pages/system/login/login.vue | 12 + src/store/modules/user.ts | 8 + src/utils/permission.ts | 253 ++++++++++++++++++++- 6 files changed, 393 insertions(+), 25 deletions(-) create mode 100644 src/api/base/notice.ts diff --git a/src/api/base/notice.ts b/src/api/base/notice.ts new file mode 100644 index 0000000..2ab7eed --- /dev/null +++ b/src/api/base/notice.ts @@ -0,0 +1,17 @@ +import { get } from "@/utils/request"; + +// 通知公告分页查询参数接口 +export interface NoticePageParams { + page: number; + rows: number; + appCode: string; + fbfw?: string; + xqId?: string; + fbNjmcId?: string; + releaseFlag?: string; +} + +// 获取通知公告列表 +export function getNoticeListApi(params: NoticePageParams) { + return get("/api/cms/article/list", params); +} \ No newline at end of file diff --git a/src/pages/base/home/index.vue b/src/pages/base/home/index.vue index c71de15..716f418 100644 --- a/src/pages/base/home/index.vue +++ b/src/pages/base/home/index.vue @@ -27,6 +27,7 @@ @@ -79,8 +80,11 @@ import { ref, computed, onMounted, watch } from "vue"; import { onShow } from "@dcloudio/uni-app"; import XsPicker from "@/pages/base/components/XsPicker/index.vue" import { cmsArticlePageApi, getUserLatestInfoApi } from "@/api/base/server"; +import { getNoticeListApi } from "@/api/base/notice"; import { useUserStore } from "@/store/modules/user"; import { useDataStore } from "@/store/modules/data"; +import { hasPermission } from "@/utils/permission"; + const { getCurXs } = useUserStore(); const { setData, getAppCode } = useDataStore(); @@ -88,6 +92,37 @@ const { setData, getAppCode } = useDataStore(); const { getLastRefreshTime, getRefreshInterval, setLastRefreshTime, updateStudentInfo, updateStudentList } = useUserStore(); const REFRESH_INTERVAL = 10 * 60 * 1000; // 10分钟刷新一次(测试用) +// 获取当前changeTime +const getCurrentChangeTime = () => { + try { + const userDataStr = uni.getStorageSync('app-user'); + if (!userDataStr) return null; + + const userData = typeof userDataStr === 'string' ? JSON.parse(userDataStr) : userDataStr; + return userData?.changeTime || null; + } catch (error) { + console.error('获取changeTime失败:', error); + return null; + } +}; + +// 检查权限(带changeTime) +const checkPermission = (permissionKey: string) => { + const changeTime = getCurrentChangeTime(); + return hasPermission(permissionKey, changeTime); +}; + +// 直接权限检查函数,避免缓存问题 +const hasPermissionDirect = (permissionKey: string) => { + if (!permissionKey) return true; + const userStore = useUserStore(); + const permissions = userStore.getAuth; + if (!permissions || permissions.length === 0) return false; + + const uniquePermissions = [...new Set(permissions)]; + return uniquePermissions.includes(permissionKey); +}; + // 检查是否需要刷新学生信息 const checkAndRefreshStudentInfo = async () => { const lastRefreshTime = getLastRefreshTime; @@ -135,37 +170,44 @@ const menuItems = ref([ title: "班级课表", icon: "/static/base/home/book-read-line.png", path: "/pages/base/class-schedule/index", + permissionKey: "school-bjkb", // 班级课表权限编码 }, { title: "成绩查询", icon: "/static/base/home/file-search-line.png", path: "/pages/base/grades/list", + permissionKey: "school-cjcx", // 成绩查询权限编码 }, { title: "在线请假", icon: "/static/base/home/draft-line.png", path: "/pages/base/leave-request/index", + permissionKey: "school-zxqj", // 在线请假权限编码 }, // TODO:需求待协商硬件对接 // { // title: "进出校园", // icon: "/static/base/home/file-transfer-line.png", // path: "/pages/base/campus-access/index", + // permissionKey: "school-jcxy", // 进出校园权限编码 // }, { title: "家校沟通", icon: "/static/base/home/file-transfer-line.png", path: "/pages/base/jl/index", + permissionKey: "school-jxgt", // 家校沟通权限编码 }, { title: "兴趣课", icon: "/static/base/home/file-text-line.png", path: "/pages/base/interest-class/index", + permissionKey: "school-xqk", // 兴趣课权限编码 }, { title: "俱乐部", icon: "/static/base/home/contacts-book-3-line.png", path: "/pages/base/club/index", + permissionKey: "school-jlb", // 俱乐部权限编码 }, ]); @@ -229,13 +271,21 @@ function goToDetail(notice: any) { const getArticleList = async () => { if (curXs.value && curXs.value.njmcId) { - const params = Object.assign({}, pageParams.value, { njmcId: curXs.value.njmcId }); + const params = { + page: pageParams.value.page, + rows: pageParams.value.rows, + appCode: getAppCode, + fbfw: 'JZ', // 发布范围:家长端 + xqId: curXs.value.xqId || curXs.value.xq_id, // 学生所在学期 + fbNjmcId: curXs.value.njmcId, // 学生所在年级 + releaseFlag: 'A' // 发布状态:有效 + }; - cmsArticlePageApi(params).then(res => { - announcements.value = res.rows; - }) - .catch((error) => { - // 接口调用失败 + getNoticeListApi(params).then(res => { + announcements.value = res.rows; + }) + .catch((error) => { + // 接口调用失败 }); } }; @@ -255,6 +305,29 @@ onMounted(async () => { // 初始化时检查是否需要刷新学生信息 await checkAndRefreshStudentInfo(); + + // 检查权限缓存,确保权限数据是最新的 + const userStore = useUserStore(); + const changeTime = userStore.getChangeTime; + if (changeTime) { + // 如果有changeTime,检查是否需要刷新权限 + const { PermissionCacheManager } = await import('@/utils/permission'); + const cacheInfo = PermissionCacheManager.getCacheInfo(); + + if (cacheInfo.hasCache && cacheInfo.changeTime) { + const serverTime = new Date(changeTime).getTime(); + const cacheTime = new Date(cacheInfo.changeTime).getTime(); + + if (serverTime > cacheTime) { + // 服务器时间更新,刷新权限缓存 + const { refreshPermissionCache } = await import('@/utils/permission'); + const currentPermissions = userStore.getAuth; + if (currentPermissions && currentPermissions.length > 0) { + refreshPermissionCache(currentPermissions, changeTime); + } + } + } + } }); // 页面显示时检查是否需要刷新 diff --git a/src/pages/system/launchPage/launchPage.vue b/src/pages/system/launchPage/launchPage.vue index 28b0259..3c6a767 100644 --- a/src/pages/system/launchPage/launchPage.vue +++ b/src/pages/system/launchPage/launchPage.vue @@ -16,6 +16,7 @@ import {onLoad} from "@dcloudio/uni-app"; import {useDataStore} from "@/store/modules/data"; import {useUserStore} from "@/store/modules/user"; import {checkOpenId} from "@/api/system/login"; +import {refreshPermissionCache} from "@/utils/permission"; const { setGlobal } = useDataStore(); const { afterLoginAction } = useUserStore(); @@ -36,24 +37,34 @@ function toHome(data: any) { onLoad(async (data: any) => { setGlobal(data); if (data && data.openId) { - checkOpenId({ openId: data.openId, appCode: "JZ" }) - .then(async (res) => { - if (res.resultCode == 1) { - if (res.result) { - afterLoginAction(res.result); - toHome(data); - return; + try { + const res = await checkOpenId({ openId: data.openId, appCode: "JZ" }); + + if (res.resultCode == 1 && res.result) { + // 执行登录操作 + afterLoginAction(res.result); + + // 如果有changeTime参数,更新权限缓存 + if (data.changeTime) { + const userStore = useUserStore(); + const currentPermissions = userStore.getAuth; + + if (currentPermissions && currentPermissions.length > 0) { + refreshPermissionCache(currentPermissions, data.changeTime); } } - uni.reLaunch({ - url: "/pages/system/login/login", - }); - }) - .catch((err) => { - uni.reLaunch({ - url: "/pages/system/login/login", - }); - }); + + toHome(data); + } else { + uni.reLaunch({ + url: "/pages/system/login/login", + }); + } + } catch (err) { + uni.reLaunch({ + url: "/pages/system/login/login", + }); + } } else { uni.reLaunch({ url: "/pages/system/login/login", diff --git a/src/pages/system/login/login.vue b/src/pages/system/login/login.vue index 3cc65e7..34ecff5 100644 --- a/src/pages/system/login/login.vue +++ b/src/pages/system/login/login.vue @@ -124,6 +124,7 @@ import { loginRegisterJzApi } from "@/api/base/server"; import { useUserStore } from "@/store/modules/user"; import { useDataStore } from "@/store/modules/data"; import {imagUrl} from "@/utils"; +import {refreshPermissionCache} from "@/utils/permission"; const dicOptions = ref([[[]]]); const dicPickerRef = ref(); @@ -305,6 +306,17 @@ async function submit() { hideLoading(); if (res.resultCode == 1) { afterLoginAction(res.result); + + // 如果有changeTime参数,更新权限缓存 + if (res.result && res.result.changeTime) { + const userStore = useUserStore(); + const currentPermissions = userStore.getAuth; + + if (currentPermissions && currentPermissions.length > 0) { + refreshPermissionCache(currentPermissions, res.result.changeTime); + } + } + toHome(); } else { showToast({ title: res.message || "提交失败", icon: "none" }); diff --git a/src/store/modules/user.ts b/src/store/modules/user.ts index 980b095..18fb319 100644 --- a/src/store/modules/user.ts +++ b/src/store/modules/user.ts @@ -15,6 +15,7 @@ interface UserState { auth: string[]; lastRefreshTime: number; // 上次刷新时间 refreshInterval: number; // 刷新间隔(毫秒) + changeTime: string; // 权限变更时间 ws: any; wsCallback: any; } @@ -32,6 +33,7 @@ export const useUserStore = defineStore({ auth: [], lastRefreshTime: 0, // 上次刷新时间 refreshInterval: 7 * 24 * 60 * 60 * 1000, // 刷新间隔(毫秒) + changeTime: '', // 权限变更时间 ws: null, wsCallback: defWsCallback }), @@ -53,6 +55,9 @@ export const useUserStore = defineStore({ }, getRefreshInterval(): number { return this.refreshInterval; + }, + getChangeTime(): string { + return this.changeTime; } }, actions: { @@ -74,6 +79,9 @@ export const useUserStore = defineStore({ setRefreshInterval(interval: number) { this.refreshInterval = interval; }, + setChangeTime(changeTime: string) { + this.changeTime = changeTime; + }, // 更新学生信息 updateStudentInfo(studentInfo: any) { this.setCurXs(studentInfo); diff --git a/src/utils/permission.ts b/src/utils/permission.ts index 9d61774..c7d5ce5 100644 --- a/src/utils/permission.ts +++ b/src/utils/permission.ts @@ -2,11 +2,258 @@ import {ISROUTERINTERCEPT} from "@/config"; import {getRouter} from "@/utils/uniapp"; import {useUserStore} from "@/store/modules/user"; -export function _auth(autd: string) { - const {getAuth} = useUserStore() - return getAuth.includes(autd); +// 权限缓存接口 +interface PermissionCache { + permissions: string[]; + timestamp: number; + userId: string; + changeTime: string; } +// 存储键名 +const PERMISSION_CACHE_KEY = 'permission_cache'; +const CHANGE_TIME_KEY = 'change_time'; + +// 存储操作 +function setStorage(key: string, value: any): void { + try { + const jsonValue = JSON.stringify(value); + uni.setStorageSync(key, jsonValue); + } catch (error) { + console.error('存储权限缓存失败:', error); + } +} + +function getStorage(key: string): any { + try { + const value = uni.getStorageSync(key); + + if (value) { + const parsedValue = JSON.parse(value); + return parsedValue; + } else { + return null; + } + } catch (error) { + console.error('获取权限缓存失败:', error); + return null; + } +} + +// 从app-user获取changeTime +export function getChangeTimeFromAppUser(): string | null { + try { + const userDataStr = uni.getStorageSync('app-user'); + if (!userDataStr) return null; + + const userData = typeof userDataStr === 'string' ? JSON.parse(userDataStr) : userDataStr; + return userData?.changeTime || null; + } catch (error) { + console.error('获取changeTime失败:', error); + return null; + } +} + +// 设置changeTime到app-user +function setChangeTimeToAppUser(changeTime: string): void { + try { + const userDataStr = uni.getStorageSync('app-user'); + if (!userDataStr) return; + + const userData = typeof userDataStr === 'string' ? JSON.parse(userDataStr) : userDataStr; + userData.changeTime = changeTime; + uni.setStorageSync('app-user', JSON.stringify(userData)); + } catch (error) { + console.error('设置changeTime失败:', error); + } +} + +// 获取权限缓存 +function getPermissionCache(): PermissionCache | null { + return getStorage(PERMISSION_CACHE_KEY); +} + +// 设置权限缓存 +function setPermissionCache(permissions: string[], userId: string, changeTime?: string): void { + const cache: PermissionCache = { + permissions, + timestamp: Date.now(), + userId, + changeTime: changeTime || '' + }; + + setStorage(PERMISSION_CACHE_KEY, cache); + + if (changeTime) { + setChangeTimeToAppUser(changeTime); + } +} + +// 清除权限缓存 +function clearPermissionCache(): void { + try { + uni.removeStorageSync(PERMISSION_CACHE_KEY); + } catch (error) { + console.error('清除权限缓存失败:', error); + } +} + +// 检查缓存是否有效 +function isCacheValid(cache: PermissionCache, currentUserId: string): boolean { + if (!cache || !cache.permissions || cache.userId !== currentUserId) { + return false; + } + + // 检查缓存是否过期(7天) + const now = Date.now(); + const cacheAge = now - cache.timestamp; + const maxAge = 7 * 24 * 60 * 60 * 1000; // 7天 + + return cacheAge < maxAge; +} + +// 获取用户权限(带缓存) +function getUserPermissionsWithCache(currentChangeTime?: string): string[] { + const userStore = useUserStore(); + const currentUser = userStore.getUser; + const currentUserId = currentUser?.userId || currentUser?.id; + + if (!currentUserId) { + return userStore.getAuth; + } + + const cache = getPermissionCache(); + + if (cache && isCacheValid(cache, currentUserId)) { + if (currentChangeTime) { + const serverTime = new Date(currentChangeTime).getTime(); + const cacheTime = new Date(cache.changeTime).getTime(); + + if (serverTime > cacheTime) { + const permissions = userStore.getAuth; + if (permissions && permissions.length > 0) { + setPermissionCache(permissions, currentUserId, currentChangeTime); + } + return permissions; + } else { + return cache.permissions; + } + } else { + return cache.permissions; + } + } + + const permissions = userStore.getAuth; + if (permissions && permissions.length > 0) { + setPermissionCache(permissions, currentUserId, currentChangeTime); + } + + return permissions; +} + +// 刷新权限缓存 +export function refreshPermissionCache(permissions?: string[], changeTime?: string): void { + const userStore = useUserStore(); + const currentUser = userStore.getUser; + const currentUserId = currentUser?.userId || currentUser?.id; + + if (!currentUserId) { + return; + } + + const permissionList = permissions || userStore.getAuth; + + const currentCache = getPermissionCache(); + if (currentCache && currentCache.permissions && permissionList) { + const isSame = JSON.stringify(currentCache.permissions.sort()) === JSON.stringify(permissionList.sort()); + if (isSame && currentCache.changeTime === changeTime) { + return; + } + } + + setPermissionCache(permissionList, currentUserId, changeTime); + + if (changeTime) { + userStore.setChangeTime(changeTime); + } +} + +// 清除权限缓存(供外部调用) +export function clearPermissionCachePublic(): void { + clearPermissionCache(); +} + +// 权限检查函数 +export function _auth(autd: string, changeTime?: string) { + const permissions = getUserPermissionsWithCache(changeTime); + return permissions.includes(autd); +} + +export function hasPermission(permissionKey: string, changeTime?: string): boolean { + if (!permissionKey) return true; + const permissions = getUserPermissionsWithCache(changeTime); + // 去重处理,避免重复权限影响判断 + const uniquePermissions = [...new Set(permissions)]; + return uniquePermissions.includes(permissionKey); +} + +export function hasAnyPermission(permissionKeys: string[], changeTime?: string): boolean { + if (!permissionKeys || permissionKeys.length === 0) return true; + const permissions = getUserPermissionsWithCache(changeTime); + // 去重处理,避免重复权限影响判断 + const uniquePermissions = [...new Set(permissions)]; + return permissionKeys.some(key => uniquePermissions.includes(key)); +} + +export function hasAllPermissions(permissionKeys: string[], changeTime?: string): boolean { + if (!permissionKeys || permissionKeys.length === 0) return true; + const permissions = getUserPermissionsWithCache(changeTime); + // 去重处理,避免重复权限影响判断 + const uniquePermissions = [...new Set(permissions)]; + return permissionKeys.every(key => uniquePermissions.includes(key)); +} + +// 获取用户权限 +export function getUserPermissions(changeTime?: string): string[] { + return getUserPermissionsWithCache(changeTime); +} + +// 权限缓存管理器 +export const PermissionCacheManager = { + getCacheInfo() { + const cache = getPermissionCache(); + const changeTime = getChangeTimeFromAppUser(); + return { + cache, + changeTime, + hasCache: !!cache, + cacheAge: cache ? Date.now() - cache.timestamp : 0 + }; + }, + + debugCache() { + const info = this.getCacheInfo(); + console.log('权限缓存信息:', info); + }, + + forceRefresh() { + clearPermissionCache(); + const userStore = useUserStore(); + const permissions = userStore.getAuth; + if (permissions && permissions.length > 0) { + const currentUser = userStore.getUser; + const currentUserId = currentUser?.userId || currentUser?.id; + if (currentUserId) { + setPermissionCache(permissions, currentUserId); + } + } + }, + + clear() { + clearPermissionCache(); + } +}; + function loginPage(url: string) { uni.redirectTo({ url: "/pages/system/login/login?redirect=" + url,