跳到正文

callflow-webpage

callflow 平台的管理台前端(Quasar 2.21.x + @quasar/app-vite 3.x + Vue 3 + TypeScript)。它通过 HTTP 调用 apps/callflow-server

当前版本已内置登录页与路由守卫,使用 localStorage 保存 Bearer token。 未登录访问受保护页面时,会跳到 /login?redirect=...&reason=required;本地 token 过期或后续接口收到 401 时,会清理本地会话并跳到 /login?redirect=...&reason=expired

页面

路由导航用途
/总览仪表盘:FreeSWITCH 概览(活跃通道、当前通话、SIP 注册)以及近期 channels / registrations
/runtime-configs运行配置编辑 tts 与录音落盘目录 recording.directory,触发 callflow-esl 重载
/number-mappings业务与号码映射业务定义、业务级 JSON 配置与被叫号码 → 业务映射配置的管理(增删改)
/freeswitch/channels通道监控当前通话与通道状态专用页
/freeswitch/registrationsSIP 注册SIP 注册与在线状态专用页
/softphone软电话浏览器 SIP over WebSocket / WebRTC 软电话:本地配置 SIP 注册、呼出、来电、接听、挂断、静音、保持与 DTMF
/verto-videophone视频电话浏览器 FreeSWITCH Verto 视频电话与会议:支持 1080P/720P 视频呼叫、前后置摄像头切换、画中画小窗、实时信令追踪与 WebRTC 统计
/outbound-call外呼测试选择或输入业务编码,填写完整外呼参数,经 callflow-server 代理提交 originate,并展示最近一次同步结果
/tables/:name通用 FreeSWITCH 表浏览:选择任意表、搜索、分页、点击单元格查看完整内容(/tables/channels/tables/sip_registrations 会重定向到上面的专用页)
/tts-auditionTTS 调试TTS 健康检查、端点切换、speaker 试听与缓存命中观察
/asr-testASR 调试上传音频、浏览器录音或实时检测,转为 16kHz mono PCM16 WAV 后提交到 ASR 服务并展示 partial / final 结果
/login管理员登录页;未登录访问业务页会自动跳转到这里

TTS 试听页从 TTS 服务的 /health 读取 model.numSpeakers,为每个可用音色渲染一个卡片; 因此多说话人模型(例如 Bert-VITS2 vits-zh-hf-fanchen-C 或 Kokoro)会自动暴露全部说话人。

“业务与号码映射”页在业务列表显示配置状态,并可用 JSON 对象弹窗编辑 businessConfig;保存 {} 会清空业务层覆盖。号码映射弹窗维护更高优先级的 mappingConfig。callflow-esl 的最终优先级为“配置文件 < 业务配置 < 号码映射配置”, 但显式 business_code 外呼不会读取号码映射层。两个配置字段都直接填写业务字段, 例如 { "model": "qwen3.5:2b" },不再额外嵌套 llmChat

外呼测试页的调用链为 callflow-webpage -> callflow-server -> callflow-esl -> FreeSWITCH。业务列表加载失败时仍可手工填写 businessCode;页面不会暴露或覆盖 服务端配置的 ESL 地址和 token。结果中的“已接受”只代表 FreeSWITCH 接受 originate, 不代表被叫已经接通,页面也不追踪后续挂机或通话状态。

软电话页首版只实现 MicroSIP 替代能力,不接入 callflow-esl 软电话会话、转写、TTS 或外呼坐席流程。当前 MicroSIP 常见配置 1000@192.168.2.184:5060 / transport=udp 不能被浏览器直接使用;浏览器必须连接 FreeSWITCH Sofia profile 暴露的 SIP WebSocket / WebRTC 地址,例如 ws://192.168.2.184:5066。如果管理台 通过 HTTPS 访问,浏览器侧 SIP WebSocket 也必须使用 wss://。页面可选择把 SIP 配置保存到本机 localStorage,不会写入后端。

主布局右下角的悬浮软电话与 /softphone 页面共用同一个全局 SIP 实例 (use-global-sip-softphone),注册与通话状态在路由切换间保持。进入 /softphone 页面时悬浮窗自动隐藏,来电由页面 UI 承接;离开页面后悬浮窗恢复,若来电仍在等待 会重新弹出提醒。远端音频由全局实例自持的 audio 元素播放,不依赖悬浮窗展开或任何 页面挂载。两处「注销」都只注销 SIP 注册,不清除已保存的本机配置。

/softphone 注册配置区提供「自动注册」开关,偏好使用独立的 localStorage 键保存在当前浏览器,未设置或存储值无效时默认开启,以保持原有 行为。关闭开关会立即注销当前 SIP UA 并停止 JsSIP 后续重连,但不会删除已保存的 SIP 配置,也不影响页面和悬浮窗中的手动「注册」。重新开启时,若当前表单的必填 配置完整会立即注册,并继续遵循「保存到本机浏览器」选项;来电或通话期间不能切换 此开关。

软电话在注册、拨号和接听前会请求受登录鉴权保护的 GET /api/softphone/ice-config。仓库默认 turn.enabled=false,后端返回 { enabled: false, iceServers: [], expiresAt: null },浏览器据此使用 host candidate 完成本地直连;此状态不缓存,也不安排刷新。跨网络生产部署应同时设置 turn.enabled=true 和真实 shared secret,成功响应会包含 STUN、TURN/UDP、TURN/TCP 及短期凭据过期时间。接口失败、启用响应为空或凭据过期时,新注册、拨号和接听会明确 失败,不会静默回退到空服务器列表。

Verto 视频通话与 WebRTC 会议(/verto-videophone

视频电话页面基于 FreeSWITCH 原生 mod_verto 协议与 WebRTC 原生 API 构建(核心封装位于 @/composables/use-verto-client):

  • 协议机制:采用纯标准的 JSON-RPC 2.0 over WebSocket 协议与 FreeSWITCH verto.conf.xml 交互(默认明文 ws://<host>:8081 或加密 wss://<host>:8082)。支持 verto.login 鉴权、verto.invite 呼叫、verto.answer 应答、verto.bye 挂断与 verto.info DTMF 发送。
  • 自适应视讯交互
    • 沉浸式视频区:远端大屏视频自动适应比例,未接通或纯音频通话时显示优雅的音频波形占位;
    • 画中画小窗:本地预览视频以右上角悬浮画中画(PiP)呈现,支持双击切换主副画面;
    • 移动端与响应式优化:针对手机/平板竖屏场景进行了全屏沉浸式适配与安全区域贴合;
    • 前后置摄像头切换:移动端提供 switchCamera 快捷翻转,支持动态无缝重协商视频轨;
    • 全功能控制栏:麦克风静音、摄像头开关、前后摄翻转、屏幕共享、拨号盘(DTMF 发送)与一键挂断。
  • 运维与排障支持
    • 信令日志抽屉:实时记录并高亮展示双方发送与接收的完整 JSON-RPC 2.0 报文;
    • WebRTC 实时统计:实时采样并展示当前音视频的分辨率、帧率(FPS)、发送/接收码率(kbps)、丢包率与往返延迟(RTT)。

开发

bash
bun install          # 或:npm install
bun run dev          # quasar dev — http://localhost:19913
bun run build        # quasar build → dist/spa
bun run test         # Bun 单元测试
bun run lint         # oxfmt + oxlint --fix
bun run typecheck    # vue-tsc --noEmit

源码结构

  • src/pages/:文件路由页面,只负责页面级编排和数据加载。
  • src/components/:可复用展示组件;例如 IncomingCallDialog 只接收来电数据并抛出操作事件,不持有 SIP 状态。
  • src/composables/:浏览器能力与有状态业务逻辑。SIP 生命周期、来电音、悬浮面板定位和离页保护均在此收口。
  • src/services/:HTTP、鉴权会话和路由鉴权边界;页面不直接维护 token 或拼装认证 Header。
  • src/router/:文件路由集成、历史地址重定向和全局鉴权守卫。

软电话相关代码遵循“协议状态与展示分离”:use-sip-softphone 管理 JsSIP 和 WebRTC 会话,SoftphoneWidget 负责编排注册与路由状态,IncomingCallDialog 仅负责 来电交互展示。刷新/关闭保护统一通过 use-before-unload-guard 注册,避免多个软电话 视图同时挂载时重复添加全局监听器。

开发服务器端口是 19913quasar.config.tsdevServer.port)。路由使用 hash 模式,并已启用 filenameBasedRouting

  • 路由文件入口保留在 src/router/index.ts,守卫和运行时重定向仍在这里维护。
  • 实际页面路由来自 src/pages/ 目录结构,不再维护 src/router/routes.ts
  • 源码 import 统一使用 @/,不再使用 src/components/stores/ 等旧别名。
  • 旧地址 /callflow/callflow/number-mappings 会分别重定向到 /runtime-configs/number-mappings

配置

环境变量默认值用途
VITE_CALLFLOW_API_BASE_URL/apicallflow-server API 根地址;值会在 Quasar/Vite 构建期固化

@/api/request.ts 只负责统一注入鉴权、 解包 { code, data, msg } 和处理请求错误;调用方直接从 @/api/auth@/api/callflow@/api/freeswitch@/api/speech@/api/softphone 引入对应领域接口,公共契约从 @/api/types 引入。领域接口只传入相对于 API 根的 路径,例如 /auth/login

API 根地址由 VITE_CALLFLOW_API_BASE_URL 在构建期注入,未设置或为空时使用同域 /api。 配置值推荐明确包含 /api;未包含时请求层会自动补齐,并清理首尾空白和末尾斜杠。 普通请求、文件上传和健康检查均通过该 API 根地址访问。

默认部署方式是在托管该前端的站点上将同域 /api 反向代理到 callflow-server (默认 http://127.0.0.1:9913),并保留上游请求中的 /api 路径。使用自定义代理前缀 或浏览器可访问的后端地址时,在构建前设置变量,例如:

bash
VITE_CALLFLOW_API_BASE_URL=/gateway/callflow/api bun run build

执行构建后,产物位于 dist/spa/。API 根地址变化后必须重新构建前端。

开发模式下:

  • 使用默认 /api 时,quasar.config.ts 会将其代理到 http://localhost:9913
  • 设置完整 http(s) API 地址时,浏览器会直接访问该地址。

推荐本地联调方式:

  • 前端:http://localhost:19913
  • 后端:http://127.0.0.1:9913
  • 启动命令:bun run dev

管理台自身健康检查也统一走 /api/health。所有请求都会统一附带 Authorization: Bearer ...,并在收到 401 时清理 localStorage 登录态、带上原目标地址和 reason=expired 跳回登录页。

登录页行为说明:

  • 登录成功后,会优先跳回 redirect 指向的站内路径;外部 URL、协议串、异常值会统一回退到 /
  • reason=required 时显示“请先登录后继续访问管理台”。
  • reason=expired 时显示“登录已过期,请重新登录”。
  • 如果后端不可达,页面仍会回到登录页,但提示会收敛为“无法连接登录服务”,避免与用户名/密码错误混淆。

文档与代码在同一仓库维护,现有 Markdown 是唯一内容源。