news 2026/10/6 4:51:34

基于ThinkPHP+Vue的饮食运动科普管理小程序开发实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于ThinkPHP+Vue的饮食运动科普管理小程序开发实践

帮一位做营养师的朋友做个人品牌小程序,是我近期接到的真实需求。需求听起来不复杂——做一个运动健康饮食知识科普管理小程序,把健身饮食类的科普文章汇总起来,同时让用户记录每天吃了什么、做了哪些运动。但真正动手之后你会发现,这其实是两个产品逻辑的合体:一边是内容平台,一边是个人管理工具。整套系统的技术组合也比较经典:ThinkPHP做后端接口,Vue生态做小程序端和管理后台,微信小程序作为分发载体。这篇文章就把这套系统的需求拆解、数据建模、接口实现到联调上线的完整过程分享一下,想复现或者拿它当参考的同学可以少走不少弯路。

1. 项目整体规划:一个“知识科普+个人记录”双引擎小程序

1.1 这类小程序要解决的三个核心问题

接到需求的第一步,不是打开编辑器写代码,而是先想清楚这个产品到底要解决什么。这类科普管理小程序的核心痛点有三个,它们决定了后续所有设计的方向。

第一个是内容触达问题。运动健康知识非常碎片化,今天“拉伸到底有没有用”,明天“减脂期能不能吃主食”,用户需要的是一个分类清晰、能检索、能收藏的内容库,而不是刷完就忘的信息流。第二个是数据记录问题。营养师或健身教练如果不知道用户实际吃了什么、练了什么,给的建议就永远等于空谈。所以这个系统必须要让用户很轻量地记录日常饮食和运动。第三个是反馈激励问题。如果只记录不给反馈,用户坚持不了几天。记录完能不能立刻看到今天摄入多少、消耗多少、离目标差多少,这个即时反馈才是用户持续使用的原因。

这三件事想清楚之后,整个系统的功能边界就划出来了:科普内容面向“知道”,饮食和运动记录面向“做到”,统计建议面向“坚持”。任何功能如果不能服务于这三个语义之一,前期就不做。

1.2 功能模块与用户流程拆解

基于上面的分析,我梳理出来的功能模块很明确,分四大块。

模块核心功能说明
科普模块文章列表、分类筛选、详情展示、收藏/点赞、阅读量统计内容库是引流的入口,也是用户每天打开小程序的理由
饮食模块食物热量库、每餐记录、当日热量汇总记录动作要轻,尽量输入即匹配
运动模块运动类型库、时长/强度记录、消耗热量计算用MET值统一计算消耗,保证口径一致
用户模块微信登录、健康档案(身高/体重/年龄)、每日统计趋势健康档案是计算和建议的基础数据

用户流程上,我的设计是:新用户通过微信授权登录,先填写基础健康档案,然后去逛科普文章,之后开始记录第一餐和第一次运动。记录两三天之后,个人中心的统计页就能展示每日热量对比和一周趋势,这时候系统给出的健康建议才有实际意义。整个流程就是“内容引导了解,记录建立档案,统计驱动坚持”。

1.3 技术选型:ThinkPHP与Vue生态的匹配逻辑

技术选型这件事,我给这类中小型项目定的原则是:成熟、低维护成本、学习曲线平缓,而不是一味追求最新最热。

后端用 ThinkPHP 6,理由很简单。ThinkPHP 的模型ORM、验证器、中间件、路由定义都是开箱即用,一个 composer 装完,部署只需要 PHP 环境加 Nginx,不像 Java 系还要维护一堆中间件。对于这种日活在几百到几千的系统,TP 的吞吐完全够用,而且出了问题能查的人也多。

前端这边,很多人误以为“thinkphp+vue”就是管理后台用 Vue,小程序用原生。实际我的方案是两头都走 Vue 生态:小程序端用 uni-app,底层就是 Vue 3 语法;后台管理端用 Vue 3 + Vite + Element Plus。这样前后端两头都是同一套 Vue 心智模型,团队里任何一个人都能同时维护两个端,不用在小程序原生 WXML 和 Vue SFC 之间来回切换。

选择微信小程序作为宿主,核心是微信生态的分发优势,用户扫一下码就能打开,不需要下载 App,对内容型工具型产品来说冷启动成本最低。

2. 数据表设计:饮食、运动、科普三类数据的建模思路

2.1 用户与健康档案表

数据库设计是我在开始写接口前花时间最多的地方。这个项目涉及三类数据:用户与健康档案、科普文章体系、饮食与运动记录。三类数据要揉在一个库,关系不复杂,但细节里全是坑。

用户表和健康档案表我分开设计。user表只存微信侧的基础信息,包括 id、openid、nickname、avatar、gender、created_at。openid 必须加唯一索引,这是微信登录的身份凭证,一个 openid 对应一个用户,不能重复建档。

健康档案我单独建了一张health_profile表,字段包括 user_id、height_cm、weight_kg、age、target_weight_kg、bmi、updated_at。身高体重都用 decimal(5,2),避免 float 带来的精度问题。BMI 字段后端算好后冗余存储,不是每次查询时现算。为什么要冗余?因为个人中心和统计页都要展示 BMI,首页推荐内容可能也要用,与其每个接口反复计算,不如在档案更新时算一次存下来,查询时直接取,性能更好。

2.2 科普文章体系:分类、标签与收藏

科普内容这块我设计了三个表。article_category分类表,字段有 id、name、sort、status。注意初期不要搞多级分类树,就用单层分类,像“增肌饮食”“减脂餐”“基础营养”“运动康复”这些就完全够用。多级分类引入父子关系后,前端分类导航、后端筛选逻辑都会变复杂,前期收益又低。

article文章表是核心,字段包括 id、category_id、title、cover、summary、content、source、read_count、like_count、status、create_time。title 用 varchar(200),content 用 text。status 字段一定要有,0草稿、1发布、2下架,内容发布必须走审核流程,这点后面上线的时候会提到。

收藏表favorite我单独建了,字段是 id、user_id、article_id、create_time,并且加了(user_id, article_id)联合唯一索引。原因是小程序端经常要判断“这篇文章我是否收藏过”,有唯一索引可以直接用 insert ignore 实现幂等插入,不用先查再插。点赞功能同理,如果只是展示总数,维护 article 表一个 like_count 字段就够了;但如果需要回显“我是否点过赞”,就必须建like_log表。我在实际开发中直接建了 like_log,因为不做状态回显,前端体验会很奇怪。

2.3 饮食与运动记录表:记录行为设计

饮食记录表diet_record的字段设计,有一个思路值得一提。表结构是 id、user_id、food_id(可空)、food_name、amount、unit、calorie、meal_type、record_date、create_time。

很多人会问:既然有食物库表,为什么不直接存 food_id,还要冗余 food_name 和 calorie?答案是快照思想。食物库里的热量数据后期很可能修正,比如某个食物实测热量从 150 千卡调整到 140 千卡。如果不冗余,历史记录都要跟着变,用户看到的“昨天吃了多少”就被悄悄改掉了,这会直接影响用户对数据的信任。冗余一份记录当时的名称和热量,就能保证历史数据稳定,这是记录类系统的通用经验。

运动记录表exercise_record同理:id、user_id、exercise_type、duration_minute、met、calorie、record_date。duration 字段统一用分钟做单位,前端用户录入“半小时”或“30分钟”,后端一律转成 30 存库,避免两套数据并存。

食物库表food_library是热量计算的基准:id、name、calorie_per_100g、unit、category、cover、status。注意这里统一用“每100克热量”作为标准,前端根据用户填写的份量自动换算,这样录入逻辑最干净。

2.4 字段设计与索引的取舍心得

关于索引,我的经验是:diet_record和exercise_record都建(user_id, record_date)联合索引,因为统计接口按天查询是最高频路径。article 表建(status, category_id)联合索引,支持列表页按分类和状态筛选。user 表 openid 唯一索引必不可少。

字段类型上,日期字段存 'Y-m-d' 字符串,不用时间戳。字符串日期在 SQL 里可以直接 group by,排序也正确,而时间戳还要做一层转换,纯属给自己添麻烦。热量用 decimal(8,2),不要用 float,统计求和时 float 的精度漂移会让人非常头大。

关于外键,我只建逻辑关联,不建物理外键。ThinkPHP ORM 的关联查询足够方便,物理外键在数据量大之后锁表问题很烦。用索引加代码逻辑保证一致性,对小程序这种规模的应用完全够用。

3. ThinkPHP后端实现:接口封装、鉴权与业务逻辑

3.1 统一返回格式与异常处理

后端接口我第一步做的,是统一返回格式。任何一个接口的成功响应都是{code: 0, msg: 'success', data: ...},失败响应是{code: 非0, msg: 错误信息, data: ...}。前端请求封装里只用判断 code 是否是 0,就能统一处理成功和失败,不需要每个页面去重复解析结构。

我写了一个基础控制器类:

<?php namespace app\controller; use think\App; use think\exception\ValidateException; abstract class BaseController { protected function success($data = [], string $msg = 'success') { return json(['code' => 0, 'msg' => $msg, 'data' => $data]); } protected function error(string $msg = 'error', int $code = 1, $data = []) { return json(['code' => $code, 'msg' => $msg, 'data' => $data]); } }

异常处理上,我在 TP6 的全局异常捕获中做了业务异常和系统异常的区分。业务异常直接返回 msg 给用户,比如“该食物不存在”;系统异常记日志,返回“系统繁忙”给前端,不把 SQL 错误和堆栈透露给用户。不要偷懒,这个工作做一次,后面接口开发会省掉大量重复 try-catch。

3.2 微信登录与token鉴权的完整链路

微信登录是整条链路的入口,这里很多人第一次做会踩坑。完整流程是这样的:小程序端uni.login()拿到临时 code,把 code 发给后端;后端带 appid、secret、code 去调微信的 jscode2session 接口,换取 openid 和 session_key;后端用 openid 查用户表,没查到就新建;然后生成一个 token 返回给前端,后续所有请求都带这个 token。

public function login(string $code) { $appId = config('wechat.appid'); $secret = config('wechat.secret'); $url = "https://api.weixin.qq.com/sns/jscode2session?appid={$appId}&secret={$secret}&js_code={$code}&grant_type=authorization_code"; $result = json_decode(file_get_contents($url), true); if (empty($result['openid'])) { return $this->error('登录失败,请重试'); } $openid = $result['openid']; $user = User::where('openid', $openid)->find(); if (!$user) { $user = User::create([ 'openid' => $openid, 'nickname' => '微信用户', 'create_time' => date('Y-m-d H:i:s') ]); } $token = md5($openid . time() . uniqid()); TokenModel::create([ 'token' => $token, 'user_id' => $user->id, 'expire_at' => date('Y-m-d H:i:s', strtotime('+7 days')) ]); return $this->success(['token' => $token, 'user_id' => $user->id]); }

有两个安全细节必须强调:session_key 绝对不要返回给前端,openid 也不要暴露成业务字段。前端只需要 token。token 校验写一个中间件,请求头里带Authorization,中间件查出 token 对应的 user_id 挂到 request 上,后续控制器直接取$request->userId就行。

public function handle($request, \Closure $next) { $token = $request->header('Authorization', ''); $userId = TokenModel::where('token', $token)->where('expire_at', '>', date('Y-m-d H:i:s'))->value('user_id'); if (!$userId) { return json(['code' => 401, 'msg' => '请先登录', 'data' => []]); } $request->userId = $userId; return $next($request); }

注意:小程序端uni.login()拿到的 code 有效期只有 5 分钟,而且只能用一次。如果用户频繁登录失败,优先排查是不是 code 被复用或者跨环境传递了。

3.3 卡路里统计接口的实现逻辑

统计接口是整个系统的“管理”核心。我的做法是统计逻辑全部放后端,前端只负责渲染。一个接口返回当天摄入、消耗、基础代谢、净摄入、建议文案五个数据,前端一次请求全部就位。

public function dailyStat(Request $request) { $userId = $request->userId; $date = $request->get('date', date('Y-m-d')); $diet = DietRecord::where('user_id', $userId) ->where('record_date', $date) ->sum('calorie'); $exercise = ExerciseRecord::where('user_id', $userId) ->where('record_date', $date) ->sum('calorie'); $profile = HealthProfile::where('user_id', $userId)->find(); $bmr = $this->calcBmr($profile); return $this->success([ 'diet_calorie' => round($diet, 1), 'exercise_calorie' => round($exercise, 1), 'bmr' => round($bmr, 1), 'net' => round($diet - $exercise - $bmr, 1), 'suggest' => $this->makeSuggestion($diet, $exercise, $bmr) ]); }

基础代谢我用的是简化版的 Mifflin-St Jeor 公式,男性10*体重kg + 6.25*身高cm - 5*年龄 + 5,女性最后一项改为减 161。这个公式不需要复杂设备,误差也可以接受。

建议文案是后端最有价值的逻辑。摄入比目标高,返回“今天比目标多摄入 XX 千卡,建议减少主食或增加 30 分钟快走”;摄入低于基础代谢,返回“基础代谢没有达到,建议增加优质蛋白摄入”。这些规则写在接口里,前端做任何改版都不影响建议逻辑,这是把核心业务逻辑放在后端的大优势。

查多天数据做七日趋势时,用 group by 让数据库聚合,不要逐条查询再在代码里累加。SQL 写着SUM(calorie) as total按日期分组,一次查完,代码量少而且数据库本身就是干这个的。

4. Vue技术栈在小程序端与管理端的落地

4.1 小程序端为什么选uni-app而不是原生小程序

小程序端是用户直接接触的部分,技术选型直接决定开发效率。这里我明确选了 uni-app,而不是原生小程序。

uni-app 最大的价值是“一套 Vue 语法,多端编译”。如果项目后续要出 H5 版本,或者打包成 App,同一套代码可以直接扩展目标平台,不用重写。它的页面生命周期做了抽象,onLoad、onShow映射到 Vue 组件的生命周期,写起来和 Web Vue 几乎没有差别。页面结构、组件复用、数据响应式,全部沿用 Vue 的心智模型。

原生小程序的性能上限确实更高,但这个项目的页面全是列表、表单、详情、图表,没有重型动画、没有实时渲染,用 uni-app 完全可以覆盖,开发周期压缩 30% 以上。

注意:创建 uni-app 项目时,在 HBuilderX 里要选 Vue 3 模板。如果误建了 Vue 2 模板,后续组合式 API 和生态库的兼容性会有一堆麻烦。

4.2 小程序端的页面结构与核心交互实现

项目页面结构按功能拆成六个核心页面:

src/ pages/ index/index.vue // 科普首页 article/detail.vue // 文章详情 diet/edit.vue // 饮食记录编辑 exercise/edit.vue // 运动记录编辑 stat/stat.vue // 数据统计 mine/mine.vue // 个人中心 utils/ request.js // 请求封装 api/ article.js // 科普模块接口 diet.js // 饮食模块接口 exercise.js // 运动模块接口

请求封装是前端的基础设施,所有请求都走这一个封装,统一注入 token 和处理 401:

// utils/request.js const BASE_URL = 'https://your-api.example.com' export function request({ url, method = 'GET', data = {} }) { return new Promise((resolve, reject) => { uni.request({ url: BASE_URL + url, method, data, header: { Authorization: uni.getStorageSync('token') || '' }, success: (res) => { if (res.data.code === 401) { uni.navigateTo({ url: '/pages/login/login' }) return } resolve(res.data) }, fail: reject }) }) }

小程序端有几个交互细节值得单独说。文章详情页我用了uni.setNavigationBarTitle动态设置页面标题,把当前文章标题同步到顶部导航,用户在列表页和详情页之间跳转时,视觉上能明确感知上下文变化。列表页做分页,onReachBottom触发加载更多,接口传 page 和 page_size,每次 20 条,拉到第二页末尾再显示“没有更多了”。饮食记录表单做智能匹配,用户输入“鸡胸肉”三个字,前端直接调用食物库接口,自动带出热量和默认单位,用户只需要填克数,录入成本被压到很低。

4.3 后台管理端:用Vue 3 + Vite搭建内容管理系统

后台管理端我用的技术栈是 Vue 3 + Vite + Element Plus + Pinia + vue-router + axios。这个组合是目前 Vue 生态最主流的一套,资料多,踩坑容易搜到方案。

路由设计上分了五个页面:

const routes = [ { path: '/login', component: () => import('@/views/Login.vue') }, { path: '/admin', component: () => import('@/layout/Admin.vue'), redirect: '/admin/article/list', children: [ { path: 'article/list', component: () => import('@/views/article/List.vue') }, { path: 'article/edit', component: () => import('@/views/article/Edit.vue') }, { path: 'category', component: () => import('@/views/category/index.vue') }, { path: 'user', component: () => import('@/views/user/index.vue') } ] } ]

路由守卫做登录拦截,router.beforeEach判断本地 token,不存在就跳登录页。这个项目不需要做按钮级权限,登录拦截就到顶了,毕竟内容管理系统只有管理员一个人用。

富文本编辑器我选了 wangEditor,简单直接。但这里有个大坑要提醒:编辑器输出的 HTML 不能直接塞给小程序端。小程序端的rich-text组件支持的标签有限,style 样式大量不生效,图片地址必须走主域名。我在设计后台录入规范时,明确规定图片必须上传到对象存储得到 HTTPS 地址,正文只用基础标题、段落、图片、列表标签。这样小程序端渲染时才不会出现排版崩掉的情况。

4.4 科普内容中的视频与PDF预览:两种容易踩坑的格式

科普内容做深入之后,用户会需要视频和 PDF,这两类格式在小程序端都有典型坑。

视频文件,我的建议是首发走 MP4 并托管到对象存储,微信小程序video组件对 MP4 的支持最稳定。m3u8 分片流常见于直播和课程视频,开发者工具里经常能播,真机上却可能黑屏,排查到最后往往不是域名问题,而是编码封装格式不被支持。稳妥的做法是后端统一转成 MP4 或 HLS 标准流,前端不要指望小程序内核能播所有格式。

PDF 更直接,小程序原生页面不能直接渲染 PDF。我实际用的是方案是:科普内容坚持图文混排,PDF 只作为附件存在后台,用户点击后用uni.downloadFile下载,再用wx.openDocument打开预览。这样最稳,也不会因为页面格式兼容问题被审核打回。

5. 健康数据的计算与可视化:容易忽略的细节

5.1 食物热量库怎么建、数据从哪来

食物热量库是整个饮食记录功能的基础,没有库,用户每样食物都得手填热量,记录成本一高,产品就废了。

数据来源我参考了公开的《中国食物成分表》和几个主流食物库网站,整理出一份初始数据,覆盖常见米面、肉蛋、蔬果、饮品类,差不多 600 条常用食物。数据整理工作量不小,但是必须做扎实,这是内容库的资产。录入时统一按每 100 克热量存储,前端根据用户填写的克数自动换算:calorie = calorie_per_100g * amount / 100。一条食物记录包括 name、calorie_per_100g、unit(克/份/个)、category、cover。

一定要提供自定义录入入口。因为用户会吃食堂的“红烧肉”、外婆做的“拿手菜”,这些不在任何食物库里。用户手动录名称和热量,后端存进diet_record,只属于当天记录,不进公共食物库,避免污染基准数据。

5.2 运动消耗计算:MET值的正确用法

运动消耗的计算公式是:消耗热量(kcal) = MET × 体重(kg) × 运动时间(小时)。MET 是代谢当量,衡量运动强度,不同运动有对应的参考值。

我整理了一份常用 MET 表:

运动类型MET 值
散步3.0
快走4.3
跑步7.0
骑行6.8
游泳5.8
跳绳11.0
力量训练5.0

举个例子:体重 60kg 的人骑自行车 30 分钟,消耗是6.8 × 60 × 0.5 ≈ 204 千卡。这个公式看起来简单,实际项目里最容易犯的错误有两个:一是 MET 值按“小时”计算,前端用户输入的是分钟,忘记转成小时直接代入公式,计算结果直接翻 60 倍;二是强度选择,同样是跑步,慢跑和快跑 MET 不同。我的方案是运动类型下拉里直接绑定 MET 值,用户不用懂概念,选择类型时系统自动带上参数。

注意:MET 值是固定参考值,个体差异是存在的,但科普管理场景用统一参考值已经足够,不用过度纠结精度,否则给用户的就不是建议而是数据焦虑了。

5.3 图表展示:小程序端怎么画每日趋势图

个人中心的统计页如果只显示数字,用户感知很弱。一周摄入与消耗趋势用折线图画出来,信息密度立刻不一样。

小程序端画图有三个方案。手写 canvas 最灵活,但折线图涉及坐标轴刻度、文字宽度测量、触摸提示,工作量不小;直接用 ECharts 的 web 包不行,小程序没有 DOM;社区常用的是借用小程序版 ECharts 或彻底转 uCharts。

我选了 uCharts,专门面向小程序 canvas 场景,轻量、文档够用。画一个最近 7 天的摄入与消耗对比折线,两个数据系列配图例,x 轴是日期,y 轴是千卡。第一次真机测试时图表空白,排查是 canvas 尺寸用了固定 px 导致机型适配失效,后来改成 rpx 换算再乘设备像素比,问题解决。这个坑比较隐蔽,uCharts 的 canvas 宽度要用uni.getSystemInfoSync()获取的 windowWidth 来计算,不能用 CSS 的百分比。

6. 联调、部署与上线踩坑:从本地环境到微信审核

6.1 本地环境:ThinkPHP项目运行与Vue环境配置的常见坑

部署之前,本地环境先跑通是第一关。很多同学卡在这一步,问题高度集中。

ThinkPHP 6 要求 PHP 版本 7.2 以上,我实际用的 PHP 7.4。用 composer 安装依赖时,如果中国网络环境拉包慢,可以切换镜像源。配完代码后第一个大坑是 Nginx 伪静态,没配置的话所有路由全部 404。Nginx 站点配置里必须加:

location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=$1 last; } }

Vue 项目这边,Node 版本推荐 16 以上。npm install之后如果 dev server 起不来,把 node_modules 整个删掉重新装,比定位半天灵异问题快得多。

接口联调的另一个高频坑是跨域。小程序开发工具本身不跨域,但管理后台跑在 localhost 上,与后端 API 是不同端口,必须处理跨域。我在后端加了一个全局跨域中间件,统一设置Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers。注意 OPTIONS 预检请求不要被登录鉴权中间件拦截,否则管理后台第一次请求就全部 401。

6.2 微信小程序合法域名与真机调试

本地联调阶段,微信开发者工具可以勾选“不校验合法域名”,真机调试也一样,这能让你先用 http 接口把功能跑通。

但上线发布前,所有请求域名必须满足两个硬条件:一是 HTTPS,小程序不支持纯 HTTP;二是域名必须在小程序后台配置为服务器域名,request 合法域名和 downloadFile 合法域名都要配。图片如果走 CDN,CDN 域名也要加进去。域名没有备案的话小程序无法上线,这是硬性门槛,项目启动的时候就要提前准备。

真机调试遇到最典型的故障是:开发者工具一切正常,真机白屏。八成是域名校验问题,排查方向直接看合法域名配置。调试请求时,开发者工具的网络面板能看到所有请求,也可以借助 Charles 这类抓包工具对小程序请求做完整分析,定位慢请求和接口异常,比单纯看控制台日志直观得多。

6.3 微信审核被拒的典型原因与应对

功能全部做完,提交微信审核是一道关。这个项目踩过的审核心得有两点。

第一是类目选择。健康类小程序如果涉及“医疗”相关功能,需要对应的行业资质。我们做的是科普和管理工具,类目选“生活服务-健康咨询”或“教育”,不碰任何“诊断”“治疗”“药方”之类字样。文章标题和内容也会做敏感词过滤,科普中允许出现“建议”“注意”,避免出现确诊性表述。

第二是隐私合规。系统收集身高体重、饮食记录等健康数据,必须在小程序后台填写《用户隐私保护指引》,并且在用户首次登录时弹窗告知。没有隐私弹窗直接提交审核,基本都会被驳回。如果后续开放评论功能,还要有内容审核和删除入口,这是平台底线。

6.4 性能优化与包体积控制

小程序一上来就面临包体积限制,主包 2MB,整包 4MB。这个项目图片必须全走 CDN,本地静态资源只保留图标和基础组件。

我用 uni-app 编译后,文章详情页和统计页拆到了分包subpackages,主包体积控制住,详情页和统计页只在用户访问时才加载。列表页数据分页,默认 20 条,触底加载更多,一开始只拉第一页。后端侧,热门文章列表加了 TP 自带缓存,文件缓存就够了,不用上 Redis,热门数据半小时刷新一次;每日统计接口用户当天反复看,缓存 10 分钟,减少数据库压力。

这些优化做完,小程序冷启动明显加快,后端数据库查询量也降下来了。

这个项目前后做了一周多,最大的体会是:这类“内容+记录”的小程序,真正的难点不在框架,而在两类用户需求的平衡。科普内容需要后台方便录入,个人记录需要录入成本足够低。所以我在表单上做了大量预填和智能匹配——输入“鸡胸肉”自动带热量,输入运动时长自动算消耗,这些看似不起眼的细节决定了用户愿不愿意坚持记录。如果你想做类似的项目,建议先把内容库和记录表设计扎实,再动手写后端和前端。技术选型其实没那么重要,ThinkPHP 也好 Vue 也好,跑通闭环才是一切的前提。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 4:51:31

OP37精密运放深度解析:JFET输入、低失调与实操稳定性设计

1. 这不是一份普通的数据手册——OP37中文资料背后的真实价值你搜“OP37中文资料”&#xff0c;页面跳出一堆“免费下载”“高速精密运放”“低噪声”“工业级”这类词&#xff0c;点开PDF却发现要么是扫描版模糊不清、要么是英文原版硬凑的机翻、要么干脆就是套壳的广告页。我…

作者头像 李华
网站建设 2026/10/6 4:51:30

干涉图生成中的多视数:从噪声抑制到空间分辨率权衡

做干涉图的人&#xff0c;几乎每天都会跟“多视数”打交道。可它不像轨道精炼、相位解缠那样有清晰的步骤感&#xff0c;它更像一个藏在参数框里、看起来填什么都行的数字。我在第一次用 Sentinel-1 数据生成干涉图时&#xff0c;就在多视数这个参数上栽过跟头&#xff1a;填了…

作者头像 李华
网站建设 2026/10/6 4:51:05

AI编码代理本地代理层架构设计与token管理实战

1. 从"caveman"说起&#xff1a;一个AI编码代理的代理层到底在解决什么问题第一次看到"caveman"这个词&#xff0c;我脑子里蹦出来的画面是原始人拿着石斧敲键盘。但真正做过AI编码代理&#xff08;AI coding agent&#xff09;基础设施的人会心一笑——这…

作者头像 李华
网站建设 2026/10/6 4:51:04

十款降AIGC工具实测:从检测原理到论文降AI率实操

熟悉我的人都知道&#xff0c;我做论文语言润色和合规检测分析这行已经很多年。2026年这波“降论文AI率”的需求&#xff0c;比往年任何一次查重改革都要猛&#xff1a;不少高校在送审前已经把AIGC检测报告列为常态化核查项&#xff0c;于是平时依赖AI辅助整理思路的同学突然发…

作者头像 李华
网站建设 2026/10/6 4:51:04

Unity工业数字孪生实战:PLC通信+SolidWorks模型+RTSP视频流集成

简介&#xff1a;本资源是一个基于Unity3d&#xff08;WebGL&#xff09;实现的轻量级数字孪生实践项目&#xff0c;面向Unity开发初学者、物联网与Web三维可视化学习者&#xff0c;以及希望掌握软硬协同建模与数据交互全流程的全栈开发者。项目完整覆盖硬件&#xff08;NodeMC…

作者头像 李华
网站建设 2026/10/6 4:50:53

小波交叉功率谱与相位分析:MATLAB实现全解析

1. 为什么偏偏是"小波交叉功率谱"——当"两路信号在哪个频段相关"答不上来时做信号处理的朋友应该都遇到过这种尴尬&#xff1a;手头有两路数据&#xff0c;明显觉得它们之间有关系&#xff0c;但传统方法一个值根本说不清楚。我去年处理两路水声信号时就撞…

作者头像 李华