useTagsViewStore().visitedViews);
const routes = computed(() => usePermissionStore().routes);
const theme = computed(() => useSettingsStore().theme);
+const tagsViewStyle = computed(() => useSettingsStore().tagsViewStyle);
watch(route, () => {
addTags();
@@ -407,6 +409,27 @@ function handleScroll() {
}
}
}
+ &.chrome-style {
+ background: #f1f3f4;
+ .tags-view-wrapper {
+ .tags-view-item {
+ border: none;
+ border-radius: 8px 8px 0 0;
+ background: #dadce0;
+ color: #5f6368;
+ margin-left: -1px;
+ padding: 0 16px;
+ &.active {
+ background: #fff;
+ color: #202124;
+ border-color: transparent;
+ &::before {
+ display: none;
+ }
+ }
+ }
+ }
+ }
}
@@ -435,5 +458,26 @@ function handleScroll() {
}
}
}
+ &.chrome-style {
+ background: #f1f3f4;
+ .tags-view-wrapper {
+ .tags-view-item {
+ border: none;
+ border-radius: 8px 8px 0 0;
+ background: #dadce0;
+ color: #5f6368;
+ margin-left: -1px;
+ padding: 0 16px;
+ &.active {
+ background: #fff;
+ color: #202124;
+ border-color: transparent;
+ &::before {
+ display: none;
+ }
+ }
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/openhis-ui-vue3/src/layout/index.vue b/openhis-ui-vue3/src/layout/index.vue
index 200aec9ab..4fed45dda 100755
--- a/openhis-ui-vue3/src/layout/index.vue
+++ b/openhis-ui-vue3/src/layout/index.vue
@@ -14,7 +14,7 @@
@@ -138,11 +138,19 @@ defineExpose({
position: fixed;
top: 50px;
right: 0;
- left: 0;
+ left: 200px;
z-index: 9;
- width: 100%;
+ width: calc(100% - 200px);
padding: 0 15px;
background: #fff;
+ box-sizing: border-box;
+}
+
+.sidebar-hidden {
+ .fixed-header {
+ left: 0 !important;
+ width: 100% !important;
+ }
}
.sidebarHide {
diff --git a/openhis-ui-vue3/src/router/index.js b/openhis-ui-vue3/src/router/index.js
index 4af5f3e40..89494c3e1 100755
--- a/openhis-ui-vue3/src/router/index.js
+++ b/openhis-ui-vue3/src/router/index.js
@@ -454,19 +454,9 @@ export const dynamicRoutes = [
}
];
-// 合并常量路由和动态路由,确保所有路由都能被访问
-const allRoutes = [...constantRoutes, ...dynamicRoutes];
-
-// 添加404路由到所有路由的最后
-allRoutes.push({
- path: "/:pathMatch(.*)*",
- component: () => import('@/views/error/404'),
- hidden: true
-});
-
const router = createRouter({
history: createWebHistory(),
- routes: allRoutes,
+ routes: constantRoutes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition
@@ -476,4 +466,17 @@ const router = createRouter({
},
});
+
+// 动态路由加载完成后再添加 404 catch-all(Vue Router 4 要求)
+export function addNotFoundRoute() {
+ if (!router.hasRoute('not-found')) {
+ router.addRoute({
+ path: '/:pathMatch(.*)*',
+ name: 'not-found',
+ component: () => import('@/views/error/404'),
+ hidden: true
+ })
+ }
+}
+
export default router;
diff --git a/openhis-ui-vue3/src/store/modules/notice.js b/openhis-ui-vue3/src/store/modules/notice.js
new file mode 100644
index 000000000..08ed51754
--- /dev/null
+++ b/openhis-ui-vue3/src/store/modules/notice.js
@@ -0,0 +1,105 @@
+import { getUnreadCount, getUserNotices, markAsRead, markAllAsRead, listNoticeTop } from '@/api/system/notice'
+
+const useNoticeStore = defineStore('notice', {
+ state: () => ({
+ unreadCount: 0,
+ noticeList: [],
+ readIds: new Set(),
+ loaded: false
+ }),
+
+ getters: {
+ unreadList(state) {
+ return state.noticeList.filter(n => !state.readIds.has(n.noticeId))
+ },
+ noticeTypeList(state) {
+ return state.noticeList.filter(n => n.noticeType === '2')
+ },
+ informTypeList(state) {
+ return state.noticeList.filter(n => n.noticeType === '1')
+ }
+ },
+
+ actions: {
+ // 获取未读数量
+ async fetchUnreadCount() {
+ try {
+ const res = await getUnreadCount()
+ this.unreadCount = res.data || 0
+ } catch (e) {
+ // ignore
+ }
+ },
+
+ // 获取通知列表
+ async fetchNotices() {
+ try {
+ const res = await getUserNotices()
+ this.noticeList = res.data || []
+ this.loaded = true
+ // 计算未读数
+ this.unreadCount = this.noticeList.filter(n => !n.readFlag || n.readFlag === '0').length
+ } catch (e) {
+ // ignore
+ }
+ },
+
+ // 获取顶部通知列表
+ async fetchTopNotices(query) {
+ try {
+ const res = await listNoticeTop(query)
+ this.noticeList = res.data || []
+ this.loaded = true
+ } catch (e) {
+ // ignore
+ }
+ },
+
+ // 标记单条已读
+ async markRead(noticeId) {
+ try {
+ await markAsRead(noticeId)
+ this.readIds.add(noticeId)
+ // 更新列表中的已读状态
+ const item = this.noticeList.find(n => n.noticeId === noticeId)
+ if (item) {
+ item.isRead = true
+ item.readFlag = '1'
+ }
+ this.unreadCount = Math.max(0, this.unreadCount - 1)
+ } catch (e) {
+ // ignore
+ }
+ },
+
+ // 全部标记已读
+ async markAllRead() {
+ try {
+ const unreadIds = this.noticeList
+ .filter(n => !this.readIds.has(n.noticeId))
+ .map(n => n.noticeId)
+ if (unreadIds.length > 0) {
+ await markAllAsRead(unreadIds)
+ unreadIds.forEach(id => this.readIds.add(id))
+ this.noticeList.forEach(n => {
+ n.isRead = true
+ n.readFlag = '1'
+ })
+ this.unreadCount = 0
+ }
+ } catch (e) {
+ // ignore
+ }
+ },
+
+ // 重置状态
+ reset() {
+ this.unreadCount = 0
+ this.noticeList = []
+ this.readIds = new Set()
+ this.loaded = false
+ }
+ }
+})
+
+export default useNoticeStore
diff --git a/openhis-ui-vue3/src/store/modules/permission.js b/openhis-ui-vue3/src/store/modules/permission.js
index 39f31e9c5..1cbc4e392 100755
--- a/openhis-ui-vue3/src/store/modules/permission.js
+++ b/openhis-ui-vue3/src/store/modules/permission.js
@@ -1,5 +1,5 @@
import auth from '@/plugins/auth'
-import router, {constantRoutes, dynamicRoutes} from '@/router'
+import router, {constantRoutes, dynamicRoutes, addNotFoundRoute} from '@/router'
import {getRouters} from '@/api/menu'
import Layout from '@/layout/index'
import ParentView from '@/components/ParentView'
@@ -44,6 +44,7 @@ const usePermissionStore = defineStore(
const defaultRoutes = filterAsyncRouter(defaultData)
const asyncRoutes = filterDynamicRoutes(dynamicRoutes)
asyncRoutes.forEach(route => { router.addRoute(route) })
+ addNotFoundRoute()
this.setRoutes(rewriteRoutes)
this.setSidebarRouters(constantRoutes.concat(sidebarRoutes))
this.setDefaultRoutes(sidebarRoutes)
diff --git a/openhis-ui-vue3/src/store/modules/settings.js b/openhis-ui-vue3/src/store/modules/settings.js
index 40cc08399..6b5c25758 100755
--- a/openhis-ui-vue3/src/store/modules/settings.js
+++ b/openhis-ui-vue3/src/store/modules/settings.js
@@ -2,7 +2,7 @@ import defaultSettings from '@/settings'
import {useDynamicTitle} from '@/utils/dynamicTitle'
const {
- sideTheme, showSettings, navType: topNav, tagsView, tagsViewPersist,
+ sideTheme, showSettings, topNav, tagsView, tagsViewPersist,
tagsIcon, tagsViewStyle, fixedHeader, sidebarLogo, dynamicTitle,
footerVisible, footerContent
} = defaultSettings