index.vue 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <script setup lang="ts">
  2. import { getMine } from "@/api/user";
  3. import { useRouter } from "vue-router";
  4. import { ref, onBeforeMount } from "vue";
  5. import { ReText } from "@/components/ReText";
  6. import Profile from "./components/Profile.vue";
  7. import Preferences from "./components/Preferences.vue";
  8. import SecurityLog from "./components/SecurityLog.vue";
  9. import { useGlobal, deviceDetection } from "@pureadmin/utils";
  10. import AccountManagement from "./components/AccountManagement.vue";
  11. import { useDataThemeChange } from "@/layout/hooks/useDataThemeChange";
  12. import LaySidebarTopCollapse from "@/layout/components/lay-sidebar/components/SidebarTopCollapse.vue";
  13. import leftLine from "~icons/ri/arrow-left-s-line";
  14. import ProfileIcon from "~icons/ri/user-3-line";
  15. import PreferencesIcon from "~icons/ri/settings-3-line";
  16. import SecurityLogIcon from "~icons/ri/window-line";
  17. import AccountManagementIcon from "~icons/ri/profile-line";
  18. defineOptions({
  19. name: "AccountSettings"
  20. });
  21. const router = useRouter();
  22. const isOpen = ref(deviceDetection() ? false : true);
  23. const { $storage } = useGlobal<GlobalPropertiesApi>();
  24. onBeforeMount(() => {
  25. useDataThemeChange().dataThemeChange($storage.layout?.overallStyle);
  26. });
  27. const userInfo = ref({
  28. avatar: "",
  29. username: "",
  30. nickname: ""
  31. });
  32. const panes = [
  33. {
  34. key: "profile",
  35. label: "个人信息",
  36. icon: ProfileIcon,
  37. component: Profile
  38. },
  39. {
  40. key: "preferences",
  41. label: "偏好设置",
  42. icon: PreferencesIcon,
  43. component: Preferences
  44. },
  45. {
  46. key: "securityLog",
  47. label: "安全日志",
  48. icon: SecurityLogIcon,
  49. component: SecurityLog
  50. },
  51. {
  52. key: "accountManagement",
  53. label: "账户管理",
  54. icon: AccountManagementIcon,
  55. component: AccountManagement
  56. }
  57. ];
  58. const witchPane = ref("profile");
  59. getMine().then(res => {
  60. userInfo.value = res.data;
  61. });
  62. </script>
  63. <template>
  64. <el-container class="h-full">
  65. <el-aside
  66. v-if="isOpen"
  67. class="pure-account-settings overflow-hidden px-2 dark:bg-(--el-bg-color)! border-r-[1px] border-[var(--pure-border-color)]"
  68. :width="deviceDetection() ? '180px' : '240px'"
  69. >
  70. <el-menu :default-active="witchPane" class="pure-account-settings-menu">
  71. <div
  72. class="h-[50px]! text-[var(--pure-theme-menu-text)] cursor-pointer text-sm transition-all duration-300 ease-in-out hover:scale-105 will-change-transform transform-gpu origin-center hover:text-base! hover:text-[var(--pure-theme-menu-title-hover)]!"
  73. @click="router.go(-1)"
  74. >
  75. <div
  76. class="h-full flex items-center px-[var(--el-menu-base-level-padding)]"
  77. >
  78. <IconifyIconOffline :icon="leftLine" />
  79. <span class="ml-2">返回</span>
  80. </div>
  81. </div>
  82. <div class="flex items-center ml-8 mt-4 mb-4">
  83. <el-avatar :size="48" :src="userInfo.avatar" />
  84. <div class="ml-4 flex flex-col max-w-[130px]">
  85. <ReText class="font-bold self-baseline!">
  86. {{ userInfo.nickname }}
  87. </ReText>
  88. <ReText class="self-baseline!" type="info">
  89. {{ userInfo.username }}
  90. </ReText>
  91. </div>
  92. </div>
  93. <el-menu-item
  94. v-for="item in panes"
  95. :key="item.key"
  96. :index="item.key"
  97. @click="
  98. () => {
  99. witchPane = item.key;
  100. if (deviceDetection()) {
  101. isOpen = !isOpen;
  102. }
  103. }
  104. "
  105. >
  106. <div class="flex items-center z-10">
  107. <el-icon><IconifyIconOffline :icon="item.icon" /></el-icon>
  108. <span>{{ item.label }}</span>
  109. </div>
  110. </el-menu-item>
  111. </el-menu>
  112. </el-aside>
  113. <el-main>
  114. <LaySidebarTopCollapse
  115. v-if="deviceDetection()"
  116. class="px-0"
  117. :is-active="isOpen"
  118. @toggleClick="isOpen = !isOpen"
  119. />
  120. <component
  121. :is="panes.find(item => item.key === witchPane).component"
  122. :class="[!deviceDetection() && 'ml-[120px]']"
  123. />
  124. </el-main>
  125. </el-container>
  126. </template>
  127. <style lang="scss">
  128. .pure-account-settings {
  129. background: var(--pure-theme-menu-bg) !important;
  130. }
  131. .pure-account-settings-menu {
  132. background-color: transparent;
  133. border: none;
  134. .el-menu-item {
  135. height: 48px !important;
  136. color: var(--pure-theme-menu-text);
  137. background-color: transparent !important;
  138. transition: color 0.2s;
  139. &:hover {
  140. color: var(--pure-theme-menu-title-hover) !important;
  141. }
  142. &.is-active {
  143. color: #fff !important;
  144. &:hover {
  145. color: #fff !important;
  146. }
  147. &::before {
  148. position: absolute;
  149. inset: 0 8px;
  150. clear: both;
  151. margin: 4px 0;
  152. content: "";
  153. background: var(--el-color-primary);
  154. border-radius: 3px;
  155. }
  156. }
  157. }
  158. }
  159. </style>
  160. <style lang="scss" scoped>
  161. body[layout] {
  162. .el-menu--vertical .is-active {
  163. color: #fff !important;
  164. transition: color 0.2s;
  165. &:hover {
  166. color: #fff !important;
  167. }
  168. }
  169. }
  170. </style>