basic.vue 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. <script lang="ts" setup>
  2. import type { NotificationItem } from '@vben/layouts';
  3. import { computed, ref, watch } from 'vue';
  4. import { useRouter } from 'vue-router';
  5. import { AuthenticationLoginExpiredModal } from '@vben/common-ui';
  6. import { VBEN_DOC_URL, VBEN_GITHUB_URL } from '@vben/constants';
  7. import { useWatermark } from '@vben/hooks';
  8. import { BookOpenText, CircleHelp, SvgGithubIcon } from '@vben/icons';
  9. import {
  10. BasicLayout,
  11. LockScreen,
  12. Notification,
  13. UserDropdown,
  14. } from '@vben/layouts';
  15. import { preferences } from '@vben/preferences';
  16. import { useAccessStore, useUserStore } from '@vben/stores';
  17. import { openWindow } from '@vben/utils';
  18. import { $t } from '#/locales';
  19. import { useAuthStore } from '#/store';
  20. import LoginForm from '#/views/_core/authentication/login.vue';
  21. const notifications = ref<NotificationItem[]>([
  22. {
  23. id: 1,
  24. avatar: 'https://avatar.vercel.sh/vercel.svg?text=VB',
  25. date: '3小时前',
  26. isRead: true,
  27. message: '描述信息描述信息描述信息',
  28. title: '收到了 14 份新周报',
  29. },
  30. {
  31. id: 2,
  32. avatar: 'https://avatar.vercel.sh/1',
  33. date: '刚刚',
  34. isRead: false,
  35. message: '描述信息描述信息描述信息',
  36. title: '朱偏右 回复了你',
  37. },
  38. {
  39. id: 3,
  40. avatar: 'https://avatar.vercel.sh/1',
  41. date: '2024-01-01',
  42. isRead: false,
  43. message: '描述信息描述信息描述信息',
  44. title: '曲丽丽 评论了你',
  45. },
  46. {
  47. id: 4,
  48. avatar: 'https://avatar.vercel.sh/satori',
  49. date: '1天前',
  50. isRead: false,
  51. message: '描述信息描述信息描述信息',
  52. title: '代办提醒',
  53. },
  54. {
  55. id: 5,
  56. avatar: 'https://avatar.vercel.sh/satori',
  57. date: '1天前',
  58. isRead: false,
  59. message: '描述信息描述信息描述信息',
  60. title: '跳转Workspace示例',
  61. link: '/workspace',
  62. },
  63. {
  64. id: 6,
  65. avatar: 'https://avatar.vercel.sh/satori',
  66. date: '1天前',
  67. isRead: false,
  68. message: '描述信息描述信息描述信息',
  69. title: '跳转外部链接示例',
  70. link: 'https://doc.vben.pro',
  71. },
  72. ]);
  73. const router = useRouter();
  74. const userStore = useUserStore();
  75. const authStore = useAuthStore();
  76. const accessStore = useAccessStore();
  77. const { destroyWatermark, updateWatermark } = useWatermark();
  78. const showDot = computed(() =>
  79. notifications.value.some((item) => !item.isRead),
  80. );
  81. const menus = computed(() => [
  82. {
  83. handler: () => {
  84. router.push({ name: 'Profile' });
  85. },
  86. icon: 'lucide:user',
  87. text: $t('page.auth.profile'),
  88. },
  89. {
  90. handler: () => {
  91. openWindow(VBEN_DOC_URL, {
  92. target: '_blank',
  93. });
  94. },
  95. icon: BookOpenText,
  96. text: $t('ui.widgets.document'),
  97. },
  98. {
  99. handler: () => {
  100. openWindow(VBEN_GITHUB_URL, {
  101. target: '_blank',
  102. });
  103. },
  104. icon: SvgGithubIcon,
  105. text: 'GitHub',
  106. },
  107. {
  108. handler: () => {
  109. openWindow(`${VBEN_GITHUB_URL}/issues`, {
  110. target: '_blank',
  111. });
  112. },
  113. icon: CircleHelp,
  114. text: $t('ui.widgets.qa'),
  115. },
  116. ]);
  117. const avatar = computed(() => {
  118. return userStore.userInfo?.avatar ?? preferences.app.defaultAvatar;
  119. });
  120. async function handleLogout() {
  121. await authStore.logout(false);
  122. }
  123. function handleNoticeClear() {
  124. notifications.value = [];
  125. }
  126. function markRead(id: number | string) {
  127. const item = notifications.value.find((item) => item.id === id);
  128. if (item) {
  129. item.isRead = true;
  130. }
  131. }
  132. function remove(id: number | string) {
  133. notifications.value = notifications.value.filter((item) => item.id !== id);
  134. }
  135. function handleMakeAll() {
  136. notifications.value.forEach((item) => (item.isRead = true));
  137. }
  138. watch(
  139. () => ({
  140. enable: preferences.app.watermark,
  141. content: preferences.app.watermarkContent,
  142. }),
  143. async ({ enable, content }) => {
  144. if (enable) {
  145. await updateWatermark({
  146. content:
  147. content ||
  148. `${userStore.userInfo?.username} - ${userStore.userInfo?.realName}`,
  149. });
  150. } else {
  151. destroyWatermark();
  152. }
  153. },
  154. {
  155. immediate: true,
  156. },
  157. );
  158. </script>
  159. <template>
  160. <BasicLayout @clear-preferences-and-logout="handleLogout">
  161. <template #user-dropdown>
  162. <UserDropdown
  163. :avatar
  164. :menus
  165. :text="userStore.userInfo?.realName"
  166. description="ann.vben@gmail.com"
  167. tag-text="Pro"
  168. @logout="handleLogout"
  169. />
  170. </template>
  171. <template #notification>
  172. <Notification
  173. :dot="showDot"
  174. :notifications="notifications"
  175. @clear="handleNoticeClear"
  176. @read="(item) => item.id && markRead(item.id)"
  177. @remove="(item) => item.id && remove(item.id)"
  178. @make-all="handleMakeAll"
  179. />
  180. </template>
  181. <template #extra>
  182. <AuthenticationLoginExpiredModal
  183. v-model:open="accessStore.loginExpired"
  184. :avatar
  185. >
  186. <LoginForm />
  187. </AuthenticationLoginExpiredModal>
  188. </template>
  189. <template #lock-screen>
  190. <LockScreen :avatar @to-login="handleLogout" />
  191. </template>
  192. </BasicLayout>
  193. </template>