App.vue 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <template>
  2. <router-view />
  3. <Notify v-model:show="notify.show" :title="notify.title" :content="notify.content" />
  4. <Dialog class="g-dialog-message" v-model:show="message.show" theme="round-button" :confirm-button-text="$t('app.close')">
  5. <template #title>
  6. <div class="g-dialog-message__header">
  7. <h4>{{ currentMessage?.title }}</h4>
  8. <span>{{ formatDate(currentMessage?.createtime) }}</span>
  9. </div>
  10. </template>
  11. <div class="g-dialog-message__content" v-html="currentMessage?.content"></div>
  12. <div class="g-dialog-message__footer" v-if="message.dataList.length > 1">
  13. <span :class="{ disabled: message.index === 0 }" @click="changeMessage(-1)">{{ $t('app.pervious') }}</span>
  14. <span :class="{ disabled: message.index === (message.dataList.length - 1) }" @click="changeMessage(1)">{{ $t('app.next') }}</span>
  15. </div>
  16. </Dialog>
  17. </template>
  18. <script lang="ts" setup>
  19. import { reactive, computed, onMounted, PropType, watch } from 'vue'
  20. import { Locale, Dialog } from 'vant'
  21. import { dialog } from '@/utils/vant'
  22. import { formatDate } from '@/filters'
  23. import { useLogin } from '@/business/login'
  24. import { Language } from '@/constants/language'
  25. import { useNavigation } from './router/navigation'
  26. import { i18n, useNoticeStore, useLoginStore } from '@/stores'
  27. import eventBus from '@/services/bus'
  28. import plus from '@/utils/h5plus'
  29. import Notify from '@mobile/components/base/notify/index.vue'
  30. import enUS from 'vant/es/locale/lang/en-US'
  31. import zhCN from 'vant/es/locale/lang/zh-CN'
  32. import thTH from 'vant/es/locale/lang/th-TH'
  33. import zhTW from 'vant/es/locale/lang/zh-TW'
  34. import viVN from 'vant/es/locale/lang/vi-VN'
  35. const props = defineProps({
  36. statusBarStyle: {
  37. type: String as PropType<'dark' | 'light'>,
  38. default: 'light'
  39. },
  40. // 是否弹出未读消息
  41. showUnread: {
  42. type: Boolean,
  43. default: true
  44. }
  45. })
  46. const { t, locale } = i18n.global
  47. // 多语言列表
  48. const languageMap = {
  49. [Language.Simplified]: zhCN,
  50. [Language.English]: enUS,
  51. [Language.Traditional]: zhTW,
  52. [Language.Thai]: thTH,
  53. [Language.Vietnamese]: viVN
  54. }
  55. if (locale in languageMap) {
  56. Locale.use(locale, languageMap[locale])
  57. } else {
  58. Locale.use('en-US', enUS)
  59. }
  60. const { userLogout } = useLogin()
  61. const { backHome } = useNavigation()
  62. const loginStore = useLoginStore()
  63. const noticeStore = useNoticeStore()
  64. // 消息弹窗
  65. const message = reactive({
  66. show: false,
  67. dataList: [] as Model.NoticeRsp[],
  68. index: 0
  69. })
  70. // 当前消息
  71. const currentMessage = computed(() => message.dataList[message.index])
  72. // 切换消息
  73. const changeMessage = (value: number) => {
  74. const i = message.index + value
  75. if (i > -1 && i < message.dataList.length) {
  76. message.index = i
  77. noticeStore.updateNoticeReaded(currentMessage.value.autoid)
  78. }
  79. }
  80. // 浮动通知
  81. const notify = reactive({
  82. show: false,
  83. title: '',
  84. content: ''
  85. })
  86. // 接收风控通知
  87. eventBus.$on('RiskToWebNtf', (msg, type) => {
  88. const res = msg as { title: string, content: string }
  89. if (type === 1) {
  90. notify.title = res.title
  91. notify.content = res.content
  92. notify.show = true
  93. } else {
  94. dialog({
  95. title: res.title,
  96. message: res.content,
  97. confirmButtonText: t('operation.confirm')
  98. })
  99. }
  100. })
  101. // 接收用户登出通知
  102. eventBus.$on('LogoutNotify', (msg) => {
  103. userLogout(() => {
  104. if (msg) {
  105. dialog({
  106. message: msg as string,
  107. confirmButtonText: t('operation.confirm')
  108. }).then(() => {
  109. backHome()
  110. })
  111. } else {
  112. backHome()
  113. }
  114. })
  115. })
  116. watch(() => noticeStore.isInitialized, () => {
  117. const readKey = 'read_' + loginStore.loginId
  118. const readValue = formatDate(new Date().toISOString(), 'YYYY-MM-DD')
  119. const localValue = localStorage.getItem(readKey)
  120. const showUnread = props.showUnread && localValue !== readValue // 未读消息一天内只会弹框一次
  121. // 过滤数据
  122. const filteredData = noticeStore.noticeList.filter((e) => (showUnread && !e.readed) || e.isforcedisplay)
  123. // 浅拷贝,防止数据引用
  124. message.dataList = filteredData.map((e) => ({ ...e }))
  125. if (message.dataList.length) {
  126. localStorage.setItem(readKey, readValue) // 记录用户已读日期
  127. message.index = 0
  128. message.show = true
  129. noticeStore.updateNoticeReaded(message.dataList[0].autoid)
  130. }
  131. })
  132. onMounted(() => plus.setStatusBarStyle(props.statusBarStyle))
  133. </script>