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:
@@ -141,6 +141,17 @@ public class ToolCheckinServiceImpl implements ToolCheckinService {
|
|||||||
if (data.containsKey("notes") && StrUtil.isNotBlank((String) data.get("notes"))) {
|
if (data.containsKey("notes") && StrUtil.isNotBlank((String) data.get("notes"))) {
|
||||||
userSign.setNotes((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"))) {
|
if (data.containsKey("voiceUrl") && StrUtil.isNotBlank((String) data.get("voiceUrl"))) {
|
||||||
userSign.setVoiceUrl((String) data.get("voiceUrl"));
|
userSign.setVoiceUrl((String) data.get("voiceUrl"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,11 @@
|
|||||||
<view class="checkin-publish-page">
|
<view class="checkin-publish-page">
|
||||||
<!-- 内容区域 -->
|
<!-- 内容区域 -->
|
||||||
<scroll-view class="content-scroll" scroll-y>
|
<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">
|
||||||
<view class="card-header">
|
<view class="card-header">
|
||||||
@@ -132,6 +137,9 @@ export default {
|
|||||||
return {
|
return {
|
||||||
selectedImages: [],
|
selectedImages: [],
|
||||||
selectedMealType: 'breakfast',
|
selectedMealType: 'breakfast',
|
||||||
|
// test-0415 P2 反馈5-2 借鉴打卡相关
|
||||||
|
sourcePostId: null,
|
||||||
|
sourceAuthorName: '',
|
||||||
mealTypes: [
|
mealTypes: [
|
||||||
{ label: '早餐', value: 'breakfast' },
|
{ label: '早餐', value: 'breakfast' },
|
||||||
{ label: '午餐', value: 'lunch' },
|
{ label: '午餐', value: 'lunch' },
|
||||||
@@ -151,12 +159,12 @@ export default {
|
|||||||
onLoad(options) {
|
onLoad(options) {
|
||||||
// 初始化录音管理器
|
// 初始化录音管理器
|
||||||
this.initRecorder();
|
this.initRecorder();
|
||||||
|
|
||||||
// 根据参数处理
|
// 根据参数处理
|
||||||
if (options.type === 'video') {
|
if (options.type === 'video') {
|
||||||
this.enableAIVideo = true;
|
this.enableAIVideo = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 处理一键复制/借鉴打卡
|
// 处理一键复制/借鉴打卡
|
||||||
if (options.mode === 'copy') {
|
if (options.mode === 'copy') {
|
||||||
try {
|
try {
|
||||||
@@ -165,10 +173,10 @@ export default {
|
|||||||
this.selectedImages = copyData.images || [];
|
this.selectedImages = copyData.images || [];
|
||||||
this.selectedMealType = copyData.mealType || 'breakfast';
|
this.selectedMealType = copyData.mealType || 'breakfast';
|
||||||
this.remark = copyData.notes || '';
|
this.remark = copyData.notes || '';
|
||||||
|
|
||||||
// 清除缓存
|
// 清除缓存
|
||||||
uni.removeStorageSync('checkin_copy_data');
|
uni.removeStorageSync('checkin_copy_data');
|
||||||
|
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
title: '已加载打卡内容',
|
title: '已加载打卡内容',
|
||||||
icon: 'success'
|
icon: 'success'
|
||||||
@@ -178,6 +186,12 @@ export default {
|
|||||||
console.error('读取复制数据失败:', e);
|
console.error('读取复制数据失败:', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test-0415 P2 反馈5-2:一键借鉴打卡——预填来源帖子的图片/餐次/文字
|
||||||
|
if (options.sourcePostId && options.sourceType === 'learn') {
|
||||||
|
this.sourcePostId = options.sourcePostId
|
||||||
|
this.loadSourcePost(options.sourcePostId)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onUnload() {
|
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() {
|
async handlePublish() {
|
||||||
if (this.selectedImages.length === 0) {
|
if (this.selectedImages.length === 0) {
|
||||||
uni.showToast({
|
uni.showToast({
|
||||||
@@ -567,20 +618,25 @@ export default {
|
|||||||
// 防止重复提交
|
// 防止重复提交
|
||||||
if (this._publishing) return
|
if (this._publishing) return
|
||||||
this._publishing = true
|
this._publishing = true
|
||||||
|
|
||||||
uni.showLoading({ title: '发布中...' });
|
uni.showLoading({ title: '发布中...' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const imageUrls = this.selectedImages;
|
const imageUrls = this.selectedImages;
|
||||||
const today = new Date().toISOString().split('T')[0];
|
const today = new Date().toISOString().split('T')[0];
|
||||||
const result = await submitCheckin({
|
const submitData = {
|
||||||
mealType: this.selectedMealType,
|
mealType: this.selectedMealType,
|
||||||
date: today,
|
date: today,
|
||||||
photosJson: JSON.stringify(imageUrls),
|
photosJson: JSON.stringify(imageUrls),
|
||||||
notes: this.remark,
|
notes: this.remark,
|
||||||
enableAIVideo: this.enableAIVideo,
|
enableAIVideo: this.enableAIVideo,
|
||||||
enableAIAnalysis: false
|
enableAIAnalysis: false
|
||||||
});
|
};
|
||||||
|
// 借鉴打卡:透传 sourcePostId 给后端做引用关系记录
|
||||||
|
if (this.sourcePostId) {
|
||||||
|
submitData.sourcePostId = this.sourcePostId;
|
||||||
|
}
|
||||||
|
const result = await submitCheckin(submitData);
|
||||||
|
|
||||||
uni.hideLoading();
|
uni.hideLoading();
|
||||||
|
|
||||||
@@ -619,6 +675,20 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<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 {
|
.checkin-publish-page {
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
background: #f4f5f7;
|
background: #f4f5f7;
|
||||||
|
|||||||
Reference in New Issue
Block a user