feat: 碎片详情页支持内联编辑

- 碎片类型详情页新增编辑按钮
- 编辑模式下显示 textarea 和保存/取消按钮
- 保存时调用更新接口并同步本地数据
This commit is contained in:
2026-05-30 15:51:04 +08:00
parent 0f1a2d8bba
commit a82c25b45c
+83 -5
View File
@@ -3,6 +3,8 @@ import { computed, onMounted, ref } from "vue";
import { useRoute, useRouter } from "vue-router"; import { useRoute, useRouter } from "vue-router";
import { getReportDetail, getFragmentDetail, getTaskReview, type ReviewFeedItem } from "@/api/review"; import { getReportDetail, getFragmentDetail, getTaskReview, type ReviewFeedItem } from "@/api/review";
import { getSessionDetail } from "@/api/studySessions"; import { getSessionDetail } from "@/api/studySessions";
import { updateFragments } from "@/api/reportFragments";
import { ElMessage } from "element-plus";
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@@ -15,6 +17,11 @@ const content = ref("");
const sourceTypeLabel = ref(""); const sourceTypeLabel = ref("");
const taskNum = ref(""); const taskNum = ref("");
// 编辑状态
const isEditing = ref(false);
const editContent = ref("");
const saving = ref(false);
// 当前会话信息 // 当前会话信息
const sessionInfo = ref<{ const sessionInfo = ref<{
taskName: string; taskName: string;
@@ -114,6 +121,42 @@ const goToDetail = (type: string, id: number) => {
router.push(`/review/detail/${type}/${id}`); router.push(`/review/detail/${type}/${id}`);
}; };
const enterEdit = () => {
editContent.value = content.value;
isEditing.value = true;
};
const cancelEdit = () => {
isEditing.value = false;
editContent.value = "";
};
const saveEdit = async () => {
if (!editContent.value.trim()) {
ElMessage.warning("内容不能为空");
return;
}
if (editContent.value === content.value) {
isEditing.value = false;
return;
}
saving.value = true;
try {
const res = await updateFragments(contentId.value, editContent.value);
if (res?.code === 200) {
content.value = editContent.value;
isEditing.value = false;
ElMessage.success("保存成功");
} else {
ElMessage.error(res?.message || "保存失败");
}
} catch (e: any) {
ElMessage.error(e.message || "请求失败");
} finally {
saving.value = false;
}
};
onMounted(() => { onMounted(() => {
loadDetail(); loadDetail();
}); });
@@ -137,14 +180,38 @@ onMounted(() => {
<span v-if="sessionInfo?.startTime" class="meta-time"> <span v-if="sessionInfo?.startTime" class="meta-time">
学习时间{{ sessionInfo.startTime?.replace("T", " ")?.substring(0, 16) }} 学习时间{{ sessionInfo.startTime?.replace("T", " ")?.substring(0, 16) }}
</span> </span>
<el-button
v-if="contentType === 'fragment' && !isEditing"
type="primary"
size="small"
@click="enterEdit"
>
编辑
</el-button>
</div> </div>
<div class="content-body" v-if="content"> <!-- 编辑模式 -->
<p v-for="(line, idx) in content.split('\n')" :key="idx"> <div v-if="isEditing" class="edit-area">
{{ line || " " }} <el-input
</p> v-model="editContent"
type="textarea"
:rows="6"
placeholder="请输入学习内容"
/>
<div class="edit-actions">
<el-button @click="cancelEdit">取消</el-button>
<el-button type="primary" :loading="saving" @click="saveEdit">保存</el-button>
</div>
</div> </div>
<div v-else class="empty-content">暂无内容</div> <!-- 只读模式 -->
<template v-else>
<div class="content-body" v-if="content">
<p v-for="(line, idx) in content.split('\n')" :key="idx">
{{ line || " " }}
</p>
</div>
<div v-else class="empty-content">暂无内容</div>
</template>
</article> </article>
<!-- 该任务下的所有学习记录 --> <!-- 该任务下的所有学习记录 -->
@@ -342,4 +409,15 @@ onMounted(() => {
color: #b8860b; color: #b8860b;
} }
.edit-area {
margin-top: 12px;
}
.edit-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
margin-top: 12px;
}
</style> </style>