28 KiB
28 KiB
M5: 团队与分配(Team / Assignment / AutoAssignment)
模块概述
本模块覆盖 Chatwoot 的团队管理、对话分配(人工/自动)、分配策略(Assignment Policy V2)、坐席容量策略(Agent Capacity Policy,企业版)等功能。核心目标是让客服团队可以组织成员、并基于策略自动或手动将对话分配给合适的坐席。
功能1:团队管理(Team CRUD)
- 功能描述:在账户级别创建、编辑、删除团队。团队是坐席的逻辑分组,可用于对话分配、权限管理等场景。团队名称在同一账户下唯一。
- 用户操作流程(UI交互步骤):
- 进入 Settings → Teams 页面
- 点击"Add Team"按钮,填写团队名称(name)和描述(description)
- 可选择是否允许自动分配(allow_auto_assign),默认为 true
- 创建后可在团队列表中查看、编辑、删除
- 涉及的API端点 + 请求/响应格式:
GET /api/v1/accounts/{account_id}/teams— 获取团队列表POST /api/v1/accounts/{account_id}/teams— 创建团队- 请求:
{ team: { name: "sales", description: "Sales team", allow_auto_assign: true } } - 响应:团队对象
{ id, name, description, allow_auto_assign, account_id, is_member }
- 请求:
GET /api/v1/accounts/{account_id}/teams/{id}— 获取单个团队PUT /api/v1/accounts/{account_id}/teams/{id}— 更新团队DELETE /api/v1/accounts/{account_id}/teams/{id}— 删除团队
- 涉及的数据模型 + 关键字段:
Team模型(表teams):id(bigint, PK)name(string, not null, 同账户下唯一,自动 downcase)description(text)allow_auto_assign(boolean, default true) — 是否允许该团队参与自动分配account_id(bigint, not null, FK)created_at,updated_at
- 关联:
has_many :team_members,has_many :members (through :team_members, source: :user),has_many :conversations (dependent: :nullify)
- 涉及的业务逻辑(service层):
- 无独立 service,CRUD 直接在 controller 中完成
Team#add_members(user_ids)— 批量添加成员,同时更新账户缓存Team#remove_members(user_ids)— 批量移除成员,同时更新账户缓存before_validation自动将 name 转为 lowercase- 删除团队时关联的 conversations 的 team_id 被设为 NULL(nullify)
- 涉及的自动化/规则/事件:
- 团队创建/删除会触发
AccountCacheRevalidator更新缓存
- 团队创建/删除会触发
- Chatwoot原实现的关键代码文件路径:
app/models/team.rbapp/controllers/api/v1/accounts/teams_controller.rbapp/views/api/v1/accounts/teams/(index, show, create, update)app/views/api/v1/models/_team.json.jbuilderdb/schema.rb— teams 表
- 版本标注:✅ 社区版
功能2:团队成员管理(Team Member CRUD)
- 功能描述:为团队添加或移除坐席成员。成员必须属于同一账户。支持批量操作。
- 用户操作流程(UI交互步骤):
- 在团队详情页中点击"Add Agents"
- 从下拉列表中选择要添加的坐席(多选)
- 可通过 update 接口同时添加新成员和移除旧成员
- 可批量删除指定成员
- 涉及的API端点 + 请求/响应格式:
GET /api/v1/accounts/{account_id}/teams/{team_id}/team_members— 获取团队成员列表POST /api/v1/accounts/{account_id}/teams/{team_id}/team_members— 添加成员- 请求:
{ user_ids: [1, 2, 3] } - 响应:成员用户对象数组
- 请求:
PATCH /api/v1/accounts/{account_id}/teams/{team_id}/team_members/update— 更新成员列表(同时添加+移除)- 请求:
{ user_ids: [1, 3, 5] }— 对比当前成员列表,自动计算添加和移除
- 请求:
DELETE /api/v1/accounts/{account_id}/teams/{team_id}/team_members/destroy— 移除指定成员- 请求:
{ user_ids: [2, 4] }
- 请求:
- 涉及的数据模型 + 关键字段:
TeamMember模型(表team_members):id(bigint, PK)team_id(bigint, not null, FK → teams)user_id(bigint, not null, FK → users)created_at,updated_at- 唯一约束:
(team_id, user_id)— 同一坐席不能在同一团队中重复
- 涉及的业务逻辑(service层):
- Controller 中校验 user_ids 必须属于当前账户(
validate_member_id_params) update动作使用members_to_be_added_ids/members_to_be_removed_ids自动计算差集- 调用
Team#add_members/Team#remove_members执行操作 - 操作后触发
AccountCacheRevalidator更新缓存
- Controller 中校验 user_ids 必须属于当前账户(
- 涉及的自动化/规则/事件:
- TeamMember 包含
Audit::TeamMember模块用于审计追踪
- TeamMember 包含
- Chatwoot原实现的关键代码文件路径:
app/models/team_member.rbapp/controllers/api/v1/accounts/team_members_controller.rbapp/views/api/v1/accounts/team_members/(index, create)db/schema.rb— team_members 表
- 版本标注:✅ 社区版
功能3:对话参与者管理(Conversation Participant)
- 功能描述:对话参与者(ConversationParticipant)是对话中除主分配人(assignee)之外的附加参与者。用于多人协作场景,多个坐席可以同时"参与"一个对话以跟踪其进展。当对话被分配给坐席时,该坐席自动成为参与者。
- 用户操作流程(UI交互步骤):
- 在对话详情面板中点击"Add Participants"
- 从坐席下拉列表中选择要添加的参与者
- 参与者可查看对话并收到通知
- 可移除不再需要的参与者
- 涉及的API端点 + 请求/响应格式:
GET /api/v1/accounts/{account_id}/conversations/{conversation_id}/participants— 获取参与者列表POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/participants— 添加参与者- 请求:
{ user_ids: [1, 2] } - 响应:参与者对象数组
- 请求:
PATCH /api/v1/accounts/{account_id}/conversations/{conversation_id}/participants— 更新参与者列表- 请求:
{ user_ids: [1, 3] }— 自动计算添加和移除差集
- 请求:
DELETE /api/v1/accounts/{account_id}/conversations/{conversation_id}/participants— 移除参与者- 请求:
{ user_ids: [2] }
- 请求:
- 涉及的数据模型 + 关键字段:
ConversationParticipant模型(表conversation_participants):id(bigint, PK)account_id(bigint, not null)user_id(bigint, not null)conversation_id(bigint, not null)created_at,updated_at- 唯一约束:
(user_id, conversation_id)— 同一坐席不重复参与同一对话
- 涉及的业务逻辑(service层):
ensure_inbox_access校验:参与者必须是该对话所在 inbox 的 assignable_agentsensure_account_id校验:account_id 自动从 conversation 继承ParticipationListener#assignee_changed:当对话 assignee 变化时,自动将新 assignee 添加为参与者Messages::MentionService:当坐席被 @提及 时自动添加为参与者Messages::NewMessageNotificationService:向所有参与者推送通知
- 涉及的自动化/规则/事件:
- 事件
ASSIGNEE_CHANGED→ParticipationListener自动创建参与者记录 - 处理并发冲突:
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
- 事件
- Chatwoot原实现的关键代码文件路径:
app/models/conversation_participant.rbapp/controllers/api/v1/accounts/conversations/participants_controller.rbapp/listeners/participation_listener.rbapp/services/messages/mention_service.rbapp/services/messages/new_message_notification_service.rbdb/schema.rb— conversation_participants 表config/routes.rb—resource :participants, only: [:show, :create, :update, :destroy]
- 版本标注:✅ 社区版
功能4:分配策略管理(Assignment Policy V2 CRUD)
- 功能描述:分配策略(Assignment Policy)定义了对话自动分配的规则,包括分配顺序(round_robin/balanced)、对话优先级、公平分配限制等。一个策略可关联多个 Inbox,每个 Inbox 只能关联一个策略。这是 V2 版本的自动分配机制。
- 用户操作流程(UI交互步骤):
- 进入 Settings → Assignment Policies 页面(需启用 assignment_v2 feature flag)
- 创建策略:填写名称、描述、分配顺序、对话优先级、公平分配限制/窗口等
- 将策略关联到 Inbox
- 可启用/禁用策略
- 涉及的API端点 + 请求/响应格式:
GET /api/v1/accounts/{account_id}/assignment_policies— 获取策略列表POST /api/v1/accounts/{account_id}/assignment_policies— 创建策略- 请求:
{ assignment_policy: { name: "Default", description: "...", assignment_order: "round_robin", conversation_priority: "earliest_created", fair_distribution_limit: 5, fair_distribution_window: 300, enabled: true } } - 响应:策略对象
{ id, name, description, assignment_order, conversation_priority, fair_distribution_limit, fair_distribution_window, enabled, assigned_inbox_count, created_at, updated_at }
- 请求:
GET /api/v1/accounts/{account_id}/assignment_policies/{id}— 获取单个策略PUT /api/v1/accounts/{account_id}/assignment_policies/{id}— 更新策略DELETE /api/v1/accounts/{account_id}/assignment_policies/{id}— 删除策略GET /api/v1/accounts/{account_id}/assignment_policies/{id}/inboxes— 获取策略关联的 Inbox 列表POST /api/v1/accounts/{account_id}/assignment_policies/{id}/inboxes— 将策略关联到 InboxDELETE /api/v1/accounts/{account_id}/assignment_policies/{id}/inboxes/{inbox_id}— 解除 Inbox 关联
- 涉及的数据模型 + 关键字段:
AssignmentPolicy模型(表assignment_policies):id(bigint, PK)account_id(bigint, not null)name(string 255, not null, 同账户下唯一)description(text)assignment_order(integer, default 0) — enum:round_robin: 0, 企业版额外balanced: 1conversation_priority(integer, default 0) — enum:earliest_created: 0,longest_waiting: 1fair_distribution_limit(integer, default 100, >0) — 在窗口内给单个坐席最多分配多少对话fair_distribution_window(integer, default 3600, >0) — 公平分配窗口时间(秒)enabled(boolean, default true)created_at,updated_at
InboxAssignmentPolicy模型(表inbox_assignment_policies):id(bigint, PK)inbox_id(bigint, not null, unique) — 每个 Inbox 只能关联一个策略assignment_policy_id(bigint, not null)created_at,updated_at
- 关联:
AssignmentPolicy has_many :inbox_assignment_policies,has_many :inboxes (through :inbox_assignment_policies)
- 涉及的业务逻辑(service层):
- CRUD 在 controller 中完成
Inboxes::AssignmentPoliciesController#create会先移除旧策略再关联新的(一对一关系)- 企业版差异:
Enterprise::Concerns::AssignmentPolicy增加balancedassignment_order enum
- 涉及的自动化/规则/事件:
- 无独立事件触发
- Chatwoot原实现的关键代码文件路径:
app/models/assignment_policy.rbapp/models/inbox_assignment_policy.rbapp/controllers/api/v1/accounts/assignment_policies_controller.rbapp/controllers/api/v1/accounts/assignment_policies/inboxes_controller.rbapp/controllers/api/v1/accounts/inboxes/assignment_policies_controller.rbapp/views/api/v1/accounts/assignment_policies/(index, show, create, update, _partial)app/views/api/v1/accounts/assignment_policies/inboxes/(index, create)enterprise/app/models/enterprise/concerns/assignment_policy.rbdb/schema.rb— assignment_policies, inbox_assignment_policies 表
- 版本标注:✅ 社区版(基础 round_robin);💎 企业版(额外 balanced 分配顺序)
功能5:Inbox 级别分配策略关联
- 功能描述:为 Inbox 直接设置其关联的分配策略。每个 Inbox 只能关联一个 AssignmentPolicy。这是一个便捷的 Inbox → AssignmentPolicy 一对一管理入口。
- 用户操作流程(UI交互步骤):
- 在 Inbox 设置页面中选择"Assignment Policy"
- 选择一个已有的分配策略进行关联
- 可查看当前关联的策略
- 可解除关联
- 涉及的API端点 + 请求/响应格式:
GET /api/v1/accounts/{account_id}/inboxes/{inbox_id}/assignment_policy— 获取 Inbox 当前关联的策略POST /api/v1/accounts/{account_id}/inboxes/{inbox_id}/assignment_policy— 关联策略- 请求:
{ assignment_policy_id: 1 } - 响应:AssignmentPolicy 对象
- 请求:
DELETE /api/v1/accounts/{account_id}/inboxes/{inbox_id}/assignment_policy— 解除关联
- 涉及的数据模型 + 关键字段:
- 同"功能4"中的
InboxAssignmentPolicy和AssignmentPolicy - Inbox 模型关联:
has_one :inbox_assignment_policy,has_one :assignment_policy, through: :inbox_assignment_policy
- 同"功能4"中的
- 涉及的业务逻辑(service层):
Inboxes::AssignmentPoliciesController#create:- 先移除旧的
inbox_assignment_policy(如果有) - 再创建新的关联
- 先移除旧的
validate_assignment_policy:确保 Inbox 已关联策略才可 show/destroy
- Chatwoot原实现的关键代码文件路径:
app/controllers/api/v1/accounts/inboxes/assignment_policies_controller.rbapp/models/inbox_assignment_policy.rbapp/models/inbox.rb—has_one :inbox_assignment_policy,has_one :assignment_policy
- 版本标注:✅ 社区版
功能6:自动分配引擎(Auto Assignment Engine)
- 功能描述:当新对话创建或对话变为 open/unassigned 状态时,系统根据 Inbox 的分配策略自动将对话分配给可用坐席。核心分配逻辑包括:筛选有容量的在线坐席、团队过滤、公平分配限制、轮询选择。
- 用户操作流程(UI交互步骤):
- 管理员在 Inbox 设置中启用自动分配(
enable_auto_assignment) - 如启用 V2(
assignment_v2feature flag),需要先为 Inbox 关联 AssignmentPolicy - 对话进入后系统自动分配给坐席
- 可在对话详情中看到被自动分配的坐席
- 管理员在 Inbox 设置中启用自动分配(
- 涉及的API端点 + 请求/响应格式:
- 无直接 API 端点,由后台 Job 自动执行
- 涉及的数据模型 + 关键字段:
Inbox模型:enable_auto_assignment(boolean, default true)auto_assignment_config(jsonb) — V1 版配置auto_assignment_v2_enabled?— 检查account.feature_enabled?('assignment_v2')
Conversation模型:assignee_id(integer) — 主分配坐席team_id(bigint) — 分配的团队status(integer) — 对话状态
- Redis 数据结构:
round_robin_key— Redis List,存储 Inbox 下坐席的轮询顺序assignment_key_pattern— Redis Key,用于公平分配限流追踪
- 涉及的业务逻辑(service层):
AutoAssignment::AssignmentService(核心调度器):perform_bulk_assignment(limit: 100)— 批量处理未分配对话unassigned_conversations(limit)— 获取 open+unassigned 对话,按策略排序find_available_agent(conversation)— 筛选可用坐席:- 按团队过滤(如果对话有 team_id 且团队 allow_auto_assign=true)
- 按 RateLimiter 过滤(超出公平分配限制的坐席被排除)
- RoundRobinSelector 从剩余坐席中选择下一个
assign_conversation(conversation, agent)— 执行分配,更新 conversation.assignee
AutoAssignment::InboxRoundRobinService(轮询队列管理):- Redis List 实现轮询队列
add_agent_to_queue(user_id)/remove_agent_from_queue(user_id)— 坐席变更时维护队列available_agent(allowed_agent_ids)— 从队列中选取下一个坐席,pop+push 实现轮询validate_queue?— 验证队列与实际 inbox_members 一致,不一致时 reset_queuereset_queue— 清空并重建队列
AutoAssignment::RoundRobinSelector:- 代理层,委托 InboxRoundRobinService 执行选择
AutoAssignment::AgentAssignmentService:- 用于已有允许坐席列表的场景(如手动指定坐席池)
- 只在在线坐席中轮询分配
- 使用
OnlineStatusTracker获取在线坐席列表
AutoAssignment::RateLimiter:within_limit?— 检查坐席在时间窗口内的分配数是否低于限制track_assignment(conversation)— 记录分配事件到 Redis- 默认限制:5 次/5分钟(V1),策略配置:fair_distribution_limit/fair_distribution_window(V2)
- 涉及的后台 Job:
AutoAssignment::AssignmentJob:- 批量分配 Job,使用 Redis
in_flightmarker 防止同 Inbox 并发 enqueue_for_inbox(inbox_id)— 带 NX 锁的 enqueue,确保每个 Inbox 同时只有一个 Job- TTL 5分钟自动释放
- 批量分配 Job,使用 Redis
AutoAssignment::PeriodicAssignmentJob:- 定时调度 Job(Cron),遍历所有启用 assignment_v2 的账户和 Inbox
- 对每个符合条件的 Inbox enqueue AssignmentJob
- 涉及的自动化/规则/事件:
- 事件
CONVERSATION_CREATED→ 触发自动分配检查 - Inbox member 变更 → 更新 round_robin 队列
- 对话状态变更 → 重新触发分配
- 事件
- Chatwoot原实现的关键代码文件路径:
app/services/auto_assignment/assignment_service.rbapp/services/auto_assignment/agent_assignment_service.rbapp/services/auto_assignment/round_robin_selector.rbapp/services/auto_assignment/inbox_round_robin_service.rbapp/services/auto_assignment/rate_limiter.rbapp/jobs/auto_assignment/assignment_job.rbapp/jobs/auto_assignment/periodic_assignment_job.rbapp/models/inbox.rb— enable_auto_assignment, auto_assignment_config, auto_assignment_v2_enabled?
- 版本标注:✅ 社区版(Round Robin 分配);💎 企业版(增加 Balanced 分配 + 容量过滤)
功能7:企业版 — 坐席容量策略(Agent Capacity Policy)
- 功能描述:企业版功能,定义坐席的对话容量上限策略。可以为不同坐席分配不同的容量策略,每个策略可以针对不同 Inbox 设置不同的对话数量上限(inbox_capacity_limit)。当坐席达到容量上限时,自动分配将跳过该坐席。
- 用户操作流程(UI交互步骤):
- 进入 Settings → Agent Capacity Policies 页面(企业版专属)
- 创建容量策略:填写名称、描述、排除规则(exclusion_rules)
- 为策略添加坐席用户
- 为策略配置每个 Inbox 的对话上限(inbox_limits)
- 涉及的API端点 + 请求/响应格式:
GET /api/v1/accounts/{account_id}/agent_capacity_policies— 列表POST /api/v1/accounts/{account_id}/agent_capacity_policies— 创建- 请求:
{ agent_capacity_policy: { name: "Standard", description: "...", exclusion_rules: { exclude_older_than_hours: 24, excluded_labels: ["spam"] } } } - 响应:AgentCapacityPolicy 对象
{ id, name, description, exclusion_rules, account_id }
- 请求:
GET /api/v1/accounts/{account_id}/agent_capacity_policies/{id}— 详情PUT /api/v1/accounts/{account_id}/agent_capacity_policies/{id}— 更新DELETE /api/v1/accounts/{account_id}/agent_capacity_policies/{id}— 删除GET /api/v1/accounts/{account_id}/agent_capacity_policies/{id}/users— 获取策略下的坐席列表POST /api/v1/accounts/{account_id}/agent_capacity_policies/{id}/users— 为坐席分配此策略- 请求:
{ user_id: 1 }
- 请求:
DELETE /api/v1/accounts/{account_id}/agent_capacity_policies/{id}/users/{user_id}— 解除坐席的策略关联POST /api/v1/accounts/{account_id}/agent_capacity_policies/{id}/inbox_limits— 为策略添加 Inbox 容量上限- 请求:
{ inbox_id: 1, conversation_limit: 10 }
- 请求:
PUT /api/v1/accounts/{account_id}/agent_capacity_policies/{id}/inbox_limits/{id}— 更新 Inbox 容量上限DELETE /api/v1/accounts/{account_id}/agent_capacity_policies/{id}/inbox_limits/{id}— 删除 Inbox 容量上限
- 涉及的数据模型 + 关键字段:
AgentCapacityPolicy模型(表agent_capacity_policies):id(bigint, PK)account_id(bigint, not null)name(string 255, not null)description(text)exclusion_rules(jsonb, default {}, not null) — 排除规则:exclude_older_than_hours— 排超过多少小时的老对话不计入容量excluded_labels— 带这些标签的对话不计入容量
created_at,updated_at
InboxCapacityLimit模型(表inbox_capacity_limits):id(bigint, PK)agent_capacity_policy_id(bigint, not null)inbox_id(bigint, not null)conversation_limit(integer, not null, ≥0) — 该 Inbox 下的对话容量上限- 唯一约束:
(agent_capacity_policy_id, inbox_id)
- 关联:
AgentCapacityPolicy has_many :inbox_capacity_limits,has_many :inboxes (through)AgentCapacityPolicy has_many :account_users (dependent: :nullify)— AccountUser 的 agent_capacity_policy_id 字段
- 涉及的业务逻辑(service层):
Enterprise::AutoAssignment::CapacityService:agent_has_capacity?(user, inbox)— 判断坐席在指定 Inbox 下是否有容量:- 获取坐席的
AccountUser.agent_capacity_policy - 如无策略或无该 Inbox 的 limit → 返回 true(无限容量)
- 计算
user.assigned_conversations.where(inbox:, status: :open).count - 比较 current_count < conversation_limit
- 获取坐席的
Enterprise::AutoAssignment::AssignmentService(扩展社区版):filter_agents_by_capacity(agents)— 过滤掉无容量的坐席capacity_filtering_enabled?— 需要advanced_assignmentfeature 且有坐席被分配了策略
Enterprise::InboxAgentAvailability(扩展 Inbox 模型):member_ids_with_assignment_capacity— 返回有容量的坐席 ID 列表(用于 V1 自动分配)
- 涉及的自动化/规则/事件:
- 无独立事件,自动分配流程中实时检查容量
- Chatwoot原实现的关键代码文件路径:
enterprise/app/models/agent_capacity_policy.rbenterprise/app/models/inbox_capacity_limit.rbenterprise/app/controllers/api/v1/accounts/agent_capacity_policies_controller.rbenterprise/app/controllers/api/v1/accounts/agent_capacity_policies/users_controller.rbenterprise/app/controllers/api/v1/accounts/agent_capacity_policies/inbox_limits_controller.rbenterprise/app/services/enterprise/auto_assignment/capacity_service.rbenterprise/app/services/enterprise/auto_assignment/assignment_service.rbenterprise/app/models/enterprise/inbox_agent_availability.rbenterprise/app/views/api/v1/accounts/agent_capacity_policies/(index, show, create, update)enterprise/app/views/api/v1/accounts/agent_capacity_policies/inbox_limits/(create, update)enterprise/app/views/api/v1/accounts/agent_capacity_policies/users/(index, create)db/schema.rb— agent_capacity_policies, inbox_capacity_limits 表
- 版本标注:💎 企业版(Business/Enterprise 计划专属,需
advanced_assignmentfeature flag)
功能8:企业版 — 均衡分配选择器(Balanced Selector)
- 功能描述:企业版的高级分配算法。与 Round Robin(轮询)不同,Balanced Selector 选择当前分配对话数最少的坐席,实现真正的负载均衡。
- 用户操作流程(UI交互步骤):
- 在 AssignmentPolicy 中设置
assignment_order为balanced - 系统自动使用 Balanced Selector 代替 Round Robin
- 在 AssignmentPolicy 中设置
- 涉及的数据模型 + 关键字段:
AssignmentPolicy.assignment_order = "balanced"(enum value 1)
- 涉及的业务逻辑(service层):
Enterprise::AutoAssignment::BalancedSelector:select_agent(available_agents)— 选择当前对话数最少的坐席fetch_assignment_counts(users)— 查询inbox.conversations.open.where(assignee_id: user_ids).group(:assignee_id).count- 使用
min_by { |user| assignment_counts[user.id] || 0 }选择负载最低的坐席
Enterprise::AutoAssignment::AssignmentService#find_available_agent:- 判断:如果
policy.balanced? && account.feature_enabled?('advanced_assignment')→ 使用 BalancedSelector - 否则使用 RoundRobinSelector
- 判断:如果
- 涉及的自动化/规则/事件:
- 无独立事件
- Chatwoot原实现的关键代码文件路径:
enterprise/app/services/enterprise/auto_assignment/balanced_selector.rbenterprise/app/services/enterprise/auto_assignment/assignment_service.rbenterprise/app/models/enterprise/concerns/assignment_policy.rb
- 版本标注:💎 企业版
功能9:手动分配对话(Assign/Unassign Agent/Team)
- 功能描述:坐席或管理员可以手动将对话分配给指定坐席或团队,或取消分配。这是最基础的对话分配操作。
- 用户操作流程(UI交互步骤):
- 在对话详情面板点击"Assign Agent"或"Assign Team"
- 从下拉列表中选择坐席或团队
- 可点击"Unassign"取消分配
- 对话面板实时更新显示分配信息
- 涉及的API端点 + 请求/响应格式:
- 对话更新 API 中包含
assignee_id和team_id字段:POST /api/v1/accounts/{account_id}/conversations/{id}/assignments— 分配坐席- 请求:
{ assignee_id: 1 }或{ team_id: 2 }
- 请求:
- 对话 update API 中也可以修改 assignee_id/team_id
- 对话更新 API 中包含
- 涉及的数据模型 + 关键字段:
Conversation模型:assignee_id(integer) — 主分配坐席 IDteam_id(bigint) — 分配的团队 IDassignee_agent_bot_id(bigint) — 分配的 Bot ID(与坐席互斥)
- 校验:
reset_agent_bot_when_assignee_present— 分配坐席时自动清除 bot 分配
- 涉及的业务逻辑(service层):
- 对话 model 中
after_update_commit :dispatcher_dispatch(CONVERSATION_UPDATED, previous_changes) dispatcher_dispatch触发CONVERSATION_UPDATED事件 →AutomationRuleListener可能触发自动化规则after_update_commit :notify_assignee_changed— 通知被分配的坐席self_assign?检查 — 如果坐席自己接管对话,不发通知
- 对话 model 中
- 涉及的自动化/规则/事件:
- 事件
CONVERSATION_UPDATED→ 触发自动化规则检查 - 事件
ASSIGNEE_CHANGED→ParticipationListener自动添加参与者
- 事件
- Chatwoot原实现的关键代码文件路径:
app/models/conversation.rb— assignee_id, team_id, after_update_commit hooksapp/controllers/api/v1/accounts/conversations/— assignments 相关app/listeners/participation_listener.rbapp/listeners/automation_rule_listener.rb
- 版本标注:✅ 社区版
模块间关系图
Account
├── Teams → TeamMembers → Users
├── AssignmentPolicies → InboxAssignmentPolicies → Inboxes
└── [企业版] AgentCapacityPolicies → AccountUsers + InboxCapacityLimits → Inboxes
Conversation
├── assignee_id → User (主分配坐席)
├── team_id → Team (分配团队)
├── ConversationParticipants → Users (附加参与者)
└── Inbox → AssignmentPolicy → AutoAssignment Engine
Auto Assignment Engine (社区版 Round Robin)
├── AssignmentService → 批量分配调度
├── InboxRoundRobinService → Redis 轮询队列
├── RoundRobinSelector → 坐席选择
├── AgentAssignmentService → 指定坐席池轮询
├── RateLimiter → 公平分配限流
├── AssignmentJob → 后台 Job (带 in-flight lock)
└── PeriodicAssignmentJob → 定时触发
Auto Assignment Engine (企业版扩展)
├── BalancedSelector → 负载均衡选择
├── CapacityService → 容量检查
└── InboxAgentAvailability → 容量过滤后的坐席列表
关键 Feature Flags
| Feature Flag | 影响范围 | 版本 |
|---|---|---|
assignment_v2 |
启用 Assignment Policy V2 + PeriodicAssignmentJob | 社区版(需手动启用) |
advanced_assignment |
启用 Balanced Selector + Agent Capacity Policy | 💎 企业版 |