feat(checkin): P2 一键借鉴打卡功能落地(test-0415 反馈5-2)

最小修改方案,零 DB 表结构变动:

前端 checkin-publish.vue:
- onLoad 识别 sourcePostId + sourceType=learn → 调 getCommunityDetail 拉原帖
- 预填 selectedImages / selectedMealType / remark(带「[借鉴自 @xxx]」前缀)
- 顶部新增黄色徽章「借鉴自 @xxx」
- handlePublish 提交时透传 sourcePostId 到后端

后端 ToolCheckinServiceImpl.submit:
- 检测 data.sourcePostId,若 notes 没有「借鉴自」字样则追加 [借鉴自 post#id] 标记
- 不新增 UserSign 列,引用关系记录在 notes,便于后续查询展示

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
msh-agent
2026-05-03 03:34:28 +08:00
parent df0273de36
commit 4b8b391674
2 changed files with 88 additions and 7 deletions

View File

@@ -141,6 +141,17 @@ public class ToolCheckinServiceImpl implements ToolCheckinService {
if (data.containsKey("notes") && StrUtil.isNotBlank((String) data.get("notes"))) {
userSign.setNotes((String) data.get("notes"));
}
// test-0415 P2 反馈5-2一键借鉴打卡——若客户端附带 sourcePostId则在 notes 末尾追加引用标记,
// 避免新增 DB 列;同时保证查询/检索时可以通过 notes 正则定位「借鉴自 @xxx」徽章
if (data.containsKey("sourcePostId") && ObjectUtil.isNotNull(data.get("sourcePostId"))) {
String sourcePostId = data.get("sourcePostId").toString();
String existingNotes = userSign.getNotes() == null ? "" : userSign.getNotes();
// 如果备注里已经包含「借鉴自」字样(前端已写),不再重复追加;否则补一条标记
if (!existingNotes.contains("借鉴自")) {
String marker = "[借鉴自 post#" + sourcePostId + "]";
userSign.setNotes(StrUtil.isBlank(existingNotes) ? marker : (existingNotes + " " + marker));
}
}
if (data.containsKey("voiceUrl") && StrUtil.isNotBlank((String) data.get("voiceUrl"))) {
userSign.setVoiceUrl((String) data.get("voiceUrl"));
}

View File

@@ -2,6 +2,11 @@
<view class="checkin-publish-page">
<!-- 内容区域 -->
<scroll-view class="content-scroll" scroll-y>
<!-- 借鉴打卡徽章test-0415 P2 反馈5-2 -->
<view class="learn-badge" v-if="sourcePostId">
<text class="learn-icon">📖</text>
<text class="learn-text">借鉴自 {{ sourceAuthorName ? '@' + sourceAuthorName : '社区帖子' }}</text>
</view>
<!-- 上传照片卡片 -->
<view class="card">
<view class="card-header">
@@ -132,6 +137,9 @@ export default {
return {
selectedImages: [],
selectedMealType: 'breakfast',
// test-0415 P2 反馈5-2 借鉴打卡相关
sourcePostId: null,
sourceAuthorName: '',
mealTypes: [
{ label: '早餐', value: 'breakfast' },
{ label: '午餐', value: 'lunch' },
@@ -151,12 +159,12 @@ export default {
onLoad(options) {
// 初始化录音管理器
this.initRecorder();
// 根据参数处理
if (options.type === 'video') {
this.enableAIVideo = true;
}
// 处理一键复制/借鉴打卡
if (options.mode === 'copy') {
try {
@@ -165,10 +173,10 @@ export default {
this.selectedImages = copyData.images || [];
this.selectedMealType = copyData.mealType || 'breakfast';
this.remark = copyData.notes || '';
// 清除缓存
uni.removeStorageSync('checkin_copy_data');
uni.showToast({
title: '已加载打卡内容',
icon: 'success'
@@ -178,6 +186,12 @@ export default {
console.error('读取复制数据失败:', e);
}
}
// test-0415 P2 反馈5-2一键借鉴打卡——预填来源帖子的图片/餐次/文字
if (options.sourcePostId && options.sourceType === 'learn') {
this.sourcePostId = options.sourcePostId
this.loadSourcePost(options.sourcePostId)
}
},
onUnload() {
// 清理录音计时器
@@ -556,6 +570,43 @@ export default {
}
})
},
// test-0415 P2 反馈5-2从来源帖子拉取图片/餐次/文字预填表单
async loadSourcePost(postId) {
try {
const { getCommunityDetail } = await import('@/api/tool.js');
const res = await getCommunityDetail(postId);
const data = (res && res.data) || res || {};
// 图片:优先 photosJson否则 images / image 单图
let imgs = [];
if (data.photosJson || data.photos_json) {
try {
const arr = JSON.parse(data.photosJson || data.photos_json);
if (Array.isArray(arr)) imgs = arr;
} catch (e) { /* ignore */ }
}
if (imgs.length === 0 && Array.isArray(data.images)) imgs = data.images.slice();
if (imgs.length === 0 && data.image) imgs = [data.image];
if (imgs.length > 0) this.selectedImages = imgs;
if (data.mealType) this.selectedMealType = data.mealType;
const author = data.userName || data.authorName || '';
this.sourceAuthorName = author;
// 备注预填来源帖子的标题/描述/内容
const seed = (data.title || data.description || data.content || '').toString().trim();
const prefix = author ? `[借鉴自 @${author}] ` : '[借鉴打卡] ';
if (seed) {
this.remark = prefix + seed;
} else {
this.remark = prefix.trim();
}
uni.showToast({ title: '已载入借鉴内容', icon: 'success' });
} catch (e) {
console.error('加载来源帖子失败', e);
uni.showToast({ title: '原帖加载失败,可手动填写', icon: 'none' });
}
},
async handlePublish() {
if (this.selectedImages.length === 0) {
uni.showToast({
@@ -567,20 +618,25 @@ export default {
// 防止重复提交
if (this._publishing) return
this._publishing = true
uni.showLoading({ title: '发布中...' });
try {
const imageUrls = this.selectedImages;
const today = new Date().toISOString().split('T')[0];
const result = await submitCheckin({
const submitData = {
mealType: this.selectedMealType,
date: today,
photosJson: JSON.stringify(imageUrls),
notes: this.remark,
enableAIVideo: this.enableAIVideo,
enableAIAnalysis: false
});
};
// 借鉴打卡:透传 sourcePostId 给后端做引用关系记录
if (this.sourcePostId) {
submitData.sourcePostId = this.sourcePostId;
}
const result = await submitCheckin(submitData);
uni.hideLoading();
@@ -619,6 +675,20 @@ export default {
</script>
<style lang="scss" scoped>
/* 借鉴打卡徽章test-0415 P2 反馈5-2 */
.learn-badge {
margin: 16rpx 32rpx 0;
padding: 16rpx 24rpx;
background: linear-gradient(135deg, #fff8e1 0%, #ffecb3 100%);
border-radius: 16rpx;
display: flex;
align-items: center;
gap: 12rpx;
border: 1rpx solid #ffd54f;
}
.learn-badge .learn-icon { font-size: 28rpx; }
.learn-badge .learn-text { font-size: 26rpx; color: #6b5300; flex: 1; }
.checkin-publish-page {
min-height: 100vh;
background: #f4f5f7;