> For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt.

# 13. Access Management

Access Management 用于管理**哪些登录账号可以访问哪些门店，以及在每家门店拥有什么角色**。从总览侧栏点击 **Access Management** 打开，页面地址为 `/access-management`。

角色按门店分别授予：同一个人在一家店可以是 Editor，在另一家店可以是 Viewer。这里的成员是有登录权限的账号；[Store Setup](/funding-strategy/02-产品说明书/12-store-setup.md) 中的 Staff 是员工名单，添加员工记录与授予登录账号访问权是两件事。

## 1 页面布局与操作入口

桌面宽度下，页面左侧是 **Stores** 门店列表，右侧是当前选中门店的成员表；右上角 **Add member** 用于给一个账号授予一家或多家门店的权限。

| 功能模块                   | 页面位置  | 用途                             |
| ---------------------- | ----- | ------------------------------ |
| Stores                 | 左侧列表  | 切换要查看和管理的门店                    |
| 当前门店标题                 | 右侧顶部  | 确认下面成员表对应哪家门店                  |
| Member / Role / Action | 右侧成员表 | 查看成员邮箱、角色及可用操作                 |
| Add member             | 页面右上角 | 填写邮箱，选择门店并逐店设置角色               |
| 铅笔                     | 成员行右侧 | 打开 Edit Member，修改该成员在可管理门店中的角色 |
| 垃圾桶                    | 成员行右侧 | 收回该成员对当前门店的访问权限                |

本页只列出当前账号具有 **Owner 或 Editor** 权限的门店。只有 Viewer 权限的门店不会出现；如果没有可管理门店，则显示空状态，而不是成员清单。

## 2 Stores：门店列表

### 2.1 门店行显示什么

每行从左到右依次是序号、门店图标、名称、Active / Inactive 标记、成员数量和右箭头。当前选中的门店以浅灰背景突出，点击其他行后右侧切换为对应的成员表。

| 元素       | 含义                       |
| -------- | ------------------------ |
| 序号       | 当前列表中的显示顺序，不是门店编号        |
| 门店名称     | 用于识别要管理的门店；长名称截断显示       |
| Active   | 该门店出现在当前账号的已激活门店清单中      |
| Inactive | 门店未出现在该已激活清单中；仍可以在本页管理成员 |
| 状态右侧数字   | 该门店成员表中的成员数量，包含 Owner    |
| 右箭头      | 提示可点击查看该门店成员             |

已激活门店排在前面；状态标记会在门店清单加载成功后显示。门店较多时左侧列表内部滚动。

### 2.2 如何理解截图中的状态和人数

截图中的 West Harlem 标记 **Active**，右侧数字为 **2**，对应成员表中的一位 Owner 和一位 Viewer；这不是员工人数，也不是在线人数。Inactive 门店仍出现在列表中，不代表访问权限已自动删除。

这里的状态标记只用于查看，不能点击启停门店。门店启停在 [Store Setup](/funding-strategy/02-产品说明书/12-store-setup.md) 操作。

## 3 成员表：查看当前门店的访问权限

右侧顶部显示门店图标和名称，下方按成员逐行排列。桌面下有三列表头；窄屏下隐藏表头，仍保留成员、角色和操作。

| 列      | 显示内容                  | 使用方式            |
| ------ | --------------------- | --------------- |
| Member | 登录邮箱；查询不到邮箱时显示账号 ID   | 核对授权对象          |
| Role   | Owner、Editor 或 Viewer | 查看该账号在当前门店的角色   |
| Action | 铅笔和垃圾桶                | 分别修改角色、收回当前门店权限 |

**Owner 和当前登录账号自己的行不显示操作按钮。** 因此截图中的 Owner 行右侧为空，Viewer 行显示铅笔和垃圾桶；按钮是否存在不是只由对方是否为 Viewer 决定。

成员表没有独立的“邀请待接受”状态列。这里展示的是门店访问关系，不是员工在职状态或是否在线。

## 4 Add Member：添加成员与多店授权

### 4.1 打开弹窗

点击页面右上角 **Add member**，打开 **Add Member**。上方填写邮箱，中间选择门店，下方是 Cancel 和 Grant Access，右上角 `×` 关闭弹窗。

这个操作面向**全部可管理门店**，不限于背景中当前选中的门店。新打开时不预选任何门店；截图中的 `0 of 13 selected` 表示可选十三家、当前尚未选择。

### 4.2 Email：授权给谁

Email 为必填项，填写对方用于登录的邮箱。占位文字 `user@example.com` 只是示例，并非已填入的成员。邮箱格式有效且至少选择一家门店后，才可以提交。

系统会按邮箱查找账号：已有账号直接获得权限；不存在时会创建新账号，并通过登录服务发送带临时密码的欢迎邮件。新用户首次登录需设置新密码，不需要事先自行注册。

### 4.3 Select Stores：选择门店

桌面下门店卡片按两列排列，窄屏为一列；列表内容较多时在选择区内部滚动。这里包含当前账号可管理的已激活和停用门店，排序不一定与主页面左栏相同。

| 控件或状态           | 含义与操作                            |
| --------------- | -------------------------------- |
| 左侧圆形选择标记        | 点击门店选择区域勾选，再点取消；支持多选             |
| 门店图标和名称         | 识别授权范围                           |
| 未选中时右侧 —        | 尚未为这次授权选择该门店，不表示该邮箱已有或没有权限       |
| 选中后的勾选标记与浅色背景   | 表示该门店已纳入本次提交                     |
| 选中后的角色下拉        | 默认 Editor，可改为 Viewer；每家店可以设置不同角色 |
| n of m selected | 当前选中数量 / 可选门店数量                  |
| Select All      | 选中全部可管理门店，包括 Inactive 门店         |
| Deselect All    | 全选后可一次取消所有选择                     |

Add Member 不会根据刚输入的邮箱自动预选已有权限。为已有成员再次选择某家店并提交时，会将其角色更新为本次选择的值，而不是新增重复成员关系。

### 4.4 提交、取消与结果

| 操作或状态                           | 结果                                                 |
| ------------------------------- | -------------------------------------------------- |
| Grant Access / Grant Access (n) | 为选中的 n 家门店提交授权                                     |
| 邮箱无效或未选择门店                      | 提交按钮禁用；截图中的灰色按钮属于此状态                               |
| 提交中                             | 显示加载指示，邮箱、选择控件和按钮暂不可操作                             |
| 已有账号授权成功                        | 提示 Access granted to N stores                      |
| 新账号创建并授权成功                      | 提示 New user created and granted access to N stores |
| 失败                              | 显示错误原因，留在弹窗中供检查和重试                                 |
| Cancel / 右上角 ×                  | 提交前关闭弹窗，不新增授权                                      |

授权没有另一步“接受邀请”流程。要为同一个人增加其他门店，可再次填写其邮箱并选择门店。

一次提交如果同时包含 Editor 和 Viewer，界面会按角色分两批请求，每批最多 50 家门店。第一批成功、第二批失败时，已完成的授权不会回滚；遇到错误应核对成员列表后再重试，不能把整次操作都视为未生效。

## 5 Edit Member：修改角色

点击成员行右侧铅笔，打开 **Edit Member**。虽然入口位于当前门店，这个弹窗会同时展示该成员在你可管理门店中的角色。

| 区块           | 编辑规则                        |
| ------------ | --------------------------- |
| Email        | 显示该成员邮箱，锁定不可修改              |
| 门店选择         | 已有成员关系预先勾选；不能勾选或取消门店        |
| 已加入门店的角色     | 可在 Editor 与 Viewer 之间切换     |
| Owner        | 若该成员在某家店是 Owner，显示固定文字，不可更改 |
| 未加入的门店       | 显示 —，不能通过这个弹窗新增访问权          |
| Save changes | 只提交角色实际发生变化的门店              |
| Cancel / ×   | 提交前关闭，放弃本次未保存的角色选择          |

保存成功提示 **Member roles updated**；没有修改则提示 **No role changes**。角色更新会先反映到界面，单店请求失败时恢复该店原角色。多店修改分别提交，不应将一次报错理解为所有门店均已撤销修改。

要增加门店权限，请使用 Add Member；要减少门店权限，请使用对应门店成员行的移除操作。

## 6 Remove access：移除门店访问权

点击成员行垃圾桶，显示 **Remove access to 门店名?** 确认框，正文列出成员邮箱和门店名称，并说明其他门店权限不受影响。

| 操作            | 结果                                  |
| ------------- | ----------------------------------- |
| Cancel        | 关闭确认框，保持权限                          |
| Remove access | 收回该账号对当前门店的访问权                      |
| 成功            | 提示 Member removed，成员从该店列表中移除        |
| 失败            | 提示 Failed to remove member，恢复列表中的成员 |

移除的是门店访问关系，**不会删除对方的登录账号，也不会删除门店业务记录**。如果这个人还能访问其他门店，那些权限继续保留。要收回全部门店权限，需要逐店操作。

Owner 不能移除；界面也不提供移除自己或修改自己角色的按钮。

## 7 Owner、Editor、Viewer：角色权限

角色只有三种，其中 Owner 不是"分配"出来的——建店的账号就是 Owner，一店一个，不能改也不能移；这页能分配的只有 Editor 和 Viewer（后端只接受这两个值，数据库成员表也只允许存这两个值）。

下表按后端各接口的权限判断逐条核对，不是按角色名字推测：

| 操作                                                                                 | Owner | Editor | Viewer | 被拒时的后端提示                                              |
| ---------------------------------------------------------------------------------- | ----- | ------ | ------ | ----------------------------------------------------- |
| 看数据：Dashboard、Calls、Contacts、Leads 等读页面                                            | ✓     | ✓      | ✓      | —（有任一角色即通过门店访问检查）                                     |
| 在本页看到这家店、加人、改角色、移除成员                                                               | ✓     | ✓      | ✗      | "Only OWNER or EDITOR can add members" 等              |
| 处理任务：记录活动、改期、关闭等日常操作                                                               | ✓     | ✓      | ✗      | "Viewers cannot modify tasks"                         |
| 任务里的高风险操作：直接新建"已关闭"任务、更正任务结果（所有任务）；把活动记到指定员工名下、重开已关闭任务（只限走新规则的任务，旧版任务 Editor 也能重开） | ✓     | ✗      | ✗      | "Only the Store owner can perform this Task command"  |
| 审阅 AI 任务提案（列表、批准、驳回）                                                               | ✓     | ✗      | ✗      | 同上                                                    |
| 改营业时间与临时调整                                                                         | ✓     | ✓      | ✗      | "Viewers cannot modify operating hours"               |
| 更正通话记录的员工归属                                                                        | ✓     | ✓      | ✗      | "Viewers cannot amend call records"                   |
| 新建 / 编辑话术（Scripts）                                                                 | ✓     | ✓      | ✗      | "No access to this store"                             |
| Store Setup：维护员工名单、把号码分配到门店（接口允许 Editor，但 Store Setup 页只列你自己建的店，Editor 在界面上碰不到共享店） | ✓     | ✓      | ✗      | "No access to this store"                             |
| Store Setup：门店设置（别名、时区、启用/停用、Lead Line、Ask AI、Send lead notifications、价目表、转写关键词）   | ✓     | ✗      | ✗      | 非 Owner 得到"门店不存在"                                     |
| 改 Revenue 基准价                                                                      | ✓     | ✓      | ✗      | "Viewers cannot change revenue benchmarks"            |
| 改任务自动化档位                                                                           | ✓     | ✗      | ✗      | "Only the store owner can change the automation tier" |
| 删除门店                                                                               | ✓     | ✗      | ✗      | "Only the store owner can delete this store"          |

两条要特别注意的：

- **Editor 的管人权限和 Owner 一样大。** Editor 可以把别人设成 Editor、把其他 Editor 降为 Viewer 或移除，包括 Owner 加进来的人；唯一动不了的是 Owner 本人那一行。
- **通过本页新建出来的账号（子账号）不能自己去接入电话系统账号**（"Sub-accounts cannot connect RingCentral"）；已有的普通账号哪怕只是别人店里的 Editor / Viewer，仍可以用自己的账号接电话系统、建自己的店并成为那些店的 Owner。

给前台、销售开 Editor 就能干活；给财务、区域督导、加盟商看报表开 Viewer，看得到但改不了；删店、门店设置（别名、时区、启停、各开关、价目表）、改自动化档位、改任务结果这类影响经营数据的动作只留给 Owner 本人。

拿不准给什么角色：只看报表 → Viewer；要处理线索和任务 → Editor；需要删店、改门店设置、改自动化档位、审提案 → 必须用 Owner 本人账号。给 Editor 前先想清楚：他能把其他 Editor 移出这家店。

## 8 加载、错误与空状态

| 状态      | 页面表现                                              | 如何处理                            |
| ------- | ------------------------------------------------- | ------------------------------- |
| 首次加载    | 门店与成员区域显示占位骨架                                     | 等待加载完成                          |
| 加载失败    | 显示错误信息和 Try Again                                 | 点击重新读取                          |
| 没有可管理门店 | No organizations to manage                        | 核对自己是否具有任一门店的 Owner 或 Editor 权限 |
| 成员列表为空  | No members. Click "Add member" to invite someone. | 有管理权限时可从 Add member 添加          |

空状态中的 organization 指门店，本页没有创建组织或门店的入口。只有 Viewer 权限时看到空状态，不等于完全没有门店访问权；可到 [Account Settings → Store Access](/funding-strategy/02-产品说明书/11-account-settings.md) 查看自己可访问的已激活门店。

## 9 当前限制与使用边界

- 只有 Owner、Editor、Viewer 三种角色，没有按功能勾选的细分权限，也没有 Owner 转让或新增第二位 Owner 的操作。
- Editor 也能管理成员，包括新增其他 Editor、修改其他 Editor 角色或移除他们；授权 Editor 时需要同时考虑这项能力。
- Add Member 不预先检查所填邮箱是否已是某家店的 Owner；当前实现可能产生 Owner 与普通成员的重复显示，不要用重复授权来尝试修改所有权。
- 界面没有邀请待接受、重发临时密码、批量收回全部门店权限或删除登录账号的功能。
- 通过本页新建的子账号不能自行接入 RingCentral；这与已有普通账号获得其他门店的共享权限不同。
- 每个角色批次最多 50 家门店，界面没有提前限制选中数量；超限会在提交时失败。
- 页面管理访问权限，不维护员工姓名、分机或在职状态；这些内容见 [Store Setup → Staff](/funding-strategy/02-产品说明书/12-store-setup.md)。

## 10 实现依据

本篇按本地代码核查，页面实际启用情况以部署版本为准。

[页面](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/web/src/pages/access-management/index.vue) · [成员表](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/web/src/components/access-management/MembersTable.vue) · [加人 / 改角色弹窗](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/web/src/components/access-management/dialogs/BatchGrantDialog.vue) · [前端状态](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/web/src/stores/access-management.ts) · [前端接口](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/web/src/api/access-management-client.ts) · [侧栏入口](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/web/src/composables/use-sidebar.ts) · [页面数据接口](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/routes/access-management/index.ts) · [成员增删改接口](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/routes/stores/members.ts) · [批量授权接口](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/routes/stores/batch-grant.ts) · [子账号接口](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/routes/sub-accounts/index.ts) · [可访问门店清单](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/utils/authorization.ts) · [门店访问判定](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/utils/store-authorization-neon.ts) · [成员关系读写](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/services/store-members-neon.ts) · [账号查找与创建](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/services/cognito.ts) · [任务写权限](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/api/src/routes/tasks/mutation-authorization.ts) · [成员表结构](https://github.com/retaintive/callytics-infrastructure/blob/main/packages/common/src/db/schema/user-stores.ts) · [首次登录改密](https://github.com/retaintive/callytics-infrastructure/blob/main/apps/web/src/components/auth/EmailLoginForm.vue)
