message-data.vue 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. <template>
  2. <div class="hc-layout-box">
  3. <div class="hc-layout-left-box">
  4. <el-scrollbar>
  5. <HcMenuSimple :datas="menuOptions" :keys="menuKey" @change="handleMenuValue" />
  6. </el-scrollbar>
  7. </div>
  8. <div class="hc-layout-content-box">
  9. <HcCard action-size="lg">
  10. <template #header>
  11. <div class="w-32 ml-2">
  12. <el-select v-model="searchForm.smsType" clearable placeholder="消息类型" size="large">
  13. <el-option v-for="item in smsTypeData" :label="item.label" :value="item.value" />
  14. </el-select>
  15. </div>
  16. <div class="w-64 ml-2">
  17. <HcDatePicker :dates="betweenTime" clearable size="large" @change="betweenTimeUpdate" />
  18. </div>
  19. <div class="ml-2">
  20. <el-button size="large" type="primary" @click="searchClick">
  21. <HcIcon name="search-2" />
  22. <span>搜索</span>
  23. </el-button>
  24. </div>
  25. </template>
  26. <template #extra>
  27. <el-button :disabled="tableCheckedKeys.length <= 0" :loading="delLoading" hc-btn @click="delClick">
  28. <HcIcon name="delete-bin-3" />
  29. <span>删除消息</span>
  30. </el-button>
  31. <el-button
  32. :disabled="tableCheckedKeys.length <= 0" :loading="markReadLoading" hc-btn
  33. @click="markReadClick"
  34. >
  35. <HcIcon name="bookmark" />
  36. <span>标记已读</span>
  37. </el-button>
  38. </template>
  39. <HcTable
  40. ref="tableListRef" :column="tableListColumn" :datas="tableListData" :loading="tableLoading"
  41. is-check border @selection-change="tableSelectionChange"
  42. >
  43. <template #content="{ row }">
  44. <div class="text-link text-cut" @click="tableContent(row)">{{ row.content }}</div>
  45. </template>
  46. </HcTable>
  47. <template #action>
  48. <HcPages :pages="searchForm" @change="pageChange" />
  49. </template>
  50. </HcCard>
  51. </div>
  52. <!-- 日志内容 -->
  53. <el-dialog v-model="operationContentModal" class="hc-modal-border" title="消息内容" width="38rem">
  54. {{ operationContent }}
  55. </el-dialog>
  56. </div>
  57. </template>
  58. <script setup>
  59. import { onMounted, ref, watch } from 'vue'
  60. import { useAppStore } from '~src/store'
  61. import { useRoute, useRouter } from 'vue-router'
  62. import messageApi from '~api/tasks/message'
  63. import { arrToId, getArrValue } from 'js-fast-way'
  64. import website from '~src/config/index'
  65. import { delMessageV2 } from '~com/message/index.js'
  66. //消息数量
  67. const props = defineProps(
  68. {
  69. msgCount: {
  70. type: Object,
  71. default: () => ({
  72. allCount: 0,
  73. taskCount: 0,
  74. messageCount: 0,
  75. messageCount_1: 0,
  76. messageCount_2: 0,
  77. messageCount_3: 0,
  78. messageCount_4: 0,
  79. messageCount_5: 0,
  80. }),
  81. },
  82. },
  83. )
  84. //变量
  85. const router = useRouter()
  86. const useRoutes = useRoute()
  87. const useAppState = useAppStore()
  88. const projectId = ref(useAppState.getProjectId)
  89. const contractId = ref(useAppState.getContractId)
  90. const userInfo = ref(useAppState.getUserInfo)
  91. //路由参数数据
  92. const routerQuery = useRoutes?.query
  93. let MenuType = routerQuery?.MenuType || '1'
  94. const menumsgCount = ref(props.msgCount)
  95. //监听
  96. //监听
  97. watch(() => [
  98. props.msgCount,
  99. ], ([val]) => {
  100. menumsgCount.value = val
  101. if (val) {
  102. queryCurrentUserMessageCount()
  103. }
  104. },
  105. )
  106. //渲染完成
  107. onMounted(() => {
  108. searchForm.value.type = MenuType
  109. searchForm.value.current = 1
  110. searchClick()
  111. })
  112. //左侧菜单
  113. const menuKey = ref(MenuType)
  114. const menuOptions = ref([
  115. { key: '1', label: '任务催办', icon: 'alarm-warning', badge: 0 },
  116. { key: '2', label: '监测预警', icon: 'eye', badge: 0 },
  117. { key: '3', label: '废除通知', icon: 'delete-bin-3', badge: 0 },
  118. { key: '4', label: '工单反馈', icon: 'question-answer', badge: 0 },
  119. { key: '5', label: '系统消息', icon: 'chat-settings', badge: 0 },
  120. ])
  121. const handleMenuValue = (item) => {
  122. searchForm.value.type = item.key
  123. searchForm.value.current = 1
  124. menuKey.value = item.key
  125. searchClick()
  126. router.push({
  127. path: useRoutes.path,
  128. query: { MenuType: item.key },
  129. })
  130. }
  131. //获取消息数量
  132. const queryCurrentUserMessageCount = async () => {
  133. const typeArr = ['messageCount_1', 'messageCount_2', 'messageCount_3', 'messageCount_4', 'messageCount_5']
  134. for (let i = 0; i < typeArr.length; i++) {
  135. menuOptions.value[i].badge = menumsgCount.value[typeArr[i]] ?? 0
  136. }
  137. }
  138. //消息类型
  139. const smsTypeData = ref([{ label: '已读消息', value: '1' }, { label: '未读消息', value: '2' }])
  140. //搜索和分页数据
  141. const searchForm = ref({
  142. isRead: null, startTime: null, endTime: null, type: 1,
  143. current: 1, size: 20, total: 0,
  144. })
  145. //日期时间被选择
  146. const betweenTime = ref(null)
  147. const betweenTimeUpdate = ({ val, arr }) => {
  148. betweenTime.value = arr
  149. if (val && val.length > 0) {
  150. searchForm.value.startTime = val['start']
  151. searchForm.value.endTime = val['end']
  152. } else {
  153. searchForm.value.startTime = null
  154. searchForm.value.endTime = null
  155. }
  156. }
  157. //搜索
  158. const searchClick = () => {
  159. searchForm.value.current = 1
  160. getTableData()
  161. }
  162. //分页被点击
  163. const pageChange = ({ current, size }) => {
  164. searchForm.value.current = current
  165. searchForm.value.size = size
  166. getTableData()
  167. }
  168. //设置表头数据
  169. const tableListRef = ref(null)
  170. const tableListColumn = ref([
  171. { key: 'typeValue', name: '类型', width: '120' },
  172. { key: 'time', name: '日期时间', width: '180' },
  173. { key: 'content', name: '内容' },
  174. ])
  175. const tableListData = ref([])
  176. //获取数据
  177. const tableLoading = ref(false)
  178. const getTableData = async () => {
  179. //处理初始数据
  180. tableLoading.value = true
  181. tableListData.value = []
  182. tableListRef.value?.clearSelection()
  183. tableCheckedKeys.value = []
  184. //获取数据
  185. const { error, code, data } = await messageApi.getPageData({
  186. ...searchForm.value,
  187. projectId: projectId.value,
  188. contractId: contractId.value,
  189. })
  190. //处理返回数据
  191. tableLoading.value = false
  192. if (!error && code === 200) {
  193. tableListData.value = getArrValue(data['records'])
  194. searchForm.value.total = data['total'] ?? 0
  195. } else {
  196. tableListData.value = []
  197. searchForm.value.total = 0
  198. }
  199. }
  200. //多选
  201. const tableCheckedKeys = ref([])
  202. const tableSelectionChange = (rows) => {
  203. tableCheckedKeys.value = rows.filter((item) => {
  204. return (item ?? '') !== ''
  205. })
  206. }
  207. //查看内容
  208. const operationContentModal = ref(false)
  209. const operationContent = ref('')
  210. const tableContent = (row) => {
  211. operationContent.value = row['content'] ?? ''
  212. operationContentModal.value = true
  213. setMessageWarningReadApi(row['id'], false)
  214. }
  215. //删除消息
  216. const delClick = () => {
  217. const rows = tableCheckedKeys.value
  218. if (rows.length > 0) {
  219. delMessageV2(async (action, instance, done) => {
  220. if (action === 'confirm') {
  221. instance.confirmButtonLoading = true
  222. removeData(rows)
  223. instance.confirmButtonLoading = false
  224. done()
  225. } else {
  226. done()
  227. }
  228. })
  229. } else {
  230. window.$message?.warning('请先勾选要删除的消息')
  231. }
  232. }
  233. //确认删除消息
  234. const delLoading = ref(false)
  235. const removeData = async (rows) => {
  236. delLoading.value = true
  237. const ids = arrToId(rows)
  238. //请求数据
  239. const { error, code } = await messageApi.removeData({
  240. ids: ids,
  241. }, false)
  242. //处理返回数据
  243. delLoading.value = false
  244. if (!error && code === 200) {
  245. tableCheckedKeys.value = []
  246. window.$message?.success('消息删除成功')
  247. queryCurrentUserMessageCount()
  248. searchClick()
  249. } else {
  250. window.$message?.error('消息删除失败')
  251. }
  252. }
  253. //标记已读
  254. const markReadClick = () => {
  255. const rows = tableCheckedKeys.value
  256. if (rows.length > 0) {
  257. const ids = arrToId(rows)
  258. window?.$messageBox?.alert('勾选的消息是否标记为已读?', '确认操作', {
  259. showCancelButton: true,
  260. confirmButtonText: '确定标记',
  261. cancelButtonText: '取消',
  262. callback: (action) => {
  263. if (action === 'confirm') {
  264. setMessageWarningReadApi(ids)
  265. }
  266. },
  267. })
  268. } else {
  269. window.$message?.warning('请先勾选要标记的消息')
  270. }
  271. }
  272. //确认标记
  273. const markReadLoading = ref(false)
  274. const setMessageWarningReadApi = async (ids, getTable = true) => {
  275. markReadLoading.value = true
  276. //请求数据
  277. const { error, code } = await messageApi.setMessageWarningRead({
  278. ids: ids,
  279. }, false)
  280. //处理返回数据
  281. markReadLoading.value = false
  282. if (!error && code === 200) {
  283. if (getTable) {
  284. tableCheckedKeys.value = []
  285. window.$message?.success('消息标记为已读成功')
  286. queryCurrentUserMessageCount()
  287. getTableData()
  288. } else {
  289. queryCurrentUserMessageCount()
  290. }
  291. } else {
  292. window.$message?.error('消息标记为已读失败')
  293. }
  294. }
  295. </script>
  296. <style lang="scss" scoped>
  297. @import "../../styles/tasks/message.scss";
  298. </style>