fix: 修复关注按钮相关问题

- 食谱详情页: 修复 applyDefaultData 中未定义变量 id 的问题
- 帖子详情页: 优化 toggleFollow 方法,提前校验 author.id,兼容多种后端字段
- 为帖子详情页已关注状态添加灰色样式
This commit is contained in:
msh-agent
2026-03-09 18:56:53 +08:00
parent b516089c4f
commit c1857ce852
14 changed files with 3590 additions and 102 deletions

View File

@@ -340,9 +340,13 @@ export default {
try {
const res = await getCommunityDetail(id)
// 兼容 CommonResultres = { code, data: 详情对象 },取 res.data 作为详情
const data = (res && res.data !== undefined && res.data !== null) ? res.data : res
// 兼容 CommonResultres = { code, data: 详情对象 } 或 { result: 详情对象 },取 data/result 作为详情
const data = (res && res.data !== undefined && res.data !== null)
? res.data
: (res && res.result !== undefined && res.result !== null)
? res.result
: res
// 格式化帖子数据
this.formatPostData(data)
@@ -412,7 +416,7 @@ export default {
if (statsFromObj.length > 0 && !statsFromObj.every(s => s.value === '-')) return statsFromObj
}
// 2) nutritionDataJson / nutrition_data_json兼容后端驼峰与下划线含 fill-nutrition 的 energyKcal/proteinG/potassiumMg/phosphorusMg、打卡字段 actualEnergy/actualProtein
// 2) nutritionDataJson / nutrition_data_json兼容后端驼峰与下划线含 fill-nutrition 的 energyKcal/proteinG、嵌套格式 calories: { value, unit }
const jsonRaw = data.nutritionDataJson || data.nutrition_data_json
if (jsonRaw) {
try {
@@ -429,7 +433,7 @@ export default {
if (!Array.isArray(nutritionData) && Object.keys(nutritionData).length === 0) {
return []
}
// 2c) 有键的对象:兼容后端 fill-nutrition 的 energyKcal/proteinG
// 2c) 有键的对象:兼容后端嵌套 { calories: { value, unit }, protein: { value, unit }, ... } 与扁平 energyKcal/proteinG
const statsFromJson = this.buildNutritionStatsFromNutritionObject(nutritionData)
// 若解析后全部为占位符 "-",视为无效数据,返回 [] 以便走打卡/服务端填充
if (statsFromJson.length > 0 && statsFromJson.every(s => s.value === '-')) {
@@ -441,6 +445,20 @@ export default {
}
}
// 2d) nutritionData / nutrition_data 为已解析对象(部分接口直接返回对象)
const nutritionDataObj = data.nutritionData || data.nutrition_data
if (nutritionDataObj && typeof nutritionDataObj === 'object' && !Array.isArray(nutritionDataObj) && Object.keys(nutritionDataObj).length > 0) {
const statsFromObj = this.buildNutritionStatsFromNutritionObject(nutritionDataObj)
if (statsFromObj.length > 0 && !statsFromObj.every(s => s.value === '-')) return statsFromObj
}
// 2e) 详情中嵌套的打卡记录(若后端返回 checkInRecord/check_in_record直接从中取营养
const checkInRecord = data.checkInRecord || data.check_in_record
if (checkInRecord && typeof checkInRecord === 'object') {
const statsFromCheckin = this.buildNutritionStatsFromCheckinDetail(checkInRecord)
if (statsFromCheckin.length > 0 && statsFromCheckin.some(s => s.value !== '-' && s.value !== '')) return statsFromCheckin
}
// 3) dietaryData / mealData / dietary_data / meal_data饮食打卡对象
const dietary = data.dietaryData || data.dietary_data || data.mealData || data.meal_data
if (dietary) {
@@ -565,8 +583,12 @@ export default {
async fillNutritionStatsFromCheckin(checkInRecordId) {
try {
const res = await getCheckinDetail(checkInRecordId)
// 兼容res 为 { code, data } 时取 res.data;部分封装直接返回 payload 则 res 即为 detail
const detail = (res && res.data !== undefined && res.data !== null) ? res.data : res
// 兼容res 为 { code, data } 或 { result } 时取 data/result;部分封装直接返回 payload 则 res 即为 detail
const detail = (res && res.data !== undefined && res.data !== null)
? res.data
: (res && res.result !== undefined && res.result !== null)
? res.result
: res
if (!detail || typeof detail !== 'object') return
const stats = this.buildNutritionStatsFromCheckinDetail(detail)
// 仅当至少有一项有效值时才更新,避免展示全部为 "-" 的卡片
@@ -706,7 +728,7 @@ export default {
description: description,
tags: tags,
author: {
id: data.userId,
id: data.userId ?? data.authorId ?? data.user_id ?? data.author_id ?? null,
avatar: data.userAvatar || '👤',
name: data.userName || '匿名用户',
time: this.formatTime(data.createdAt)
@@ -717,7 +739,7 @@ export default {
likeCount: data.likeCount || 0,
favoriteCount: data.collectCount || 0,
commentCount: data.commentCount || 0,
checkInRecordId: data.checkInRecordId,
checkInRecordId: data.checkInRecordId ?? data.check_in_record_id ?? null,
videoUrl: data.videoUrl || null,
videoStatus: data.videoStatus,
hasVideo: data.hasVideo || false
@@ -852,12 +874,16 @@ export default {
setTimeout(() => toLogin(), 1000)
return
}
// 先检查 author.id 是否存在,再改状态、调 API避免无效请求导致「操作失败」
const authorId = this.postData && this.postData.author && (this.postData.author.id ?? this.postData.author.userId)
if (authorId == null || authorId === '') {
uni.showToast({ title: '无法获取作者信息', icon: 'none' })
return
}
const newFollowState = !this.isFollowed
this.isFollowed = newFollowState
try {
await apiToggleFollow(this.postData.author.id, newFollowState)
await apiToggleFollow(authorId, newFollowState)
uni.showToast({
title: newFollowState ? '已关注' : '取消关注',
icon: 'none'
@@ -1327,6 +1353,11 @@ export default {
}
}
.follow-btn.followed {
background: linear-gradient(135deg, #9fa5c0 0%, #8a90a8 100%);
box-shadow: none;
}
/* 营养统计卡片 */
.nutrition-stats-card {
margin: 10rpx 32rpx;