修改完成
This commit is contained in:
@@ -1,5 +1,113 @@
|
||||
<!-- 页面编号:F-05;用途:谱文详情。 -->
|
||||
<template><ModulePage page-id="f05" /></template>
|
||||
<!-- 页面编号:F-05;用途:谱文正文、收藏、编辑与受控状态。 -->
|
||||
<template>
|
||||
<view class="article-detail-page" :class="articleStateClasses">
|
||||
<ModulePageBackground module="family" />
|
||||
<view class="article-detail-header"><PageHeader title="谱文详情" /></view>
|
||||
|
||||
<view v-if="articleState === 'loading'" class="article-detail-loading">
|
||||
<AppLoading text="正在读取谱文" description="请稍候,正在整理正文与收录信息。" />
|
||||
</view>
|
||||
|
||||
<view v-else class="article-detail-content">
|
||||
<template v-if="articleState === 'ready'">
|
||||
<view class="article-paper">
|
||||
<text class="article-paper__category">{{ article.category }}</text>
|
||||
<text class="article-paper__title">{{ article.title }}</text>
|
||||
<view class="article-paper__meta"><text>{{ article.author }}</text><text>{{ article.updatedAt }}</text></view>
|
||||
<view class="article-paper__body">
|
||||
<text v-for="(paragraph, index) in articleParagraphs" :key="index">{{ paragraph }}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="article-actions">
|
||||
<AppButton block :label="favorite ? '已收藏谱文' : '收藏谱文'" @click="toggleFavorite" />
|
||||
<AppButton type="secondary" block label="编辑谱文" @click="editArticle" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<view v-else class="article-state-card">
|
||||
<text>{{ stateCopy.title }}</text>
|
||||
<text>{{ stateCopy.copy }}</text>
|
||||
<AppButton :type="articleState === 'error' ? 'secondary' : 'primary'" block :label="stateCopy.action" @click="handleStateAction" />
|
||||
</view>
|
||||
</view>
|
||||
<AppToast :visible="toastVisible" :message="favorite ? '已收藏谱文' : '已取消收藏'" />
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import ModulePage from "@/components/ModulePage.vue";
|
||||
import { computed, onUnmounted, reactive, ref } from "vue";
|
||||
import { onLoad } from "@dcloudio/uni-app";
|
||||
import AppButton from "@/components/AppButton.vue";
|
||||
import AppLoading from "@/components/AppLoading.vue";
|
||||
import AppToast from "@/components/AppToast.vue";
|
||||
import ModulePageBackground from "@/components/ModulePageBackground.vue";
|
||||
import PageHeader from "@/components/PageHeader.vue";
|
||||
|
||||
const articleRecords = [
|
||||
{ id: "101", category: "家风家训", title: "孝友传家的日常", author: "汤文正", updatedAt: "2024 年 5 月 12 日", paragraphs: ["孝友传家,不只在族谱序言里,也在一家人每日的言行中。长辈以宽厚待晚辈,晚辈以耐心照料长辈,亲友之间守信互助,便是最朴素也最长久的家风。", "勤俭并非一味节省,而是珍惜所得、量入为出,也愿意在家人需要时伸出援手。家中每一代人都可以用自己的方式,把这份分寸与担当继续传下去。", "敬祖睦宗,最终是为了让今天的家人彼此认识、彼此关心。记录姓名与世代之外,也应留下真实的生活、共同经历和温暖记忆。"] },
|
||||
{ id: "102", category: "家族往事", title: "祖居门前的那棵桂花树", author: "汤淑华", updatedAt: "2024 年 5 月 10 日", paragraphs: ["祖居门前曾有一棵桂花树。每到中秋,院里都是清甜的香气,远道回来的家人也总能循着那股味道找到家门。", "后来房屋几经修缮,桂花树仍被大家小心保留下来。它见过孩子长大,也见过长辈把往事一遍遍讲给后来人。"] },
|
||||
{ id: "103", category: "族谱序言", title: "续修族谱序", author: "谱主", updatedAt: "2024 年 5 月 8 日", paragraphs: ["本次续修以旧谱、碑记、户籍资料和长辈口述为基础,由家人共同核对补充。凡暂不能确认之处,均保留来源和疑问,留待后续查证。", "愿这份记录不仅理清世系,也能保存家风、人物与共同记忆。"] },
|
||||
];
|
||||
const articleId = ref("101");
|
||||
const article = reactive({ ...articleRecords[0] });
|
||||
const articleState = ref("loading");
|
||||
const favorite = ref(false);
|
||||
const toastVisible = ref(false);
|
||||
let toastTimer = null;
|
||||
const articleParagraphs = computed(() => article.paragraphs || []);
|
||||
const articleStateClasses = computed(() => ({
|
||||
[`article-state--${articleState.value}`]: true,
|
||||
"article-state--expired": articleState.value === "expired",
|
||||
"article-state--privacy": articleState.value === "privacy",
|
||||
"article-state--error": articleState.value === "error",
|
||||
}));
|
||||
const stateCopy = computed(() => ({
|
||||
expired: { title: "这篇谱文已无法查看", copy: "内容可能已被作者删除或取消公开,请返回谱文列表查看其他内容。", action: "返回谱文列表" },
|
||||
privacy: { title: "这篇谱文暂未公开", copy: "作者仅向有权限的家人开放正文,请返回谱文列表查看其他内容。", action: "返回谱文列表" },
|
||||
error: { title: "谱文暂不可用", copy: "请稍后重新查看,已有谱文不会受到影响。", action: "重新查看" },
|
||||
}[articleState.value] || {}));
|
||||
|
||||
onLoad((query) => {
|
||||
articleId.value = String(query.articleId || "101");
|
||||
const selected = articleRecords.find((item) => item.id === articleId.value);
|
||||
if (selected) Object.assign(article, selected);
|
||||
articleState.value = ["loading", "error", "expired", "privacy"].includes(query.state)
|
||||
? query.state
|
||||
: selected
|
||||
? "ready"
|
||||
: "expired";
|
||||
});
|
||||
|
||||
const toggleFavorite = () => {
|
||||
favorite.value = !favorite.value;
|
||||
toastVisible.value = true;
|
||||
if (toastTimer) clearTimeout(toastTimer);
|
||||
toastTimer = setTimeout(() => { toastVisible.value = false; }, 1800);
|
||||
};
|
||||
const editArticle = () => uni.navigateTo({ url: `/pages/family/f06-article-editor?mode=edit&articleId=${articleId.value}` });
|
||||
const backToArticles = () => uni.redirectTo({ url: "/pages/family/f04-article-list" });
|
||||
const handleStateAction = () => { if (articleState.value === "error") articleState.value = "ready"; else backToArticles(); };
|
||||
onUnmounted(() => { if (toastTimer) clearTimeout(toastTimer); });
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.article-detail-page { display: flex; min-height: 100vh; flex-direction: column; background: $paper; }
|
||||
.article-detail-header, .article-detail-loading, .article-detail-content { z-index: 1; }
|
||||
.article-detail-loading { min-height: calc(100vh - 100rpx); }
|
||||
.article-detail-content { padding: 18rpx 24rpx 72rpx; }
|
||||
.article-paper, .article-state-card { width: 100%; box-sizing: border-box; background: url("/static/assets/modules/family/transparent/module-content-frame.png") center / 100% 100% no-repeat; }
|
||||
.article-paper { padding: 50rpx 48rpx 54rpx; }
|
||||
.article-paper > text { display: block; }
|
||||
.article-paper__category { color: $brand-red; font-size: 22rpx; font-weight: 700; letter-spacing: 3rpx; }
|
||||
.article-paper__title { margin-top: 12rpx; color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 39rpx; font-weight: 700; line-height: 1.35; }
|
||||
.article-paper__meta { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6rpx 18rpx; margin-top: 16rpx; color: $ink-muted; font-size: 21rpx; }
|
||||
.article-paper__body { margin-top: 28rpx; }
|
||||
.article-paper__body text { display: block; margin-top: 18rpx; color: $ink; font-size: 25rpx; line-height: 1.85; text-align: justify; }
|
||||
.article-actions { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 14rpx; margin-top: 18rpx; }
|
||||
.article-state-card { min-height: 350rpx; margin-top: 36rpx; padding: 78rpx 52rpx 50rpx; text-align: center; }
|
||||
.article-state-card > text { display: block; }
|
||||
.article-state-card > text:first-child { color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 35rpx; font-weight: 700; }
|
||||
.article-state-card > text:nth-child(2) { margin-top: 18rpx; color: $ink-muted; font-size: 24rpx; line-height: 1.65; }
|
||||
.article-state-card .app-button { margin-top: 30rpx; }
|
||||
@media (max-width: 340px) { .article-actions { grid-template-columns: minmax(0, 1fr); } }
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user