From 06b8e9cf002da404b82c6b63ba6ba2b7a897d6a3 Mon Sep 17 00:00:00 2001 From: lq Date: Fri, 11 Apr 2025 17:06:02 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=AE=8C=E6=88=90:=20=E8=AF=8A=E6=89=80?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E4=B8=AD=E5=BF=83,=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E4=B8=AD=E5=BF=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/api/request.ts | 18 +- apps/web-antd/src/layouts/basic.vue | 68 +++--- apps/web-antd/src/preferences.ts | 5 +- apps/web-antd/src/router/guard.ts | 2 +- apps/web-antd/src/router/index.ts | 11 +- apps/web-antd/src/store/auth.ts | 5 +- .../src/views/_core/authentication/login.vue | 1 + .../components/DoctorOrderModal.vue | 4 +- .../src/views/notice/compoents/detail.vue | 207 ++++++++++-------- apps/web-antd/src/views/notice/index.vue | 178 +++++++-------- package.json | 3 +- .../common-ui/src/ui/authentication/login.vue | 2 +- .../src/request-client/preset-interceptors.ts | 2 +- pnpm-lock.yaml | 26 ++- 14 files changed, 279 insertions(+), 253 deletions(-) diff --git a/apps/web-antd/src/api/request.ts b/apps/web-antd/src/api/request.ts index 672bb4e9..90c8a6a5 100644 --- a/apps/web-antd/src/api/request.ts +++ b/apps/web-antd/src/api/request.ts @@ -13,11 +13,12 @@ import { import { useAccessStore } from '@vben/stores'; import { message } from 'ant-design-vue'; +// eslint-disable-next-line n/no-extraneous-import +import { Base64 } from 'js-base64'; import { useAuthStore } from '#/store'; import { refreshTokenApi } from './core'; -import {Base64} from "js-base64"; const { apiURL } = useAppConfig(import.meta.env, import.meta.env.PROD); @@ -45,7 +46,6 @@ function createRequestClient(baseURL: string) { * 重新认证逻辑 */ async function doReAuthenticate() { - console.warn('Access token or refresh token is invalid or expired. '); const accessStore = useAccessStore(); const authStore = useAuthStore(); accessStore.setAccessToken(null); @@ -55,7 +55,7 @@ function createRequestClient(baseURL: string) { ) { accessStore.setLoginExpired(true); } else { - await authStore.logout(); + await authStore.logout(true); } } @@ -102,7 +102,7 @@ function createRequestClient(baseURL: string) { // 这里吧 data 换成了 result const { code, result } = responseData; // 判断返回状态码 - if (status >= 200 && status < 400) { + if (status >= 200 && status <= 500) { switch (code) { case 0: { // 解密 @@ -113,8 +113,16 @@ function createRequestClient(baseURL: string) { return result; } case 401: { + response.status = 401; // 401 错误,需要重新登录 - return doReAuthenticate(); + authenticateResponseInterceptor({ + client, + doReAuthenticate, + doRefreshToken, + enableRefreshToken: preferences.app.enableRefreshToken, + formatToken, + }); + break; } case 403: case 404: diff --git a/apps/web-antd/src/layouts/basic.vue b/apps/web-antd/src/layouts/basic.vue index 99823d12..d2837e24 100644 --- a/apps/web-antd/src/layouts/basic.vue +++ b/apps/web-antd/src/layouts/basic.vue @@ -60,37 +60,6 @@ const typeBorderColors = { 2: 'border-emerald-200', }; -// const notifications = ref([ -// // TODO 通知列表 -// { -// avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB', -// date: '3小时前', -// isRead: true, -// message: '描述信息描述信息描述信息', -// title: '收到了 14 份新周报', -// }, -// { -// avatar: 'https://avatar.vercel.sh/1', -// date: '刚刚', -// isRead: false, -// message: '描述信息描述信息描述信息', -// title: '朱偏右 回复了你', -// }, -// { -// avatar: 'https://avatar.vercel.sh/1', -// date: '2024-01-01', -// isRead: false, -// message: '描述信息描述信息描述信息', -// title: '曲丽丽 评论了你', -// }, -// { -// avatar: 'https://avatar.vercel.sh/satori', -// date: '1天前', -// isRead: false, -// message: '描述信息描述信息描述信息', -// title: '代办提醒', -// }, -// ]); const notifications = ref([]); // 获取消息列表数据 @@ -99,16 +68,31 @@ const getNoticeList = async () => { const res = await getNoticeListApi({ status: 0, }); - notifications.value = res.items.map(item => ({ - id: item.id, - icon: typeIcons[item.type], - // 将API返回的数据映射到组件需要的格式 - message: item.title, - title: getMessageTypeName(item.type), - date: formatTimeToRelative(item.created_at), - color: typeColors[item.type], - isRead: item.status - })); + let message = '未读消息'; + if (res.items.length > 0) { + if (res.items.length > notifications.value.length) { + if (notifications.value.length === 0) { + message = '新消息'; + } + notification.info({ + message: `您有${message}`, + description: `您有 ${res.items.length} 条${message}请注意查收`, + duration: 5, + }); + } + + notifications.value = res.items.map(item => ({ + id: item.id, + icon: typeIcons[item.type], + // 将API返回的数据映射到组件需要的格式 + message: item.title, + title: getMessageTypeName(item.type), + date: formatTimeToRelative(item.created_at), + color: typeColors[item.type], + isRead: item.status + })); + } + } catch (error) { console.error('获取消息列表失败:', error); } finally { @@ -177,8 +161,8 @@ const goNoticeList = () => { const handleItemClick = (item) => { notifications.value.forEach((value) => { if (value.id === item.id) { - // 删除这个对象 value.status = 1; + value.isRead = 1; } }); router.push(`/notice/detail/${item.id}`); diff --git a/apps/web-antd/src/preferences.ts b/apps/web-antd/src/preferences.ts index ae514845..7c7002b5 100644 --- a/apps/web-antd/src/preferences.ts +++ b/apps/web-antd/src/preferences.ts @@ -11,10 +11,11 @@ export const overridesPreferences = defineOverridesPreferences({ name: import.meta.env.VITE_APP_TITLE, layout: 'sidebar-mixed-nav', // 登录过期模式 - loginExpiredMode: 'modal', + // loginExpiredMode: 'modal', + loginExpiredMode: 'page', // 权限模式 frontend 默认前端控制 backend 后端控制 accessMode: 'backend', - enableRefreshToken: true, + enableRefreshToken: false, defaultAvatar: 'https://yanydy.oss-cn-hangzhou.aliyuncs.com/uploads/20241219/2b38e38414a2b9383b8643983e3f69d7.png', watermark: true, diff --git a/apps/web-antd/src/router/guard.ts b/apps/web-antd/src/router/guard.ts index 6ebbbc2a..92788851 100644 --- a/apps/web-antd/src/router/guard.ts +++ b/apps/web-antd/src/router/guard.ts @@ -109,7 +109,7 @@ function setupAccessGuard(router: Router) { accessStore.setIsAccessChecked(true); const redirectPath = (from.query.redirect ?? (to.path === DEFAULT_HOME_PATH - ? userInfo.homePath || DEFAULT_HOME_PATH + ? userInfo.home_path || DEFAULT_HOME_PATH : to.fullPath)) as string; return { diff --git a/apps/web-antd/src/router/index.ts b/apps/web-antd/src/router/index.ts index 48402303..be2a370a 100644 --- a/apps/web-antd/src/router/index.ts +++ b/apps/web-antd/src/router/index.ts @@ -13,16 +13,19 @@ import { routes } from './routes'; * @zh_CN 创建vue-router实例 */ const router = createRouter({ - history: - import.meta.env.VITE_ROUTER_HISTORY === 'hash' - ? createWebHashHistory(import.meta.env.VITE_BASE) - : createWebHistory(import.meta.env.VITE_BASE), + // 根据环境变量配置选择合适的路由历史模式 + history: import.meta.env.VITE_ROUTER_HISTORY === 'hash' + ? createWebHashHistory(import.meta.env.VITE_BASE) + : createWebHistory(import.meta.env.VITE_BASE), // 应该添加到路由的初始路由列表。 routes, + // 自定义滚动行为以提升用户体验 scrollBehavior: (to, _from, savedPosition) => { + // 如果有保存的位置,则恢复到该位置 if (savedPosition) { return savedPosition; } + // 如果路由带有哈希,则平滑滚动到该哈希对应的元素;否则滚动到页面顶部 return to.hash ? { behavior: 'smooth', el: to.hash } : { left: 0, top: 0 }; }, // 是否应该禁止尾部斜杠。 diff --git a/apps/web-antd/src/store/auth.ts b/apps/web-antd/src/store/auth.ts index 8ec377db..01277549 100644 --- a/apps/web-antd/src/store/auth.ts +++ b/apps/web-antd/src/store/auth.ts @@ -53,10 +53,7 @@ export const useAuthStore = defineStore('auth', () => { userStore.setUserInfo(userInfo); accessStore.setAccessCodes(accessCodes); - console.log(userInfo.home_path); - console.log(DEFAULT_HOME_PATH); - console.log(userInfo.home_path || DEFAULT_HOME_PATH, 'ssssssssssssssss'); - console.log(userInfo.home_path || DEFAULT_HOME_PATH, 'ssssssssssssssss'); + console.log('userInfo', accessStore.loginExpired); if (accessStore.loginExpired) { accessStore.setLoginExpired(false); } else { diff --git a/apps/web-antd/src/views/_core/authentication/login.vue b/apps/web-antd/src/views/_core/authentication/login.vue index f97983d8..fd641d1e 100644 --- a/apps/web-antd/src/views/_core/authentication/login.vue +++ b/apps/web-antd/src/views/_core/authentication/login.vue @@ -10,6 +10,7 @@ import { $t } from '@vben/locales'; import { sendVerificationCode } from '#/api'; import { useAuthStore } from '#/store'; import {message} from "ant-design-vue"; +import {useRouter} from "vue-router"; defineOptions({ name: 'Login' }); diff --git a/apps/web-antd/src/views/doctor/doctor-reception/components/DoctorOrderModal.vue b/apps/web-antd/src/views/doctor/doctor-reception/components/DoctorOrderModal.vue index 68a8c817..70d029fb 100644 --- a/apps/web-antd/src/views/doctor/doctor-reception/components/DoctorOrderModal.vue +++ b/apps/web-antd/src/views/doctor/doctor-reception/components/DoctorOrderModal.vue @@ -136,12 +136,12 @@ function selectDiagnosis(item, type = 1) { - + - + diff --git a/apps/web-antd/src/views/notice/compoents/detail.vue b/apps/web-antd/src/views/notice/compoents/detail.vue index 0741a0a0..8e33d12b 100644 --- a/apps/web-antd/src/views/notice/compoents/detail.vue +++ b/apps/web-antd/src/views/notice/compoents/detail.vue @@ -1,81 +1,76 @@
-
+
-
+
{{ error }} @@ -144,26 +139,35 @@ onMounted(() => {
-
+
-

{{ notice.title }}

+

{{ notice.title }}

- + {{ getTypeInfo(notice.type).name }}
-
+
来自: @@ -176,7 +180,7 @@ onMounted(() => { {{ notice.admin?.nick_name || '系统' }}
-
+
@@ -185,11 +189,11 @@ onMounted(() => {
-
+
-
-
+
+
@@ -197,7 +201,7 @@ onMounted(() => {
-
- -

通知不存在

-

该通知可能已被删除或您没有权限查看

+
+ +

通知不存在

+

该通知可能已被删除或您没有权限查看

@@ -241,4 +245,13 @@ onMounted(() => { :deep(.prose) { white-space: pre-line; } + +/* 暗黑模式特有样式 */ +.dark .bg-gray-750 { + background-color: #1e293b; +} + +.dark .bg-gray-650 { + background-color: #334155; +} diff --git a/apps/web-antd/src/views/notice/index.vue b/apps/web-antd/src/views/notice/index.vue index bce1377f..5c74fc4f 100644 --- a/apps/web-antd/src/views/notice/index.vue +++ b/apps/web-antd/src/views/notice/index.vue @@ -15,8 +15,8 @@ import { Search, X, } from 'lucide-vue-next'; -import {getNoticeListApi, readAllApi, readApi} from "#/views/notice/api"; -import {notification} from "ant-design-vue"; +import { getNoticeListApi, readAllApi, readApi } from "#/views/notice/api"; +import { notification } from "ant-design-vue"; const router = useRouter(); @@ -104,21 +104,21 @@ const typeIcons = { }; const typeColors = { - 0: 'text-sky-500', - 1: 'text-amber-500', - 2: 'text-emerald-500', + 0: 'text-sky-500 dark:text-sky-400', + 1: 'text-amber-500 dark:text-amber-400', + 2: 'text-emerald-500 dark:text-emerald-400', }; const typeBgColors = { - 0: 'bg-sky-50', - 1: 'bg-amber-50', - 2: 'bg-emerald-50', + 0: 'bg-sky-50 dark:bg-sky-900/30', + 1: 'bg-amber-50 dark:bg-amber-900/30', + 2: 'bg-emerald-50 dark:bg-emerald-900/30', }; const typeBorderColors = { - 0: 'border-sky-200', - 1: 'border-amber-200', - 2: 'border-emerald-200', + 0: 'border-sky-200 dark:border-sky-800', + 1: 'border-amber-200 dark:border-amber-800', + 2: 'border-emerald-200 dark:border-emerald-800', }; // 处理消息点击 @@ -130,14 +130,14 @@ const handleItemClick = (item) => { const markAsRead = async (event, item) => { event.stopPropagation(); try { - readApi(item.id).then(() => { - item.status = 1; // 临时更新UI状态 - // 成功后可以重新获取数据或者直接更新本地状态 - notification.success({ - message: '标记成功', - duration: 2, - }); + await readApi(item.id); + item.status = 1; // 临时更新UI状态 + // 成功后可以重新获取数据或者直接更新本地状态 + notification.success({ + message: '标记成功', + duration: 2, }); + getNoticeList(); } catch (error) { console.error('标记已读失败:', error); } @@ -146,19 +146,16 @@ const markAsRead = async (event, item) => { // 标记所有消息为已读 const markAllAsRead = async () => { try { - // 这里应该调用标记全部已读的API - // await markAllAsReadApi(); - readAllApi().then(() => { - messages.value.forEach(msg => { - msg.status = 1; - }); - // 成功后可以重新获取数据或者直接更新本地状态 - notification.success({ - message: '标记成功', - duration: 2, - }); - }) + await readAllApi(); + messages.value.forEach(msg => { + msg.status = 1; + }); // 成功后可以重新获取数据或者直接更新本地状态 + notification.success({ + message: '标记成功', + duration: 2, + }); + getNoticeList(); } catch (error) { console.error('标记全部已读失败:', error); } @@ -205,10 +202,10 @@ const toggleExpand = (event, id) => {