主题
管理后台门店上下文系统
涉及子系统:管理后台(核心)、云端 API(参数透传)
核心业务:在管理后台顶部提供全局门店切换器,切换为单店模式后,受影响的功能页面自动追加该门店的数据筛选范围
系统概述
健身房系统支持多门店运营。管理后台提供两种数据视角:
| 模式 | 说明 |
|---|---|
| 全体店模式(默认) | 数据跨所有门店汇总展示,不限定门店范围 |
| 单店模式 | 顶部选择某一门店后,受影响的页面自动在查询中附加该门店的筛选条件 |
门店上下文是一个全局状态,保存在前端应用的全局 Store(如 Pinia / Vuex)中,页面切换时保持不变,刷新后可从 localStorage 恢复。
UI 设计
门店切换器位置
门店切换器位于管理后台顶部导航栏右侧,始终可见。
┌─────────────────────────────────────────────────────┐
│ Logo 菜单项... [🏪 全体店 ▼] 👤 │
└─────────────────────────────────────────────────────┘点击后展开下拉菜单:
┌──────────────┐
│ ✓ 全体店 │
│ 朝阳门店 │
│ 西二旗门店 │
│ ... │
└──────────────┘单店模式视觉标识
选中某门店后,切换器显示该门店名称,并在顶部导航栏增加一条醒目的颜色条(如橙色),提示当前处于单店筛选模式,避免管理员误以为在查看全量数据。
┌─────────────────────────────────────────────────────┐
│ 当前视图:朝阳门店 │ ← 橙色提示条
├─────────────────────────────────────────────────────┤
│ Logo 菜单项... [🏪 朝阳门店 ▼] 👤 │
└─────────────────────────────────────────────────────┘受影响的功能模块
以下功能模块在单店模式下,会自动在数据请求中附加当前门店的筛选条件(store_id 参数),无需用户在每个页面手动选择门店:
| 功能模块 | 自动追加筛选的数据范围 |
|---|---|
| 订单列表 / 订单详情 | 仅展示该门店产生的订单 |
| 用户列表 / 会员管理 | 仅展示在该门店注册或有消费记录的用户 |
| 门禁事件日志 | 仅展示该门店的门禁事件 |
| 硬件控制面板 | 仅展示该门店的硬件设备 |
| 数据分析 / 经营报表 | 仅统计该门店的数据 |
| 优惠券核销记录 | 仅展示该门店的核销记录 |
| 外部券码核销记录 | 仅展示该门店的核销记录 |
| 淋浴使用记录 | 仅展示该门店的淋浴使用记录 |
不受门店上下文影响的功能
以下功能属于全局配置,不跟随门店上下文切换:
| 功能模块 | 原因 |
|---|---|
| 系统账号 / 角色权限管理 | 属于平台级配置 |
| 产品/套餐配置 | 套餐通常全局共享,若有门店差异则单独处理 |
| 优惠券模板管理 | 优惠券模板为全局配置,发放记录受门店影响 |
前端实现
全局状态结构
typescript
interface StoreContext {
mode: 'all' | 'single' // 当前模式
storeId: string | null // 单店模式下的门店 ID,全体店模式为 null
storeName: string | null // 单店模式下的门店名称,用于 UI 展示
}API 请求拦截器
在 HTTP 请求拦截器中,自动将当前门店上下文注入到受影响接口的请求参数中:
typescript
// 请求拦截器
axios.interceptors.request.use((config) => {
const storeContext = useStoreContextStore()
if (storeContext.mode === 'single' && storeContext.storeId) {
// 仅对受影响的接口路径追加 store_id
if (isStoreContextAwareApi(config.url)) {
config.params = { ...config.params, store_id: storeContext.storeId }
}
}
return config
})通过维护一个受影响接口路径白名单(isStoreContextAwareApi)来控制哪些接口自动追加门店筛选,避免对全局接口产生副作用。
本地持久化
门店上下文持久化到 localStorage,key 为 admin_store_context,页面刷新后自动恢复上次选择的门店。
后端 API 层
受影响的查询接口需支持可选的 store_id 参数:
- 传入
store_id:仅返回该门店数据 - 不传
store_id(或传null):返回所有门店数据(即全体店模式)
后端无需感知"全体店/单店"概念,仅需处理 store_id 是否存在的过滤逻辑。
权限约束
| 角色 | 可选门店范围 |
|---|---|
| 超级管理员 | 所有门店 + 全体店 |
| 门店管理员 | 仅限其被授权的门店,无全体店选项 |
门店管理员登录后,门店切换器默认且锁定为其所属门店,不允许切换至其他门店或全体店视图。
待确认事项
- [ ] 门店列表的数据来源:是否有独立的"门店管理"模块维护门店信息
- [ ] 套餐/产品是否存在门店差异,若有则产品配置页也需纳入受影响模块
- [ ] 门店管理员的权限边界(是否可以看到跨店用户信息)