NotificationView.vue 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <template>
  2. <div class="app-page">
  3. <section class="glass-card section-card">
  4. <div class="table-toolbar">
  5. <div class="chip-list">
  6. <el-button type="primary" @click="openSend">发送通知</el-button>
  7. </div>
  8. <el-form :model="filters" inline>
  9. <el-form-item label="类型">
  10. <el-select v-model="filters.type" placeholder="全部" clearable style="width:120px">
  11. <el-option label="系统通知" value="系统通知" />
  12. <el-option label="业务通知" value="业务通知" />
  13. <el-option label="待办提醒" value="待办提醒" />
  14. <el-option label="公告" value="公告" />
  15. </el-select>
  16. </el-form-item>
  17. <el-form-item label="状态">
  18. <el-select v-model="filters.readStatus" placeholder="全部" clearable style="width:120px">
  19. <el-option label="未读" value="unread" />
  20. <el-option label="已读" value="read" />
  21. </el-select>
  22. </el-form-item>
  23. </el-form>
  24. </div>
  25. </section>
  26. <section class="glass-card section-card">
  27. <el-table :data="filteredItems" style="width:100%" v-loading="loading">
  28. <el-table-column type="selection" width="45" />
  29. <el-table-column prop="type" label="类型" width="100">
  30. <template #default="{ row }">
  31. <el-tag :type="getNotificationType(row.type).type" size="small">{{ getNotificationType(row.type).label }}</el-tag>
  32. </template>
  33. </el-table-column>
  34. <el-table-column prop="title" label="标题" min-width="250" />
  35. <el-table-column prop="content" label="内容" min-width="300" show-overflow-tooltip />
  36. <el-table-column prop="sender" label="发送人" width="100" />
  37. <el-table-column prop="time" label="时间" width="160" />
  38. <el-table-column prop="readStatus" label="状态" width="80">
  39. <template #default="{ row }">
  40. <el-tag :type="getNotificationStatus(row.readStatus).type" size="small">{{ getNotificationStatus(row.readStatus).label }}</el-tag>
  41. </template>
  42. </el-table-column>
  43. <el-table-column label="操作" width="120" fixed="right">
  44. <template #default="{ row }">
  45. <el-button link type="primary" @click="openDetail(row)">查看</el-button>
  46. <el-button link type="danger" @click="deleteNotice(row)">删除</el-button>
  47. </template>
  48. </el-table-column>
  49. <template #empty>
  50. <el-empty description="暂无数据" />
  51. </template>
  52. </el-table>
  53. </section>
  54. <el-dialog v-model="sendDialogVisible" title="发送通知" width="500px" destroy-on-close>
  55. <el-form :model="sendForm" label-width="80px">
  56. <el-form-item label="接收人" required>
  57. <el-select v-model="sendForm.receiverType" placeholder="选择接收范围" style="width:100%">
  58. <el-option label="全部用户" value="all" />
  59. <el-option label="指定角色" value="role" />
  60. <el-option label="指定用户" value="user" />
  61. </el-select>
  62. </el-form-item>
  63. <el-form-item label="消息类型" required>
  64. <el-select v-model="sendForm.type" placeholder="选择类型" style="width:100%">
  65. <el-option label="系统通知" value="系统通知" />
  66. <el-option label="业务通知" value="业务通知" />
  67. <el-option label="待办提醒" value="待办提醒" />
  68. <el-option label="公告" value="公告" />
  69. </el-select>
  70. </el-form-item>
  71. <el-form-item label="标题" required>
  72. <el-input v-model="sendForm.title" placeholder="通知标题" />
  73. </el-form-item>
  74. <el-form-item label="内容" required>
  75. <el-input v-model="sendForm.content" type="textarea" :rows="4" placeholder="通知内容" />
  76. </el-form-item>
  77. <el-form-item label="重要">
  78. <el-switch v-model="sendForm.important" />
  79. </el-form-item>
  80. </el-form>
  81. <template #footer>
  82. <el-button @click="sendDialogVisible = false">取消</el-button>
  83. <el-button type="primary" @click="confirmSend">发送</el-button>
  84. </template>
  85. </el-dialog>
  86. <el-dialog v-model="detailDialogVisible" title="通知详情" width="500px">
  87. <el-descriptions :column="1" border v-if="detailItem">
  88. <el-descriptions-item label="类型">
  89. <el-tag :type="getNotificationType(detailItem.type).type" size="small">{{ getNotificationType(detailItem.type).label }}</el-tag>
  90. </el-descriptions-item>
  91. <el-descriptions-item label="标题">{{ detailItem.title }}</el-descriptions-item>
  92. <el-descriptions-item label="内容">{{ detailItem.content }}</el-descriptions-item>
  93. <el-descriptions-item label="发送人">{{ detailItem.sender }}</el-descriptions-item>
  94. <el-descriptions-item label="时间">{{ detailItem.time }}</el-descriptions-item>
  95. </el-descriptions>
  96. <template #footer>
  97. <el-button @click="detailDialogVisible = false">关闭</el-button>
  98. </template>
  99. </el-dialog>
  100. </div>
  101. </template>
  102. <script setup lang="ts">
  103. import { computed, onMounted, reactive, ref } from 'vue';
  104. import { ElMessage, ElMessageBox } from 'element-plus';
  105. import { getNotificationType, getNotificationStatus } from '@/utils/enumMappings';
  106. interface NoticeItem {
  107. id: string;
  108. type: string;
  109. title: string;
  110. content: string;
  111. sender: string;
  112. time: string;
  113. readStatus: string;
  114. }
  115. const items = ref<NoticeItem[]>([
  116. { id: 'N001', type: '系统通知', title: '系统维护公告', content: '平台将于2026-04-25 02:00-04:00进行系统维护,届时部分功能将暂停使用。', sender: '系统管理员', time: '2026-04-20 10:00:00', readStatus: '未读' },
  117. { id: 'N002', type: '业务通知', title: '新订单提醒', content: '您有5笔新订单待处理,请及时登录系统查看。', sender: 'OMS系统', time: '2026-04-20 09:30:00', readStatus: '未读' },
  118. { id: 'N003', type: '待办提醒', title: '采购单待审批', content: '您有待审批的采购单 PO-20260420-003,请及时处理。', sender: '采购系统', time: '2026-04-20 09:00:00', readStatus: '已读' },
  119. { id: 'N004', type: '公告', title: '五一劳动节放假安排', content: '五一假期期间(5月1日-5月5日),仓库暂停发货,4月30日中午12点后的订单将于5月6日起陆续发货。', sender: '运营部', time: '2026-04-19 15:00:00', readStatus: '已读' },
  120. { id: 'N005', type: '业务通知', title: '库存预警', content: 'SKU-LUGG-20-BLK 当前库存15件,低于安全库存50件,请及时补货。', sender: '库存系统', time: '2026-04-19 14:30:00', readStatus: '已读' }
  121. ]);
  122. const loading = ref(false);
  123. const sendDialogVisible = ref(false);
  124. const detailDialogVisible = ref(false);
  125. const detailItem = ref<NoticeItem | null>(null);
  126. const filters = ref({ type: '', readStatus: '' });
  127. const sendForm = reactive({
  128. receiverType: 'all',
  129. type: '',
  130. title: '',
  131. content: '',
  132. important: false
  133. });
  134. const filteredItems = computed(() => {
  135. return items.value.filter(item => {
  136. if (filters.value.type && item.type !== filters.value.type) return false;
  137. if (filters.value.readStatus && item.readStatus !== (filters.value.readStatus === 'read' ? '已读' : '未读')) return false;
  138. return true;
  139. });
  140. });
  141. const loadData = () => { loading.value = true; setTimeout(() => { loading.value = false; }, 300); };
  142. const openSend = () => { Object.assign(sendForm, { receiverType: 'all', type: '', title: '', content: '', important: false }); sendDialogVisible.value = true; };
  143. const confirmSend = () => {
  144. if (!sendForm.type || !sendForm.title || !sendForm.content) { ElMessage.warning('请填写必填项'); return; }
  145. items.value.unshift({ id: `N${String(items.value.length + 1).padStart(3, '0')}`, type: sendForm.type, title: sendForm.title, content: sendForm.content, sender: '当前用户', time: new Date().toLocaleString(), readStatus: '未读' });
  146. sendDialogVisible.value = false;
  147. ElMessage.success('通知已发送');
  148. };
  149. const openDetail = (row: NoticeItem) => {
  150. detailItem.value = row;
  151. if (row.readStatus === '未读') {
  152. const idx = items.value.findIndex(i => i.id === row.id);
  153. if (idx !== -1) items.value[idx].readStatus = '已读';
  154. }
  155. detailDialogVisible.value = true;
  156. };
  157. const deleteNotice = async (row: NoticeItem) => {
  158. await ElMessageBox.confirm('确认删除此通知?', '删除确认');
  159. const idx = items.value.findIndex(i => i.id === row.id);
  160. if (idx !== -1) items.value.splice(idx, 1);
  161. ElMessage.success('通知已删除');
  162. };
  163. onMounted(loadData);
  164. </script>
  165. <style scoped>
  166. .filter-form :deep(.el-form-item) { margin-bottom: 0; }
  167. </style>