cwg-right-drawer.vue 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. <template>
  2. <view class="notice-container">
  3. <cwg-dropdown ref="dropdownRef" :menu-list="[]">
  4. <view class="pc-header-btn cursor-pointer" :data-tooltip="t('vu.tooltip.t100')">
  5. <cwg-icon name="icon_my" color="#97A1C0" @click="openNotice" />
  6. </view>
  7. <template #btn>
  8. <view class="dropdown-menu dropdown-menu-end w-225px mt-1 show">
  9. <view class="d-flex align-items-center p-2">
  10. <view class="avatar avatar-sm rounded-circle">
  11. <image class="avatar1" src="/static/images/vu/logo.png" mode="aspectFill" />
  12. </view>
  13. <view class="ms-2">
  14. <view class="fw-bold text-dark text-ellipsis mb-2">{{ _displayName }}</view>
  15. <view class="text-body d-block lh-sm text-ellipsis mb-2">{{ _email }}</view>
  16. <text class="cid">CID: <text class="cwg-cursor cursor-pointer cursor-pointer1" :data-tooltip="t('vu.tooltip.t102')" @click="copy(_displayCid)">{{ _displayCid
  17. }}</text></text>
  18. </view>
  19. </view>
  20. <view>
  21. <view class="dropdown-divider my-1"></view>
  22. </view>
  23. <view v-for="item in menuList" :key="item.id">
  24. <view class="dropdown-item user-menu-item d-flex align-items-center gap-2 cursor-pointer cursor-pointer1"
  25. :data-tooltip="t(item.name)"
  26. @click="handleNavigate(item.path)">
  27. <cwg-icon :name="item.icon" :size="16" color="#000" />
  28. <text v-t="item.name"></text>
  29. </view>
  30. </view>
  31. <view>
  32. <view class="dropdown-divider my-1"></view>
  33. </view>
  34. <view>
  35. <view class="dropdown-item d-flex align-items-center gap-2 text-danger cursor-pointer cursor-pointer1" :data-tooltip="t('language.i6')"
  36. @click="handleLogout">
  37. <cwg-icon name="logout" :size="16" color="#FF401C" />
  38. <text v-t="'language.i6'"></text>
  39. </view>
  40. </view>
  41. </view>
  42. </template>
  43. </cwg-dropdown>
  44. </view>
  45. </template>
  46. <script setup lang="ts">
  47. import { ref, watch, onMounted, computed } from 'vue'
  48. import { onLoad, onShow, onLaunch } from '@dcloudio/uni-app'
  49. import useRoute from '@/hooks/useRoute'
  50. import useUserStore from '@/stores/use-user-store'
  51. import { userApi } from '@/api/user'
  52. import { useI18n } from "vue-i18n"
  53. import useRouter from "@/hooks/useRouter"
  54. import useGlobalStore from '@/stores/use-global-store'
  55. const globalStore = useGlobalStore()
  56. const isDark = computed(() => globalStore.theme === 'dark')
  57. const { t } = useI18n()
  58. const router = useRouter()
  59. const dropdownRef = ref(null)
  60. const userStore = useUserStore()
  61. const route = useRoute()
  62. // 强制用 ref 让插槽能渲染
  63. const menuList = ref([])
  64. const _displayName = ref('--')
  65. const _displayCid = ref('--')
  66. const _activePath = ref('')
  67. const _email = ref('--')
  68. // 复制文本
  69. const copy = (text: string) => {
  70. uni.setClipboardData({
  71. data: text,
  72. success: function () {
  73. uni.showToast({
  74. title: t('Btn.item8'),
  75. icon: 'none',
  76. duration: 2000
  77. });
  78. }
  79. });
  80. };
  81. // 初始化菜单
  82. function initMenu() {
  83. menuList.value = [
  84. { id: 1, path: '/pages/mine/info?type=1', name: 'PersonalManagement.Title.PersonalInformation', icon: 'crm-circle-user' },
  85. { id: 2, path: '/pages/mine/info?type=2', name: 'PersonalManagement.Title.BankInformation', icon: 'crm-building-columns' },
  86. { id: 3, path: '/pages/mine/info?type=3', name: 'PersonalManagement.Title.FileManagement', icon: 'crm-file' },
  87. { id: 4, path: '/pages/mine/info?type=4', name: 'PersonalManagement.Title.SecurityCenter', icon: 'crm-lock' },
  88. ]
  89. }
  90. // 强制同步用户信息
  91. function syncUserInfo() {
  92. const info = userStore.userInfo?.customInfo || {}
  93. const firstName = info.firstName || ''
  94. const lastName = info.lastName || ''
  95. _displayName.value = (firstName + ' ' + lastName).trim() || info.name || info.email || '--'
  96. _displayCid.value = info.cId || info.id || '--'
  97. _email.value = info.email || '--'
  98. }
  99. // 强制同步路径
  100. function syncPath() {
  101. _activePath.value = route.path + (route.query?.type ? `?type=${route.query.type}` : '')
  102. }
  103. onMounted(() => {
  104. initMenu()
  105. syncUserInfo()
  106. syncPath()
  107. })
  108. onShow(() => {
  109. initMenu()
  110. syncUserInfo()
  111. syncPath()
  112. })
  113. // 监听变化自动更新
  114. watch(() => userStore.userInfo, () => {
  115. syncUserInfo()
  116. }, { deep: true })
  117. watch(() => route, () => {
  118. syncPath()
  119. }, { deep: true })
  120. // 打开抽屉
  121. function openNotice() {
  122. // dropdownRef.value?.open()
  123. }
  124. // 关闭
  125. function close() {
  126. dropdownRef.value?.close()
  127. }
  128. // 跳转
  129. function handleNavigate(path) {
  130. router.push({ path })
  131. close()
  132. }
  133. // 登出
  134. async function handleLogout() {
  135. try {
  136. await userApi.logout()
  137. } catch (e) { }
  138. userStore.clearUserInfo()
  139. uni.setStorageSync('logoutToSystem', 1)
  140. // uni.$emit('updateSystemList')
  141. router.push('/pages/login/index')
  142. close()
  143. }
  144. defineExpose({ openNotice, close })
  145. </script>
  146. <style scoped lang="scss">
  147. @import "@/uni.scss";
  148. .notice-container {
  149. .text-ellipsis {
  150. display: block !important;
  151. white-space: normal !important;
  152. word-wrap: break-word !important;
  153. word-break: break-all !important;
  154. overflow: visible !important;
  155. text-overflow: unset !important;
  156. }
  157. :deep(.cwg-dropdown-menu-container) {
  158. left: px2rpx(-190) !important;
  159. right: px2rpx(0) !important;
  160. .menu {
  161. border: 0;
  162. overflow: visible;
  163. }
  164. }
  165. @media screen and (max-width: 991px) {
  166. :deep(.cwg-dropdown-menu-container) {
  167. left: px2rpx(-190) !important;
  168. max-width: px2rpx(400);
  169. }
  170. }
  171. .pc-header-btn {
  172. position: relative;
  173. }
  174. .user-menu-item {
  175. color: var(--bs-emphasis-color);
  176. text {
  177. color: var(--bs-emphasis-color);
  178. }
  179. }
  180. .right-drawer {
  181. width: px2rpx(300);
  182. background-color: rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important;
  183. display: flex;
  184. flex-direction: column;
  185. padding: px2rpx(20) px2rpx(16);
  186. box-sizing: border-box;
  187. }
  188. .drawer-header {
  189. display: flex;
  190. align-items: center;
  191. gap: px2rpx(12);
  192. padding: px2rpx(20);
  193. border-bottom: 1px solid #d9dde5;
  194. }
  195. .avatar1 {
  196. width: px2rpx(40);
  197. height: px2rpx(40);
  198. border-radius: 50%;
  199. // background: #fff;
  200. }
  201. .user-info {
  202. display: flex;
  203. flex-direction: column;
  204. gap: px2rpx(6);
  205. }
  206. .name {
  207. font-size: px2rpx(22);
  208. font-weight: 600;
  209. color: var(--bs-heading-color);
  210. }
  211. .cid {
  212. font-size: px2rpx(14);
  213. color: #ef4444;
  214. }
  215. .menu-list {
  216. padding: px2rpx(12) 0;
  217. }
  218. .menu-item {
  219. height: px2rpx(48);
  220. display: flex;
  221. align-items: center;
  222. gap: px2rpx(10);
  223. padding: 0 px2rpx(16);
  224. color: var(--bs-heading-color);
  225. font-size: px2rpx(16);
  226. font-weight: 600;
  227. &:hover {
  228. background-color: rgba(0, 0, 0, 0.05);
  229. }
  230. }
  231. .menu-item.active {
  232. background: rgba(108, 133, 149, 0.12) !important;
  233. border-radius: 0.125rem;
  234. }
  235. .logout-wrap {
  236. margin-top: auto;
  237. padding: px2rpx(20);
  238. margin-bottom: px2rpx(20);
  239. }
  240. .logout-btn {
  241. height: px2rpx(44);
  242. background-color: var(--bs-btn-bg);
  243. display: flex;
  244. align-items: center;
  245. justify-content: center;
  246. gap: px2rpx(8);
  247. color: #fff;
  248. font-weight: 600;
  249. font-size: px2rpx(16);
  250. cursor: pointer;
  251. }
  252. }
  253. </style>