批量推送代码

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
郭庆泰
2026-08-29 17:52:05 +08:00
co-authored by Claude
parent 36528b6e0c
commit e47f76478b
130 changed files with 3972 additions and 2546 deletions
+44 -5
View File
@@ -41,6 +41,19 @@
<li v-if="!rows.length" class="empty">{{ emptyText }}</li>
</ul>
<!-- 分页 (pageable=true 时显示; 嵌入式小列表 pageable=false 隐藏) -->
<div v-if="pageable && total > 0" class="notice-pager">
<el-pagination
v-model:current-page="page.pageNum"
v-model:page-size="page.pageSize"
:total="total"
:page-sizes="[10, 20, 50]"
layout="total, sizes, prev, pager, next, jumper"
@current-change="load"
@size-change="load"
/>
</div>
<el-dialog
v-model="detailOpen"
:title="detail.title || '消息详情'"
@@ -70,7 +83,7 @@
</template>
<script setup>
import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { ref, reactive, computed, onMounted, onBeforeUnmount } from 'vue'
import { ElMessage } from 'element-plus'
import QRCode from 'qrcode'
import { listMyMessages, markMessageRead, markAllMessagesRead } from '@/api/public'
@@ -80,10 +93,18 @@ const props = defineProps({
limit: { type: Number, default: 5 },
showCategory: { type: Boolean, default: false },
showHeader: { type: Boolean, default: true },
emptyText: { type: String, default: '暂无通知' }
emptyText: { type: String, default: '暂无通知' },
/**
* 是否启用分页
* - false (默认): 嵌入式小列表, 拉 props.limit 条, 不显示 el-pagination
* - true: 独立页, 显示 el-pagination, 按 page.pageSize 拉, total 读后端真实值
*/
pageable: { type: Boolean, default: false }
})
const rows = ref([])
const total = ref(0)
const page = reactive({ pageNum: 1, pageSize: 20 })
const detailOpen = ref(false)
const detail = ref({})
const detailLink = ref('')
@@ -94,18 +115,29 @@ let unsubscribeNewMessage = null
async function load() {
try {
const r = await listMyMessages({ limit: props.limit })
// 分页模式: 传 pageNum/pageSize (后端返回真实 total); 非分页模式: 传 limit
const params = props.pageable
? { pageNum: page.pageNum, pageSize: page.pageSize }
: { limit: props.limit }
const r = await listMyMessages(params)
rows.value = r.rows || []
total.value = r.total || 0
} catch (e) {
rows.value = []
total.value = 0
}
}
/** SSE 触发的静默重拉 (失败不打扰用户, 下次手动刷新可见) */
/** SSE 触发的静默重拉 (失败不打扰用户, 下次手动刷新可见)
* 分页模式: 重拉当前页; 非分页模式: 仍按 limit 拉 */
async function refresh() {
try {
const r = await listMyMessages({ limit: props.limit })
const params = props.pageable
? { pageNum: page.pageNum, pageSize: page.pageSize }
: { limit: props.limit }
const r = await listMyMessages(params)
rows.value = r.rows || []
total.value = r.total || 0
} catch (e) { /* swallow */ }
}
@@ -260,6 +292,13 @@ onBeforeUnmount(() => {
font-size: 13px;
}
/* 分页 (独立页用, 嵌入式不显示) */
.notice-pager {
display: flex;
justify-content: flex-end;
margin-top: 12px;
}
/* 详情 dialog */
.detail-body .meta {
display: flex;