幌斛者 发表于 昨天 18:05

搭建产品原型

本人使用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": }
],
"schedule": [
    {
      "round": 1,
      "courts": [
      { "team1": , "team2": , "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行

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: 搭建产品原型