index.vue 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <script lang="ts" setup>
  2. import { useSettingsStore } from '@/store/modules/settings'
  3. import { translate } from '@/i18n'
  4. import { getList, getAllRead, getRead } from '@/api/notice'
  5. const VabNoticeDetail = defineAsyncComponent(
  6. () => import('./VabNoticeDetail.vue')
  7. )
  8. const $baseMessage: any = inject('$baseMessage')
  9. const settingsStore = useSettingsStore()
  10. const { theme } = storeToRefs(settingsStore)
  11. const activeName = ref('no-read')
  12. const notices: any = ref([])
  13. const badge = ref(undefined)
  14. const isRead = ref(0)
  15. const infoDetail: any = ref(null)
  16. const fetchData = async () => {
  17. const {
  18. data: { data, meta },
  19. } = await getList({
  20. guard: 'admins',
  21. is_read: isRead.value,
  22. })
  23. notices.value = data
  24. if (isRead.value === 0)
  25. badge.value =
  26. meta.pagination.total === 0 ? undefined : meta.pagination.total
  27. }
  28. const allRead = async () => {
  29. await getAllRead({
  30. guard: 'admins',
  31. })
  32. $baseMessage('清空消息成功', 'success', 'vab-hey-message-success')
  33. await fetchData()
  34. }
  35. const handleRead = async (id: any) => {
  36. await getRead({
  37. guard: 'admins',
  38. id: id,
  39. })
  40. $baseMessage('标记成功', 'success', 'vab-hey-message-success')
  41. await fetchData()
  42. }
  43. nextTick(() => {
  44. if (theme.value.showNotice) fetchData()
  45. })
  46. const handleClick = () => {
  47. if (activeName.value == 'no-read') {
  48. isRead.value = 0
  49. } else {
  50. isRead.value = 1
  51. }
  52. badge.value = undefined
  53. notices.value = []
  54. fetchData()
  55. }
  56. const handleClearNotice = () => {
  57. badge.value = undefined
  58. notices.value = []
  59. allRead()
  60. }
  61. const handleDetail = (row: any) => {
  62. infoDetail.value.showEdit(row)
  63. }
  64. </script>
  65. <template>
  66. <el-badge v-if="theme.showNotice" type="danger" :value="badge">
  67. <el-popover placement="bottom" trigger="hover" :width="300">
  68. <template #reference>
  69. <vab-icon icon="notification-line" />
  70. </template>
  71. <el-tabs v-model="activeName" @tab-change="handleClick">
  72. <el-tab-pane label="未读" name="no-read" />
  73. <el-tab-pane label="已读" name="is_read" />
  74. <div class="notice-list">
  75. <el-scrollbar>
  76. <ul>
  77. <li v-for="(item, index) in notices" :key="index">
  78. <span class="detail-tip">【{{ item.name }}】</span>
  79. <span>{{ item.body }}</span>
  80. <span class="detail-tip" @click="handleDetail(item)">
  81. &nbsp;&nbsp; 详情>>
  82. </span>
  83. <div class="time">
  84. <div class="time-item">{{ item.created_at }}</div>
  85. <div
  86. v-if="isRead == 0"
  87. class="biaoji"
  88. @click.stop="handleRead(item.id)"
  89. >
  90. 标记已读
  91. </div>
  92. </div>
  93. </li>
  94. </ul>
  95. <el-empty
  96. v-if="notices.length == 0"
  97. description="暂无消息"
  98. :image-size="60"
  99. />
  100. </el-scrollbar>
  101. </div>
  102. </el-tabs>
  103. <div
  104. v-if="isRead == 0 && badge"
  105. class="notice-clear"
  106. @click="handleClearNotice"
  107. >
  108. <el-button text type="primary">
  109. <span>{{ translate('全部已读') }}</span>
  110. </el-button>
  111. </div>
  112. </el-popover>
  113. </el-badge>
  114. <VabNoticeDetail ref="infoDetail" />
  115. </template>
  116. <style lang="scss" scoped>
  117. :deep() {
  118. .el-tabs__active-bar {
  119. min-width: 28px;
  120. }
  121. }
  122. .notice-list {
  123. height: 35vh;
  124. ul {
  125. padding: 0 15px 0 0;
  126. margin: 0;
  127. li {
  128. /* display: flex;
  129. align-items: center; */
  130. padding: 10px 0 10px 0;
  131. cursor: pointer;
  132. border-bottom: dashed 1px #bbbbbb;
  133. :deep() {
  134. .el-avatar {
  135. flex-shrink: 0;
  136. width: 50px;
  137. height: 50px;
  138. border-radius: 50%;
  139. }
  140. }
  141. .detail-tip {
  142. font-size: 14px;
  143. color: #ff4d4f;
  144. }
  145. .time {
  146. display: flex;
  147. margin-top: 6px;
  148. font-size: 12px;
  149. color: #919191;
  150. .time-item {
  151. flex: 1;
  152. }
  153. .biaoji {
  154. flex: 1;
  155. text-align: right;
  156. color: #409eff;
  157. cursor: pointer;
  158. }
  159. }
  160. &:last-child {
  161. border-bottom: none;
  162. }
  163. }
  164. }
  165. }
  166. .notice-clear {
  167. display: flex;
  168. align-items: center;
  169. justify-content: center;
  170. padding: 10px 0 0 0;
  171. font-size: 14px;
  172. text-align: center;
  173. cursor: pointer;
  174. border-top: 1px solid #e8eaec;
  175. i {
  176. margin-right: 3px;
  177. }
  178. }
  179. </style>