feat:增加菜谱收藏功能
This commit is contained in:
@@ -34,6 +34,12 @@ export const queryRecipeByUserApi = (id: number): Promise<IRecipe[]> =>
|
|||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const queryRecipeUserFavouriteApi = (): Promise<IRecipe[]> =>
|
||||||
|
cloudService({
|
||||||
|
url: '/food-service/food/recipe/user/favourite',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
|
||||||
export const queryRecipeApi = (query: IFoodQuery): Promise<IRecipe[]> =>
|
export const queryRecipeApi = (query: IFoodQuery): Promise<IRecipe[]> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: '/food-service/food/recipe',
|
url: '/food-service/food/recipe',
|
||||||
@@ -94,6 +100,18 @@ export const deleteRecipeLikeApi = (id: number): Promise<boolean> =>
|
|||||||
method: 'delete'
|
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[]> =>
|
export const queryRecordApi = (startDate: string, endDate: string): Promise<IRecord[]> =>
|
||||||
cloudService({
|
cloudService({
|
||||||
url: '/food-service/food/record',
|
url: '/food-service/food/record',
|
||||||
|
|||||||
@@ -39,21 +39,25 @@
|
|||||||
|
|
||||||
<div class="bottom-container">
|
<div class="bottom-container">
|
||||||
<div class="info-list">
|
<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>
|
<i class="fa-solid fa-utensils"></i>
|
||||||
{{ props.item.category }}
|
{{ props.item.category }}
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item like-item">
|
|
||||||
|
<div v-if="isCurrentUser" class="info-item like-item">
|
||||||
<i class="fa-regular fa-thumbs-up"></i>
|
<i class="fa-regular fa-thumbs-up"></i>
|
||||||
{{ props.item.likeCount }}
|
{{ props.item.likeCount }}
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item comment-item">
|
<div v-if="isCurrentUser" class="info-item comment-item">
|
||||||
<i class="fa-regular fa-comment"></i>
|
<i class="fa-regular fa-comment"></i>
|
||||||
{{ props.item.commentCount }}
|
{{ props.item.commentCount }}
|
||||||
</div>
|
</div>
|
||||||
<div class="info-item start-item">
|
<div v-if="isCurrentUser" class="info-item start-item">
|
||||||
<i class="fa-solid fa-star"></i>
|
<i class="fa-solid fa-star"></i>
|
||||||
0
|
{{ props.item.favouriteCount }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -75,17 +79,18 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { Edit, Collection, DeleteFilled } from '@element-plus/icons-vue'
|
import { Edit, Collection, DeleteFilled } from '@element-plus/icons-vue'
|
||||||
import { useFoodStore } from '@/store/food'
|
import { useFoodStore } from '@/store/food'
|
||||||
|
import { useUserStore } from '@/store/user'
|
||||||
import { computed, defineProps, onMounted, reactive } from 'vue'
|
import { computed, defineProps, onMounted, reactive } from 'vue'
|
||||||
import type { PropType } from 'vue'
|
import type { PropType } from 'vue'
|
||||||
import type { IRecipe, IRecord } from '@/types/food.ts'
|
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 { formatDate } from 'vue3-common/utils/dateUtil'
|
||||||
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
import { commonElMessageBox } from 'vue3-common/utils/elUtil'
|
||||||
import { serviceFileRootPath } from '@/utils'
|
import { serviceFileRootPath } from '@/utils'
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const route = useRoute()
|
|
||||||
const foodStore = useFoodStore()
|
const foodStore = useFoodStore()
|
||||||
|
const userStore = useUserStore()
|
||||||
|
|
||||||
const foodCardInfo = reactive({
|
const foodCardInfo = reactive({
|
||||||
recommendRate: 0,
|
recommendRate: 0,
|
||||||
@@ -103,7 +108,15 @@ onMounted(() => {
|
|||||||
foodCardInfo.recommendRate = props.item?.recommendRate as number
|
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[]) => {
|
const getRecord = (recordList: IRecord[]) => {
|
||||||
return recordList.filter((item) => item.imageUrl)
|
return recordList.filter((item) => item.imageUrl)
|
||||||
|
|||||||
@@ -4,25 +4,12 @@ import type {
|
|||||||
IStats, IRecord, IMoment, IFoodSegment
|
IStats, IRecord, IMoment, IFoodSegment
|
||||||
} from '@/types/food'
|
} from '@/types/food'
|
||||||
import {
|
import {
|
||||||
addRecipeApi,
|
addRecipeApi, addRecordApi, deleteRecipeApi, deleteRecordApi,
|
||||||
addRecordApi,
|
queryFoodNameListApi, queryRecipeByIdApi, queryRecordApi, queryStatsApi,
|
||||||
deleteRecipeApi,
|
updateRecipeApi, updateRecordApi, queryCategoryApi, queryRecordStatsApi,
|
||||||
deleteRecordApi,
|
queryCategoryStatsApi, queryRankStatsApi,
|
||||||
queryFoodNameListApi,
|
queryRecipeApi, queryRecipeByUserApi, deleteRecipeLikeApi,
|
||||||
queryRecipeByIdApi,
|
addRecipeLikeApi, addRecipeCommentApi, addRecipeFavouriteApi, deleteRecipeFavouriteApi, queryRecipeUserFavouriteApi
|
||||||
queryRecordApi,
|
|
||||||
queryStatsApi,
|
|
||||||
updateRecipeApi,
|
|
||||||
updateRecordApi,
|
|
||||||
queryCategoryApi,
|
|
||||||
queryRecordStatsApi,
|
|
||||||
queryCategoryStatsApi,
|
|
||||||
queryRankStatsApi,
|
|
||||||
queryRecipeApi,
|
|
||||||
queryRecipeByUserApi,
|
|
||||||
deleteRecipeLikeApi,
|
|
||||||
addRecipeLikeApi,
|
|
||||||
addRecipeCommentApi
|
|
||||||
} from '@/apis/food.ts'
|
} from '@/apis/food.ts'
|
||||||
import type { IDialog, IHandleApi, IStatsChart } from 'vue3-common/types'
|
import type { IDialog, IHandleApi, IStatsChart } from 'vue3-common/types'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
@@ -45,11 +32,17 @@ export const useFoodStore = defineStore('food', {
|
|||||||
category: '',
|
category: '',
|
||||||
recommendRate: 0,
|
recommendRate: 0,
|
||||||
remark: '',
|
remark: '',
|
||||||
|
isShare: false,
|
||||||
|
username: '',
|
||||||
|
userId: 0,
|
||||||
|
avatar: '',
|
||||||
materialList: [],
|
materialList: [],
|
||||||
stepList: [],
|
stepList: [],
|
||||||
recordList: [],
|
recordList: [],
|
||||||
likeCount: 0,
|
likeCount: 0,
|
||||||
likeList: [],
|
likeList: [],
|
||||||
|
favouriteCount: 0,
|
||||||
|
favouriteList: [],
|
||||||
commentCount: 0,
|
commentCount: 0,
|
||||||
commentList: []
|
commentList: []
|
||||||
} as IRecipe,
|
} as IRecipe,
|
||||||
@@ -133,6 +126,11 @@ export const useFoodStore = defineStore('food', {
|
|||||||
this.recipeList = await queryRecipeByUserApi(id)
|
this.recipeList = await queryRecipeByUserApi(id)
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
},
|
},
|
||||||
|
async queryRecipeUserFavourite() {
|
||||||
|
this.isLoading = true
|
||||||
|
this.recipeList = await queryRecipeUserFavouriteApi()
|
||||||
|
this.isLoading = false
|
||||||
|
},
|
||||||
async queryRecordList() {
|
async queryRecordList() {
|
||||||
const { year, month } = this.queryRecord
|
const { year, month } = this.queryRecord
|
||||||
const date = this.queryDateType === 'year' ? year : month
|
const date = this.queryDateType === 'year' ? year : month
|
||||||
@@ -249,6 +247,14 @@ export const useFoodStore = defineStore('food', {
|
|||||||
await deleteRecipeLikeApi(id)
|
await deleteRecipeLikeApi(id)
|
||||||
await this.queryRecipe(this.currentRecipe.id as number)
|
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 {
|
getEmptyRecipe(): IRecipe {
|
||||||
return {
|
return {
|
||||||
commentCount: 0,
|
commentCount: 0,
|
||||||
@@ -259,6 +265,7 @@ export const useFoodStore = defineStore('food', {
|
|||||||
materialList: [],
|
materialList: [],
|
||||||
name: '',
|
name: '',
|
||||||
recommendRate: 0,
|
recommendRate: 0,
|
||||||
|
isShare: false,
|
||||||
remark: '',
|
remark: '',
|
||||||
stepList: [],
|
stepList: [],
|
||||||
recordList: []
|
recordList: []
|
||||||
|
|||||||
@@ -53,6 +53,11 @@ $card-image-height: 200px;
|
|||||||
font-size: 1.2rem;
|
font-size: 1.2rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.user {
|
||||||
|
// font-size: 0.9rem;
|
||||||
|
color: #9C9C9C;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.category-item {
|
.category-item {
|
||||||
|
|||||||
@@ -59,6 +59,10 @@ export interface IRecipe {
|
|||||||
* 备注
|
* 备注
|
||||||
*/
|
*/
|
||||||
remark: string;
|
remark: string;
|
||||||
|
isShare: boolean;
|
||||||
|
userId?: number;
|
||||||
|
username?: string;
|
||||||
|
avatar?: string;
|
||||||
/**
|
/**
|
||||||
* 食材
|
* 食材
|
||||||
*/
|
*/
|
||||||
@@ -71,10 +75,12 @@ export interface IRecipe {
|
|||||||
* 成果
|
* 成果
|
||||||
*/
|
*/
|
||||||
recordList: IRecord[];
|
recordList: IRecord[];
|
||||||
likeList: number[];
|
likeList?: number[];
|
||||||
likeCount: number;
|
likeCount?: number;
|
||||||
commentList: IComment[];
|
favouriteList?: number[];
|
||||||
commentCount: number;
|
favouriteCount?: number;
|
||||||
|
commentList?: IComment[];
|
||||||
|
commentCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
<moment-list />
|
<moment-list />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="菜谱收藏" name="recipe">
|
<el-tab-pane label="菜谱收藏" name="recipe">
|
||||||
|
<recipe-list />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="系统设置" name="system">
|
<el-tab-pane label="系统设置" name="system">
|
||||||
<div class="menu-card card-item">
|
<div class="menu-card card-item">
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ProfileCard from '@/components/Profile/ProfileCard.vue'
|
import ProfileCard from '@/components/Profile/ProfileCard.vue'
|
||||||
|
import RecipeList from '@/components/Food/RecipeList.vue'
|
||||||
import MomentList from '@/components/Moment/MomentList.vue'
|
import MomentList from '@/components/Moment/MomentList.vue'
|
||||||
import { useUserStore } from '@/store/user.ts'
|
import { useUserStore } from '@/store/user.ts'
|
||||||
import { useAppStore } from '@/store/app.ts'
|
import { useAppStore } from '@/store/app.ts'
|
||||||
@@ -113,6 +114,9 @@ const handleClick = async (tab: TabsPaneContext) => {
|
|||||||
case 'moment':
|
case 'moment':
|
||||||
await foodStore.queryMoment(userStore.getUserId())
|
await foodStore.queryMoment(userStore.getUserId())
|
||||||
break
|
break
|
||||||
|
case 'recipe':
|
||||||
|
await foodStore.queryRecipeUserFavourite()
|
||||||
|
break
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,14 @@
|
|||||||
<i class="fa-regular fa-thumbs-up"></i>
|
<i class="fa-regular fa-thumbs-up"></i>
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-badge>
|
</el-badge>
|
||||||
<el-button circle><i class="fa-regular fa-star"></i></el-button>
|
<el-badge v-if="!isCurrentUser"
|
||||||
<!-- <el-button circle><i class="fa-regular fa-comment"></i></el-button>-->
|
: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>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
@@ -49,6 +55,8 @@ onMounted(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const isLike = computed(() => foodStore.currentRecipe.likeList.includes(userStore.getUserId()))
|
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 = () => {
|
const handleLikeClick = () => {
|
||||||
if (isLike.value) {
|
if (isLike.value) {
|
||||||
@@ -57,6 +65,14 @@ const handleLikeClick = () => {
|
|||||||
foodStore.addRecipeLike(foodStore.currentRecipe.id as number)
|
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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|||||||
@@ -22,6 +22,13 @@
|
|||||||
:colors="foodStore.rateColorList"/>
|
:colors="foodStore.rateColorList"/>
|
||||||
</el-form-item>
|
</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="食材">
|
<el-form-item label="食材">
|
||||||
<food-material-form />
|
<food-material-form />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|||||||
Reference in New Issue
Block a user