feat:增加菜谱收藏功能

This commit is contained in:
2025-07-02 19:55:18 +08:00
parent 1037edeed4
commit 1d0cb061d0
8 changed files with 110 additions and 34 deletions

View File

@@ -34,6 +34,12 @@ export const queryRecipeByUserApi = (id: number): Promise<IRecipe[]> =>
method: 'get'
})
export const queryRecipeUserFavouriteApi = (): Promise<IRecipe[]> =>
cloudService({
url: '/food-service/food/recipe/user/favourite',
method: 'get'
})
export const queryRecipeApi = (query: IFoodQuery): Promise<IRecipe[]> =>
cloudService({
url: '/food-service/food/recipe',
@@ -94,6 +100,18 @@ export const deleteRecipeLikeApi = (id: number): Promise<boolean> =>
method: 'delete'
})
export const addRecipeFavouriteApi = (id: number): Promise<boolean> =>
cloudService({
url: `/food-service/food/recipe/${id}/favourite`,
method: 'post'
})
export const deleteRecipeFavouriteApi = (id: number): Promise<boolean> =>
cloudService({
url: `/food-service/food/recipe/${id}/favourite`,
method: 'delete'
})
export const queryRecordApi = (startDate: string, endDate: string): Promise<IRecord[]> =>
cloudService({
url: '/food-service/food/record',

View File

@@ -39,21 +39,25 @@
<div class="bottom-container">
<div class="info-list">
<div class="info-item category-item">
<el-avatar v-if="!isCurrentUser" :src="avatarUrl" :size="20" fit="contain"/>
<span v-if="!isCurrentUser" class="user">{{ props.item.username }}</span>
<div v-if="isCurrentUser" class="info-item category-item">
<i class="fa-solid fa-utensils"></i>
{{ props.item.category }}
</div>
<div class="info-item like-item">
<div v-if="isCurrentUser" class="info-item like-item">
<i class="fa-regular fa-thumbs-up"></i>
{{ props.item.likeCount }}
</div>
<div class="info-item comment-item">
<div v-if="isCurrentUser" class="info-item comment-item">
<i class="fa-regular fa-comment"></i>
{{ props.item.commentCount }}
</div>
<div class="info-item start-item">
<div v-if="isCurrentUser" class="info-item start-item">
<i class="fa-solid fa-star"></i>
0
{{ props.item.favouriteCount }}
</div>
</div>
@@ -75,17 +79,18 @@
<script setup lang="ts">
import { Edit, Collection, DeleteFilled } from '@element-plus/icons-vue'
import { useFoodStore } from '@/store/food'
import { useUserStore } from '@/store/user'
import { computed, defineProps, onMounted, reactive } from 'vue'
import type { PropType } from 'vue'
import type { IRecipe, IRecord } from '@/types/food.ts'
import { useRouter, useRoute } from 'vue-router'
import { useRouter } from 'vue-router'
import { formatDate } from 'vue3-common/utils/dateUtil'
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
import { serviceFileRootPath } from '@/utils'
const router = useRouter()
const route = useRoute()
const foodStore = useFoodStore()
const userStore = useUserStore()
const foodCardInfo = reactive({
recommendRate: 0,
@@ -103,7 +108,15 @@ onMounted(() => {
foodCardInfo.recommendRate = props.item?.recommendRate as number
})
const isCurrentUser = computed(() => route.path.includes('record'))
const avatarUrl = computed(() => {
if (props.item?.avatar) {
return serviceFileRootPath + props.item.avatar
} else {
return 'https://cube.elemecdn.com/3/7c/3ea6beec64369c2642b92c6726f1epng.png'
}
})
const isCurrentUser = computed(() => props.item?.userId === userStore.getUserId())
const getRecord = (recordList: IRecord[]) => {
return recordList.filter((item) => item.imageUrl)

View File

@@ -4,25 +4,12 @@ import type {
IStats, IRecord, IMoment, IFoodSegment
} from '@/types/food'
import {
addRecipeApi,
addRecordApi,
deleteRecipeApi,
deleteRecordApi,
queryFoodNameListApi,
queryRecipeByIdApi,
queryRecordApi,
queryStatsApi,
updateRecipeApi,
updateRecordApi,
queryCategoryApi,
queryRecordStatsApi,
queryCategoryStatsApi,
queryRankStatsApi,
queryRecipeApi,
queryRecipeByUserApi,
deleteRecipeLikeApi,
addRecipeLikeApi,
addRecipeCommentApi
addRecipeApi, addRecordApi, deleteRecipeApi, deleteRecordApi,
queryFoodNameListApi, queryRecipeByIdApi, queryRecordApi, queryStatsApi,
updateRecipeApi, updateRecordApi, queryCategoryApi, queryRecordStatsApi,
queryCategoryStatsApi, queryRankStatsApi,
queryRecipeApi, queryRecipeByUserApi, deleteRecipeLikeApi,
addRecipeLikeApi, addRecipeCommentApi, addRecipeFavouriteApi, deleteRecipeFavouriteApi, queryRecipeUserFavouriteApi
} from '@/apis/food.ts'
import type { IDialog, IHandleApi, IStatsChart } from 'vue3-common/types'
import { ElMessage } from 'element-plus'
@@ -45,11 +32,17 @@ export const useFoodStore = defineStore('food', {
category: '',
recommendRate: 0,
remark: '',
isShare: false,
username: '',
userId: 0,
avatar: '',
materialList: [],
stepList: [],
recordList: [],
likeCount: 0,
likeList: [],
favouriteCount: 0,
favouriteList: [],
commentCount: 0,
commentList: []
} as IRecipe,
@@ -133,6 +126,11 @@ export const useFoodStore = defineStore('food', {
this.recipeList = await queryRecipeByUserApi(id)
this.isLoading = false
},
async queryRecipeUserFavourite() {
this.isLoading = true
this.recipeList = await queryRecipeUserFavouriteApi()
this.isLoading = false
},
async queryRecordList() {
const { year, month } = this.queryRecord
const date = this.queryDateType === 'year' ? year : month
@@ -249,6 +247,14 @@ export const useFoodStore = defineStore('food', {
await deleteRecipeLikeApi(id)
await this.queryRecipe(this.currentRecipe.id as number)
},
async addRecipeFavourite(id: number) {
await addRecipeFavouriteApi(id)
await this.queryRecipe(this.currentRecipe.id as number)
},
async deleteRecipeFavourite(id: number) {
await deleteRecipeFavouriteApi(id)
await this.queryRecipe(this.currentRecipe.id as number)
},
getEmptyRecipe(): IRecipe {
return {
commentCount: 0,
@@ -259,6 +265,7 @@ export const useFoodStore = defineStore('food', {
materialList: [],
name: '',
recommendRate: 0,
isShare: false,
remark: '',
stepList: [],
recordList: []

View File

@@ -53,6 +53,11 @@ $card-image-height: 200px;
font-size: 1.2rem;
font-weight: bold;
}
.user {
// font-size: 0.9rem;
color: #9C9C9C;
}
}
.category-item {

View File

@@ -59,6 +59,10 @@ export interface IRecipe {
* 备注
*/
remark: string;
isShare: boolean;
userId?: number;
username?: string;
avatar?: string;
/**
* 食材
*/
@@ -71,10 +75,12 @@ export interface IRecipe {
* 成果
*/
recordList: IRecord[];
likeList: number[];
likeCount: number;
commentList: IComment[];
commentCount: number;
likeList?: number[];
likeCount?: number;
favouriteList?: number[];
favouriteCount?: number;
commentList?: IComment[];
commentCount?: number;
}
/**

View File

@@ -34,7 +34,7 @@
<moment-list />
</el-tab-pane>
<el-tab-pane label="菜谱收藏" name="recipe">
<recipe-list />
</el-tab-pane>
<el-tab-pane label="系统设置" name="system">
<div class="menu-card card-item">
@@ -77,6 +77,7 @@
<script lang="ts" setup>
import ProfileCard from '@/components/Profile/ProfileCard.vue'
import RecipeList from '@/components/Food/RecipeList.vue'
import MomentList from '@/components/Moment/MomentList.vue'
import { useUserStore } from '@/store/user.ts'
import { useAppStore } from '@/store/app.ts'
@@ -113,6 +114,9 @@ const handleClick = async (tab: TabsPaneContext) => {
case 'moment':
await foodStore.queryMoment(userStore.getUserId())
break
case 'recipe':
await foodStore.queryRecipeUserFavourite()
break
default:
break
}

View File

@@ -20,8 +20,14 @@
<i class="fa-regular fa-thumbs-up"></i>
</el-button>
</el-badge>
<el-button circle><i class="fa-regular fa-star"></i></el-button>
<!-- <el-button circle><i class="fa-regular fa-comment"></i></el-button>-->
<el-badge v-if="!isCurrentUser"
:value="foodStore.currentRecipe.favouriteList.length" :max="9">
<el-button v-if="!isCurrentUser"
:type="isFavourite ? 'danger' : 'default'"
circle @click="handleFavouriteClick()">
<i class="fa-regular fa-star"></i>
</el-button>
</el-badge>
</div>
</section>
</div>
@@ -49,6 +55,8 @@ onMounted(() => {
})
const isLike = computed(() => foodStore.currentRecipe.likeList.includes(userStore.getUserId()))
const isFavourite = computed(() => foodStore.currentRecipe.favouriteList.includes(userStore.getUserId()))
const isCurrentUser = computed(() => foodStore.currentRecipe.userId === userStore.getUserId())
const handleLikeClick = () => {
if (isLike.value) {
@@ -57,6 +65,14 @@ const handleLikeClick = () => {
foodStore.addRecipeLike(foodStore.currentRecipe.id as number)
}
}
const handleFavouriteClick = () => {
if (isFavourite.value) {
foodStore.deleteRecipeFavourite(foodStore.currentRecipe.id as number)
} else {
foodStore.addRecipeFavourite(foodStore.currentRecipe.id as number)
}
}
</script>
<style lang="scss">

View File

@@ -22,6 +22,13 @@
:colors="foodStore.rateColorList"/>
</el-form-item>
<el-form-item label="共享">
<el-radio-group v-model="foodStore.currentRecipe.isShare">
<el-radio :value="false"></el-radio>
<el-radio :value="true"></el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="食材">
<food-material-form />
</el-form-item>