Files
jiapuapp/pages/notification/n02-message-detail.vue
T
2026-07-21 07:53:08 +08:00

112 lines
5.3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 页面编号N-02用途消息详情已读状态与上下文操作 -->
<template>
<view class="notice-detail-page" :class="{ 'notice-state--ready': noticeState === 'ready', 'notice-state--loading': noticeState === 'loading', 'notice-state--expired': noticeState === 'expired' }">
<ModulePageBackground module="notification" />
<view class="page-layer"><PageHeader title="消息详情" /></view>
<view class="notice-content page-layer">
<AppLoading v-if="noticeState === 'loading'" text="正在读取消息" description="请稍候,正在整理消息详情。" />
<view v-else-if="noticeState === 'expired'" class="paper-panel state-card">
<text class="state-title">这条消息已失效</text>
<text class="state-copy">消息可能已撤回或超过保留期限请返回消息中心查看其他内容</text>
<AppButton block label="返回消息中心" @click="backToMessages" />
</view>
<template v-else>
<view class="paper-panel notice-card">
<view class="notice-meta">
<text :class="{ 'is-unread': !noticeDetail.read }">{{ noticeDetail.read ? "已读" : "未读提醒" }}</text>
<text>{{ noticeDetail.time }}</text>
</view>
<text class="notice-title">{{ noticeDetail.title }}</text>
<text class="notice-body">{{ noticeDetail.body }}</text>
<text class="notice-source">来自{{ noticeDetail.source }}</text>
</view>
<view class="action-stack">
<AppButton v-if="!noticeDetail.read" block label="标记已读" @click="markAsRead" />
<AppButton v-if="noticeDetail.target" block type="secondary" :label="noticeDetail.targetLabel" @click="openNoticeTarget" />
</view>
</template>
</view>
<AppToast :visible="toastVisible" :message="toastMessage" />
</view>
</template>
<script setup>
import { onUnmounted, 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 noticeState = ref("loading");
const toastVisible = ref(false);
const toastMessage = ref("");
let toastTimer = null;
const noticeDetail = ref({
id: "review-1",
title: "申请待审核",
body: "汤志成申请加入汤氏家谱,请核实申请人的亲属关系与世代信息后完成审核。",
time: "今天 10:28",
source: "汝南汤氏家谱",
read: false,
target: "/pages/genealogy/g10-application-review",
targetLabel: "前往入谱审核",
});
onLoad((query) => {
if (query.state === "expired") {
noticeState.value = "expired";
return;
}
if (query.id === "approved") {
noticeDetail.value = {
id: "approved",
title: "入谱申请已通过",
body: "你申请加入汝南汤氏家谱的请求已通过,现在可以查看家谱与家族动态。",
time: "昨天 18:10",
source: "汝南汤氏家谱",
read: true,
target: "/pages/genealogy/g01-my-genealogies",
targetLabel: "查看我的家谱",
};
}
noticeState.value = "ready";
});
const showToast = (message) => {
toastMessage.value = message;
toastVisible.value = true;
if (toastTimer) clearTimeout(toastTimer);
toastTimer = setTimeout(() => (toastVisible.value = false), 1800);
};
const markAsRead = () => {
noticeDetail.value.read = true;
showToast("已标记为已读");
};
const openNoticeTarget = () => uni.navigateTo({ url: noticeDetail.value.target });
const backToMessages = () => uni.navigateBack();
onUnmounted(() => toastTimer && clearTimeout(toastTimer));
</script>
<style scoped lang="scss">
.notice-detail-page { display: flex; min-height: 100vh; flex-direction: column; background: $paper; }
.page-layer { z-index: 1; }
.notice-content { flex: 1; padding: 28rpx 30rpx 72rpx; }
.paper-panel { background: url("/static/assets/modules/notification/transparent/n01-notice-card.png") center / 100% 100% no-repeat; }
.notice-card { min-height: 430rpx; padding: 54rpx 52rpx; box-sizing: border-box; }
.notice-meta { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8rpx 20rpx; color: $ink-muted; font-size: 22rpx; }
.notice-meta .is-unread { color: $brand-red; font-weight: 700; }
.notice-title { display: block; margin-top: 24rpx; color: $ink; font-family: STKaiti, KaiTi, serif; font-size: 38rpx; font-weight: 700; overflow-wrap: anywhere; }
.notice-body { display: block; margin-top: 22rpx; color: #5f4a38; font-size: 25rpx; line-height: 1.75; overflow-wrap: anywhere; }
.notice-source { display: block; margin-top: 28rpx; color: $ink-muted; font-size: 22rpx; overflow-wrap: anywhere; }
.action-stack { display: flex; flex-direction: column; gap: 18rpx; margin-top: 28rpx; }
.state-card { min-height: 340rpx; padding: 72rpx 50rpx 48rpx; box-sizing: border-box; text-align: center; }
.state-title { display: block; color: $ink; font-size: 34rpx; font-weight: 700; }
.state-copy { display: block; margin: 18rpx 0 28rpx; color: $ink-muted; font-size: 24rpx; line-height: 1.65; }
@media (max-width: 340px) { .notice-content { padding-right: 22rpx; padding-left: 22rpx; } .notice-card { padding-right: 40rpx; padding-left: 40rpx; } }
</style>