Files
hfb_sys/frontend/src/features/auth/views/NotificationsView.vue
T
yml2213 4461e7929e feat(distribution): 站内信与通知体系多租户独立分支隔离
- 新增 000071 数据库迁移:notifications 表支持 distribution_site_id 并自动回填历史分销订单通知
- 通知自动归属:在事务内根据订单或申诉自动关联当前分销站点 ID
- 隔离查询与已读控制:列表、未读统计与批量已读均严格按站点隔离,防止主站与分站交叉泄漏
- 前台界面联动:消息中心通知 Tab 及移动端/PC端站内信页面展示分站专属标识与精准过滤
2026-09-07 19:10:02 +08:00

132 lines
3.8 KiB
Vue

<script setup lang="ts">
import { ElMessage } from 'element-plus'
import { onMounted, ref } from 'vue'
import {
fetchNotifications,
markNotificationRead,
type NotificationItem,
} from '@/features/auth/api/notifications'
import { notificationUnreadChangedEvent } from '@/features/auth/composables/useNotificationUnreadCount'
import { formatDateTime } from '@/shared/utils/time'
import { useDistributionSiteStore } from '@/stores/distributionSite'
const distributionStore = useDistributionSiteStore()
const loading = ref(false)
const notifications = ref<NotificationItem[]>([])
const currentPage = ref(1)
const currentPageSize = ref(20)
const total = ref(0)
onMounted(loadNotifications)
async function loadNotifications() {
loading.value = true
try {
const siteCode = distributionStore.isDistribution ? distributionStore.siteCode : undefined
const result = await fetchNotifications(currentPage.value, currentPageSize.value, siteCode)
notifications.value = result.items
total.value = result.total
} finally {
loading.value = false
}
}
function handleSizeChange() {
currentPage.value = 1
loadNotifications()
}
async function markRead(id: number) {
const siteCode = distributionStore.isDistribution ? distributionStore.siteCode : undefined
await markNotificationRead(id, siteCode)
window.dispatchEvent(new Event(notificationUnreadChangedEvent))
ElMessage.success('已标记为已读')
await loadNotifications()
}
</script>
<template>
<section class="page">
<div class="page-header">
<p class="eyebrow">
Notifications
<el-tag
v-if="distributionStore.isDistribution"
type="warning"
effect="light"
size="small"
class="distribution-site-tag"
>
{{ distributionStore.siteName }}专属分站
</el-tag>
</p>
<h1>
{{ distributionStore.isDistribution ? `${distributionStore.siteName} · 站内信` : '站内信' }}
</h1>
<p>
{{
distributionStore.isDistribution
? `接收【${distributionStore.siteName}】专属分站订单交易、交接、申诉和客服通知。`
: '接收审核、交接、归还、申诉和仲裁结果通知。'
}}
</p>
</div>
<el-empty
v-if="!loading && notifications.length === 0"
:description="
distributionStore.isDistribution
? `暂无【${distributionStore.siteName}】专属站内信`
: '暂无站内信'
"
/>
<div v-else v-loading="loading" class="notification-list">
<div
v-for="item in notifications"
:key="item.id"
class="notification-item"
:class="{ unread: !item.read_at }"
>
<div>
<span>{{ item.type }}</span>
<h2>{{ item.title }}</h2>
<p>{{ item.content }}</p>
<small>{{ formatDateTime(item.created_at) }}</small>
</div>
<div class="notification-actions">
<RouterLink
v-if="item.biz_type === 'order' && item.biz_id"
:to="`/orders/${item.biz_id}`"
>
<el-button size="small">查看订单</el-button>
</RouterLink>
<el-button v-if="!item.read_at" size="small" type="primary" @click="markRead(item.id)"
>已读</el-button
>
</div>
</div>
</div>
<div class="pagination-wrap" v-if="total > 0">
<el-pagination
v-model:current-page="currentPage"
v-model:page-size="currentPageSize"
:total="total"
:page-sizes="[10, 20, 50, 100]"
layout="total, sizes, prev, pager, next"
@current-change="loadNotifications"
@size-change="handleSizeChange"
/>
</div>
</section>
</template>
<style scoped>
.distribution-site-tag {
margin-left: 8px;
vertical-align: middle;
font-weight: 500;
}
</style>