HarmonyOS ArkTS 实战:实现一个校园食堂评价与美食推荐应用
HarmonyOS ArkTS 实战:校园食堂评价与美食推荐完整实现
摘要
项目难度:⭐⭐⭐ 中级实战
适用人群:有 ArkTS 基础、希望学习生活类应用开发的 HarmonyOS 开发者
开发环境:DevEco Studio Next / API 24+
代码规模:单页面约 700 行,可直接运行
通过本项目,你将掌握:
- 星级评分组件的实现与交互设计
- 评价系统的数据结构与排序算法
- 菜品收藏与推荐机制的设计
- 瀑布流布局与卡片视觉设计
- 多维度筛选与排行榜功能实现
目录
- [一、项目概述与功能架构]
- [1.1 应用场景与项目价值]
- [1.2 完整功能清单]
- [1.3 技术选型说明]
- [二、数据结构设计]
- [2.1 菜品模型 Dish]
- [2.2 评价模型 Comment]
- [2.3 设计思路说明]
- [三、核心功能实现详解]
- [3.1 菜品浏览与筛选]
- [3.2 星级评分与发表评价]
- [3.3 收藏与推荐算法]
- [3.4 食堂排行榜]
- [四、UI 设计与交互体验]
- [4.1 整体布局结构]
- [4.2 主题色与视觉规范]
- [4.3 状态视觉区分表]
- [五、关键技术点解析]
- [5.1 星级评分的交互设计考量]
- [5.2 美食推荐算法的基础设计]
- [六、常见问题与优化建议]
- [七、项目总结与扩展方向]
- [附录:运行方式]
一、项目概述与功能架构
1.1 应用场景与项目价值
"今天吃什么"是大学生每天都要面对的灵魂拷问。校园食堂窗口众多、菜品丰富,但质量参差不齐,新生不了解哪些好吃,老生想尝新又怕踩雷。食堂评价与美食推荐应用正是为了解决这个痛点。
本项目基于 HarmonyOS ArkTS 实现了一个校园食堂评价与美食推荐应用,整合了菜品打分评价、美食推荐、收藏菜品、食堂排行、热门窗口、吐槽反馈等功能,通过UGC评价体系帮助学生发现美食、避开雷区。
项目核心价值:
- 决策效率价值:看评分选菜,减少选择困难,降低踩雷概率
- 信息透明价值:建立公开评价体系,促进食堂提升菜品质量
- 社区互动价值:美食分享形成校园饮食文化,增加生活乐趣
1.2 完整功能清单
| 功能模块 | 具体功能 | 实现难度⭐ |
|---|---|---|
| 菜品浏览 | 菜品列表、食堂筛选、搜索查找、分类浏览 | ⭐⭐ |
| 评价系统 | 星级评分、文字评价、点赞互动、评价列表 | ⭐⭐⭐ |
| 收藏管理 | 收藏菜品、我的收藏、收藏分类、快速查找 | ⭐⭐ |
| 排行榜 | 菜品排行、食堂排行、窗口排行、新晋热门 | ⭐⭐⭐ |
| 推荐系统 | 每日推荐、猜你喜欢、新品推荐、高分推荐 | ⭐⭐⭐ |
| 反馈互动 | 吐槽反馈、问题上报、点赞评论、分享美食 | ⭐⭐ |
1.3 技术选型说明
| 技术维度 | 选型方案 | 选型理由 |
|---|---|---|
| 开发语言 | ArkTS | 强类型支持,适合评分、排序等数据处理 |
| 状态管理 | @State 装饰器 | 轻量响应式,满足评价和收藏状态更新 |
| 布局方式 | 瀑布流/网格布局 | 适合菜品卡片展示,视觉效果好 |
| 数据存储 | 内存状态 | 演示简化,生产环境需对接后端服务 |
| 最低版本 | API 24 | 兼容主流 HarmonyOS 设备 |
⚠️ 注意:本项目为前端演示版本,评价数据均为本地模拟。真实食堂评价平台需要运营审核机制,防止恶意差评和广告灌水。
二、数据结构设计
2.1 菜品模型 Dish
菜品是系统的核心实体,包含基本信息和评分数据。
/**
* 食堂菜品数据模型
*/
interface Dish {
id: number; // 菜品ID
name: string; // 菜品名称
canteen: string; // 所属食堂
window: string; // 所属窗口
price: number; // 价格(元)
score: number; // 综合评分 0-5
tags: string[]; // 标签:好吃/性价比高/分量足 等
image: string; // 菜品图片
isCollected: boolean; // 是否已收藏
commentCount: number; // 评价数量
}
2.2 评价模型 Comment
评价是用户对菜品的反馈,包含评分和文字内容。
/**
* 菜品评价数据模型
*/
interface Comment {
id: number; // 评价ID
dishId: number; // 所属菜品ID
userName: string; // 评价用户
score: number; // 评分 1-5星
content: string; // 评价内容
time: string; // 评价时间
likes: number; // 点赞数
}
2.3 设计思路说明
为什么评分采用5星制?
5星评分是最经典也最符合用户习惯的评分体系:
- 认知成本低:几乎所有人都理解5星代表好,1星代表差
- 粒度适中:5个等级足够区分好坏,又不会因为选项太多让用户纠结
- 计算方便:平均分、加权分等统计都很直观
- 视觉友好:星星图标美观,交互反馈好
10分制太精细,3分制太粗糙,5星制是体验和精度的最佳平衡点。
关于标签系统的设计
标签是对评分的补充,提供更多维度的信息:
- 口味维度:好吃、一般、难吃
- 性价比维度:性价比高、有点贵、便宜
- 分量维度:分量足、刚好、吃不饱
- 其他:排队久、环境好、新品等
标签让评价信息更结构化,用户可以快速了解菜品的特点,而不只是一个干巴巴的分数。
三、核心功能实现详解
3.1 页面状态初始化
/**
* 页面状态变量定义
*/
@State private commentContentText: string = ''; // 评价内容输入
@State private rating: number = 5; // 当前评分(默认5星)
@State private selectedCanteen: string = '全部'; // 食堂筛选
@State private nextCommentId: number = 10; // 下一条评价ID
@State private dishes: Dish[] = []; // 菜品列表
@State private comments: Comment[] = []; // 评价列表
3.2 菜品筛选与搜索
/**
* 获取筛选后的菜品列表
* 支持按食堂筛选和排序
*/
private getFilteredDishes(): Dish[] {
let result = this.dishes;
// 按食堂筛选
if (this.selectedCanteen !== '全部') {
result = result.filter(d => d.canteen === this.selectedCanteen);
}
// 按评分降序排序,高分在前
return result.sort((a, b) => b.score - a.score);
}
/**
* 切换收藏状态
*/
private toggleCollect(dishId: number): void {
this.dishes = this.dishes.map(d =>
d.id === dishId ? { ...d, isCollected: !d.isCollected } : d
);
}
3.3 发表评价与星级评分
用户选择星级并填写评价内容后提交。
/**
* 提交菜品评价
* @param dishId 菜品ID
*/
private submitComment(dishId: number): void {
const content = this.commentContentText.trim();
if (content.length === 0) return;
// 1. 创建新评价
const comment: Comment = {
id: this.nextCommentId,
dishId: dishId,
userName: '我',
score: this.rating,
content: content,
time: new Date().toLocaleString(),
likes: 0
};
this.comments = [comment, ...this.comments];
this.nextCommentId++;
// 2. 更新菜品的平均评分和评价数
this.updateDishScore(dishId);
// 3. 清空输入
this.commentContentText = '';
this.rating = 5;
}
/**
* 重新计算菜品平均评分
* 简化版:取所有评价的平均分
*/
private updateDishScore(dishId: number): void {
const dishComments = this.comments.filter(c => c.dishId === dishId);
if (dishComments.length === 0) return;
const totalScore = dishComments.reduce((sum, c) => sum + c.score, 0);
const avgScore = Math.round((totalScore / dishComments.length) * 10) / 10;
this.dishes = this.dishes.map(d =>
d.id === dishId ? {
...d,
score: avgScore,
commentCount: dishComments.length
} : d
);
}
设计要点解析:
- 实时更新平均分:提交评价后立即重新计算菜品平均分,保证数据一致性
- 保留一位小数:评分精度到0.1分,既精确又不会太琐碎
- 评价数同步更新:评价数量也是重要参考指标,避免只有1个5分就排第一
3.4 评价点赞功能
/**
* 给评价点赞
*/
private likeComment(commentId: number): void {
this.comments = this.comments.map(c =>
c.id === commentId ? { ...c, likes: c.likes + 1 } : c
);
}
/**
* 获取某菜品的热门评价
* 按点赞数排序,取前3条
*/
private getTopComments(dishId: number): Comment[] {
return this.comments
.filter(c => c.dishId === dishId)
.sort((a, b) => b.likes - a.likes)
.slice(0, 3);
}
3.5 食堂排行榜
/**
* 计算各食堂的平均评分
* 生成食堂排行榜
*/
private getCanteenRanking() {
const canteenMap = new Map<string, { total: number; count: number }>();
this.dishes.forEach(d => {
if (!canteenMap.has(d.canteen)) {
canteenMap.set(d.canteen, { total: 0, count: 0 });
}
const data = canteenMap.get(d.canteen)!;
data.total += d.score;
data.count++;
});
const ranking: { name: string; avgScore: number }[] = [];
canteenMap.forEach((value, key) => {
ranking.push({
name: key,
avgScore: Math.round((value.total / value.count) * 10) / 10
});
});
// 按平均分降序
return ranking.sort((a, b) => b.avgScore - a.avgScore);
}
四、UI 设计与交互体验
4.1 整体布局结构
┌─────────────────────────┐
│ 数据统计栏 │ ← 收录菜品/我的收藏/已评价/今日推荐
├─────────────────────────┤
│ 搜索栏 + 食堂筛选 │ ← 搜索 + 一食堂/二食堂 切换
├─────────────────────────┤
│ Tab 切换栏 │ ← 推荐 / 排行榜 / 我的收藏
├─────────────────────────┤
│ │
│ 菜品瀑布流 │ ← 菜品卡片 + 评分 + 价格
│ │
└─────────────────────────┘
4.2 主题色与视觉规范
主色调:玫瑰红 #F43F5E
选择玫瑰红作为主题色的设计考量:
- 美食属性联想:玫瑰红/玫红色与美食、食欲有着天然的视觉关联,令人联想到美味的食物,激发用户探索美食的兴趣
- 热情活力调性:玫红色传递热情、活力、愉悦的情绪,与"发现美食、分享快乐"的产品定位高度契合
- 视觉吸引力强:高饱和度的红色系在视觉上非常醒目,能够快速抓住用户注意力,适合推荐和热门标记
- 层次感丰富:从浅粉到深红的色阶变化丰富,可以用于评分高低、热门程度等不同层级的视觉区分
辅助色规范:
- 主色调:#F43F5E(玫瑰红)
- 高分菜品:#F43F5E(红色高亮推荐)
- 中等评分:#F59E0B(琥珀色)
- 低分菜品:#6B7280(灰色)
- 价格标签:#1F2937(深灰加粗)
- 收藏高亮:#F59E0B(金色星星)
4.3 状态视觉区分表
| 评分等级 | 星星颜色 | 文字颜色 | 推荐标签 | 心理暗示 |
|---|---|---|---|---|
| 4.5-5分 | 全金色星星 | 玫瑰红 | 强烈推荐 | 必吃美食 |
| 4.0-4.4分 | 金色星星 | 深橙 | 推荐 | 值得一试 |
| 3.5-3.9分 | 半金半灰 | 琥珀 | 还行 | 可以尝试 |
| 3.0-3.4分 | 灰色星星 | 灰色 | 一般 | 谨慎选择 |
| 3分以下 | 全灰星星 | 深灰 | 不推荐 | 建议避雷 |
| 收藏状态 | 图标样式 | 视觉表现 | 交互反馈 |
|---|---|---|---|
| 未收藏 | 空心星星 | 灰色 | 点击填充金色 |
| 已收藏 | 实心星星 | 金色 | 点击变空心 |
五、关键技术点解析
5.1 星级评分的交互设计考量
星级评分看似简单,实际上有很多交互细节影响用户体验。
交互设计要点:
- 实时预览:手指滑到第几颗星,星星就实时点亮到第几颗,给用户即时反馈
- 点击区域:每颗星的点击区域要比视觉图标大,方便手指点击
- 半星支持:可选支持0.5星精度,提供更精细的评分粒度
- 取消评分:再次点击当前星级可以取消,回到未评分状态
- 文字辅助:可以配合"很差/一般/好/很好/非常好"等文字提示
常见的评分偏差问题:
- 分数膨胀:大多数人都打4-5分,导致区分度不高
- 极端评价:特别好或特别差才会评价,中间的不评价
- 恶意差评:竞争对手或情绪性的不合理低分
解决方案:增加评价审核、加权计算、异常检测等机制。
5.2 美食推荐算法的基础设计
推荐系统是美食应用的核心竞争力,从简单到复杂有多个层级。
推荐算法演进路径:
| 算法级别 | 实现方式 | 推荐效果 | 开发难度 |
|---|---|---|---|
| L1 基础 | 按评分排序推荐 | 一般 | 低 |
| L2 标签 | 基于标签的相似推荐 | 中等 | 中 |
| L3 协同过滤 | 基于用户行为的协同过滤 | 较好 | 高 |
| L4 深度学习 | 深度学习个性化推荐 | 很好 | 很高 |
本项目采用的简化推荐策略:
- 热门推荐:评分高 + 评价数多的菜品,质量有保障
- 新品推荐:最近新增的菜品,鼓励尝鲜
- 收藏相似:根据用户收藏的菜品,推荐同食堂同类型的菜品
对于校园场景,简单的规则推荐已经能满足基本需求,开发成本低效果也不错。
六、常见问题与优化建议
踩坑点 1:评分水军刷分
问题表现:有人恶意刷高分或恶意刷低分,影响评分公正性
解决方案:增加评价审核机制,限制单人评价次数,异常评分加权处理
踩坑点 2:菜品信息不准确
问题表现:窗口换了菜品、价格变了,信息更新不及时
解决方案:建立用户纠错机制,允许用户上报信息变更,运营审核后更新
踩坑点 3:评价内容质量低
问题表现:很多评价只有"好吃""一般"几个字,参考价值不大
解决方案:引导用户填写结构化评价(口味、分量、性价比等维度),奖励优质评价
踩坑点 4:搜索匹配度差
问题表现:搜索"红烧肉"搜不到"红烧五花肉"
解决方案:增加同义词和模糊匹配,支持拼音搜索,优化搜索算法
优化方向
- 增加菜品图片上传功能,用户评价时可以配图
- 实现实时排队人数显示,帮助学生错峰就餐
- 增加营养成分信息,提供健康饮食建议
- 接入每日菜单更新,提前知道今天有什么菜
七、项目总结与扩展方向
核心收获
通过完成食堂评价与美食推荐项目,你将掌握:
- 星级评分组件的完整交互实现
- 评价系统的数据结构与排序算法
- 瀑布流布局的卡片视觉设计
- 基础推荐系统的设计思路
后续扩展功能
- 📸 图片评价:评价可以上传图片,有图有真相
- 👥 排队人数:实时显示各食堂窗口排队情况,错峰就餐
- 🥗 营养成分:展示菜品热量和营养,健康饮食
- 📋 每日菜单:每日更新菜单,提前知道今天吃什么
- 🛒 外卖点餐:在线点餐,送到宿舍楼下
- 🏆 美食榜单:周榜月榜年榜,发现校园美食天花板
运行效果

更多推荐



所有评论(0)