# eat **Repository Path**: vickchen/eat ## Basic Information - **Project Name**: eat - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-18 - **Last Updated**: 2026-08-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 今天吃什么?🌷 选不出去吃什么?随机抽取菜品的小工具(纯前端 PWA,零运行时依赖)。 支持口味偏好加权抽取、模糊搜索与标签筛选、喜欢/排除管理、菜品增删改与拖拽排序、时段智能推荐、JSON/CSV 导入导出、微信推送分享,可安装到手机桌面离线使用。 ## 快速开始 ```bash npm install # 安装构建依赖(esbuild 等) npm run dev # 开发构建并启动本地服务 npm run watch # 监听 src/ 变化自动重建 npm run build # 生产构建 → dist/ npm run serve # 仅启动静态服务(服务 dist/) npm test # 运行单元测试(node:test,零依赖) ``` 生产构建产物在 `dist/`,其中 `single.html` 是 CSS/JS 全部内联的单文件版,可直接发送给他人打开。 ## 功能一览 - **随机抽取**:加权随机(喜欢的菜 ×8 概率,连续同菜系降权,最近抽过的不重复,今日已定降权),四阶段动画(蓄力→快滚→悬念→揭晓)+ 连击彩纸 + 合成音效 - **搜索与筛选**:菜名/标签模糊搜索(支持片段与乱序匹配)、匹配度排序与高亮、标签多选(AND/OR 模式可切换)、正餐/小吃分类、仅显示喜欢 - **范围抽取**:勾选「仅在筛选结果中抽取」后,只在当前搜索+筛选命中里抽 - **口味偏好**:左键筛选 / 右键排除标签,喜欢与排除统一管理面板,筛选偏好(正餐/小吃、AND/OR、标签)自动记忆 - **菜品管理**:新增(重名检测 + 智能标签推荐 + emoji 选择)、编辑(默认菜编辑生成自定义副本)、删除、拖拽排序 - **智能时段**:根据时间自动切换正餐/小吃并推荐标签(手动选择后不再覆盖) - **数据导入导出**:JSON 全量备份恢复;CSV(带 BOM,Excel 直接打开不乱码) - **PWA**:manifest + Service Worker(stale-while-revalidate),可离线使用 - **分享**:抽取结果可推送到微信(Server酱) ## 目录结构 ``` ├── index.html 单页 UI(含 4 个弹窗 overlay) ├── style.css 全部样式 ├── dishes.js 默认菜品数据(ES 模块,408 道) ├── sw.js Service Worker 源码(__BUILD__ 由构建注入版本号) ├── manifest.json PWA manifest ├── build.mjs 构建脚本(esbuild 打包 + HTML 压缩 + 版本注入 + 产物自检) ├── scripts/ │ ├── serve.mjs 零依赖静态服务器 │ └── gen-icons.mjs PNG 图标生成 ├── src/ │ ├── main.js 入口:事件绑定(按功能域拆分)、初始化、快捷键 │ ├── render.js 渲染:标签组 / 菜品表格(虚拟滚动 + 拖拽排序)/ 统计 │ ├── spin.js 抽取算法(加权随机)+ 四阶段动画 + 结果弹窗 + 相似推荐 │ ├── forms.js 新增/编辑菜品、标签多选下拉、重名检测 │ ├── prefs.js 筛选状态与偏好(持久化)、时段智能推荐 │ ├── data.js foodData 重建 / 默认菜标签补全 / 可抽范围 │ ├── search.js 模糊匹配 + 高亮 + 统一过滤 │ ├── state.js localStorage 持久化状态 │ ├── storage.js localStorage 工具(失败 toast 提示) │ ├── bus.js 轻量事件总线(状态模块 → 渲染模块解耦) │ ├── constants.js 常量、标签池、NAME_RULES 推断规则、主题 │ ├── io.js JSON/CSV 导入导出 │ ├── ui.js 转义 / toast / 确认弹窗 / 管理面板 │ ├── fx.js 连击徽章 / 彩纸 / 涟漪 / Web Audio 音效 │ ├── today.js 今日已定(隔天自动清空) │ ├── theme.js 5 套主题切换 │ └── share.js Server酱 推送 └── tests/ 单元测试(搜索过滤 / CSV 解析 / 菜名规则 / 抽取权重) ``` ## 数据格式 **JSON 备份**(导出为 `我的菜品.json`): ```json { "version": 1, "exportedAt": "2026-01-01T00:00:00.000Z", "customItems": [{ "name": "菜名", "emoji": "🍽️", "isMeal": true, "tags": ["家常"] }], "dislikedTags": [], "likedDishes": [], "excludedDishes": [], "deletedDefaults": [] } ``` **CSV**(列为 `菜名,图标,标签,类型`,标签用 `|` 分隔,类型为 `正餐`/`小吃`): ```csv 菜名,图标,标签,类型 "麻婆豆腐",🍲,"川菜|辣|荤菜",正餐 ``` ## 测试 ```bash npm test ``` 覆盖核心纯函数:模糊匹配与匹配度排序、统一过滤(AND/OR/仅喜欢)、CSV 行解析、NAME_RULES 菜名标签推断、加权随机抽取权重计算。 ## 技术说明 - 构建:esbuild IIFE 打包(生产模式 drop console),html-minifier-terser 压缩 HTML,`?v=__BUILD__` 缓存版本号与 SW 缓存版本由构建时间戳自动注入 - 渲染:无框架,手写 innerHTML + 转义;菜品列表超过 60 条自动启用虚拟滚动(spacer 占位 + rAF 节流,响应窗口 resize 与字体加载) - 状态与渲染通过 `src/bus.js` 事件总线解耦,避免环依赖