「计算机设计大赛」AI互动微课开发日志·第2篇:核心功能——从“空白页”到“能互动”

上回说到,我们搞定了技术选型问题,今天我们将具体聊一聊具体的「课前问答模态框」如何实现的,「智能体对话功能」是怎么调 Coze API 的,以及如何纯靠前端操作+后端轻量接口,实现数据储存功能。

课前问答:用 JS「搭积木」

需求是做一个「渐进式问答」:用户点「开启微课」按钮 → 弹出问题1→ 选答案 → 显示解析 → 自动跳到问题2→ 最后跳转视频页。这功能看起来简单,实际写起来全是细节。

1.1 模态框的「显隐控制」

首先得让模态框能弹出来。在index.html里,模态框是一个 div,默认display: none。点击「开启微课」按钮(#start-lesson)时,用 JS 给它加active类,触发显示:

1
2
3
4
// 绑定按钮点击事件
document.getElementById('start-lesson').addEventListener('click', () => {
document.getElementById('welcome-modal').classList.add('active');
});

隐藏模态框则是通过「下一步」按钮触发,移除active类。这里有个小技巧:用 CSS 过渡(transition: all 0.3s)让弹出/关闭更丝滑——对应index.html 里的border-radius: 5px;就是为了让圆角过渡更自然。

1.2 问题的「动态生成」

问答题目不能写在 HTML 里(改题要改代码很麻烦),所以用 JS 动态生成选项。比如问题 1 的选项,用document.createElement('button') 创建按钮,再塞到 #q1-options 里:

1
2
3
4
5
6
7
const q1Options = ['A) 拉尔夫·蒂托(Ralph Teetor),1948年', 'B) 亨利·福特,1908年', 'C) 卡尔·本茨,1886年'];
q1Options.forEach(option => {
const btn = document.createElement('button');
btn.textContent = option;
btn.addEventListener('click', () => checkAnswer('q1', option));
document.getElementById('q1-options').appendChild(btn);
});

1.3 答案的「即时判题」

用户选答案后,需要立刻判断对错并显示解析。这里用了个简单的checkAnswer函数,对比用户选择和正确答案(硬编码在 JS 里):

1
2
3
4
5
6
7
8
9
10
11
12
function checkAnswer(questionId, selected) {
const correctAnswers = {
q1: 'A) 拉尔夫·蒂托(Ralph Teetor),1948年',
q2: 'C) 1925年',
q3: 'B) Advanced Driver Assistance Systems(高级驾驶辅助系统)',
q4: 'C) 摄像头'
};
const isCorrect = selected === correctAnswers[questionId];
document.getElementById(`${questionId}-result`).textContent = isCorrect ? '答对啦!' : '再想想~';
// 显示解析并跳转到下一题
document.getElementById(`explanation-${questionId}`).style.display = 'block';
}

1.4 交互流程

这里不用文字说明了,画了个简单的 mermaid 流程图,这样更清晰一些:

智能体调用:Coze API

需求是让用户能和「小眼」「激小光」等智能体聊天,后端调用 Coze 的 AI 接口。这部分主要在app.py 里写接口,前端用 JS 发请求。

2.1 后端接口的「极简设计」

Coze API 需要 tokenmessage 参数,所以后端只需要一个 /chat接口,接收用户输入和智能体 ID,转发请求并返回结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@app.route('/chat', methods=['POST'])
def chat():
data = request.json
message = data['message']
agent_id = data['agent_id']
# 模拟不同智能体的角色设定(实际可从知识库读取)
system_prompt = {
'7493551619116843043': '你是小眼,专注讲解传感器原理',
'7493564974036910092': '你是激小光,擅长解释激光雷达技术'
}[agent_id]
response = requests.post(
COZE_MESSAGE_URL,
json={'system': system_prompt, 'message': message},
headers={'Authorization': f'Bearer {COZE_API_TOKEN}'}
)
return jsonify(response.json())

2.2 前端的「对话渲染」

前端用 chat-container div 显示对话记录,用户输入后发请求,收到回复再动态添加消息气泡。这里用了「消息包装器」类(message-wrapper)区分用户和 AI:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
async function sendMessage() {
const userInput = document.getElementById('user-input');
const message = userInput.value.trim();
if (!message) return;
// 显示用户消息
const userMsg = document.createElement('div');
userMsg.className = 'message-wrapper user';
userMsg.innerHTML = `<div class="name">你</div><div class="message user">${message}</div>`;
document.getElementById('chat-container').appendChild(userMsg);
// 调用后端接口
const response = await fetch('/chat', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({message, agent_id: currentAgentId})
});
const aiResponse = await response.json();
// 显示AI消息
const aiMsg = document.createElement('div');
aiMsg.className = 'message-wrapper assistant';
aiMsg.innerHTML = `<div class="name">${currentAgentName}</div><div class="message assistant">${aiResponse.content}</div>`;
document.getElementById('chat-container').appendChild(aiMsg);
}

2.3 通信流程的「序列图」

为了说明前后端如何配合,画了个 mermaid 序列图:

踩坑:模态框卡停背景视频

事情的起因非常简单——我们希望在微课首页用一段酷炫的背景视频,营造科技感满满的氛围。

视频循环播放,配合按钮和渐变色,让整个页面看起来更加炫酷。 可就在点下「开启微课」按钮,模态框优雅地弹出来的那一刻,诡异的事情发生了:

背景视频突然“定格”了! 仿佛时间静止,画面戛然而止。最初我们还以为是 JS 触发冲突,查了半天事件绑定,console 里一片风平浪静。

难道是 CSS 动画影响了视频?一顿调试后,依然毫无头绪。

问了各种大模型,仍然无果,事情变得越来越诡异。作品提交时间日渐逼近,无奈之下我们祭出原始办法:查阅HTML官方文档中关于视频部分的相关说明。

果然,有时候排查问题还是需要最朴素的办法,文档里清晰的写着:

当视频元素被覆盖、尤其是在移动端,浏览器可能会自动暂停视频播放,以节省资源和电量。

既然找到了元凶,解决方案也就水落石出。我们先给‎<video>标签加上‎playsinline属性,让视频支持内联播放,避免被浏览器“误伤”;再用 JS 监听模态框弹出事件,每次弹窗出现时,主动调用‎video.play(),让背景视频继续嗨起来。

小结:功能开发的「三句话心得」

动态内容用 JS 生成:别写死 HTML,用createElement +appendChild更灵活

接口要极简:后端只做转发,避免复杂逻辑.

交互细节要抠:比如模态框的圆角、视频的内联播放,这些小细节能大幅提升体验。

今天的分享就到这里,下一篇计划展开聊一聊在coze平台如何使用工作流和知识库,构建微课的智能体,让动画里的每个人物活起来~