<script lang="ts" setup>
|
import { computed, onMounted, ref } from 'vue';
|
import { useRouter } from 'vue-router';
|
|
import { IconifyIcon } from '@vben/icons';
|
|
import { getNoticePage as getOaNoticePage } from '#/api/bpm/oa/notice';
|
import { getNoticePage as getSystemNoticePage } from '#/api/system/notice';
|
|
defineOptions({ name: 'DashboardNoticePanel' });
|
const props = defineProps<{ menuPath: string }>();
|
const router = useRouter();
|
const loading = ref(true);
|
const failed = ref(false);
|
const isOa = computed(() => props.menuPath.includes('/bpm/'));
|
const notices = ref<{ id?: number; title: string; date: string }[]>([]);
|
|
function dateText(value: string | Date | undefined) {
|
if (!value) return '';
|
if (typeof value === 'string') return value.slice(0, 10);
|
return new Intl.DateTimeFormat('zh-CN').format(value);
|
}
|
|
async function load() {
|
loading.value = true;
|
failed.value = false;
|
try {
|
if (isOa.value) {
|
const result = await getOaNoticePage({ pageNo: 1, pageSize: 6 });
|
notices.value = (result.list ?? []).map((item) => ({ id: item.id, title: item.title, date: dateText(item.publishTime || item.createTime) }));
|
} else {
|
const result = await getSystemNoticePage({ pageNo: 1, pageSize: 6 });
|
notices.value = (result.list ?? []).map((item) => ({ id: item.id, title: item.title, date: dateText(item.createTime) }));
|
}
|
} catch {
|
notices.value = [];
|
failed.value = true;
|
} finally {
|
loading.value = false;
|
}
|
}
|
onMounted(load);
|
|
function openNotice(notice: { id?: number }) {
|
if (isOa.value && notice.id && router.hasRoute('OANoticeDetail')) {
|
router.push({ name: 'OANoticeDetail', query: { id: notice.id } });
|
} else router.push(props.menuPath);
|
}
|
</script>
|
|
<template>
|
<div class="notice-panel">
|
<div class="notice-head">
|
<h2><IconifyIcon icon="lucide:megaphone" /> 通知公告</h2>
|
<button type="button" @click="router.push(menuPath)">更多 <IconifyIcon icon="lucide:chevron-right" /></button>
|
</div>
|
<div v-if="loading" class="notice-empty" role="status">加载中…</div>
|
<div v-else-if="failed" class="notice-empty notice-error" role="status">
|
<span>公告加载失败,请重试</span>
|
<button type="button" @click="load">重试</button>
|
</div>
|
<div v-else-if="!notices.length" class="notice-empty">暂无通知公告</div>
|
<ul v-else>
|
<li v-for="notice in notices" :key="notice.id">
|
<button type="button" @click="openNotice(notice)">
|
<span class="notice-title">{{ notice.title }}</span>
|
<time>{{ notice.date }}</time>
|
</button>
|
</li>
|
</ul>
|
</div>
|
</template>
|
|
<style scoped>
|
.notice-panel { height: 100%; min-width: 0; min-height: 300px; padding: 18px; border: 1px solid #e1ebf5; border-radius: 6px; background: #fff; box-shadow: 0 3px 10px rgb(24 66 106 / 4%); }
|
.notice-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
|
.notice-head h2 { display: flex; align-items: center; gap: 9px; margin: 0; color: #153a62; font-size: 17px; font-weight: 700; }
|
.notice-head h2 :deep(svg) { width: 19px; color: #b7242d; }
|
.notice-head button { display: inline-flex; align-items: center; gap: 2px; color: #58799b; font-size: 12px; }
|
.notice-empty { display: grid; min-height: 230px; place-items: center; color: #5c7187; font-size: 13px; }
|
.notice-error { align-content: center; gap: 10px; }
|
.notice-error button { min-height: 36px; padding: 0 18px; border: 1px solid #c3d5e6; border-radius: 5px; color: #245987; background: #f4f8fc; }
|
ul { margin: 0; padding: 0; list-style: none; }
|
li + li { border-top: 1px solid #edf2f6; }
|
li button { display: flex; width: 100%; min-height: 39px; align-items: center; gap: 12px; padding: 9px 2px; text-align: left; }
|
li button::before { width: 5px; height: 5px; flex: none; border-radius: 50%; background: #b7242d; content: ''; }
|
.notice-title { min-width: 0; flex: 1; overflow: hidden; color: #284563; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
|
time { flex: none; color: #5c7187; font-size: 11px; }
|
li button:hover .notice-title, .notice-head button:hover { color: #b7242d; }
|
button:focus-visible { outline: 2px solid #2775bd; outline-offset: 2px; }
|
.dark .notice-panel { border-color: #33485e; background: #14283e; }
|
.dark .notice-head h2, .dark .notice-title { color: #e8eef7; }
|
.dark .notice-empty, .dark time { color: #afc2d5; }
|
.dark li + li { border-color: #33485e; }
|
</style>
|