feat: 打卡详情页一键分享到社区功能

- 新增后端接口 POST /api/front/tool/checkin/{checkinId}/share-to-community
- 实现 shareCheckinToCommunity 方法,复制打卡数据到社区帖子表
- 前端修改 handleCopyCheckin 方法,直接调用后端接口创建帖子
- 支持将打卡图片、描述、营养分析数据复制到社区
- 添加重复分享检查,防止重复创建帖子
- 创建成功后显示提示并可跳转到社区详情页
This commit is contained in:
2026-03-08 00:40:01 +08:00
parent f692c75f7b
commit 314a29ea70
5 changed files with 179 additions and 12 deletions

View File

@@ -7,6 +7,7 @@ import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.response.NutritionAdoptResponse;
import com.zbkj.common.response.NutritionCalculateResponse;
import com.zbkj.common.result.CommonResult;
import com.zbkj.common.token.FrontTokenComponent;
import com.zbkj.service.service.tool.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -65,6 +66,9 @@ public class ToolController {
@Autowired
private ToolUploadService toolUploadService;
@Autowired
private FrontTokenComponent frontTokenComponent;
// ==================== 食谱计算器相关 ====================
/**
@@ -230,6 +234,17 @@ public class ToolController {
return CommonResult.success(toolCheckinService.learn((Long) data.get("sourcePostId"), data));
}
/**
* 分享打卡记录到社区
*/
@ApiOperation(value = "分享打卡记录到社区")
@PostMapping("/checkin/{checkinId}/share-to-community")
public CommonResult<Map<String, Object>> shareCheckinToCommunity(
@ApiParam(value = "打卡记录ID", required = true) @PathVariable Integer checkinId) {
Integer userId = frontTokenComponent.getUserId();
return CommonResult.success(toolCheckinService.shareCheckinToCommunity(checkinId, userId));
}
// ==================== 食物百科相关 ====================
/**

View File

@@ -663,4 +663,108 @@ public class ToolCheckinServiceImpl implements ToolCheckinService {
return "饮食";
}
}
/**
* 分享打卡记录到社区
*
* @param checkinId 打卡记录ID
* @param userId 当前用户ID
* @return 创建的帖子信息
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Map<String, Object> shareCheckinToCommunity(Integer checkinId, Integer userId) {
if (ObjectUtil.isNull(checkinId)) {
throw new CrmebException("打卡记录ID不能为空");
}
if (ObjectUtil.isNull(userId)) {
throw new CrmebException("用户ID不能为空");
}
// 1. 获取打卡记录详情
UserSign sign = userSignDao.selectById(checkinId);
if (sign == null) {
throw new CrmebException("打卡记录不存在");
}
// 2. 检查打卡记录是否属于当前用户
if (!sign.getUid().equals(userId)) {
throw new CrmebException("无权分享他人的打卡记录");
}
// 3. 检查是否已分享过(可选:根据需求可以更新或报错)
LambdaQueryWrapper<V2CommunityPost> existingQuery = new LambdaQueryWrapper<V2CommunityPost>()
.eq(V2CommunityPost::getCheckInRecordId, checkinId)
.eq(V2CommunityPost::getUserId, userId.longValue())
.orderByDesc(V2CommunityPost::getCreatedAt)
.last("LIMIT 1");
V2CommunityPost existingPost = v2CommunityPostDao.selectOne(existingQuery);
if (existingPost != null) {
// 已分享过返回已有的帖子ID
Map<String, Object> result = new HashMap<>();
result.put("postId", existingPost.getPostId());
result.put("message", "该打卡记录已分享到社区");
return result;
}
// 4. 生成标题
String mealTypeLabel = getMealTypeLabel(sign.getMealType());
String title = mealTypeLabel + "打卡";
// 5. 准备营养数据JSON如果有AI分析结果
String nutritionDataJson = null;
if (StrUtil.isNotBlank(sign.getAiRecognizedFoodsJson())) {
try {
Map<String, Object> nutritionData = new HashMap<>();
nutritionData.put("aiRecognizedFoods", sign.getAiRecognizedFoodsJson());
nutritionData.put("aiStatus", sign.getAiRecognitionStatus());
nutritionData.put("actualProtein", sign.getActualProtein());
nutritionData.put("actualEnergy", sign.getActualEnergy());
nutritionData.put("nutritionScore", sign.getNutritionScore());
nutritionDataJson = com.alibaba.fastjson.JSON.toJSONString(nutritionData);
} catch (Exception e) {
log.warn("生成营养数据JSON失败: {}", e.getMessage());
}
}
// 6. 解析封面图
String coverImage = parseFirstImage(sign.getPhotosJson());
// 7. 创建社区帖子
V2CommunityPost communityPost = new V2CommunityPost();
communityPost.setUserId(userId.longValue());
communityPost.setCheckInRecordId(checkinId);
communityPost.setTitle(title);
communityPost.setContent(sign.getNotes());
communityPost.setCoverImage(coverImage);
communityPost.setImagesJson(sign.getPhotosJson());
communityPost.setNutritionDataJson(nutritionDataJson);
communityPost.setStatus("published");
communityPost.setPrivacy("public");
communityPost.setAuditStatus("approved"); // 自动审核通过
communityPost.setCreatedAt(new Date());
communityPost.setUpdatedAt(new Date());
communityPost.setLikeCount(0);
communityPost.setCommentCount(0);
communityPost.setCollectCount(0);
communityPost.setShareCount(0);
communityPost.setViewCount(0);
communityPost.setQuickCheckinCount(0);
communityPost.setAiVideoCount(0);
communityPost.setRecommendScore(new BigDecimal("0.00"));
communityPost.setHotScore(new BigDecimal("0.00"));
v2CommunityPostDao.insert(communityPost);
log.info("分享打卡记录到社区成功postId: {}, checkinId: {}, userId: {}",
communityPost.getPostId(), checkinId, userId);
// 8. 返回结果
Map<String, Object> result = new HashMap<>();
result.put("postId", communityPost.getPostId());
result.put("title", title);
result.put("message", "分享成功");
return result;
}
}

View File

@@ -70,5 +70,13 @@ public interface ToolCheckinService {
* @return 新打卡记录信息
*/
Map<String, Object> learn(Long sourcePostId, Map<String, Object> data);
/**
* 分享打卡记录到社区
* @param checkinId 打卡记录ID
* @param userId 当前用户ID
* @return 创建的帖子信息
*/
Map<String, Object> shareCheckinToCommunity(Integer checkinId, Integer userId);
}

View File

@@ -177,6 +177,14 @@ export function learnCheckin(sourcePostId, data) {
});
}
/**
* 分享打卡记录到社区
* @param {Number} checkinId - 打卡记录ID
*/
export function shareCheckinToCommunity(checkinId) {
return request.post('tool/checkin/' + checkinId + '/share-to-community');
}
// ==================== 食物百科相关 ====================
/**

View File

@@ -101,7 +101,7 @@
</template>
<script>
import { getCheckinDetail } from '@/api/tool.js';
import { getCheckinDetail, shareCheckinToCommunity } from '@/api/tool.js';
import { mapGetters } from 'vuex';
export default {
@@ -220,18 +220,50 @@ export default {
};
return map[type] || '🍽️';
},
handleCopyCheckin() {
// 将数据存储到本地缓存避免URL参数过长
uni.setStorageSync('checkin_copy_data', {
images: this.checkinData.images,
mealType: this.checkinData.mealType,
notes: this.checkinData.notes
});
// 跳转到发布页
uni.navigateTo({
url: '/pages/tool/checkin-publish?mode=copy'
async handleCopyCheckin() {
if (!this.checkinData.id) {
uni.showToast({
title: '打卡记录ID不存在',
icon: 'none'
});
return;
}
uni.showLoading({
title: '分享中...',
mask: true
});
try {
const res = await shareCheckinToCommunity(this.checkinData.id);
uni.hideLoading();
if (res && res.code === 200) {
const postId = res.data && res.data.postId;
uni.showModal({
title: '分享成功',
content: '您的打卡记录已成功分享到社区',
confirmText: '去查看',
cancelText: '知道了',
success: (modalRes) => {
if (modalRes.confirm && postId) {
uni.navigateTo({
url: '/pages/tool/community-detail?id=' + postId
});
}
}
});
} else {
throw new Error(res.message || '分享失败');
}
} catch (e) {
uni.hideLoading();
console.error('分享到社区失败:', e);
uni.showToast({
title: e.message || '分享失败,请重试',
icon: 'none'
});
}
}
}
}