178 lines
4.6 KiB
Vue
178 lines
4.6 KiB
Vue
<template>
|
||
<view class="mailbox-detail">
|
||
<view class="nav-back" @tap="goBack">
|
||
<text class="nav-back-icon">←</text>
|
||
</view>
|
||
<!-- <Header title="明信片" :showBack="true" /> -->
|
||
<view v-if="notification" class="postcard-wrap">
|
||
<Postcard
|
||
:notification="notification"
|
||
@mark-read="onMarkRead"
|
||
@delete="onDeleteOne"
|
||
/>
|
||
</view>
|
||
<view v-else class="empty-detail">明信片不存在或已删除</view>
|
||
<!-- 底部固定 toolbar: 单条 [✓标已读] + [🗑删除] -->
|
||
<view v-if="notification" class="postcard-toolbar">
|
||
<button
|
||
v-if="!notification.is_read"
|
||
class="btn-mark-read"
|
||
@click="onMarkRead"
|
||
>[✓ 标已读]</button>
|
||
<button v-else class="btn-mark-read-disabled" disabled>[已读]</button>
|
||
<button class="btn-delete" @click="onDeleteOne">[🗑 删除]</button>
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { ref, computed } from 'vue'
|
||
import { useStore } from 'vuex'
|
||
import { onLoad } from '@dcloudio/uni-app'
|
||
// import Header from '../components/Header.vue'
|
||
import Postcard from './components/Postcard.vue'
|
||
import { useMailboxCenter } from './composables/useMailboxCenter.js'
|
||
import { getNotificationsApi } from '@/utils/api.js'
|
||
|
||
const store = useStore()
|
||
const { onMarkRead: mr, onDeleteOne: del } = useMailboxCenter()
|
||
const nid = ref(null)
|
||
const type = ref(null)
|
||
|
||
const goBack = () => {
|
||
// 获取页面栈
|
||
const pages = getCurrentPages();
|
||
if (pages.length > 1) {
|
||
// 有上一页,执行返回
|
||
uni.navigateBack();
|
||
} else {
|
||
// 没有上一页,跳转到square页面
|
||
uni.reLaunch({
|
||
url: '/pages/square/square'
|
||
});
|
||
}
|
||
};
|
||
|
||
onLoad((options) => {
|
||
nid.value = Number(options.nid)
|
||
type.value = options.type
|
||
})
|
||
|
||
const notification = computed(() => {
|
||
if (!nid.value || !type.value) return null
|
||
// 优先从 store 取(已加载过的条目)
|
||
const item = store.state.mailbox.itemsByType[type.value]?.find(n => n.id === nid.value)
|
||
if (item) return item
|
||
// store 没有则单条拉一次(杀进程后退 push 进来场景)
|
||
loadOne()
|
||
return store.state.mailbox.detailCache || null
|
||
})
|
||
|
||
async function loadOne() {
|
||
try {
|
||
// P0-2 fix:utils/api.js 统一返回 { code, message, data: { items, ... } },
|
||
// 旧写法读 resp.items 永远是 undefined → find 永远 null → detailCache 不写。
|
||
const resp = await getNotificationsApi({ type: type.value, page: 1, page_size: 50 })
|
||
const item = (resp.data?.items || []).find(n => n.id === nid.value)
|
||
if (item) store.commit('mailbox/SET_DETAIL_CACHE', item)
|
||
} catch (e) {
|
||
console.warn('[mailbox/detail] loadOne failed:', e)
|
||
}
|
||
}
|
||
|
||
async function onMarkRead() {
|
||
try {
|
||
await mr(nid.value, type.value)
|
||
uni.showToast({ title: '已标已读', icon: 'none' })
|
||
} catch (e) {
|
||
console.warn('[mailbox/detail] onMarkRead failed:', e)
|
||
uni.showToast({ title: '标已读失败', icon: 'none' })
|
||
}
|
||
// 留在本页(用户可能想再看一眼),也可选择 setTimeout 后 navigateBack
|
||
}
|
||
|
||
async function onDeleteOne() {
|
||
try {
|
||
await del(nid.value, type.value)
|
||
uni.showToast({ title: '已删除', icon: 'none' })
|
||
setTimeout(() => uni.navigateBack(), 500)
|
||
} catch (e) {
|
||
console.warn('[mailbox/detail] onDeleteOne failed:', e)
|
||
uni.showToast({ title: '删除失败', icon: 'none' })
|
||
}
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.mailbox-detail {
|
||
display: flex;
|
||
flex-direction: column;
|
||
min-height: 100vh;
|
||
background: #f8f8f8;
|
||
padding-bottom: 160rpx; /* 给底部 toolbar 留位 */
|
||
|
||
.nav-back {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
/* background: rgba(255,255,255,0.5);
|
||
border-radius: 50%; */
|
||
}
|
||
|
||
.nav-back-icon {
|
||
font-size: 48rpx;
|
||
font-weight: bold;
|
||
color: #fff;
|
||
}
|
||
|
||
.postcard-wrap {
|
||
flex: 1;
|
||
padding: 24rpx;
|
||
}
|
||
|
||
.empty-detail {
|
||
flex: 1;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
color: #999;
|
||
font-size: 28rpx;
|
||
padding: 96rpx 0;
|
||
}
|
||
|
||
.postcard-toolbar {
|
||
position: fixed;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
display: flex;
|
||
gap: 16rpx;
|
||
padding: 16rpx 24rpx;
|
||
background: #fff;
|
||
border-top: 1rpx solid #f0f0f0;
|
||
box-shadow: 0 -2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||
|
||
button {
|
||
flex: 1;
|
||
font-size: 26rpx;
|
||
padding: 20rpx 0;
|
||
border-radius: 8rpx;
|
||
&::after { border: 0; }
|
||
}
|
||
.btn-mark-read {
|
||
background: #e8f4ff;
|
||
color: #5C40FF;
|
||
}
|
||
.btn-mark-read-disabled {
|
||
background: #f5f5f5;
|
||
color: #999;
|
||
}
|
||
.btn-delete {
|
||
background: #fff1f0;
|
||
color: #f5222d;
|
||
}
|
||
}
|
||
}
|
||
</style> |