feat: 碎片详情页支持内联编辑
- 碎片类型详情页新增编辑按钮 - 编辑模式下显示 textarea 和保存/取消按钮 - 保存时调用更新接口并同步本地数据
This commit is contained in:
@@ -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>
|
||||||
Reference in New Issue
Block a user