云
8 小时以前 91bfcf61f44f353dfebc54a57b5b774721de3e9a
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<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>