# 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 索引 |