Browse Source

消息提醒

ZaiZai 1 year ago
parent
commit
936cbbc3a6

+ 36 - 0
src/api/modules/tasks/message.js

@@ -0,0 +1,36 @@
+import { HcApi } from '../../request/index'
+
+export default {
+    //轮询获取未读消息数量
+    async getUnreadMessage(form) {
+        return HcApi({
+            url: '/api/blade-meter/messageBiz/get-unread-message',
+            method: 'get',
+            params: form,
+        })
+    },
+    //废除通知分页
+    async repealPage(form) {
+        return HcApi({
+            url: '/api/blade-meter/messageBiz/repealPage',
+            method: 'post',
+            data: form,
+        })
+    },
+    //查看
+    async batchRead(ids) {
+        return HcApi({
+            url: '/api/blade-meter/messageBiz/batchRead',
+            method: 'post',
+            data: { ids },
+        })
+    },
+    //删除
+    async batchDelete(ids) {
+        return HcApi({
+            url: '/api/blade-meter/messageBiz/batchDelete',
+            method: 'post',
+            data: { ids },
+        })
+    },
+}

+ 2 - 2
src/config/index.json

@@ -1,9 +1,9 @@
 {
     "version": "20230607160059",
     "target1": "http://127.0.0.1:8090",
-    "target2": "http://192.168.0.125:8090",
+    "target": "http://192.168.0.125:8090",
     "target3": "http://39.108.216.210:8090",
-    "target": "http://192.168.0.109:8090",
+    "target4": "http://192.168.0.109:8090",
     "smsPhone": "",
     "vite": {
         "port": 5180,

+ 19 - 14
src/layout/index.vue

@@ -10,19 +10,19 @@
                 <HcIcon v-else name="menu-fold" />
             </div>
             <div class="header-top-menu-bar">
-                <HcTopMenuBar @load="topMenuLoad" @change="topMenuChange" />
+                <HcTopMenuBar :msg-count="taskCount" @load="topMenuLoad" @change="topMenuChange" />
             </div>
             <div class="header-content-bar">
                 <HcCascader @send="cascaderSend" @change="cascaderChange" />
                 <hc-upload-bar />
                 <HelpInfoBar />
                 <ConfigBar />
-                <UserInfoBar @load="userInfoLoad" />
+                <UserInfoBar />
             </div>
         </el-header>
         <el-container class="hc-layout-container">
             <el-aside v-if="isAsideMenu" class="hc-layout-aside" :class="[isCollapse ? 'is-collapse' : '']" :width="isCollapse ? '90px' : '200px'">
-                <MenuBar :collapse="isCollapse" :cur="menuBarKey" :datas="menuBarData" :msg-count="msgCount" @change="menuBarChange" />
+                <MenuBar :collapse="isCollapse" :cur="menuBarKey" :datas="menuBarData" :msg-count="taskCount" @change="menuBarChange" />
             </el-aside>
             <el-main class="hc-layout-main">
                 <div class="hc-router-menu-bar">
@@ -33,7 +33,7 @@
                         <router-view v-if="reloadRouter" v-slot="{ Component }">
                             <transition name="fade-transform">
                                 <keep-alive :max="10">
-                                    <component :is="Component" :msg-count="msgCount" />
+                                    <component :is="Component" :msg-count="taskCount" />
                                 </keep-alive>
                             </transition>
                         </router-view>
@@ -49,8 +49,8 @@ import { nextTick, onMounted, ref, watch } from 'vue'
 import { useAppStore } from '~src/store'
 import { useRoute, useRouter } from 'vue-router'
 import { initButtons } from '~sto/app'
-import HcSocket from '~src/plugins/HcSocket'
-import { getObjValue, isNullES } from 'js-fast-way'
+import { isNullES } from 'js-fast-way'
+import messageApi from '~api/tasks/message'
 
 //初始组合式
 const router = useRouter()
@@ -133,16 +133,21 @@ const msgCount = ref({
     messageCount_5: 0,
 })
 
-//用户信息
-const userInfoLoad = ({ user_id }) => {
-    HcSocket.create(user_id, (data) => {
-        msgCount.value = getObjValue(data)
-    })
+//项目合同段的ID
+const cascaderSend = async ({ projectId, contractId }) => {
+    await getUnreadMessage({ projectId, contractId })
+    setInterval(async () => {
+        await getUnreadMessage({ projectId, contractId })
+    }, 10000)
 }
 
-//项目合同段的ID
-const cascaderSend = ({ projectId, contractId }) => {
-    HcSocket.send(projectId + ',' + contractId)
+//获取未读消息数量
+const taskCount = ref(0)
+const getUnreadMessage = async ({ projectId, contractId }) => {
+    const { data } = await messageApi.getUnreadMessage({
+        projectId, contractId,
+    })
+    taskCount.value = data ?? 0
 }
 
 // 项目切换

+ 17 - 1
src/layout/modules/HcTopMenu.vue

@@ -2,7 +2,10 @@
     <el-scrollbar>
         <div class="hc-header-top-menu-bar">
             <template v-for="(item, index) in topMenuData" :key="index">
-                <div class="item" :class="curKey === item?.code ? 'cur' : '' " @click="topMenuClick(item)">{{ item?.name }}</div>
+                <div class="item" :class="curKey === item?.code ? 'cur' : '' " @click="topMenuClick(item)">
+                    <span>{{ item?.name }}</span>
+                    <el-badge v-if="item?.code === 'tasks' && taskCounts > 0" :value="taskCounts" />
+                </div>
             </template>
         </div>
     </el-scrollbar>
@@ -15,6 +18,13 @@ import { useAppStore } from '~src/store'
 import HcTopMenu from '~src/plugins/HcTopMenu'
 import { getArrValue } from 'js-fast-way'
 
+const props = defineProps({
+    msgCount: {
+        type: [Number, String],
+        default: 0,
+    },
+})
+
 const emit = defineEmits(['change', 'load'])
 
 //初始组合式
@@ -26,6 +36,12 @@ const setMenuItem = async (item) => {
     emit('change', await HcTopMenu.setMenuItem(item))
 }
 
+//监听菜单数据
+const taskCounts = ref(props.msgCount)
+watch(() => props.msgCount, (val) => {
+    taskCounts.value = val ?? 0
+}, { immediate: true, deep: true })
+
 //监听菜单数据
 const topMenuData = ref([])
 watch(() => store.getMenus, (val) => {

+ 9 - 3
src/layout/modules/MenuBar.vue

@@ -1,7 +1,7 @@
 <template>
     <el-scrollbar>
         <el-menu :collapse="isCollapse" :default-active="curKey" class="hc-aside-menu" unique-opened text-color="#fff">
-            <MenuItem :collapse="isCollapse" :cur="curKey" :datas="datas" :msg-count="msgCount" @change="MenuClick" />
+            <MenuItem :collapse="isCollapse" :cur="curKey" :datas="datas" :msg-count="taskCounts" @change="MenuClick" />
         </el-menu>
     </el-scrollbar>
 </template>
@@ -24,8 +24,8 @@ const props = defineProps({
         default: false,
     },
     msgCount: {
-        type: Object,
-        default: () => ({}),
+        type: [Number, String],
+        default: 0,
     },
 })
 
@@ -45,6 +45,12 @@ watch(() => [
     isCollapse.value = collapse
 })
 
+//监听菜单数据
+const taskCounts = ref(props.msgCount)
+watch(() => props.msgCount, (val) => {
+    taskCounts.value = val ?? 0
+}, { immediate: true, deep: true })
+
 //处理菜单数据
 const setMenuItem = async (item) => {
     curKey.value = item?.code || ''

+ 10 - 15
src/layout/modules/MenuItem.vue

@@ -7,7 +7,6 @@
                         <HcIcon v-if="item?.source" :name="item?.source" :fill="curKey === item?.code" class="hc-menu-icon" />
                         <div v-if="isCollapse" class="name truncate">{{ item?.name.substring(0, 2) }}</div>
                         <div v-else class="name truncate">{{ item?.name }}</div>
-                        <el-badge v-if="item?.code === 'tasks' && msgCount?.allCount > 0" :value="msgCount.allCount" />
                     </div>
                 </div>
                 <HcIcon name="arrow-down-s" ui="el-icon el-sub-menu__icon-arrow" />
@@ -19,9 +18,8 @@
                 <div class="menu---item">
                     <HcIcon v-if="item?.source" :name="item?.source" :fill="curKey === item?.code" class="hc-menu-icon" />
                     <div v-if="isCollapse" class="name truncate">{{ item?.name.substring(0, 2) }}</div>
-                    <div v-else class="name truncate">{{ item?.name }}</div>
-                    <el-badge v-if="item?.code === 'tasks-data' && msgCount?.taskCount > 0" :value="msgCount.taskCount" />
-                    <el-badge v-if="item?.code === 'message-data' && msgCount?.messageCount > 0" :value="msgCount.messageCount" />
+                    <div v-else class="name truncate" :data-key="item?.code">{{ item?.name }}</div>
+                    <el-badge v-if="item?.code === 'tasks-message' && taskCounts > 0" :value="taskCounts" />
                 </div>
             </div>
         </el-menu-item>
@@ -46,17 +44,8 @@ const props = defineProps({
         default: false,
     },
     msgCount: {
-        type: Object,
-        default: () => ({
-            allCount: 0,
-            taskCount: 0,
-            messageCount: 0,
-            messageCount_1: 0,
-            messageCount_2: 0,
-            messageCount_3: 0,
-            messageCount_4: 0,
-            messageCount_5: 0,
-        }),
+        type: [Number, String],
+        default: 0,
     },
 })
 //事件
@@ -75,6 +64,12 @@ watch(() => [
     isCollapse.value = collapse
 })
 
+//监听菜单数据
+const taskCounts = ref(props.msgCount)
+watch(() => props.msgCount, (val) => {
+    taskCounts.value = val ?? 0
+}, { immediate: true, deep: true })
+
 const MenuClick = (item) => {
     emit('change', item)
 }

+ 1 - 1
src/views/tasks/hc-data.vue

@@ -168,7 +168,7 @@ const getTableData = async () => {
     //处理数据
     tableLoading.value = false
     if (!error && code === 200) {
-        tableListData.value = getArrValue(data['records'])
+        tableListData.value = getArrValue(data?.records)
         searchForm.value.total = data.total || 0
     } else {
         tableListData.value = []

+ 121 - 34
src/views/tasks/message.vue

@@ -9,44 +9,46 @@
             <hc-card>
                 <template #header>
                     <div class="w-32">
-                        <el-select v-model="searchForm.tasksType" clearable block placeholder="任务类型">
-                            <el-option label="暂无接口" value=" 1" />
+                        <el-select v-model="searchForm.taskType" clearable block placeholder="任务类型">
+                            <el-option v-for="item in tasksType" :key="item.dictKey" :label="item.dictValue" :value="item.dictKey" />
                         </el-select>
                     </div>
                     <div class="ml-2 w-32">
-                        <el-select v-model="searchForm.smsType" clearable block placeholder="消息类型">
-                            <el-option label="暂无接口" value=" 1" />
+                        <el-select v-model="searchForm.messageType" clearable block placeholder="消息类型">
+                            <el-option label="未读" :value="1" />
+                            <el-option label="已读" :value="2" />
                         </el-select>
                     </div>
                     <div class="ml-2 w-64">
                         <hc-date-picker :dates="betweenTime" clearable @change="betweenTimeUpdate" />
                     </div>
                     <div class="ml-2 w-64">
-                        <hc-search-input v-model="searchForm.queryValue" @search="searchClick" />
+                        <hc-search-input v-model="searchForm.searchValue" @search="searchClick" />
                     </div>
                 </template>
                 <template #extra>
-                    <el-button hc-btn type="danger">
+                    <el-button hc-btn type="danger" @click="delClick">
                         <hc-icon name="delete-bin-3" />
                         <span>删除</span>
                     </el-button>
-                    <el-button hc-btn type="primary">
+                    <el-button hc-btn type="primary" @click="batchReadClick">
                         <hc-icon name="check" />
-                        <span>批量确认</span>
+                        <span>标记已读</span>
                     </el-button>
                 </template>
                 <hc-table
-                    :column="tableColumn" :datas="tableData" :loading="tableLoading"
+                    ref="tableRef" :column="tableColumn" :datas="tableData" :loading="tableLoading"
                     :index-style="{ width: 60 }" is-check :check-style="{ width: 29 }"
                     @selection-change="tableSelection"
                 >
-                    <template #key8="{ row }">
-                        <span class="text-red-5">未读</span>
-                        <span class="text-green-5">已读</span>
+                    <template #messageStatusName="{ row }">
+                        <span v-if="row.messageStatusName === '未读'" class="text-red-5">未读</span>
+                        <span v-else-if="row.messageStatusName === '已读'" class="text-green-5">已读</span>
+                        <span v-else>未知</span>
                     </template>
                     <template #action="{ row }">
-                        <el-link type="primary">确认</el-link>
-                        <el-link type="info" disabled>已确认</el-link>
+                        <el-link v-if="row.messageStatusName === '未读'" type="primary" @click="rowReadClick(row)">确认</el-link>
+                        <el-link v-else type="info" disabled>已确认</el-link>
                     </template>
                 </hc-table>
                 <template #action>
@@ -58,13 +60,38 @@
 </template>
 
 <script setup>
-import { onActivated, ref } from 'vue'
+import { HcDelMsg } from 'hc-vue3-ui'
+import { onActivated, ref, watch } from 'vue'
+import { useAppStore } from '~src/store'
+import { arrToId, getArrValue } from 'js-fast-way'
+import taskApi from '~api/tasks/hc-data'
+import mainApi from '~api/tasks/message'
+
+const props = defineProps({
+    msgCount: {
+        type: [Number, String],
+        default: 0,
+    },
+})
 
 //渲染完成
 onActivated(() => {
+    queryTaskType()
     searchClick()
 })
 
+//获取项目合同段ID
+const store = useAppStore()
+const projectId = ref(store.getProjectId)
+const contractId = ref(store.getContractId)
+
+//监听菜单数据
+const taskCount = ref(props.msgCount)
+watch(() => props.msgCount, (val) => {
+    taskCount.value = val ?? 0
+    menuOptions.value[0].badge = taskCount.value
+}, { deep: true })
+
 //搜索和分页数据
 const searchForm = ref({ current: 1, size: 20, total: 0 })
 
@@ -73,7 +100,7 @@ const menuKey = ref('3')
 const menuOptions = ref([
     //{ key: '1', label: '任务催办', icon: 'alarm-warning', badge: 0 },
     //{ key: '2', label: '监测预警', icon: 'eye', badge: 0 },
-    { key: '3', label: '废除通知', icon: 'delete-bin-3', badge: 0 },
+    { key: '3', label: '废除通知', icon: 'delete-bin-3', badge: taskCount.value },
     //{ key: '4', label: '工单反馈', icon: 'question-answer', badge: 0 },
     //{ key: '5', label: '系统消息', icon: 'chat-settings', badge: 0 },
 ])
@@ -83,16 +110,23 @@ const handleMenuValue = (item) => {
     searchClick()
 }
 
+//获取任务类型
+const tasksType = ref([])
+const queryTaskType = async () => {
+    const { data } = await taskApi.queryTaskType()
+    tasksType.value = getArrValue(data)
+}
+
 //日期时间被选择
 const betweenTime = ref(null)
 const betweenTimeUpdate = ({ val, arr }) => {
     betweenTime.value = arr
     if (val && val.length > 0) {
-        searchForm.value.startTime = val['start']
-        searchForm.value.endTime = val['end']
+        searchForm.value.startDate = val['start']
+        searchForm.value.endDate = val['end']
     } else {
-        searchForm.value.startTime = null
-        searchForm.value.endTime = null
+        searchForm.value.startDate = null
+        searchForm.value.endDate = null
     }
 }
 
@@ -110,25 +144,37 @@ const pageChange = ({ current, size }) => {
 }
 
 //表格
+const tableRef = ref(null)
 const tableColumn = [
-    { key: 'key1', name: '任务类型' },
-    { key: 'key2', name: '任务名称' },
-    { key: 'key3', name: '开始时间' },
-    { key: 'key4', name: '废除时间' },
-    { key: 'key5', name: '任务流程' },
-    { key: 'key6', name: '驳回人' },
-    { key: 'key7', name: '驳回原因' },
-    { key: 'key8', name: '消息状态' },
-    { key: 'action', name: '操作', width: 94 },
+    { key: 'meterTaskTypeName', name: '任务类型' },
+    { key: 'taskName', name: '任务名称' },
+    { key: 'startDate', name: '开始时间' },
+    { key: 'repealDate', name: '废除时间' },
+    { key: 'taskFlowName', name: '任务流程' },
+    { key: 'rejectPersonName', name: '驳回人' },
+    { key: 'rejectReason', name: '驳回原因' },
+    { key: 'messageStatusName', name: '消息状态', width: 80, align: 'center' },
+    { key: 'action', name: '操作', width: 80, align: 'center' },
 ]
-const tableData = ref([
-    {},
-])
+const tableData = ref([])
 
 //获取消息数据
 const tableLoading = ref(false)
-const getTableData = () => {
-
+const getTableData = async () => {
+    tableLoading.value = true
+    //清空数据
+    tableData.value = []
+    tableRef.value?.clearSelection()
+    tableCheckedKeys.value = []
+    //发起请求
+    const { data } = await mainApi.repealPage({
+        ...searchForm.value,
+        projectId: projectId.value,
+        contractId: contractId.value,
+    })
+    tableLoading.value = false
+    tableData.value = getArrValue(data?.records)
+    searchForm.value.total = data.total || 0
 }
 
 //多选
@@ -136,6 +182,47 @@ const tableCheckedKeys = ref([])
 const tableSelection = (rows) => {
     tableCheckedKeys.value = rows
 }
+
+//单个查看
+const rowReadClick = ({ id }) => {
+    batchReadApi(id)
+}
+
+//批量查看
+const batchReadClick = () => {
+    const rows = tableCheckedKeys.value
+    if (rows.length <= 0) {
+        window.$message.warning('请先勾选要已读的数据')
+        return
+    }
+    const ids = arrToId(rows, 'id')
+    batchReadApi(ids)
+}
+
+//统一查看
+const batchReadApi = async (id) => {
+    const { isRes } = await mainApi.batchRead(id)
+    if (!isRes) return
+    window.$message.success('删除成功')
+    getTableData().then()
+}
+
+//批量删除
+const delClick = () => {
+    const rows = tableCheckedKeys.value
+    if (rows.length <= 0) {
+        window.$message.warning('请先勾选要删除的数据')
+        return
+    }
+    HcDelMsg(async (resolve) => {
+        const ids = arrToId(rows, 'id')
+        const { isRes } = await mainApi.batchDelete(ids)
+        if (!isRes) return
+        window.$message.success('删除成功')
+        getTableData().then()
+        resolve() //关闭弹窗的回调
+    })
+}
 </script>
 
 <style lang="scss" scoped>