chore: update pom.xml Lombok config and deploy settings

- Update Maven compiler plugin to support Lombok annotation processing
- Add deploy.conf for automated deployment
- Update backend models and controllers
- Update frontend pages and API
This commit is contained in:
2026-03-04 12:21:29 +08:00
parent 4646fbc9b5
commit 6f2dc27fbc
20 changed files with 352 additions and 151 deletions

View File

@@ -110,8 +110,8 @@
</view>
</view>
<!-- 营养统计卡片:仅根据是否有数据展示 -->
<view class="nutrition-stats-card" v-if="nutritionStatsLength > 0">
<!-- 营养统计卡片:仅当 nutritionStats.length > 0 时展示,不依赖后端字段存在性 -->
<view class="nutrition-stats-card" v-if="nutritionStats.length > 0">
<view class="stats-header">
<view class="stats-title">
<text class="title-icon">📊</text>
@@ -122,7 +122,7 @@
</view>
</view>
<view class="stats-grid">
<view class="stat-item" v-for="(stat, index) in postData.nutritionStats" :key="index">
<view class="stat-item" v-for="(stat, index) in nutritionStats" :key="index">
<view class="stat-value">{{ stat.value }}</view>
<view class="stat-label">{{ stat.label }}</view>
</view>
@@ -286,16 +286,17 @@ export default {
}
},
computed: {
// 营养统计数,用于卡片显示条件(避免 postData.nutritionStats 未定义时报错
nutritionStatsLength() {
// 营养统计数,用于卡片显示与列表渲染(单一数据源,避免未定义
nutritionStats() {
const stats = this.postData && this.postData.nutritionStats
return Array.isArray(stats) ? stats.length : 0
return Array.isArray(stats) ? stats : []
}
},
onLoad(options) {
if (options.id) {
this.postId = options.id
this.loadPostData(options.id)
// Ensure postId is number for API calls (URL params are strings)
this.postId = parseInt(options.id, 10) || options.id
this.loadPostData(this.postId)
}
},
methods: {
@@ -343,6 +344,14 @@ export default {
*/
buildNutritionStatsFromDetailData(data) {
if (!data) return []
console.log('[post-detail] buildNutritionStatsFromDetailData API response data:', JSON.stringify({
nutritionStats: data.nutritionStats,
nutrition_stats: data.nutrition_stats,
nutritionDataJson: data.nutritionDataJson,
nutrition_data_json: data.nutrition_data_json,
dietaryData: data.dietaryData,
mealData: data.mealData
}))
// 1) 后端直接返回的 stat 数组(兼容不同命名)
const rawStats = data.nutritionStats || data.nutrition_stats
@@ -353,17 +362,21 @@ export default {
})).filter(s => s.label)
}
// 2) nutritionDataJson / nutrition_data_json
// 2) nutritionDataJson / nutrition_data_json(兼容后端驼峰与下划线;含打卡字段 actualEnergy/actualProtein
const jsonRaw = data.nutritionDataJson || data.nutrition_data_json
if (jsonRaw) {
try {
const nutritionData = typeof jsonRaw === 'string' ? JSON.parse(jsonRaw) : jsonRaw
if (nutritionData && typeof nutritionData === 'object') {
const cal = nutritionData.calories ?? nutritionData.energy ?? nutritionData.calorie ?? nutritionData.actualEnergy
const pro = nutritionData.protein ?? nutritionData.proteins ?? nutritionData.actualProtein
const pot = nutritionData.potassium ?? nutritionData.k
const pho = nutritionData.phosphorus ?? nutritionData.p
return [
{ label: '热量(kcal)', value: nutritionData.calories != null ? String(nutritionData.calories) : '-' },
{ label: '蛋白质', value: nutritionData.protein != null ? nutritionData.protein + 'g' : '-' },
{ label: '钾', value: nutritionData.potassium != null ? nutritionData.potassium + 'mg' : '-' },
{ label: '磷', value: nutritionData.phosphorus != null ? nutritionData.phosphorus + 'mg' : '-' }
{ label: '热量(kcal)', value: cal != null ? String(cal) : '-' },
{ label: '蛋白质', value: this.formatNutritionValue(pro, 'g') },
{ label: '钾', value: pot != null ? (typeof pot === 'number' ? pot + 'mg' : String(pot)) : '-' },
{ label: '磷', value: pho != null ? (typeof pho === 'number' ? pho + 'mg' : String(pho)) : '-' }
]
}
} catch (e) {
@@ -376,13 +389,13 @@ export default {
if (dietary) {
const obj = typeof dietary === 'string' ? (() => { try { return JSON.parse(dietary) } catch (_) { return null } })() : dietary
if (obj && typeof obj === 'object') {
const cal = obj.calories ?? obj.energy ?? obj.calorie
const pro = obj.protein ?? obj.proteins
const cal = obj.calories ?? obj.energy ?? obj.calorie ?? obj.actualEnergy
const pro = obj.protein ?? obj.proteins ?? obj.actualProtein
const pot = obj.potassium ?? obj.k
const pho = obj.phosphorus ?? obj.p
return [
{ label: '热量(kcal)', value: cal != null ? String(cal) : '-' },
{ label: '蛋白质', value: pro != null ? (typeof pro === 'number' ? pro + 'g' : String(pro)) : '-' },
{ label: '蛋白质', value: this.formatNutritionValue(pro, 'g') },
{ label: '钾', value: pot != null ? (typeof pot === 'number' ? pot + 'mg' : String(pot)) : '-' },
{ label: '磷', value: pho != null ? (typeof pho === 'number' ? pho + 'mg' : String(pho)) : '-' }
]
@@ -392,22 +405,26 @@ export default {
return []
},
/** 格式化营养素显示值(兼容 number/string/BigDecimal 等) */
formatNutritionValue(val, unit) {
if (val == null || val === '') return '-'
const str = typeof val === 'number' ? String(val) : String(val)
return str === '' || str === 'undefined' || str === 'null' ? '-' : (unit ? str + unit : str)
},
/**
* 根据打卡详情接口返回的数据构建 nutritionStats蛋白质、热量、钾、磷
*/
buildNutritionStatsFromCheckinDetail(detail) {
if (!detail || typeof detail !== 'object') return []
const items = []
// 热量
const energy = detail.actualEnergy ?? detail.energy
items.push({ label: '热量(kcal)', value: energy != null ? String(energy) : '-' })
// 蛋白质
const protein = detail.actualProtein ?? detail.protein
items.push({ label: '蛋白质', value: protein != null ? (typeof protein === 'number' ? protein + 'g' : String(protein)) : '-' })
// 钾、磷:打卡详情可能没有,用 -
items.push({ label: '', value: '-' })
items.push({ label: '', value: '-' })
return items
return [
{ label: '热量(kcal)', value: energy != null ? String(energy) : '-' },
{ label: '蛋白质', value: this.formatNutritionValue(protein, 'g') },
{ label: '', value: '-' },
{ label: '磷', value: '-' }
]
},
/**
@@ -715,6 +732,13 @@ export default {
return
}
const postIdNum = typeof this.postId === 'number' ? this.postId : parseInt(this.postId, 10)
if (!postIdNum || isNaN(postIdNum)) {
console.error('[post-detail] toggleLike: invalid postId', this.postId)
uni.showToast({ title: '操作失败,请重试', icon: 'none' })
return
}
const newLikeState = !this.isLiked
const newLikeCount = newLikeState
? this.postData.likeCount + 1
@@ -725,8 +749,9 @@ export default {
this.postData.likeCount = newLikeCount
try {
await apiToggleLike(this.postId, newLikeState)
await apiToggleLike(postIdNum, newLikeState)
} catch (error) {
console.error('[post-detail] toggleLike failed:', error)
// 回滚
this.isLiked = !newLikeState
this.postData.likeCount = newLikeState
@@ -747,6 +772,13 @@ export default {
return
}
const postIdNum = typeof this.postId === 'number' ? this.postId : parseInt(this.postId, 10)
if (!postIdNum || isNaN(postIdNum)) {
console.error('[post-detail] toggleFavorite: invalid postId', this.postId)
uni.showToast({ title: '操作失败,请重试', icon: 'none' })
return
}
const newCollectState = !this.isCollected
const newCollectCount = newCollectState
? this.postData.favoriteCount + 1
@@ -757,12 +789,13 @@ export default {
this.postData.favoriteCount = newCollectCount
try {
await toggleCollect(this.postId, newCollectState)
await toggleCollect(postIdNum, newCollectState)
uni.showToast({
title: newCollectState ? '已收藏' : '取消收藏',
icon: 'none'
})
} catch (error) {
console.error('[post-detail] toggleFavorite failed:', error)
// 回滚
this.isCollected = !newCollectState
this.postData.favoriteCount = newCollectState