1.5小时用AI+静态网页+Google Sheets打造家庭餐食规划器
1. 项目概述:一个用AI快速构建的餐食规划工具
每天早上,我都要花上半小时到四十分钟,在厨房里跟阿姨“开会”,讨论今天吃什么。这感觉特别低效——我的时间被浪费了,阿姨的时间也被占用了,而且讨论来讨论去,无非就是那几样菜。我相信很多自己做饭或者需要安排家庭饮食的朋友,都或多或少有过类似的困扰。决策疲劳在吃什么这个问题上,体现得淋漓尽致。
于是,我决定用技术来解决这个生活里的小痛点。我的核心需求很简单:提前定好一周的健康餐食计划,并且能让执行者(比如阿姨)一目了然地看到,无需每天重复沟通。我不想把它做成一个功能复杂、需要维护的“大项目”,那样本末倒置。我的目标是极简、快速、有效。
最终,我利用当下唾手可得的AI编程助手,在一个半小时内,从零到一构建了一个可用的“AI驱动的定时餐食查看器”。它本质上是一个静态网页,数据存放在Google Sheets里,通过简单的JavaScript读取并展示。整个开发过程,从构思、写代码到部署上线,ChatGPT和Cursor等AI工具提供了绝大部分的代码和思路,我更像是一个“产品经理”和“代码审查员”。
这个工具虽然简单,但直击痛点。现在,我每周日晚上花10分钟,在表格里填好下一周的餐食计划。第二天早上,阿姨只需要打开我分享给她的链接,就能看到今天、明天甚至整周的安排,沟通成本几乎降为零。对我自己而言,也免去了每日的决策过程,饮食更健康、更有计划。这个项目完美诠释了:技术不必高深,解决真实问题才是关键。它适合任何想优化日常生活流程、对AI辅助开发感兴趣,或者正在寻找一个轻量级餐食管理方案的朋友。
2. 核心思路与技术选型解析
2.1 为什么选择“静态网页 + 云端表格”的架构?
在构思这个项目时,我评估了几个方向:开发一个完整的移动App、做一个微信小程序,或者直接用一个共享的备忘录。但最终,我选择了“静态网页 + Google Sheets”这个组合,原因如下:
- 开发与维护成本极低:我不需要购买服务器,不需要配置数据库,也不需要处理复杂的后端API。Google Sheets充当了一个免费、稳定且易于操作的“数据库”,而GitHub Pages提供了免费的静态网站托管。整个项目除了我的时间,几乎没有金钱成本。
- 更新极其便捷:对于餐食计划这种需要频繁(每周)更新的内容,没有比电子表格更友好的界面了。我、我的家人,甚至阿姨(稍加指导)都可以直接在熟悉的表格界面里修改内容,网页上的数据会自动同步。这比登录某个管理后台、修改数据库要直观得多。
- 访问门槛低:只需一个浏览器,在任何设备(手机、电脑、平板)上打开链接即可查看。无需下载安装,分享一个URL就行,这对于给阿姨使用来说再合适不过。
- 技术栈简单可靠:HTML、CSS、JavaScript是前端开发的基石,相关资源丰富,AI助手对它们的代码生成和理解也最为成熟。这意味着我可以将精力完全集中在业务逻辑(如何展示数据)上,而不是学习新技术。
这个架构的核心理念是“用最成熟、最简单的工具,组合出最高效的解决方案”。它避免了过度工程化,让项目能够真正快速落地。
2.2 AI在项目开发中的具体角色与工作流
这个项目之所以能在1.5小时内完成,AI助手(我主要使用了ChatGPT和Cursor)起到了决定性作用。它并非替代我,而是成为了一个能力超强的“结对编程”伙伴。我的工作流大致如下:
- 需求澄清与拆解(我来主导):我首先明确告诉AI:“我要做一个网页,用来展示一周的餐食计划。数据源是一个公开的Google Sheets。网页需要能按天显示,最好能突出显示今天。” 这一步的关键是将模糊的想法转化为清晰、可执行的技术指令。
- 技术方案与代码生成(AI主力输出):AI会根据我的描述,推荐使用Google Sheets的API(实际上是公开的CSV导出链接),并生成对应的JavaScript代码来获取和解析数据。它会一次性给出包含HTML结构、CSS样式和JS逻辑的完整代码片段。
- 代码审查与调试(我负责把关):AI生成的代码并非总是完美运行。我会将代码复制到本地环境中测试。遇到错误(比如API链接格式不对、日期处理有误),我会把错误信息反馈给AI:“这段代码在控制台报了XX错误,可能是日期格式问题,请检查并修正。” AI会快速给出修正方案。
- 细节优化与功能微调(协同完成):基础功能完成后,我会提出优化点,比如“让今天的日期行高亮显示”、“添加一个简单的加载状态”、“让表格在手机上显示得更好看”。AI会据此调整CSS和JS代码。
在这个过程中,我的角色从“编码者”转变为“架构师”和“测试员”。我负责定义问题、评估方案、验收结果,而将重复性的、语法性的编码工作交给AI。这极大地提升了开发效率,尤其适合这种功能明确、逻辑不复杂的小工具。
注意:完全依赖AI生成代码的前提是,你自身需要具备基础的前端知识和调试能力。你需要能看懂代码逻辑,能设置本地测试环境,能使用浏览器开发者工具查看错误。否则,当AI给出错误代码时,你将无法辨别和纠正。
2.3 工具链选择:为什么是这些组合?
- ChatGPT (GPT-4) / Gemini:用于宏观的方案咨询和代码块生成。例如,我可以直接问:“如何使用JavaScript从一个公开的Google Sheets中读取数据并解析成数组?” 它们能给出详细的步骤和示例代码,是优秀的“启动引擎”。
- Cursor:这是我本次开发的核心编辑器。它的强大之处在于集成了AI智能体,允许我直接对代码库进行对话。我可以选中一段代码说:“重构这个函数,让它更简洁”,或者直接在新文件里用“/”指令描述需求:“创建一个
index.html,包含一个响应式表格,用于展示从Google Sheets获取的每日餐食”。Cursor能理解项目上下文,生成或修改的代码契合度更高,是高效的“实施与重构助手”。 - Google Sheets:不仅仅是数据存储,更是数据管理后台。我利用其“发布到网页”的功能,获得一个CSV格式的公开链接,这个链接就是我的数据API。
- GitHub Pages:最简便的静态网站部署平台。只需将代码推送到GitHub仓库,在设置中开启Pages功能,网站就上线了。它提供了免费的
https://username.github.io/repo-name域名,非常适合此类项目。
这套工具链形成了一个完美闭环:AI负责生成代码,表格管理数据,GitHub托管页面,全部免费且高效。
3. 从零到一的详细实现步骤
3.1 第一步:准备数据源——配置Google Sheets
这是整个项目的“大脑”,所有餐食信息都存储在这里。
- 创建新的Google Sheets:在Google Drive中新建一个表格,并为其命名,例如“家庭每周餐食计划”。
- 设计表头结构:我的表格结构非常简单实用:
日期 (Date) 星期 (Day) 早餐 (Breakfast) 午餐 (Lunch) 晚餐 (Dinner) 备注 (Notes) 2024-05-20 周一 燕麦粥,鸡蛋 糙米饭,番茄炒蛋,清炒西兰花 荞麦面,鸡胸肉沙拉 晚餐少油 2024-05-21 周二 全麦面包,牛奶 米饭,红烧排骨,蒜蓉菠菜 外出就餐 - 日期:使用标准的YYYY-MM-DD格式,便于JavaScript的
Date对象处理。 - 星期:可以手动填写,也可以使用公式
=TEXT(A2, “dddd”)自动根据日期生成(需将区域格式设置为中文)。 - 餐食列:按需划分,我这里分了早、中、晚三列。
- 备注:用于记录特殊要求,如“少辣”、“某人忌口”等。
- 日期:使用标准的YYYY-MM-DD格式,便于JavaScript的
- 发布表格为网页:这是最关键的一步,让表格数据能被我们的网页读取。
- 点击菜单栏的
文件->共享->发布到网页。 - 在弹出窗口中,选择
整个文档和工作表(例如Sheet1)。 - 在格式下拉菜单中,务必选择
逗号分隔值 (.csv)。这是最容易被JavaScript解析的格式。 - 点击
发布。系统会生成一个链接。复制这个链接,它看起来像这样:https://docs.google.com/spreadsheets/d/e/2PACX-.../pub?output=csv。这个链接就是你的数据API接口。
- 点击菜单栏的
实操心得:在表格中,尽量保持数据格式的整洁。避免合并单元格,因为合并单元格在导出为CSV时可能会产生空行或错乱的数据,给前端解析带来麻烦。如果需要突出显示某天,可以使用条件格式(如将今天的餐食行标为浅绿色),但这只是视觉辅助,不影响数据本身。
3.2 第二步:构建前端页面——HTML与CSS
有了数据接口,接下来创建展示数据的网页。我使用了一个非常简洁的单页面结构。
index.html核心结构:
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>家庭每周餐食计划</title> <link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> </head> <body> <div class="container"> <header> <h1><i class="fas fa-utensils"></i> 本周餐食安排</h1> <p class="subtitle">数据每周日更新,今日日期:<span id="current-date">加载中...</span></p> <p class="tip">提示:高亮行为今日餐食。点击表头可按列排序。</p> </header> <main> <!-- 加载状态 --> <div id="loading"> <i class="fas fa-spinner fa-spin"></i> 正在加载餐食数据... </div> <!-- 数据表格区域 --> <div id="meal-table-container" style="display: none;"> <table id="meal-table"> <thead> <tr> <th>* { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: #333; background-color: #f8f9fa; padding: 20px; } .container { max-width: 1200px; margin: 0 auto; background: white; border-radius: 12px; box-shadow: 0 5px 15px rgba(0,0,0,0.08); padding: 30px; } header { text-align: center; margin-bottom: 30px; border-bottom: 2px solid #eaeaea; padding-bottom: 20px; } h1 { color: #2c3e50; margin-bottom: 10px; } .subtitle { color: #7f8c8d; font-size: 1.1em; } .tip { background-color: #e8f4fc; color: #2980b9; padding: 10px; border-radius: 6px; margin-top: 15px; font-size: 0.95em; } /* 表格样式 */ #meal-table-container { overflow-x: auto; } table { width: 100%; border-collapse: collapse; margin-top: 20px; } th, td { padding: 15px; text-align: left; border-bottom: 1px solid #ddd; } th { background-color: #2c3e50; color: white; font-weight: 600; cursor: pointer; position: relative; } th:hover { background-color: #34495e; } .sort-icon { margin-left: 8px; opacity: 0.6; } th.sorted-asc .sort-icon::after { content: " ↑"; } th.sorted-desc .sort-icon::after { content: " ↓"; } tbody tr:hover { background-color: #f5f5f5; } /* 今日高亮行 - 核心视觉反馈 */ tbody tr.today { background-color: #e1f5e1 !important; /* 浅绿色背景 */ font-weight: 600; border-left: 4px solid #27ae60; } /* 响应式设计 */ @media (max-width: 768px) { .container { padding: 15px; } th, td { padding: 10px 8px; font-size: 0.9em; } h1 { font-size: 1.5em; } }注意事项:CSS中的
.today类选择器是关键,它定义了“今日”行的独特样式。我们在JavaScript中会通过计算日期,为对应的表格行添加这个类。overflow-x: auto确保了在小屏幕设备上,表格可以横向滚动,避免布局错乱。
3.3 第三步:实现数据交互——JavaScript逻辑
这是页面的“灵魂”,负责从Google Sheets获取数据、处理并渲染到页面上。script.js文件包含了所有逻辑。
核心函数解析:
获取并解析CSV数据:
const SHEET_URL = '你从Google Sheets获取的CSV发布链接'; async function fetchMealData() { showLoading(true); try { const response = await fetch(SHEET_URL); if (!response.ok) throw new Error(`网络响应异常: ${response.status}`); const csvText = await response.text(); const data = parseCSV(csvText); renderTable(data); updateLastUpdated(); } catch (error) { console.error('获取数据失败:', error); showError(); } finally { showLoading(false); } }这里使用
fetchAPI异步获取数据。parseCSV函数需要将CSV格式的文本转换成JavaScript数组对象。解析CSV字符串:
function parseCSV(csvText) { const lines = csvText.trim().split('\n'); const headers = lines[0].split(',').map(h => h.trim()); const result = []; for (let i = 1; i < lines.length; i++) { const currentLine = lines[i].split(','); // 处理可能包含逗号的字段(简易处理) const row = {}; headers.forEach((header, index) => { row[header] = currentLine[index] ? currentLine[index].trim() : ''; }); // 将日期字符串转换为Date对象,便于比较 if (row['日期 (Date)']) { row._dateObj = new Date(row['日期 (Date)']); } result.push(row); } return result; }这是一个基础的CSV解析器。对于更复杂的情况(如字段内包含逗号),可以考虑使用成熟的库如
PapaParse。这里我们做了简化,并为日期创建了Date对象备用。渲染表格与高亮今日:
function renderTable(data) { const tbody = document.querySelector('#meal-table tbody'); tbody.innerHTML = ''; // 清空现有内容 const today = new Date(); today.setHours(0, 0, 0, 0); // 标准化为当天零点,便于精确比较 data.forEach(row => { const tr = document.createElement('tr'); // 判断是否为今天 const rowDate = row._dateObj; if (rowDate && rowDate.getTime() === today.getTime()) { tr.classList.add('today'); } // 创建单元格并填充数据 const headers = ['日期 (Date)', '星期 (Day)', '早餐 (Breakfast)', '午餐 (Lunch)', '晚餐 (Dinner)', '备注 (Notes)']; headers.forEach(header => { const td = document.createElement('td'); td.textContent = row[header] || '-'; // 若无数据则显示‘-’ tr.appendChild(td); }); tbody.appendChild(tr); }); document.getElementById('meal-table-container').style.display = 'block'; }核心逻辑是遍历数据数组,为每一行创建
<tr>元素,并判断该行日期是否与今天相同。日期比较是关键,我们通过比较标准化后Date对象的getTime()值来实现精确匹配。附加功能:排序与状态更新:
// 表格排序功能(示例:按日期排序) function initSorting() { document.querySelectorAll('th[data-sort]').forEach(th => { th.addEventListener('click', () => { const sortKey = th.getAttribute('data-sort'); // ... 实现排序逻辑,并重新调用 renderTable }); }); } // 更新页面底部“最后更新”时间 function updateLastUpdated() { const now = new Date(); const formatted = now.toLocaleDateString('zh-CN') + ' ' + now.toLocaleTimeString('zh-CN', {hour: '2-digit', minute:'2-digit'}); document.getElementById('last-updated').textContent = formatted; } // 页面加载完成后执行 document.addEventListener('DOMContentLoaded', () => { document.getElementById('current-date').textContent = new Date().toLocaleDateString('zh-CN', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' }); fetchMealData(); initSorting(); });
3.4 第四步:部署与分享
- 本地测试:在浏览器中直接打开
index.html文件,检查功能是否正常,样式是否符合预期。使用开发者工具(F12)的Console面板查看是否有JavaScript错误。 - 创建GitHub仓库:在GitHub上新建一个公共仓库(例如命名为
Meal-Plan-Viewer)。 - 上传代码:将你的
index.html,style.css,script.js三个文件上传至该仓库。 - 启用GitHub Pages:
- 进入仓库的
Settings(设置)页面。 - 在左侧边栏找到
Pages(页面)选项。 - 在
Source(源)下拉菜单中,选择你代码所在的分支(通常是main或master),然后选择根目录/(root)。 - 点击
Save(保存)。几分钟后,你的网站就会发布在https://[你的用户名].github.io/[仓库名]/。
- 进入仓库的
- 分享链接:将这个链接发送给需要查看餐食计划的人(如家人、阿姨)。他们就可以在任何设备上通过浏览器访问了。
4. 避坑指南与进阶优化思路
在实际开发和后续使用中,我遇到并总结了一些典型问题及解决方案。
4.1 常见问题排查速查表
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
页面空白,控制台报错Failed to fetch | 1. Google Sheets链接错误或未发布。 2. 网络问题或跨域限制(本地文件直接打开时常见)。 | 1. 检查并复制正确的CSV发布链接。 2. 使用本地服务器(如VS Code的Live Server插件)运行,或直接部署到GitHub Pages上测试。 |
| 表格数据显示为“undefined”或错乱 | 1. CSV解析逻辑错误,表头与数据未对齐。 2. Google Sheets中使用了合并单元格或复杂格式。 | 1. 在parseCSV函数中打印headers和currentLine,检查解析结果。2. 简化表格结构,避免合并单元格,确保数据区域规整。 |
| “今日”高亮行不显示或显示错误 | 1. 日期格式不匹配(Sheets中格式与JS解析格式)。 2. 时区问题导致日期比较有误。 | 1. 确保Sheets中日期列为YYYY-MM-DD标准格式。2. 在JS中比较日期时,使用 setHours(0,0,0,0)将时间归零,只比较年月日。 |
| 在手机上表格布局混乱,文字换行不佳 | CSS未做充分的响应式设计。 | 1. 添加<meta name="viewport">标签。2. 使用媒体查询( @media)调整小屏幕下的字体大小和边距。3. 为表格容器添加 overflow-x: auto。 |
| 数据更新后,网页上还是旧内容 | 浏览器缓存了旧的CSV文件或HTML/JS文件。 | 1.强制刷新:按Ctrl+F5(Windows) 或Cmd+Shift+R(Mac)。2. 在 fetch请求的URL后添加时间戳参数(如?t=${Date.now()})来绕过缓存。 |
4.2 安全性考量与隐私设置
这个方案的默认设置是数据完全公开,因为Google Sheets的“发布到网页”链接是公开可读的。这适用于不包含敏感信息的餐食计划。如果你的计划涉及隐私,可以采取以下措施:
- 最小化信息:不要在表格中填写家庭住址、电话号码等敏感信息。
- 使用Google Sheets的“仅知道链接的人可查看”:在表格的“共享”设置中,将权限设置为“任何拥有链接的人”可以“查看者”。这比完全公开稍好,但链接一旦泄露,数据仍可被访问。
- (进阶)使用Google Apps Script创建私有API:这是更安全的方案。你可以编写一个简单的Apps Script,从表格中读取数据,然后以JSON格式返回,并在此脚本中设置访问权限(如需要令牌)。网页前端调用这个私有API。这需要更多的开发工作,但可控性更强。
对于绝大多数家庭餐食分享场景,使用公开链接并注意不泄露敏感信息已经足够。
4.3 未来功能扩展思路
这个基础版本已经解决了核心的“查看”问题。如果你希望它更强大,以下是一些可以轻松扩展的方向:
- 多周/月份视图切换:在页面顶部添加按钮,让用户可以在“本周”、“下周”甚至“本月”视图间切换。这需要调整数据获取逻辑,可能需要在Sheets中管理多周数据,或通过JS动态计算日期范围。
- 餐食详情与食谱链接:将表格中的餐食名称(如“番茄炒蛋”)做成可点击的链接,点击后弹窗或跳转显示详细食谱、烹饪步骤或关联的YouTube教学视频。可以在Google Sheets中新增一列“食谱链接”来存储URL。
- 简易的反馈或完成打卡:在每一餐旁边添加一个复选框或“已完成”按钮。虽然数据无法直接写回公开的Sheets,但可以通过其他方式记录,例如利用浏览器的本地存储(
localStorage)在个人设备上记录完成情况。 - 自动生成购物清单:这是一个更高级的功能。可以维护一个“食材-餐食”的映射表(另一个Sheets),当一周计划确定后,运行一个脚本(可以用Google Apps Script实现)自动汇总所需食材及数量,生成购物清单。
- 与日历应用同步:利用Google Calendar API,将餐食计划自动创建为日历事件,这样就能在手机自带日历中收到提醒。
我个人在实际操作中的体会是,这类工具的价值在于持续解决痛点,而不是一次性追求功能完美。我的建议是,先用最简单可用的版本跑起来,让它为你服务。在使用的过程中,你自然会发现哪些功能是“锦上添花”,哪些是“雪中送炭”。届时,再利用AI助手,针对性地去实现那个对你最重要的新功能。这种迭代方式,压力最小,成就感也最高。
