398 lines
27 KiB
Markdown
398 lines
27 KiB
Markdown
# M7 报告与CSAT — Chatwoot 功能梳理文档
|
||
|
||
> 基于 Chatwoot 源码深度阅读 + CodeGraph 上下文梳理
|
||
> 生成日期:2026-05-22
|
||
> 参照仓库:chatwoot-reference
|
||
> 模块覆盖:CSAT Survey · Campaign · Reporting Event + Rollup · Dashboard Stats · Inbox CSAT模板 · Report Metrics
|
||
|
||
---
|
||
|
||
## 1. CSAT Survey(客户满意度调查)
|
||
|
||
### CSAT 调查发送
|
||
- 功能描述:当会话被标记为已解决时,系统自动向客户发送满意度调查(CSAT Survey)。支持网站Widget内嵌消息、WhatsApp/Twilio模板消息三种投递通道,同时支持基于标签的 Survey Rules 精准定向。
|
||
- 用户操作流程:
|
||
1. 客服解决会话 → 系统监听 `conversation_status_changed` 事件
|
||
2. `CsatSurveyListener` 触发 `CsatSurveyService`
|
||
3. 服务判断 inbox 是否开启 CSAT、是否已发过 CSAT、是否符合 Survey Rules
|
||
4. WhatsApp 通道:使用 WhatsApp CSAT 模板投递;Twilio 通道:使用 Twilio CSAT 模板投递;Website 通道:在消息窗口内创建 `input_csat` 类型消息
|
||
5. 客户看到评分界面(1-5分 + 文本反馈框)
|
||
- 涉及的API端点:
|
||
- `GET /public/api/v1/csat_survey/:id` — 客户端获取 CSAT 调查页面(通过 conversation UUID)
|
||
- `PUT /public/api/v1/csat_survey/:id` — 客户提交/更新 CSAT 评分与反馈(14天内可修改)
|
||
- `GET /api/v1/accounts/:account_id/csat_survey_responses` — 列表查询(支持分页、排序、日期/agent/inbox/team 过滤)
|
||
- `GET /api/v1/accounts/:account_id/csat_survey_responses/metrics` — 统计汇总(总评分数、各评分等级分布、发送总数)
|
||
- `GET /api/v1/accounts/:account_id/csat_survey_responses/download` — CSV 导出下载
|
||
- 涉及的数据模型+关键字段:
|
||
- **CsatSurveyResponse**(`csat_survey_responses` 表):
|
||
- `rating` (integer, 1-5) — 评分等级
|
||
- `feedback_message` (text) — 文本反馈
|
||
- `csat_review_notes` (text) — 内部审阅备注
|
||
- `message_id` (bigint, UNIQUE) — 关联消息(一条消息唯一对应一条 CSAT 响应)
|
||
- `account_id`, `conversation_id`, `contact_id`, `assigned_agent_id` — 多维度关联
|
||
- `review_notes_updated_by_id`, `review_notes_updated_at` — 审阅追踪
|
||
- 涉及的业务逻辑:
|
||
- **CsatSurveyListener**(`app/listeners/csat_survey_listener.rb`):监听会话状态变化,触发 CSAT 发送;监听消息更新,构建 CSAT 响应
|
||
- **CsatSurveyService**(`app/services/csat_survey_service.rb`):发送前多重校验(`conversation_allows_csat?` / `csat_enabled?` / `csat_already_sent?` / `csat_allowed_by_survey_rules?`);根据通道类型选择发送方式
|
||
- **CsatSurveys::ResponseBuilder**(`app/builders/csat_surveys/response_builder.rb`):解析消息 `submitted_values` 中的 rating 和 feedback,创建/更新 CsatSurveyResponse 记录
|
||
- **MessageTemplates::Template::CsatSurvey**(`app/services/message_templates/template/csat_survey.rb`):创建 `content_type: input_csat` 的消息,支持自定义消息内容和 display_type(emoji / 文本)
|
||
- 涉及的自动化/规则/事件:
|
||
- 会话状态变更 → `CsatSurveyListener.conversation_status_changed` → 自动发送
|
||
- CSAT 消息提交 → `CsatSurveyListener.message_updated` → 自动构建 Response
|
||
- **Survey Rules**:基于会话标签的定向规则(`contains` / `does_not_contain` 操作符),配置在 inbox `csat_config` 中
|
||
- **14天锁定**:CSAT 提交后14天内可更新,超期锁定(`Public::CsatSurveyController.check_csat_locked`)
|
||
- Chatwoot原实现代码路径:
|
||
- `app/models/csat_survey_response.rb`
|
||
- `app/listeners/csat_survey_listener.rb`
|
||
- `app/services/csat_survey_service.rb`
|
||
- `app/services/message_templates/template/csat_survey.rb`
|
||
- `app/builders/csat_surveys/response_builder.rb`
|
||
- `app/controllers/public/api/v1/csat_survey_controller.rb`
|
||
- `app/controllers/api/v1/accounts/csat_survey_responses_controller.rb`
|
||
- 版本标注:v1(CSAT 基础)+ Enterprise(CSAT Response update 端点)
|
||
|
||
---
|
||
|
||
## 2. Campaign(营销活动/主动推送)
|
||
|
||
### Campaign CRUD + 触发
|
||
- 功能描述:Campaign 是面向 Inbox 中联系人进行主动消息推送的功能。支持两种类型:**ongoing**(持续性,当新对话进入时自动触发)和 **one_off**(一次性,向指定 audience 批量发送)。仅支持 Website、Twilio SMS、SMS、WhatsApp Inbox。
|
||
- 用户操作流程:
|
||
1. 用户在 Inbox 设置中创建 Campaign(选择类型、填写标题/消息/触发规则/受众)
|
||
2. ongoing 类型:当新对话匹配 trigger_rules 时,自动发送 Campaign 消息
|
||
3. one_off 类型:设置 scheduled_at,系统通过 Campaigns::TriggerOneoffCampaignJob 定时触发
|
||
4. 触发时根据 Inbox 类型调用对应 Service(Twilio SMS / SMS / WhatsApp)
|
||
- 涉及的API端点:
|
||
- `POST /api/v1/accounts/:account_id/campaigns` — 创建
|
||
- `GET /api/v1/accounts/:account_id/campaigns` — 列表
|
||
- `GET /api/v1/accounts/:account_id/campaigns/:id` — 详情
|
||
- `PUT /api/v1/accounts/:account_id/campaigns/:id` — 更新
|
||
- `DELETE /api/v1/accounts/:account_id/campaigns/:id` — 删除
|
||
- `GET /api/v1/widget/campaigns` — Widget端获取进行中的 Campaign
|
||
- 涉及的数据模型+关键字段:
|
||
- **Campaign**(`campaigns` 表):
|
||
- `campaign_type` (enum: ongoing=0, one_off=1) — 活动类型
|
||
- `campaign_status` (enum: active=0, completed=1) — 活动状态
|
||
- `title` (string, required) — 活动标题
|
||
- `message` (text, required) — 活动消息内容
|
||
- `enabled` (boolean, default true) — 是否启用
|
||
- `trigger_only_during_business_hours` (boolean) — 是否仅在营业时间触发
|
||
- `trigger_rules` (jsonb) — 触发规则(ongoing 类型使用)
|
||
- `audience` (jsonb) — 受众筛选条件(one_off 类型使用)
|
||
- `template_params` (jsonb) — 模板参数(WhatsApp Campaign)
|
||
- `scheduled_at` (datetime) — 定时发送时间(one_off 类型)
|
||
- `inbox_id` (bigint, required) — 关联 Inbox
|
||
- `sender_id` (integer) — 发送者 ID
|
||
- `display_id` (integer) — 展示 ID(自增)
|
||
- 涉及的业务逻辑:
|
||
- **Campaign.trigger!**:one_off 活动触发执行,根据 inbox.inbox_type 选择对应 Service
|
||
- **Twilio::OneoffSmsCampaignService** / **Sms::OneoffSmsCampaignService** / **Whatsapp::OneoffCampaignService**:各通道的具体发送实现
|
||
- **Liquid::CampaignTemplateService**:支持 Liquid 模板语法(`{{contact.name}}` 等)的消息变量替换
|
||
- 创建前校验:`validate_campaign_inbox`(仅支持 Website/Twilio SMS/SMS/WhatsApp)、`sender_must_belong_to_account`、`inbox_must_belong_to_account`
|
||
- 已完成的活动不可更新(`prevent_completed_campaign_from_update`)
|
||
- 涉及的自动化/规则/事件:
|
||
- **Campaigns::TriggerOneoffCampaignJob**:one_off 活动定时触发(scheduled_at 时间到达后执行)
|
||
- ongoing 活动:在会话创建时由前端 / Conversation 创建流程中判断 trigger_rules 匹配并发送
|
||
- 活动完成后状态自动标记为 `completed`
|
||
- Chatwoot原实现代码路径:
|
||
- `app/models/campaign.rb`
|
||
- `app/controllers/api/v1/accounts/campaigns_controller.rb`
|
||
- `app/controllers/api/v1/widget/campaigns_controller.rb`
|
||
- `app/jobs/campaigns/trigger_oneoff_campaign_job.rb`
|
||
- `app/services/twilio/oneoff_sms_campaign_service.rb`
|
||
- `app/services/sms/oneoff_sms_campaign_service.rb`
|
||
- `app/services/whatsapp/oneoff_campaign_service.rb`
|
||
- `app/services/liquid/campaign_template_service.rb`
|
||
- 版本标注:v1 基础;WhatsApp Campaign 需要 feature flag `whatsapp_campaign`
|
||
|
||
---
|
||
|
||
## 3. Reporting Event + Rollup(报告事件与数据聚合)
|
||
|
||
### Reporting Event 采集
|
||
- 功能描述:ReportingEvent 是 Chatwoot 报告系统的原始数据层,通过事件监听器在关键业务节点自动采集指标事件。涵盖首次响应时间、回复时间、会话解决时间、Bot 解决/移交等核心指标。每条事件包含时间值、营业时间值、多维度关联(account/inbox/user/conversation)。
|
||
- 用户操作流程:
|
||
1. 客服首次回复 → `ReportingEventListener.first_reply_created` → 写入 `first_response` 事件
|
||
2. 客服后续回复 → `reply_time_created` → 写入 `reply_time` 事件
|
||
3. 会话被解决 → `conversation_resolved` → 写入 `conversation_resolved` + `resolution_time` 事件
|
||
4. Bot 解决 → `conversation_bot_resolved` → 写入 Bot 解决事件
|
||
5. Bot 移交人类 → `conversation_bot_handoff` → 写入 Bot 移交事件
|
||
6. 每条事件写入后 → `ReportingEvents::RollupService` 异步聚合到 Rollup 表
|
||
- 涉及的API端点:
|
||
- `GET /api/v1/accounts/:account_id/conversations/:id/reporting_events` — 会话级事件列表(Enterprise)
|
||
- `GET /api/v1/accounts/:account_id/reporting_events` — 账户级事件列表(Enterprise)
|
||
- 涉及的数据模型+关键字段:
|
||
- **ReportingEvent**(`reporting_events` 表):
|
||
- `name` (string, required) — 事件名(first_response / reply_time / conversation_resolved / conversation_bot_resolved / conversation_bot_handoff / conversation_opened)
|
||
- `value` (float, required) — 时间值(秒)
|
||
- `value_in_business_hours` (float) — 营业时间内的时间值
|
||
- `event_start_time` / `event_end_time` (datetime) — 事件起止时间
|
||
- `account_id`, `inbox_id`, `user_id`, `conversation_id` — 多维度关联
|
||
- **ReportingEventsRollup**(`reporting_events_rollups` 表):
|
||
- `metric` (enum: resolutions_count / first_response / resolution_time / reply_time / bot_resolutions_count / bot_handoffs_count) — 指标名
|
||
- `dimension_type` (enum: account / agent / inbox / team) — 维度类型
|
||
- `dimension_id` (bigint) — 维度值
|
||
- `date` (date) — 聚合日期
|
||
- `count` (bigint) — 事件计数
|
||
- `sum_value` (float) — 时间值总和
|
||
- `sum_value_business_hours` (float) — 营业时间值总和
|
||
- 涉及的业务逻辑:
|
||
- **ReportingEventListener**(`app/listeners/reporting_event_listener.rb`):监听6种事件,计算时间差并写入 ReportingEvent
|
||
- `first_reply_created`:计算首次响应时间 = message.created_at - last_non_human_activity
|
||
- `conversation_resolved`:计算解决时间 = event_end_time - conversation.created_at
|
||
- `reply_time_created`:计算回复时间差
|
||
- `conversation_bot_resolved` / `conversation_bot_handoff`:Bot 相关指标
|
||
- **ReportingEventHelper.last_non_human_activity**:计算首次响应基线时间,优先取 bot_handoff / conversation_opened 事件时间,回退到 bot_resolved 或 conversation.created_at
|
||
- **ReportingEventHelper.business_hours**:利用 `working_hours` gem 计算 inbox 营业时间内的有效时长
|
||
- **ReportingEvents::RollupService**:每条 ReportingEvent 写入后触发,按 account/agent/inbox 三维度聚合到 Rollup 表(upsert + count/sum 累加)
|
||
- **ReportingEvents::EventMetricRegistry**:定义事件 → Rollup 指标的映射关系
|
||
- **ReportingEvents::BackfillService**:历史数据回填,批量聚合指定日期范围内的原始事件
|
||
- 涉及的自动化/规则/事件:
|
||
- 事件写入 → `safe_rollup(reporting_event)` 自动触发 Rollup 聚合
|
||
- Rollup 仅在账户设置了 `reporting_timezone` 时启用(软开关)
|
||
- Rollup 读取路径通过 feature flag `reporting_events_rollup` 控制
|
||
- 首次响应时间基线考虑 Bot 移交 / 重开等场景(`last_non_human_activity`)
|
||
- Chatwoot原实现代码路径:
|
||
- `app/models/reporting_event.rb`
|
||
- `app/models/reporting_events_rollup.rb`
|
||
- `app/listeners/reporting_event_listener.rb`
|
||
- `app/helpers/reporting_event_helper.rb`
|
||
- `app/services/reporting_events/rollup_service.rb`
|
||
- `app/services/reporting_events/event_metric_registry.rb`
|
||
- `app/services/reporting_events/metric_registry.rb`
|
||
- `app/services/reporting_events/backfill_service.rb`
|
||
- `db/migrate/20260211145813_create_reporting_events_rollup.rb`
|
||
- 版本标注:v1 ReportingEvent 基础;Rollup 为后续增强(2026年新增 Rollup 表 + 聚合机制)
|
||
|
||
---
|
||
|
||
## 4. Dashboard Stats(仪表盘实时统计)
|
||
|
||
### Live Reports(实时会话指标)
|
||
- 功能描述:LiveReports 提供会话维度的实时统计,包括打开数、未关注数、未分配数、等待数。支持按 team_id / assignee_id 分组聚合,用于仪表盘实时展示。
|
||
- 用户操作流程:
|
||
1. 用户打开仪表盘首页 → 前端请求 live report API
|
||
2. 系统查询当前账户的会话实时状态
|
||
3. 返回 open/unattended/unassigned/pending 计数
|
||
4. 如请求 grouped 接口 → 按 team 或 agent 分组返回各组计数
|
||
- 涉及的API端点:
|
||
- `GET /api/v2/accounts/:account_id/live_reports/conversation_metrics` — 全局实时指标(需 `report:view` 权限)
|
||
- `GET /api/v2/accounts/:account_id/live_reports/grouped_conversation_metrics?group_by=team_id/assignee_id` — 分组实时指标
|
||
- 参数:`team_id`, `inbox_id`, `user_ids[]` — 过滤条件
|
||
- 涉及的数据模型+关键字段:
|
||
- 基于 **Conversation** 模型的 scope 查询:
|
||
- `open` — 状态为 open 的会话
|
||
- `unattended` — open + 无人工回复的会话
|
||
- `unassigned` — open + 无 assignee 的会话
|
||
- `pending` — 状态为 pending 的会话
|
||
- 涉及的业务逻辑:
|
||
- **LiveReportsController** 直接用 Conversation scope 做 count/group 查询
|
||
- 分组模式:`group(@group_scope).count` 按 team_id 或 assignee_id 分组统计
|
||
- 权限控制:`authorize :report, :view?`
|
||
- 涉及的自动化/规则/事件:无(纯查询接口)
|
||
- Chatwoot原实现代码路径:
|
||
- `app/controllers/api/v2/accounts/live_reports_controller.rb`
|
||
- 版本标注:v2
|
||
|
||
### Dashboard Apps(自定义仪表盘应用)
|
||
- 功能描述:DashboardApp 是嵌入在 Chatwoot 主仪表盘中的自定义 iframe 应用模块。用户可配置标题和内容(URL + type=frame),将外部报表/工具嵌入到客服工作界面。
|
||
- 用户操作流程:
|
||
1. 管理员在设置中创建 Dashboard App(配置标题和 iframe URL)
|
||
2. 前端在仪表盘侧边栏或主区域渲染 iframe
|
||
3. 外部应用通过 iframe 嵌入展示
|
||
- 涉及的API端点:
|
||
- `POST /api/v1/accounts/:account_id/dashboard_apps` — 创建
|
||
- `GET /api/v1/accounts/:account_id/dashboard_apps` — 列表
|
||
- `GET /api/v1/accounts/:account_id/dashboard_apps/:id` — 详情
|
||
- `PUT /api/v1/accounts/:account_id/dashboard_apps/:id` — 更新
|
||
- `DELETE /api/v1/accounts/:account_id/dashboard_apps/:id` — 删除
|
||
- 涉及的数据模型+关键字段:
|
||
- **DashboardApp**(`dashboard_apps` 表):
|
||
- `title` (string, required) — 应用标题
|
||
- `content` (jsonb, required) — 内容配置,结构为 `[ { url: "https://...", type: "frame" } ]`
|
||
- `account_id`, `user_id` — 关联
|
||
- 涉及的业务逻辑:
|
||
- JSON Schema 校验 content 格式(必须为 array,每项必须有 url 和 type=frame,url 必须为 http/https)
|
||
- 空内容自动置为 `[]`
|
||
- 涉及的自动化/规则/事件:无
|
||
- Chatwoot原实现代码路径:
|
||
- `app/models/dashboard_app.rb`
|
||
- `app/controllers/api/v1/accounts/dashboard_apps_controller.rb`
|
||
- 版本标注:v1
|
||
|
||
---
|
||
|
||
## 5. Inbox CSAT 模板(WhatsApp/Twilio CSAT 模板管理)
|
||
|
||
### CSAT 模板创建与管理
|
||
- 功能描述:针对 WhatsApp 和 Twilio WhatsApp 通道,CSAT 调查需要通过官方模板(Template)发送。此功能提供 CSAT 模板的状态查询、创建、效用分析(Captain AI 评分)三部分能力。模板创建后自动更新 Inbox 的 `csat_config` 配置。
|
||
- 用户操作流程:
|
||
1. 管理员进入 Inbox 设置 → CSAT 模板管理
|
||
2. 查看当前模板状态(是否已创建、是否已审批通过)
|
||
3. 创建新模板(填写消息文本、按钮文本、语言)→ 系统调用 WhatsApp/Twilio API 创建
|
||
4. 可选使用 AI 分析功能(analyze)对模板文本质量进行评分
|
||
5. 模板审批通过后,CsatSurveyService 在 WhatsApp 通道优先使用模板发送
|
||
- 涉及的API端点:
|
||
- `GET /api/v1/accounts/:account_id/inboxes/:inbox_id/csat_template` — 查看模板状态
|
||
- `POST /api/v1/accounts/:account_id/inboxes/:inbox_id/csat_template` — 创建模板
|
||
- `POST /api/v1/accounts/:account_id/inboxes/:inbox_id/csat_template/analyze` — AI 分析模板效用(需 Captain feature flag)
|
||
- 涉及的数据模型+关键字段:
|
||
- **Inbox** 的 `csat_config` (jsonb):
|
||
- `csat_survey_enabled` (boolean) — 是否开启 CSAT
|
||
- `message` (string) — 自定义 CSAT 消息文本
|
||
- `display_type` (string) — 评分展示类型(emoji / text)
|
||
- `survey_rules` — 标签定向规则
|
||
- `template` — WhatsApp/Twilio 模板配置(template name、language、status 等)
|
||
- 涉及的业务逻辑:
|
||
- **CsatTemplateManagementService**:
|
||
- `template_status`:根据 Inbox 类型调用 WhatsApp/Twilio API 查询模板审批状态
|
||
- `create_template`:验证参数 → 删除旧模板 → 调用对应 Provider API 创建 → 更新 `csat_config`
|
||
- **Whatsapp::CsatTemplateService** / **Twilio::CsatTemplateService**:封装 WhatsApp Business API 和 Twilio API 的模板 CRUD
|
||
- **CsatTemplateUtilityAnalysisService**:调用 Captain AI 分析模板文本质量(按钮文字、语言适配性)
|
||
- **CsatTemplateNameService**:生成标准化的 CSAT 模板命名
|
||
- **CsatTemplateUtilityRubric**:定义 CSAT 模板质量评分标准
|
||
- 涉及的自动化/规则/事件:
|
||
- 模板创建 → 自动更新 Inbox `csat_config` 的 `template` 字段
|
||
- 模板审批状态变更 → 前端重新查询状态
|
||
- CsatSurveyService 发送时检查 `template_available_and_approved?`,优先使用模板
|
||
- Chatwoot原实现代码路径:
|
||
- `app/controllers/api/v1/accounts/inbox_csat_templates_controller.rb`
|
||
- `app/services/csat_template_management_service.rb`
|
||
- `app/services/csat_template_utility_analysis_service.rb`
|
||
- `app/services/csat_template_utility_rubric.rb`
|
||
- `app/services/csat_template_name_service.rb`
|
||
- `app/services/whatsapp/csat_template_service.rb`
|
||
- `app/services/twilio/csat_template_service.rb`
|
||
- `app/services/twilio/csat_template_api_client.rb`
|
||
- 版本标注:v1;AI analyze 需要 Captain feature flag
|
||
|
||
---
|
||
|
||
## 6. Report Metrics(报告指标与数据查询体系)
|
||
|
||
### 指标注册体系
|
||
- 功能描述:Chatwoot 报告系统采用双层指标注册机制。**ReportingEvents::EventMetricRegistry** 定义写入侧(原始事件 → Rollup 指标的映射),**Reports::ReportMetricRegistry** 定义读取侧(API 请求指标名 → 查询策略的映射)。两者保持指标名对齐,确保写入和读取路径一致。
|
||
- 核心指标清单:
|
||
- **conversations_count** — 会话数(count)
|
||
- **incoming_messages_count** — 收到消息数(count)
|
||
- **outgoing_messages_count** — 发出消息数(count)
|
||
- **avg_first_response_time** — 平均首次响应时间(average, raw_event: first_response, rollup: first_response)
|
||
- **avg_resolution_time** — 平均解决时间(average, raw_event: conversation_resolved, rollup: resolution_time)
|
||
- **avg_reply_time** — 平均回复时间(average, raw_event: reply_time, rollup: reply_time)
|
||
- **resolved_conversations_count** — 已解决会话数(count, raw_event: conversation_resolved)
|
||
- **bot_resolutions_count** — Bot 解决数(count)
|
||
- **bot_handoffs_count** — Bot 移交数(count)
|
||
|
||
### 时序报告(Timeseries Report)
|
||
- 功能描述:时序报告按时间维度(day/week/month/year/hour)聚合指标数据,支持按 account/inbox/agent/label/team 维度过滤,返回 `{ value, timestamp, count }` 结构的时序数据。数据源自动选择 RawDataSource(原始事件查询)或 RollupDataSource(聚合表查询,预留)。
|
||
- 用户操作流程:
|
||
1. 前端请求指定 metric + type + id + 时间范围的报告 API
|
||
2. ReportBuilder 根据 metric 从 ReportMetricRegistry 获取查询策略
|
||
3. DataSource.for() 创建数据源实例(当前默认 RawDataSource)
|
||
4. 执行 timeseries 或 aggregate 查询 → 返回时间序列数据
|
||
- 涉及的API端点:
|
||
- `GET /api/v2/accounts/:account_id/reports?metric=avg_first_response_time&type=account&id=1&since=...&until=...` — 时序数据
|
||
- `GET /api/v2/accounts/:account_id/reports/summary` — 全局汇总
|
||
- `GET /api/v2/accounts/:account_id/reports/bot_summary` — Bot 汇总
|
||
- 涉及的数据模型+关键字段:
|
||
- 基于 ReportingEvent + ReportingEventsRollup 的查询
|
||
- DataSource 参数:`account, metric, dimension_type, dimension_id, scope, range, group_by, timezone_offset, business_hours`
|
||
- 涉及的业务逻辑:
|
||
- **V2::Reports::Conversations::ReportBuilder** → **V2::Reports::Timeseries::ReportBuilder** → **Reports::DataSource.for()** → **Reports::RawDataSource**
|
||
- RawDataSource.timeseries:average 指标 → `group_by_period + average + count`;count 指标 → `group_by_period + count`
|
||
- RawDataSource.summary:按 dimension_type 分组查询各指标(conversations_count / resolved_count / avg_resolution_time / avg_first_response_time / avg_reply_time)
|
||
- 支持 business_hours 参数:当 `use_business_hours?` 为 true 时查询 `value_in_business_hours` 字段
|
||
- 涉及的自动化/规则/事件:
|
||
- Rollup 读取路径预留:DataSource.for() 中注释 `# TODO: Route to Reports::RollupDataSource when rollup reads are implemented`
|
||
- Chatwoot原实现代码路径:
|
||
- `app/services/reports/report_metric_registry.rb`
|
||
- `app/services/reports/data_source.rb`
|
||
- `app/services/reports/raw_data_source.rb`
|
||
- `app/builders/v2/reports/conversations/report_builder.rb`
|
||
- `app/builders/v2/reports/conversations/base_report_builder.rb`
|
||
- `app/builders/v2/reports/timeseries/report_builder.rb`
|
||
- `app/builders/v2/reports/timeseries/base_timeseries_builder.rb`
|
||
- `app/controllers/api/v2/accounts/reports_controller.rb`
|
||
- 版本标注:v2;Rollup 读取路径待实现
|
||
|
||
### Summary Reports(分组汇总报告)
|
||
- 功能描述:Summary Reports 按不同维度(Agent / Team / Inbox / Label / Channel)提供分组汇总数据,每组返回 conversations_count、resolved_conversations_count、avg_resolution_time、avg_first_response_time、avg_reply_time 五项指标。支持 business_hours 和日期范围过滤。Channel Summary 有额外日期范围长度限制(≤31天)。
|
||
- 用户操作流程:
|
||
1. 前端选择维度(Agent/Team/Inbox/Label/Channel)+ 日期范围 + 是否仅营业时间
|
||
2. 后端调用对应 SummaryBuilder → DataSource.summary → 聚合查询
|
||
3. Builder 将结果按维度分组整理返回
|
||
- 涉及的API端点:
|
||
- `GET /api/v2/accounts/:account_id/summary_reports/agent?since=...&until=...&business_hours=true`
|
||
- `GET /api/v2/accounts/:account_id/summary_reports/team`
|
||
- `GET /api/v2/accounts/:account_id/summary_reports/inbox`
|
||
- `GET /api/v2/accounts/:account_id/summary_reports/label`
|
||
- `GET /api/v2/accounts/:account_id/summary_reports/channel`(≤31天限制)
|
||
- 涉及的数据模型+关键字段:
|
||
- 通过 Reports::DataSource.summary 查询 ReportingEvent / ReportingEventsRollup
|
||
- SummaryBuilder 的 group_by_key:Agent → `user_id`,Team → `conversations.team_id`,Inbox → `inbox_id`
|
||
- 涉及的业务逻辑:
|
||
- **V2::Reports::AgentSummaryBuilder**:按 user_id 分组,遍历 account_users 构建每个 Agent 的指标字典
|
||
- **V2::Reports::TeamSummaryBuilder** / **InboxSummaryBuilder** / **LabelSummaryBuilder** / **ChannelSummaryBuilder**:类似模式
|
||
- **V2::Reports::BaseSummaryBuilder**:统一 load_data → prepare_report 流程,data_source 使用 summary_dimension_type 映射
|
||
- Channel Summary 特殊:日期范围 ≤31天校验
|
||
- 涉及的自动化/规则/事件:无(纯查询)
|
||
- Chatwoot原实现代码路径:
|
||
- `app/controllers/api/v2/accounts/summary_reports_controller.rb`
|
||
- `app/builders/v2/reports/base_summary_builder.rb`
|
||
- `app/builders/v2/reports/agent_summary_builder.rb`
|
||
- `app/builders/v2/reports/team_summary_builder.rb`
|
||
- `app/builders/v2/reports/inbox_summary_builder.rb`
|
||
- `app/builders/v2/reports/label_summary_builder.rb`
|
||
- `app/builders/v2/reports/channel_summary_builder.rb`
|
||
- 版本标注:v2
|
||
|
||
### CSV 导出报告
|
||
- 功能描述:Reports Controller 的 agents/inboxes/labels/teams/conversations_summary/conversation_traffic 端点同时支持 JSON 和 CSV 导出。前端请求时根据响应格式选择渲染方式。
|
||
- 涉及的API端点:
|
||
- `GET /api/v2/accounts/:account_id/reports/agents` — Agent 报告(JSON/CSV)
|
||
- `GET /api/v2/accounts/:account_id/reports/inboxes` — Inbox 报告(JSON/CSV)
|
||
- `GET /api/v2/accounts/:account_id/reports/labels` — Label 报告
|
||
- `GET /api/v2/accounts/:account_id/reports/teams` — Team 报告
|
||
- `GET /api/v2/accounts/:account_id/reports/conversations_summary` — 会话汇总
|
||
- `GET /api/v2/accounts/:account_id/reports/conversation_traffic` — 会话流量热力图
|
||
- `GET /api/v2/accounts/:account_id/reports/bot_metrics` — Bot 指标
|
||
- `GET /api/v2/accounts/:account_id/reports/first_response_time_distribution` — 首次响应时间分布
|
||
- 涉及的业务逻辑:
|
||
- **ReportsHelper**(`app/helpers/api/v2/accounts/reports_helper.rb`):调用各 SummaryBuilder 构建 JSON 数据,再转换为 CSV 格式
|
||
- **HeatmapHelper**:会话流量热力图数据,按小时 × 日期矩阵组织
|
||
- `generate_csv` 方法:根据格式参数渲染 CSV template 或 JSON
|
||
- Chatwoot原实现代码路径:
|
||
- `app/helpers/api/v2/accounts/reports_helper.rb`
|
||
- `app/helpers/api/v2/accounts/heatmap_helper.rb`
|
||
- `app/controllers/api/v2/accounts/reports_controller.rb`
|
||
- `app/views/api/v2/accounts/reports/` — CSV 模板
|
||
- 版本标注:v2
|
||
|
||
---
|
||
|
||
## 附录:模块间依赖关系
|
||
|
||
| 功能 | 依赖 |
|
||
|------|------|
|
||
| CSAT Survey | Inbox.csat_config, Conversation.resolved, Message.input_csat, WhatsApp/Twilio Template |
|
||
| Campaign | Inbox.inbox_type, Liquid Template, Contact/Audience |
|
||
| Reporting Event | Conversation lifecycle events, Inbox.working_hours, User assignments |
|
||
| Reporting Rollup | Reporting Event (写入触发), Account.reporting_timezone |
|
||
| Live Reports | Conversation.open/unattended/unassigned/pending scopes |
|
||
| Dashboard Apps | Account, User |
|
||
| Inbox CSAT Template | Inbox.channel (WhatsApp/Twilio), csat_config, Captain AI |
|
||
| Report Metrics | ReportingEvent + Rollup (数据源), ReportMetricRegistry (查询策略) |
|
||
| Summary Reports | DataSource.summary, Conversation group scopes |
|
||
| CSAT Survey → Reporting | CSAT 评分数据未直接写入 ReportingEvent(独立查询体系) |
|
||
|
||
---
|
||
|
||
## 附录:核心数据表一览
|
||
|
||
| 表名 | 主要字段 | 索引特点 |
|
||
|------|---------|---------|
|
||
| `csat_survey_responses` | rating(1-5), feedback_message, message_id(UNIQUE), assigned_agent_id, contact_id | message_id 唯一索引,多维度关联索引 |
|
||
| `campaigns` | campaign_type(ongoing/one_off), campaign_status(active/completed), trigger_rules(jsonb), audience(jsonb), scheduled_at | campaign_type/status/scheduled_at 索引 |
|
||
| `reporting_events` | name, value, value_in_business_hours, account_id, inbox_id, user_id, conversation_id, event_start/end_time | (account_id,name,created_at) 复合索引,response_distribution 复合索引 |
|
||
| `reporting_events_rollups` | metric, dimension_type, dimension_id, date, count, sum_value, sum_value_business_hours | (account_id,date,dimension_type,dimension_id,metric) UNIQUE,timeseries/summary 索引 |
|
||
| `dashboard_apps` | title, content(jsonb: [{url,type:"frame"}]), account_id, user_id | account_id, user_id 索引 | |