From 92780ef52eb672a79ea1a5c2d54e6c2306ab8c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B2=A1=E5=A4=8D=E4=B9=A0?= <2353956224@qq.com> Date: Wed, 11 Feb 2026 14:49:18 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.vue | 9 ++ src/api/notice.js | 6 + src/components/NoticeBar.vue | 249 +++++++++++++++++++++++++++++++++++ src/locales/en.js | 3 + src/locales/zh.js | 3 + src/stores/noticeStore.js | 78 +++++++++++ 6 files changed, 348 insertions(+) create mode 100644 src/api/notice.js create mode 100644 src/components/NoticeBar.vue create mode 100644 src/stores/noticeStore.js diff --git a/src/App.vue b/src/App.vue index e656719..aadd8ea 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,6 +4,9 @@ + + + @@ -38,6 +41,8 @@ import ConfigPage from './pages/ConfigPage.vue' import UpdateChecker from './pages/UpdateChecker.vue' import WorkbenchLayout from './layout/WorkbenchLayout.vue' import UpdateNotification from './components/UpdateNotification.vue' +import NoticeBar from './components/NoticeBar.vue' +import { useNoticeStore } from './stores/noticeStore' // Constants const USER_KEY = 'user_data' @@ -57,6 +62,10 @@ const automationLogs = ref([]) const isElectronEnv = isElectron() const isDev = window.location.port === '5173' +// 公告通知 +const noticeStore = useNoticeStore() +noticeStore.fetchNotices() + // Lifecycle onMounted(() => { // Set Title diff --git a/src/api/notice.js b/src/api/notice.js new file mode 100644 index 0000000..aa332c8 --- /dev/null +++ b/src/api/notice.js @@ -0,0 +1,6 @@ +import { getAxios } from '@/utils/axios.js' + +// 获取当前生效的公告列表 +export function getActiveNotices() { + return getAxios({ url: '/api/notice/active' }) +} diff --git a/src/components/NoticeBar.vue b/src/components/NoticeBar.vue new file mode 100644 index 0000000..cc3263f --- /dev/null +++ b/src/components/NoticeBar.vue @@ -0,0 +1,249 @@ + + + + campaign + + + + + {{ currentNotice.content }} + + + + + + {{ currentIndex + 1 }}/{{ activeNotices.length }} + + + + + close + + + + + + + diff --git a/src/locales/en.js b/src/locales/en.js index a4926f1..084398a 100644 --- a/src/locales/en.js +++ b/src/locales/en.js @@ -206,6 +206,9 @@ export default { TC: "Turks and Caicos Islands", TD: "Chad", TF: "French Southern Territories", TG: "Togo", TH: "Thailand", TJ: "Tajikistan", TK: "Tokelau", TL: "Timor-Leste", TM: "Turkmenistan", TN: "Tunisia", TO: "Tonga", TR: "Turkey", TT: "Trinidad and Tobago", TV: "Tuvalu", TW: "Taiwan", TZ: "Tanzania", UA: "Ukraine", UG: "Uganda", UM: "United States Minor Outlying Islands", US: "United States", UY: "Uruguay", UZ: "Uzbekistan", VA: "Vatican City", VC: "Saint Vincent and the Grenadines", VE: "Venezuela", VG: "British Virgin Islands", VI: "U.S. Virgin Islands", VN: "Vietnam", VN1: "Vietnam", VU: "Vanuatu", WS: "Samoa", YE: "Yemen", YT: "Mayotte", ZA: "South Africa", ZM: "Zambia", ZW: "Zimbabwe" }, + notice: { + close: 'Close notice', + }, // PK Mini module translations pkMini: { // Navigation diff --git a/src/locales/zh.js b/src/locales/zh.js index 6410c99..bc838df 100644 --- a/src/locales/zh.js +++ b/src/locales/zh.js @@ -186,6 +186,9 @@ export default { countries: { AD: "安道尔", AE: "阿拉伯联合酋长国", AF: "阿富汗", AG: "安提瓜和巴布达", AI: "安圭拉", AL: "阿尔巴尼亚", AM: "亚美尼亚", AO: "安哥拉", AQ: "南极洲", AR: "阿根廷", AS: "美属萨摩亚", AT: "奥地利", AU: "澳大利亚", AU1: "澳大利亚", AW: "阿鲁巴", AX: "奥兰群岛", AZ: "阿塞拜疆", }, + notice: { + close: '关闭通知', + }, // PK Mini 模块翻译 pkMini: { // 导航 diff --git a/src/stores/noticeStore.js b/src/stores/noticeStore.js new file mode 100644 index 0000000..47fd93e --- /dev/null +++ b/src/stores/noticeStore.js @@ -0,0 +1,78 @@ +import { defineStore } from 'pinia' +import { ref, computed } from 'vue' +import { getActiveNotices } from '@/api/notice' + +export const useNoticeStore = defineStore('notice', () => { + // 状态 + const notices = ref([]) + const isLoading = ref(false) + const dismissedIds = ref([]) // 当前会话已关闭的公告 ID + const lastFetchTime = ref(null) + const useMock = ref(true) // 后台接口就绪后改为 false + + // 过滤已关闭公告后的有效列表 + const activeNotices = computed(() => + notices.value.filter(n => !dismissedIds.value.includes(n.id)) + ) + + // 是否有可显示的公告 + const hasNotices = computed(() => activeNotices.value.length > 0) + + /** + * 从后台拉取公告 + */ + const fetchNotices = async () => { + if (isLoading.value) return + if (useMock.value) { + loadMockNotices() + return + } + + isLoading.value = true + try { + const res = await getActiveNotices() + if (res && res.data) { + notices.value = res.data + lastFetchTime.value = Date.now() + } + } catch (error) { + console.error('[NoticeStore] 获取公告失败:', error) + } finally { + isLoading.value = false + } + } + + /** + * 关闭某条公告(仅当前会话生效) + */ + const dismissNotice = (id) => { + if (!dismissedIds.value.includes(id)) { + dismissedIds.value.push(id) + } + } + + /** + * 加载 Mock 数据(后台接口未就绪时使用) + */ + const loadMockNotices = () => { + notices.value = [ + { id: 1, content: '欢迎使用 Yolo 系统,如有问题请联系管理员。', type: 'info' }, + { id: 2, content: '系统将于本周六凌晨 2:00-4:00 进行维护升级,届时服务将暂停,请提前做好安排。', type: 'warning' }, + ] + lastFetchTime.value = Date.now() + } + + return { + // 状态 + notices, + activeNotices, + hasNotices, + isLoading, + useMock, + + // 方法 + fetchNotices, + dismissNotice, + loadMockNotices, + } +})