9.1 KiB
bricks.QAFrame 技术文档
一个基于 WebSocket 的问答交互框架组件,支持多媒体课件展示、题目呈现与用户答案提交。
概述
bricks.QAFrame 是 bricks UI 框架中的一个复合组件类,继承自 bricks.VBox。它用于构建一个完整的问答互动界面,通过 WebSocket 与后端服务通信,支持以下功能:
- 展示多媒体课件(视频、音频、图片、Markdown)
- 显示问题并接收用户输入(文本或语音)
- 控制答题流程(开始确认、题目切换、结果反馈等)
该组件广泛适用于在线教育、智能测评和互动学习场景。
继承关系
bricks.QAFrame → bricks.VBox → bricks.Widget
构造函数
new bricks.QAFrame(options)
参数:options (Object)
| 属性名 | 类型 | 必填 | 描述 |
|---|---|---|---|
ws_url |
String | 是 | WebSocket 连接地址 |
ws_params |
Object | 否 | WebSocket 查询参数对象,将被序列化为 URL 查询字符串 |
title |
String | 否 | 页面标题(未在代码中使用,保留字段) |
description |
String | 否 | 描述信息(未在代码中使用,保留字段) |
courseware |
Object | 否 | 初始课件配置,结构见下文 |
courseware 子属性
| 属性名 | 类型 | 可选值 | 描述 |
|---|---|---|---|
type |
String | "audio", "video", "image", "markdown" |
媒体类型 |
url |
String | - | 资源 URL |
timeout |
Number | 秒数,0 表示无超时 | 自动跳转时间 |
示例:
courseware: { type: 'video', url: '/media/intro.mp4', timeout: 30 }
内部结构布局
QAFrame 使用垂直布局容器(VBox),包含三个主要区域:
| 区域 | 组件 | 功能说明 |
|---|---|---|
top_w |
HBox |
顶部工具栏区域(可显示题号) |
main_w |
Filler |
主内容区,动态加载课件或问题 |
bottom_w |
HBox |
底部操作区,放置按钮或输入控件 |
WebSocket 通信协议
QAFrame 通过内置的 bricks.WebSocket 实例与服务器进行双向通信。
WebSocket 初始化
自动拼接 ws_params 成查询字符串:
const url = this.ws_url + '?' + new URLSearchParams(this.ws_params).toString();
this.ws = new bricks.WebSocket({ ws_url: url });
监听事件绑定
| 事件名 | 回调方法 | 触发时机 |
|---|---|---|
onopen |
start_question_answer() |
WebSocket 连接建立时 |
onquestion |
show_question(d) |
收到新问题数据 |
oncourseware |
show_courseware(d) |
收到课件数据 |
onaskstart |
show_conform(d) |
请求用户确认开始 |
⚠️ 注意:
oncourseware被重复绑定三次 —— 此为冗余代码,建议优化。
接收消息格式(Server → Client)
由 WebSocket 推送的消息通过 data 字段传递,type 标识消息类型。
| 编号 | 类型 | data 结构 |
说明 |
|---|---|---|---|
| 1 | courseware |
{ type, url } |
播放指定类型的媒体资源 |
| 2 | askready |
{ total_q, cur_q } |
提示准备开始第几题 |
| 3 | question |
{ q_desc, total_q, cur_q } |
显示具体问题 |
| 4 | result |
{ total_q, correct_cnt, error_cnt } |
显示答题结果统计 |
| 5 | error_list |
{ error_cnt, rows: [...] } |
错误详情列表 |
error_list.rows[] 元素结构
| 字段 | 类型 | 说明 |
|---|---|---|
pos |
Number | 题目位置索引 |
q_desc |
String | 题干描述 |
your_a |
String | 用户答案 |
corrent_a |
String | 正确答案 |
error_desc |
String | 错误原因说明 |
发送消息格式(Client → Server)
| 编号 | 类型 | data 值 |
触发方式 |
|---|---|---|---|
| 1 | qa_start |
null 或 { d: "test data", v: 100 } |
点击“开始”或连接打开时自动发送 |
| 2 | conform_start |
null |
用户点击“Start?”按钮触发 |
| 3 | text_answer |
{ texta: "用户输入内容" } |
文本输入框失去焦点时 |
| 4 | audio_answer |
Base64 编码的音频 Blob | 录音结束时自动发送 |
示例:
{ type: 'text_answer', data: 'Hello world' } { type: 'audio_answer', data: 'base64:...' }
核心方法说明
show_question(d)
显示一道新问题。
参数
d:{ q_desc, total_q, cur_q }
行为
- 更新顶部题号显示(需确保已创建
qtotal_w和qcur_w,当前代码缺失定义) - 使用
widgetBuild解析q_desc内容生成子组件 - 添加至主区域
✅ 支持富内容渲染(如 HTML、自定义组件)
show_courseware(d)
播放指定课件资源。
参数
d:{ type, url }
支持类型
| 类型 | 组件 | 特性 |
|---|---|---|
video |
bricks.Video |
全屏自动播放 |
audio |
bricks.AudioPlayer |
自动播放 |
image |
bricks.Image |
全屏展示 |
markdown |
bricks.MdWidget |
加载远程 .md 文件 |
所有组件均设置宽高为
100%,适应容器。
show_conform(d)
显示“是否开始”确认按钮。
行为
- 清空主区域
- 添加一个标签为
"Start ?"的按钮 - 绑定点击事件调用
start_question_answer()
start_question_answer()
向服务端发送启动信号。
this.ws.send({
type: 'qa_start',
data: { d: 'test data', v: 100 }
});
通常由 WebSocket.onopen 或用户点击触发。
conform_start()
发送用户确认开始指令。
this.ws.send({
type: 'conform_start',
data: null
});
send_text_answer(e)
处理文本答案提交。
参数
e.data.texta: 用户输入文本
流程
- 获取输入值
- 发送
text_answer消息
绑定于
StrInput的blur事件(失焦即提交)
send_audio_answer(e)
异步处理录音答案提交。
参数
e.data.audio: Blob 音频数据
流程
- 将 Blob 转为 Base64 字符串(依赖
blobToBase64函数) - 发送
audio_answer消息
⚠️ 注意:
send_audio_data方法未定义,应为笔误,实际应为send_audio_answer
build_input_widgets()
构建底部输入控件区。
创建组件
StrInput: 文本输入框(name=texta,样式填充)AudioRecorder: 语音录制按钮(带图标动画)
事件绑定
- 文本框失焦 →
send_text_answer - 录音结束 →
send_audio_answer(原写错为send_audio_data)
❗ 注释部分包含图像/视频采集功能预留接口(SVG 图标),目前未启用。
play_course()
【未使用】根据 this.courseware 播放初始课程内容。
当前逻辑中未调用此方法。若需启用,应在构造函数中补充调用。
build_startbtn()
构建底部“press to start”按钮。
当前未在构造函数中调用,可能用于手动控制启动流程。
工厂注册
bricks.Factory.register('QAFrame', bricks.QAFrame);
允许通过工厂模式按名称创建实例:
bricks.create({ type: 'QAFrame', ws_url: 'ws://localhost:8080' });
使用示例
<div id="qa-container"></div>
<script>
const qa = new bricks.QAFrame({
ws_url: 'ws://example.com/ws/qa',
ws_params: {
session_id: 'abc123',
user_id: 'u456'
},
courseware: {
type: 'video',
url: '/intro.mp4',
timeout: 15
}
});
document.getElementById('qa-container').appendChild(qa.root());
</script>
已知问题与改进建议
| 问题 | 描述 | 建议 |
|---|---|---|
qtotal_w / qcur_w 未定义 |
show_question 中尝试调用 .set_text(),但未初始化这些 widget |
应在构造函数中创建并加入 top_w |
oncourseware 多次绑定 |
同一事件监听器重复注册三次 | 保留一次即可 |
send_audio_data 调用错误 |
bind('record_ended') 指向不存在的方法 |
改为 this.send_audio_answer.bind(this) |
play_course() 未调用 |
初始化课件无法自动播放 | 在合适时机调用(如构造末尾判断是否存在 courseware) |
StrInput 工厂调用不明确 |
StrInput({...}) 不符合常规语法 |
应为 new bricks.StrInput(...) 或使用 widgetBuild |
总结
bricks.QAFrame 是一个功能完整、结构清晰的互动问答组件,具备以下优势:
✅ 支持多种媒体格式
✅ 实时双向通信
✅ 模块化设计便于扩展
✅ 适合嵌入式教学系统
建议修复上述问题以提升稳定性和可维护性。
文档版本:v1.0
最后更新:2025年4月