如何设计一个高效的产品原型?
摘要:本人使用Claude Code制作了一个羽毛球轮转系统。然后让Claude Code生成了一个系统架构文档。文档内容如下: 羽毛球轮转管理系统 - 系统架构文档 一、项目概述 1.1 项目简介 羽毛球轮转管理系统是一个基于纯前端技术实现的单
本人使用Claude Code制作了一个羽毛球轮转系统。然后让Claude Code生成了一个系统架构文档。文档内容如下:
羽毛球轮转管理系统 - 系统架构文档
一、项目概述
1.1 项目简介
羽毛球轮转管理系统是一个基于纯前端技术实现的单页应用(SPA),用于羽毛球活动的组织、轮转管理和比赛统计。系统支持从人员录入、分组管理、轮转生成到比赛进行和报表统计的完整流程。
1.2 技术栈
前端框架:原生 HTML5 + CSS3 + JavaScript(无依赖库)
数据存储:LocalStorage(客户端持久化存储)
架构模式:单页应用(SPA) + MVC 模式
分享机制:URL Hash + Base64 编码
二、整体架构设计
2.1 架构层次
┌─────────────────────────────────────────────────────────────┐
│ 用户界面层(View) │
│ ├─ 页面模块(6个主要页面) │
│ ├─ 响应式布局(桌面/移动端) │
│ ├─ 组件化UI(卡片、表单、表格、按钮等) │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 控制层(Controller) │
│ ├─ 页面导航管理 │
│ ├─ 事件处理与验证 │
│ ├─ 业务逻辑协调 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 数据层(Model) │
│ ├─ 核心数据对象(people, groups, config, schedule) │
│ ├─ LocalStorage 存储 │
│ └─ 数据迁移与版本管理 │
└─────────────────────────────────────────────────────────────┘
2.2 核心数据结构
data = {
people: [ // 人员列表
{ id, name, gender, level, isFreeAgent }
],
groups: [ // 圈子(分组)列表
{ id, name, memberIds[] }
],
config: { // 配置参数
courtCount, // 场地数量
matchDuration, // 每场比赛时长(分钟)
totalDuration, // 总时长(分钟)
totalRounds, // 总轮次
allowIntraGroup, // 允许同圈子比赛
maximizeCross, // 最大化跨圈子比赛
balancePlayTime // 均衡上场次数
},
schedule: [ // 轮转表
{
round, // 轮次
courts: [
{ team1, team2, score1, score2, confirmed }
]
}
],
rankings: [ // 排名数据(动态计算)
{ personId, gamesWon, gamesLost, netScore, netGames }
],
playCount: {}, // 每人上场次数统计
partnerCount: {} // 搭档次数统计
}
三、功能模块详解
3.1 页面导航系统
6个主要页面:
页面ID
页面名称
功能描述
people
人员管理
添加、编辑、删除人员,支持批量导入
groups
分组管理
创建圈子,分配人员到圈子
config
配置设置
场地、时间配置,轮转策略
schedule
轮转预览
预览生成的轮转表,确认后进入比赛
play
比赛进行
实时录入比分,确认每场比赛
report
报表统计
查看最终排名、搭档统计、对阵历史
导航机制:
页面切换通过 nextPage(pageName) 函数实现
支持前进验证(validatePage),确保数据完整性
自动生成桌面端和移动端导航栏
页面状态通过 CSS class .active 控制显示/隐藏
3.2 人员管理模块
主要功能:
✅ 添加单个人员(姓名、性别、水平等级、自由人标志)
✅ 批量导入(CSV格式:姓名,性别,等级)
✅ 编辑人员信息(弹窗编辑)
✅ 删除人员(级联删除)
✅ 自由人标记(可与其他任何人在同一圈子)
✅ 排序功能(按性别、等级排序)
✅ 重复检查(姓名+性别必须唯一)
水平等级系统:L0.5 ~ L6(共12个等级,递增)
数据验证:
姓名必填
性别必须为"男"或"女"
等级必须在预设列表中
3.3 分组管理模块
核心概念:
圈子:人员分组,用于约束合法的搭档组合
自由人:标记为自由人的人员可以与任何其他人员搭档,不受圈子限制
分配规则:非自由人必须被分配到至少一个圈子
主要功能:
✅ 创建圈子(名称唯一性校验)
✅ 删除圈子
✅ 展开/折叠圈子查看成员
✅ 从圈子中移除成员
✅ 批量分配未分配人员到指定圈子
✅ 可视化显示未分配人员列表
分配流程:
左侧显示未分配人员(可多选)
中间选择目标圈子(下拉框)
点击"加入选中圈子"完成分配
3.4 配置设置模块
场地与时间配置:
场地数量:1-10个
每场比赛时长:5-60分钟
总时长:30-600分钟
自动计算轮次:轮次 = floor(总时长 / 比赛时长) / 场地数量(向上取整)
轮转策略(3个核心策略):
策略
说明
影响
allowIntraGroup
允许同圈子比赛
无法跨圈时的fallback方案
maximizeCross
最大化跨圈子比赛
优先安排不同圈子的人员对垒
balancePlayTime
均衡每个人上场次数
避免有人长时间轮空
3.5 轮转生成算法(核心)
算法类型:贪心启发式算法 + 多目标优化
算法流程:
1. 预处理阶段:
- 构建 personToGroups 映射(人员→圈子)
- 识别自由人列表
- 生成所有合法搭档对(validPairs)
2. 逐轮生成(for round = 1 to totalRounds):
- 初始化 usedThisRound(已使用人员集合)
- 对每个场地:
a. 从可用搭档对中筛选(双方都未使用)
b. 尝试组合两对(4人互不相同)
c. 计算综合得分:
- crossScore:跨圈分数(0/5/10)
- balanceScore:平衡惩罚(基于历史出场次数)
- diversityPenalty:搭档多样性惩罚
totalScore = crossScore*10 + balanceScore - diversityPenalty
d. 选择最高分的组合
e. 更新 playCount 和 partnerCount
f. 标记4人为已使用
3. 输出 schedule 和统计信息
合法搭档判定:
任意一方是自由人 ✅
双方有共同圈子 ✅
否则 ❌
评分函数详解:
crossScore:
完全跨圈(无共同圈子) → 10分
部分重叠(有自由人) → 5分
完全同圈 → 0分
balanceScore:
avgPlayCount = 当前总出场次数平均值
totalPlayCount = 这4人的总出场次数
balanceScore = (avgPlayCount * 4 - totalPlayCount) * 2
// 低于平均时得正分,高于平均时得负分
diversityPenalty:
= (搭档历史次数 + 另一对的搭档历史次数) * 1
// 鼓励与不同人搭档
算法复杂度:
配对生成:O(n²),n为人数
每轮每场地:O(m²),m为合法搭档对数(限制为50对)
总体:O(rounds × courts × 50²)
3.6 比赛进行模块
界面布局:
顶部显示总轮次
所有轮次/场地卡片化展示
每个场地卡片包含:
场地编号和状态(已确定/待录入)
两队人员列表
两队得分输入框
快速填入按钮(10、16、21分)
确定按钮(比赛完成后点击)
工作流程:
录入比分(两队都输入后,确定按钮才可用)
点击确定 → 验证比分有效性(21分制规则或30:29)
确认后该场比赛锁定(不能再修改,除非点击"修改"按钮)
实时更新积分排名
比分验证规则:
isGameOver = (maxScore >= 21 && diff >= 2) || (maxScore === 30 && minScore === 29)
3.7 报表统计模块
3.7.1 最终排名
排名规则(优先级从高到低):
胜场数(gamesWon)↓
负场数(gamesLost)↑(越少越好)
总净胜分(netScore)↓
并列排名处理:三项指标完全相同则并列
3.7.2 搭档统计
显示每个人与所有搭档的组合次数
按搭档次数降序排列
格式:搭档A(3), 搭档B(2), 搭档C(1)
3.7.3 对阵历史
按轮次排序,每轮内按场地排序
显示完整比分和胜方标识
3.7.4 分享与导出
生成分享链接:将数据序列化为Base64编码到URL Hash#/share/{base64(data)}
复制Markdown报表:格式化为Markdown表格,复制到剪贴板
导出JSON数据:下载完整数据备份文件
四、UI/UX设计系统
4.1 设计规范
色彩系统(CSS变量):
--primary: #0EA5E9 /* 主色调:天空蓝 */
--primary-dark: #0284C7 /* 深色主色调 */
--secondary: #14B8A6 /* 次要色:青绿 */
--background: #F8FAFC /* 背景色 */
--surface: #FFFFFF /* 卡片/表面色 */
--text: #1E293B /* 主要文字 */
--text-light: #64748B /* 次要文字 */
--success: #22C55E /* 成功色 */
--warning: #F59E0B /* 警告色 */
--danger: #EF4444 /* 危险色 */
间距与圆角:
卡片圆角:12px
按钮圆角:8px
标签圆角:999px(胶囊形)
阴影:轻微多层阴影 0 1px 3px rgba(0,0,0,0.1)
字体:
系统字体栈:-apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Microsoft YaHei'
移动端强制16px防止iOS缩放
4.2 响应式设计
桌面端(>768px):
顶部横向导航栏
两栏布局(分组管理页面)
表格完整显示
移动端(≤768px):
横向滚动导航条
单栏堆叠布局
按钮最小高度44px(触控友好)
表格横向滚动
字体和间距优化
五、数据流与状态管理
5.1 数据持久化
存储机制:
STORAGE_KEY = 'badminton_data'
localStorage.setItem(STORAGE_KEY, JSON.stringify(data))
数据加载:
页面加载时自动从LocalStorage恢复
支持URL分享链接直接加载数据
数据迁移(migrateData)确保向后兼容
自动保存策略:
每次数据变更立即保存(saveData())
页面刷新后自动恢复状态
5.2 状态同步
关键状态同步点:
添加/删除/修改人员 → 更新人员表和分组页
圈子变更 → 更新分组页和未分配列表
比分录入 → 更新实时排名
比赛确认 → 锁定比赛,更新排名
六、核心算法深度分析
6.1 轮转生成的优化目标
系统通过加权评分机制实现多目标优化:
总得分 = crossScore × 10 + balanceScore - diversityPenalty
目标优先级:
最大化跨圈(权重10):确保不同圈子人员尽可能对战
平衡上场(权重2):避免某些人上场过多/过少
搭档多样性(权重1):避免同一对人反复搭档
6.2 贪心算法的局限性
当前实现的问题:
❌ 每轮独立决策,缺乏全局规划
❌ 可能在某些轮次出现配对困难(场地空闲)
❌ 仅考虑当前场地的局部最优,未考虑整体公平性
可改进方向:
✅ 引入回溯机制,当当前轮次无解时重新分配
✅ 使用模拟退火或遗传算法进行全局优化
✅ 增加约束条件:性别平衡、水平平衡等
七、系统扩展建议
7.1 功能增强
短期优化(无需重大重构):
导入导出增强:
支持Excel/CSV批量导入人员
导出PDF报表
导出图片格式的轮转表
规则扩展:
支持混双规则(男女混合)
支持水平平衡约束(每队水平总和接近)
支持性别平衡约束(每队男女比例)
交互优化:
拖拽分配人员到圈子
比赛进行时自动跳转到下一个未确认比赛
键盘快捷键支持(如Enter快速添加)
中期重构(需要模块化):
后端集成:
保存到云端数据库
多用户协作
历史活动记录
实时协作:
WebSocket实现多端同步
扫码加入活动
智能调度:
多种调度算法可选(贪心、匈牙利、模拟退火)
算法可视化展示决策过程
A/B测试不同算法效果
7.2 代码质量提升
当前问题:
单文件2522行,难以维护
函数过长,缺乏模块化
硬编码的配置值(如maxPairs=50)
缺少单元测试
重构建议:
badminton-system/
├── src/
│ ├── models/ # 数据模型
│ ├── views/ # 页面视图
│ ├── controllers/ # 控制器
│ ├── services/ # 业务服务(轮转算法、排名计算)
│ ├── utils/ # 工具函数
│ └── styles/ # CSS模块
├── tests/
└── index.html
八、使用场景与流程
8.1 典型使用流程
1. 人员管理
└─> 添加所有参与者(或批量导入)
└─> 标记自由人(如教练、替补)
2. 分组管理
└─> 创建圈子(如:A组、B组、俱乐部1、俱乐部2)
└─> 将人员分配到对应圈子
└─> 确保所有非自由人已分配
3. 配置设置
└─> 设置场地数量、时长、总时长
└─> 选择轮转策略(建议全选)
└─> 查看自动计算的轮次
4. 生成轮转
└─> 点击"生成轮转表"
└─> 算法自动计算所有轮次的配对
└─> 预览并确认
5. 比赛进行
└─> 逐场录入比分
└─> 确认比赛结果(锁定)
└─> 实时查看积分排名
6. 报表统计
└─> 查看最终排名、搭档统计、对阵历史
└─> 生成分享链接或导出数据
8.2 适用场景
✅ 业余羽毛球活动组织(4-40人)
✅ 俱乐部内部循环赛
✅ 训练课的轮转练习
✅ 双打配对优化
不适用场景:
❌ 单打比赛(系统为双打设计)
❌ 淘汰赛制(仅支持循环赛)
❌ 超过40人的大型赛事(算法复杂度较高)
九、关键技术实现
9.1 分享链接原理
// 编码
const shareData = { people, groups, config, schedule, rankings }
const jsonStr = JSON.stringify(shareData)
const encoded = btoa(unescape(encodeURIComponent(jsonStr))) // UTF-8 + Base64
const url = window.location.origin + window.location.pathname + '#/share/' + encoded
// 解码
const hash = window.location.hash
const encoded = hash.replace('#/share/', '')
const decoded = JSON.parse(atob(encoded))
优点:无服务器支持即可分享完整数据
缺点:URL可能过长(超过2000字符限制)
9.2 本地存储策略
键名:badminton_data
存储内容:完整数据对象
容量:约几KB到几十KB(取决于人数和轮次)
生命周期:永久存储,除非用户清除浏览器数据
9.3 数据迁移机制
function migrateData() {
// 版本升级时确保数据结构兼容
if (data.schedule) {
data.schedule.forEach(round => {
round.courts.forEach(court => {
if (court.confirmed === undefined) {
court.confirmed = false;
}
});
});
}
}
十、总结与评价
10.1 系统优点
零依赖:无需安装任何库,打开即用
数据安全:完全本地存储,隐私无忧
响应式设计:完美支持手机和电脑
算法实用:贪心算法速度快,适合中小规模活动
功能完整:覆盖活动组织全流程
10.2 局限性与改进方向
算法局限性:
贪心算法可能陷入局部最优
无解时无fallback机制(直接停止生成)
扩展性不足:
单文件架构难以维护
规则硬编码,不支持自定义排名规则
缺少插件机制
用户体验:
缺少撤销/重做功能
轮转表生成时UI阻塞(虽用setTimeout但仍有卡顿)
无数据导入导出格式验证
10.3 适用度评分
维度
评分
说明
易用性
⭐⭐⭐⭐⭐
界面简洁,操作直观
性能
⭐⭐⭐⭐
50人以下流畅,100人以上开始卡顿
稳定性
⭐⭐⭐⭐⭐
纯前端无服务器故障风险
扩展性
⭐⭐
单文件架构难以扩展
算法质量
⭐⭐⭐
满足基本需求,但非最优解
附录
附录A:数据格式参考
{
"people": [
{ "id": 1, "name": "张三", "gender": "男", "level": "L2", "isFreeAgent": false }
],
"groups": [
{ "id": "group_123", "name": "A组", "memberIds": [1, 2, 3] }
],
"schedule": [
{
"round": 1,
"courts": [
{ "team1": [1, 2], "team2": [3, 4], "score1": 21, "score2": 18, "confirmed": true }
]
}
]
}
附录B:快速开始
在浏览器中打开 badminton.html
按页面顺序逐步操作
数据自动保存,关闭后重新打开即可恢复
附录C:浏览器兼容性
✅ Chrome 90+
✅ Firefox 88+
✅ Safari 14+
✅ Edge 90+
⚠️ 需要支持 ES6、localStorage、Clipboard API
文档生成时间:2026-03-24
代码行数:2522行
