fix(auth): 统一超级管理员标识为布尔值true

- 将所有页面和菜单中超级管理员校验由数字1改为布尔true
- 平台管理、门店中心菜单项仅在isSuperAdmin===true时显示
- 门店中心页面移除店员门槛,改为超级管理员访问限制
- 非超级管理员访问门店中心弹窗提示并返回
- 首页工作台入口及相关访问权限判定切换为布尔判断
- 优化首屏加载状态,避免权限校验闪烁和误判
This commit is contained in:
2026-07-23 18:29:48 +08:00
parent 5da7d17c55
commit dc72e530c7
6 changed files with 16 additions and 16 deletions

View File

@@ -48,15 +48,15 @@
**待验证**`npm run build:weapp` 未实跑(环境 tsc 报 @tarojs/taro 类型库缺失属全局问题,与本次无关)。 **待验证**`npm run build:weapp` 未实跑(环境 tsc 报 @tarojs/taro 类型库缺失属全局问题,与本次无关)。
## 平台管理 / 门店中心 改为 isSuperAdmin=1 才显示 ## 平台管理 / 门店中心 改为 isSuperAdmin=true 才显示
**需求**:平台管理与门店中心两个入口都需要 `isSuperAdmin=1` 才显示(原先平台管理=isAdmin、门店中心=店员 storeInfo。门店中心页面本身按用户确认改为「仅超级管理员可进」。 **需求**:平台管理与门店中心两个入口都需要 `isSuperAdmin=true`(布尔)才显示(原先平台管理=isAdmin、门店中心=店员 storeInfo。门店中心页面本身按用户确认改为「仅超级管理员可进」。
**改动文件** **改动文件**
- `src/pages/user/user.tsx`:菜单项 平台管理、门店中心 的显示条件均由 `isAdmin` / `storeInfo` 改为 `(user as any)?.isSuperAdmin === 1` - `src/pages/user/user.tsx`:菜单项 平台管理、门店中心 的显示条件均由 `isAdmin` / `storeInfo` 改为 `(user as any)?.isSuperAdmin === 1`
- `src/pages/index/index.tsx`:首页角色工作台外层容器补 `|| isSuperAdmin===1`,平台管理入口 `(user as any)?.isAdmin``isSuperAdmin === 1` - `src/pages/index/index.tsx`:首页角色工作台外层容器补 `|| isSuperAdmin===true`,平台管理入口 `(user as any)?.isAdmin``isSuperAdmin === true`
- `src/pages/admin/index/index.tsx`:页面访问门槛 `isAdmin``isSuperAdmin===1`(含空态文案);`loading` 拆为 `userLoading`(来自 useUser防闪烁) + `dataLoading`(角标数据);首屏 `if (userLoading || dataLoading) spinner` - `src/pages/admin/index/index.tsx`:页面访问门槛 `isAdmin``isSuperAdmin===true`(含空态文案);`loading` 拆为 `userLoading`(来自 useUser防闪烁) + `dataLoading`(角标数据);首屏 `if (userLoading || dataLoading) spinner`
- `src/pages/store/center/index.tsx`:移除 `getMyClerk()` 店员门槛,改为 `isSuperAdmin===1` 才进;非超管弹「仅超级管理员可访问」并 navigateBack头部加 `header` 兜底(超管非店员时显示「门店中心」+ 管理员昵称/手机号);渲染守卫 `userLoading → 请先登录 → 无访问权限`,去掉原 `if(!storeInfo) return null`(否则非店员超管整页空白)。 - `src/pages/store/center/index.tsx`:移除 `getMyClerk()` 店员门槛,改为 `isSuperAdmin===true` 才进;非超管弹「仅超级管理员可访问」并 navigateBack头部加 `header` 兜底(超管非店员时显示「门店中心」+ 管理员昵称/手机号);渲染守卫 `userLoading → 请先登录 → 无访问权限`,去掉原 `if(!storeInfo) return null`(否则非店员超管整页空白)。
**验证**`npm run build:weapp` 在沙箱被 OOM/锁文件杀掉exit 137无报错属环境问题非代码错误改动均为项目既有写法useUser / Badge / 渐变头部)。 **验证**`npm run build:weapp` 在沙箱被 OOM/锁文件杀掉exit 137无报错属环境问题非代码错误改动均为项目既有写法useUser / Badge / 渐变头部)。

View File

@@ -10,9 +10,9 @@
- **vip-review 审核通过流程(用户 2026-07-22 最终确认2026-07-23 补充)**:前端 `handleApprove` 依次调 ① `updateShopDealerApply(applyStatus=20)`;② `setUserDeveloper(userId)`(不碰 `sys_user_role`);③ **`addShopStoreUser`**——在当前门店下给申请人补一条 `shop_store_user`(店员)记录(`userId=申请人, storeId=审核店员所属门店, tenantId=同店员, isDelete=0`)。后端 `markAsDeveloper` 做两件事:① 把 `sys_user.is_developer``1`;② **替换**用户角色为 `developer`——`roleService.getByRoleCode(roleCode=developer, tenantId=用户租户)` 找到角色 → 删掉该用户现有 `sys_user_role` → 只绑定 developer 这一个角色,**不与原角色并存**(角色替换包 try/catch失败不影响 isDeveloper 落库)。即"升级为开发者 = 单角色 developer + isDeveloper 标记位 + 一条门店店员记录",不是新增第二个角色。审核店员的 `storeId/tenantId` 来自 `getMyClerk()` 返回值(存于 `clerkStoreId/clerkTenantId` state - **vip-review 审核通过流程(用户 2026-07-22 最终确认2026-07-23 补充)**:前端 `handleApprove` 依次调 ① `updateShopDealerApply(applyStatus=20)`;② `setUserDeveloper(userId)`(不碰 `sys_user_role`);③ **`addShopStoreUser`**——在当前门店下给申请人补一条 `shop_store_user`(店员)记录(`userId=申请人, storeId=审核店员所属门店, tenantId=同店员, isDelete=0`)。后端 `markAsDeveloper` 做两件事:① 把 `sys_user.is_developer``1`;② **替换**用户角色为 `developer`——`roleService.getByRoleCode(roleCode=developer, tenantId=用户租户)` 找到角色 → 删掉该用户现有 `sys_user_role` → 只绑定 developer 这一个角色,**不与原角色并存**(角色替换包 try/catch失败不影响 isDeveloper 落库)。即"升级为开发者 = 单角色 developer + isDeveloper 标记位 + 一条门店店员记录",不是新增第二个角色。审核店员的 `storeId/tenantId` 来自 `getMyClerk()` 返回值(存于 `clerkStoreId/clerkTenantId` state
- 注意:前端 `vip-review` / `vip-upgrade` 等页面的变量名仍残留 `VIP_ROLE_*``pendingVipCount``dealerPrice` 等旧标识符(仅文案改成了「开发者」),后端角色与缓存 key 仍对应这些旧名,重命名需谨慎。 - 注意:前端 `vip-review` / `vip-upgrade` 等页面的变量名仍残留 `VIP_ROLE_*``pendingVipCount``dealerPrice` 等旧标识符(仅文案改成了「开发者」),后端角色与缓存 key 仍对应这些旧名,重命名需谨慎。
### 超级管理员isSuperAdmin=1访问门槛2026-07-23 确认) ### 超级管理员isSuperAdmin=true访问门槛2026-07-23 确认)
- 用户对象字段 `isSuperAdmin``(user as any)?.isSuperAdmin === 1`,数值 1 才算),前端此前未引用,由后端 `sys_user` 返回。 - 用户对象字段 `isSuperAdmin``(user as any)?.isSuperAdmin === true`,布尔 true 才算),前端此前未引用,由后端 `sys_user` 返回。
- **平台管理**`pages/admin/index/index`)与**门店中心**`pages/store/center/index`)两个入口,**菜单与首页工作台均只在 `isSuperAdmin===1` 时显示**(原先平台管理是 `isAdmin`、门店中心是店员 `storeInfo`)。 - **平台管理**`pages/admin/index/index`)与**门店中心**`pages/store/center/index`)两个入口,**菜单与首页工作台均只在 `isSuperAdmin===true` 时显示**(原先平台管理是 `isAdmin`、门店中心是店员 `storeInfo`)。
- 门店中心页面已改为「仅超级管理员可进」:移除原 `getMyClerk()` 店员门槛;非超管访问弹「仅超级管理员可访问」并 `navigateBack`;超管若同时是店员仍会加载门店信息用于头部,否则头部兜底显示「门店中心」+ 管理员昵称/手机号。 - 门店中心页面已改为「仅超级管理员可进」:移除原 `getMyClerk()` 店员门槛;非超管访问弹「仅超级管理员可访问」并 `navigateBack`;超管若同时是店员仍会加载门店信息用于头部,否则头部兜底显示「门店中心」+ 管理员昵称/手机号。
- 两页都用 `useUser()``loading`userLoading做首屏门卫避免超管用户未从 storage 解析完时先闪「无访问权限」。注意:`pages/store/center` 的入口曾依赖 `user.tsx` 里的 `storeInfo`getMyClerk现已不再用 `storeInfo` 决定菜单可见性。 - 两页都用 `useUser()``loading`userLoading做首屏门卫避免超管用户未从 storage 解析完时先闪「无访问权限」。注意:`pages/store/center` 的入口曾依赖 `user.tsx` 里的 `storeInfo`getMyClerk现已不再用 `storeInfo` 决定菜单可见性。

View File

@@ -58,7 +58,7 @@ const FEATURE_CARDS = [
export default function AdminCenterPage() { export default function AdminCenterPage() {
const { user, isLoggedIn, loading: userLoading } = useUser() const { user, isLoggedIn, loading: userLoading } = useUser()
const isSuperAdmin = (user as any)?.isSuperAdmin === 1 const isSuperAdmin = (user as any)?.isSuperAdmin === true
const [dataLoading, setDataLoading] = useState(true) const [dataLoading, setDataLoading] = useState(true)
const [pendingApps, setPendingApps] = useState(0) const [pendingApps, setPendingApps] = useState(0)

View File

@@ -256,7 +256,7 @@ const IndexPage: React.FC = () => {
<ScrollView scrollY style={{ height: scrollHeight }}> <ScrollView scrollY style={{ height: scrollHeight }}>
{/* 角色工作台入口:仅开发者 / 平台管理员 / 超级管理员可见 */} {/* 角色工作台入口:仅开发者 / 平台管理员 / 超级管理员可见 */}
{(isLoggedIn && ((user as any)?.isDeveloper || (user as any)?.isAdmin || (user as any)?.isSuperAdmin === 1)) && ( {(isLoggedIn && ((user as any)?.isDeveloper || (user as any)?.isAdmin || (user as any)?.isSuperAdmin === true)) && (
<View className='mx-3 mt-2 grid grid-cols-2 gap-2'> <View className='mx-3 mt-2 grid grid-cols-2 gap-2'>
{(user as any)?.isDeveloper && ( {(user as any)?.isDeveloper && (
<View <View
@@ -268,7 +268,7 @@ const IndexPage: React.FC = () => {
<Text className='text-sm font-medium text-blue-700'></Text> <Text className='text-sm font-medium text-blue-700'></Text>
</View> </View>
)} )}
{(user as any)?.isSuperAdmin === 1 && ( {(user as any)?.isSuperAdmin === true && (
<View <View
className='flex items-center justify-center py-3 rounded-lg border border-purple-100' className='flex items-center justify-center py-3 rounded-lg border border-purple-100'
style={{ background: 'linear-gradient(135deg, #f5f3ff 0%, #ede9fe 100%)' }} style={{ background: 'linear-gradient(135deg, #f5f3ff 0%, #ede9fe 100%)' }}

View File

@@ -63,7 +63,7 @@ const SUBSCRIBE_TMPL_IDS = [
export default function StoreCenterPage() { export default function StoreCenterPage() {
const { user, isLoggedIn, loading: userLoading } = useUser() const { user, isLoggedIn, loading: userLoading } = useUser()
const isSuperAdmin = (user as any)?.isSuperAdmin === 1 const isSuperAdmin = (user as any)?.isSuperAdmin === true
const [storeInfo, setStoreInfo] = useState<any>(null) const [storeInfo, setStoreInfo] = useState<any>(null)
const [pendingVipCount, setPendingVipCount] = useState(0) const [pendingVipCount, setPendingVipCount] = useState(0)
const [pendingOrderCount, setPendingOrderCount] = useState(0) const [pendingOrderCount, setPendingOrderCount] = useState(0)

View File

@@ -105,10 +105,10 @@ const UserPage: React.FC = () => {
...((user as any)?.isDeveloper ...((user as any)?.isDeveloper
? [{ icon: '🛠️', label: '进入开发者中心', url: '/pages/developer/index/index', highlight: true, requireAuth: true }] ? [{ icon: '🛠️', label: '进入开发者中心', url: '/pages/developer/index/index', highlight: true, requireAuth: true }]
: [{ icon: '🔰', label: '申请成为开发者', url: '/pages/user/vip-upgrade/index', highlight: true, requireAuth: true }]), : [{ icon: '🔰', label: '申请成为开发者', url: '/pages/user/vip-upgrade/index', highlight: true, requireAuth: true }]),
// 平台管理:仅 isSuperAdmin=1 用户显示 // 平台管理:仅 isSuperAdmin=true 用户显示
...((user as any)?.isSuperAdmin === 1 ? [{ icon: '🛡️', label: '平台管理', url: '/pages/admin/index/index', requireAuth: true }] : []), ...((user as any)?.isSuperAdmin === true ? [{ icon: '🛡️', label: '平台管理', url: '/pages/admin/index/index', requireAuth: true }] : []),
// 门店中心:仅 isSuperAdmin=1 用户显示 // 门店中心:仅 isSuperAdmin=true 用户显示
...((user as any)?.isSuperAdmin === 1 ? [{ icon: '🏪', label: '门店中心', url: '/pages/store/center/index', requireAuth: true }] : []), ...((user as any)?.isSuperAdmin === true ? [{ icon: '🏪', label: '门店中心', url: '/pages/store/center/index', requireAuth: true }] : []),
{ icon: '💰', label: '我的钱包', url: '/pages/user/wallet', requireAuth: true }, { icon: '💰', label: '我的钱包', url: '/pages/user/wallet', requireAuth: true },
{ icon: '📍', label: '收货地址', url: '/pages/user/address-list', requireAuth: true }, { icon: '📍', label: '收货地址', url: '/pages/user/address-list', requireAuth: true },
// { icon: '⭐', label: '积分明细', url: '/pages/user/points-record' }, // { icon: '⭐', label: '积分明细', url: '/pages/user/points-record' },