一键开通华为云码道 CodeArts 代码智能体:https://developer.huaweicloud.com/codeartsco.html?source=dmzntgwatomgit1&sourcead=dmzntgwatomgithd
项目地址:https://atomgit.com/yangqing88/class-random-picker (public)
一、一件小事,为什么会变成一个项目
点名这件事,每个带过课的人都有体会。
花名册摊在讲台上,眼睛扫一遍,手指划一勾,嘴里念一个名字——看着挺顺,实际上有三个说不清的地方:点谁全凭手感,坐在前排的和爱回答问题的容易被反复点到;点过谁记不住,一节课下来"张三回答一下"说了两遍;期末想复盘"这个班谁最活跃",翻遍记录本也找不到依据。
单次成本很低,低到没人愿意为它专门做个工具。但一学期累积下来,你会发现它其实是个小规模的状态管理问题:一份名单、一个随机选择器、一条操作历史。三件事,正好是前端能独立完成的边界。
于是我把需求丢给了华为云码道 CodeArts,一句话:
帮我做一个班级点名系统,页面需要比较好看一点,功能还需要导入 excel 文档,里面有学员的 ID、NAME 字段
后面发生的事,比我预想的有意思。它没有直接开始写index.html。
二、它做的第一件事,是先"问",不是先"写"
对话刚开局,CodeArts 先加载了一个叫brainstorming的技能,随后把整个工作拆成 8 个任务:
探索项目上下文→逐个向用户澄清问题→提出 2-3 种技术方案与权衡→分部分展示设计并获得用户认可→撰写设计文档并保存→设计文档自审→用户审阅设计文档→转入实现阶段
底部任务条上写的是"1 进行中 · 7 待处理"。它先去/workspace看了一眼目录,发现是空的——只有一个.codeartsdoer配置文件,确认这是个全新项目,然后才开始提问。
提问的方式不是丢一堆文字过来,而是交互式选项卡片,一次只问一个问题:
| 澄清轮次 | 它问的问题 | 给出的选项 | 最终选择 |
|---|---|---|---|
| 1 | 点名系统的核心玩法是什么? | 随机抽取一个学员 / 轮转点名 / 整班签到 | 随机抽取一个学员 |
| 2 | 抽中一名学员后,已抽中的学生还要继续参与吗? | 轮流出勤式(抽过的不再参与,全部抽完自动重开)/ 纯随机可重复 / 手动移除式 | 纯随机可重复 |
| 3 | 除了导入 Excel + 随机抽取,还需要哪些数据功能? | 显示抽取历史 / 无需历史记录 / 支持手动增删学员 | 显示抽取历史 |
| 4 | 页面视觉风格你偏好哪种? | 清新简约风 / 炫酷科技风 / 俏皮活泼风 | 清新简约风 |
| 5 | 选择哪种方案实现? | A 纯前端单页 / B Vue3 + Vite / C 前后端分离 | A 纯前端单页 |
这张表值得多看两眼。第 2 问和第 3 问,是新手自己写代码时最容易漏掉的两个语义问题:允许不允许重复抽中?抽过的要不要留痕?这两个问题不定义清楚,代码写到一半必然返工——而返工的代价不是重写函数,是重做交互。
第 4 问更微妙。视觉风格被独立成一个需求项,而不是"顺手写点 CSS"。我选了清新简约风,后面styles.css才有明确的收敛目标:蓝紫主色、圆角卡片、柔和阴影。审美这件事,一旦不提前定,就会无限发散。
技术方案的三选一
真正体现判断力的是第 5 问前面的那段分析。它列了方案对比表:
| 方案 | 架构 | 优点 | 缺点 |
|---|---|---|---|
| A. 纯前端单页应用(推荐) | 原生 HTML/CSS/JS + SheetJS 解析 Excel | 双击即用、无需构建、无需后端,课堂场景零门槛 | 数据只在浏览器本地,换设备不通用 |
| B. Vue 3 + Vite | 组件化前端框架 | 可维护性强,便于后续扩展 | 需要 Node 构建环境,部署要打包 |
| C. 前端 + 后端服务 | Node / FastAPI + 数据库 | 可持久化考勤记录,支持多人数据共享 | 需要启动服务器,对单页小工具属于过度工程 |
它的推荐语写得很实在:“这是一个典型的一次性课堂工具,方案 A 生成单个(或少量)静态文件,导入 Excel → 随机抽取 → 显示历史,完全无需服务器,刷新即重置,最贴合你的需求。方案 B/C 更适合以后扩展成完整考勤管理系统(多记录、导出报表、多人数据共享)的场景。”
判断依据不是"哪个技术栈更先进",而是这个工具会被谁、在什么场景下打开。讲台上的电脑往往连管理员权限都没有,双击 HTML 就能跑,这个约束的权重远高于"以后可能扩展"。
三、落地时真正需要想清楚的技术点
方案敲定后,任务清单刷新成实现阶段:创建项目结构并下载 SheetJS、编写index.html骨架、编写styles.css、编写app.js核心逻辑、生成示例 Excel 并验证解析、浏览器实测完整流程。产出的目录是干净的:
class-random-picker/ ├── index.html ├── styles.css ├── app.js ├── sample/student_list.xlsx ├── docs/ ├── .gitignore └── README.md技术上真正花心思的是这四个地方。
Excel 解析的表头容错。用 SheetJS 把文件读成 JSON 数组后,字段名不能写死。实际课上导出来的表格,表头可能是ID/NAME,也可能是编号/学号/姓名。所以先做一次表头归一化:
// 表头别名表:把各种叫法统一收敛成 ID / NAMEconstHEADER_ALIAS={ID:['id','编号','学号','序号'],NAME:['name','姓名','学员姓名','学生']};functionnormalizeHeader(raw){constkey=String(raw||'').trim().toLowerCase();for(const[field,aliases]ofObject.entries(HEADER_ALIAS)){if(aliases.some(a=>key===a.toLowerCase()))returnfield;}returnnull;// 认不出来的列直接忽略}抽取逻辑要跟"纯随机可重复"这个决策严格对齐。我在第 2 轮问答里选了可重复,所以每次抽取都必须从全名单里取,不能悄悄维护一个"已抽池":
// 纯随机可重复:每次都在全名单里取,允许重复命中functionpickOne(list){returnlist[Math.floor(Math.random()*list.length)];}名字滚动大约 1 秒后定格,配放大、高亮和光晕粒子动画。动画时长直接决定了课堂体验——太快学生没反应过来,超过 2 秒就开始拖节奏。
历史记录走 localStorage。每次抽中写一条带时间戳的记录,最新的排在最上面,刷新页面不丢,也可以一键清空:
constKEY='rollcall.history';functionappendHistory(student){constrows=readHistory();rows.unshift({id:student.ID,name:student.NAME,at:Date.now()});localStorage.setItem(KEY,JSON.stringify(rows.slice(0,200)));}容错比功能更需要认真对待。传进来的如果不是 Excel(表头缺失、文件超过 20MB),要有明确提示而不是白屏;名单为空时抽取按钮直接禁用。这类边界处理在演示场景下看不出价值,但在真课堂上每一次触发都是事故。
四、它是怎么"自证没写错"的
代码写完,CodeArts 给了一张验证表:
| 验证项 | 结果 |
|---|---|
| JS 语法检查 | ✅ 通过 |
| Excel 解析(9 人有效 / 3 行脏数据跳过) | ✅ 通过 |
| jsdom DOM 自动化测试 | ✅ 17 / 17 通过 |
| 页面预览 | ➡ 已推送前端板,可直接查看效果 |
那个"9 人有效 / 3 行脏数据跳过"是我认为最像工程的一笔。测试用的 Excel 里被故意塞了空行和残缺行,解析器没有抛异常,而是静默跳过并继续——这正是真实班级名单的样子。它甚至用 Playwright 起了一次真实浏览器,去验证导入、随机抽取、历史删除、localStorage 持久化这几条链路。
不过有一句必须如实说:真实浏览器端到端测试卡在了 Chromium 下载上,受带宽限制没跑完,所以最终验收靠的是 jsdom + 前端板预览,属于"半自动验证"。CodeArts 自己把这条限制标了出来,没有假装全绿。
这一轮的运行数据是:耗时 18.4s、缓存命中 100%、输入 2.3k token、输出 416 token。
五、从本地文件夹到线上仓库
最后一步是我额外提的:“帮我初始化到仓库,自动生成 readme 文件”。
它的处理顺序很讲究:先写README.md,再git init、git add、git commit,然后检查远程地址是否已配置。这里还遇到一个真实的平台限制——本地ag(AtomGit CLI)只支持atomgit.com,而全局 Git 身份邮箱是yangqing88@noreply.atomgit.com。它没有自作主张地推,而是抛回来两个选项让我选:推到 atomgit.com,还是提供 atomgit 仓库 URL。
选完之后,一路走到位:
ag repo create class-random-picker # 创建公开仓库 git remote add origin https://atomgit.com/yangqing88/class-random-picker.git git push -u origin main # main 分支 3fcde31结果是仓库已公开、main与origin/main完全同步、工作区干净。仓库的语言占比统计出来是这样:
| 语言 | 占比 |
|---|---|
| JavaScript | 45.91% |
| CSS | 33.85% |
| Python | 11.39% |
| HTML | 8.85% |
那个 11.39% 的 Python 不是业务代码,是验证脚本留下的痕迹。它是"测试确实被执行过"的一条旁证——这种事情在人工项目里往往查不出来。
README 里的功能清单也整理得可以直接交付:“Excel 导入支持.xlsx/.xls/.csv,读取 ID、NAME 两列(兼容编号/学号/姓名等中文表头);随机抽取时名字滚动约 1 秒定格,放大 + 高亮 + 光晕粒子动画;抽取历史记录每次抽中的学员与时间戳,最新在上,支持一键清空;数据用 localStorage 持久化,刷新不丢;非 Excel 文件、缺表头、文件过大、空名单均有明确提示。”
六、新手手搓 vs AI 生成:差距到底在哪
这是这篇文章真正想说清楚的部分。避免只喊"AI 真强",我们逐项拆开看。
| 维度 | 新手常见做法 | 这次 AI 的做法 | 差距性质 |
|---|---|---|---|
| 需求澄清 | 脑子里想个大概就开写,靠感觉补细节 | 5 轮交互式提问,先钉死抽取语义、历史、视觉风格 | 思维差距,也是最大的一项 |
| 技术选型 | 上来就npm create vue,不管场景需不需要 | 列 3 套方案做权衡,按"讲台电脑零安装"这个约束选纯前端 | 思维差距 |
| 目录结构 | 单个 HTML 里塞完,或者结构随意 | 拆成 html / css / js / sample / docs,边界清晰 | 效率差距 |
| 数据持久化 | 抽完就忘,刷新即空 | localStorage 落历史,保留最近 200 条 | 质量差距 |
| 异常处理 | 文件传错就白屏,控制台报错 | 表头别名归一化、脏行跳过、空名单禁用按钮 | 质量差距,新手最常忽略 |
| 测试验证 | 手点两下,看着没问题就交 | jsdom 17/17 自动化用例 + 脏数据用例;跑不完的 E2E 明确标注 | 质量差距 |
| 文档交付 | 代码就是文档,别人看不懂怎么用 | README 含功能特性、快速开始、示例文件路径 | 效率差距 |
| 版本管理 | 拖到文件夹里,或者只git init不推 | 建仓 + 远程配置 + 推送 + 校验同步状态 | 效率差距 |
| 收尾动作 | 功能跑通就结束 | 附前端板预览 + 后续操作建议 | 效率差距 |
看完这张表,只有一句话值得记住:AI 生成项目真正的优势,从来不是"打代码快"。现在任何人让模型吐 200 行代码都会成功,那个环节的门槛早就消失了。真正的差距出现在三个地方:
第一是写之前问的问题。新手手搓点名器,通常不会想到"抽过的还要不要继续参与"这种语义边界,因为它在脑子里是"明显"的——直到实现跟预期不一致才返工。而那 5 轮问答把隐式假设逼成了显式决策。
第二是把自己当成待验证对象。jsdom 自动化测试、故意掺脏数据的 Excel、跑不动的 E2E 如实标注,这三件事的性质是一样的:先假设自己会写错。新手更常见的路径是"跑一遍没崩,那就是对的"。
第三是工程收尾的完整度。README、.gitignore、远程推送、同步校验——这些不产生功能,却决定了一个项目能不能被别人接住。它们也是自学者最容易整段跳过的部分。
当然也得说反面。AI 给的"推荐项"是会塑造决策的。五张卡片里几乎每张都标了一个"(推荐)",新手很容易一路点"推荐"到底,最后拿到一个"合理但没有个性"的产品。这次我特意在第 2、3 轮没有顺着走,选了可重复和历史记录——如果我全选推荐,得到的就是一个轮流出勤式的点名器,跟我的课堂习惯并不一致。选项框是在帮你收敛,不是在替你决定。
另外两处局限也该讲清楚:方案 A 的"换设备不通用"是这个架构的固有代价,不是 bug;对话中途还出现过一次"后台正在处理上一轮对话,请过一分钟后再重试"——CodeArts 不是不会卡,只是它卡的时候知道自己卡在哪。
七、总结
这个项目的技术含量确实不高,一百多行 JS 撑得起来。但从"我想做个点名器"到"一个别人能看懂、能复现、能继续迭代的仓库",中间隔着的不是代码量,而是一整套工程习惯:先澄清语义再动手、按使用场景选型而不是按技术栈热度、给边界情况写用例、把跑不通的部分如实标注、把交付物收拾干净。
AI 生成项目最大的意义,不是替代人写代码,而是把过去要靠师父带、靠项目摔打才能长出来的这套习惯,平移到一次对话里摊开给你看。对新手来说,最值得抄的从来不是那几百行实现,而是那 8 个任务节点和 5 个澄清问题——它们是比代码更耐用的东西。