#33 oa待办消息

Merged
yanghao merged 2 commits from ruiqigogs/flow into ruiqigogs/master 19 hours ago
6 changed files with 146 additions and 63 deletions
  1. 24 3
      src/api/user.ts
  2. 87 53
      src/components/home/header.vue
  3. 19 3
      src/config/axios/service.ts
  4. 3 1
      src/router/index.ts
  5. 10 3
      src/views/flow/index.vue
  6. 3 0
      src/views/login.vue

+ 24 - 3
src/api/user.ts

@@ -120,23 +120,44 @@ export const getCRMTasks = async (params) => {
   });
 };
 
-// 消息通知
+// CMR消息通知
 export const getNotifyMessages = async (id) => {
   return await request.get({
     url: "/admin-api/portal/todo/crm/notice?workcode=" + id,
   });
 };
 
-// 消息列表
+// CRM消息列表
 export const getNotifyMessageList = async (id) => {
   return await request.get({
     url: "/admin-api/portal/todo/crm/notice/self?workcode=" + id,
   });
 };
 
-// 标记消息为已读
+// CRM标记消息为已读
 export const markMessageAsRead = async (id) => {
   return await request.get({
     url: "/admin-api/portal/todo/crm/notice/readed?workcode=" + id,
   });
 };
+
+// OA消息通知
+export const getOANotifyMessages = async (id) => {
+  return await request.get({
+    url: "/admin-api/portal/todo/oa/notice?workcode=" + id,
+  });
+};
+
+// OA消息列表
+export const getOANotifyMessageList = async (id) => {
+  return await request.get({
+    url: "/admin-api/portal/todo/oa/notice/self?workcode=" + id, // /portal/todo/oa/notice/self
+  });
+};
+
+// OA标记消息为已读
+export const markOAMessageAsRead = async (id) => {
+  return await request.get({
+    url: "/admin-api/portal/todo/oa/notice/readed?workcode=" + id, // portal/todo/oa/notice/readed
+  });
+};

+ 87 - 53
src/components/home/header.vue

@@ -37,9 +37,9 @@
         <el-dropdown trigger="click" placement="bottom-end">
           <div class="flex items-center gap-2 cursor-pointer pr-6 pt-2">
             <el-badge
-              :value="unreadMessageCount"
+              :value="unreadMessageCount + oaUnreadCount"
               class="item"
-              v-if="hasUnreadMessages"
+              v-if="hasUnreadMessages || oaHasUnreadCount"
             >
               <Icon
                 icon="mdi:bell"
@@ -76,10 +76,6 @@
                           @click="markAllAsRead"
                           >全部标为已读</span
                         >
-
-                        <span v-else class="cursor-pointer text-[#b2aaaa]"
-                          >全部已读</span
-                        >
                       </div>
                       <div
                         class="message-item"
@@ -108,14 +104,25 @@
                     </div>
                   </el-tab-pane>
                   <el-tab-pane label="OA" name="tasks">
+                    <template #label>
+                      <span class="custom-tabs-label">
+                        <span>OA</span>
+                        <el-badge
+                          :value="oaUnreadCount"
+                          class="item ml-1"
+                          v-if="oaHasUnreadCount"
+                        ></el-badge>
+                      </span>
+                    </template>
                     <div class="tab-content">
-                      <!-- <div>
+                      <div>
                         <span
+                          v-if="oaHasUnreadCount"
                           class="cursor-pointer text-blue-500"
-                          @click="markAllAsRead"
+                          @click="oaMarkAllAsRead"
                           >全部标为已读</span
                         >
-                      </div> -->
+                      </div>
                       <!-- OA消息 -->
                       <div
                         class="task-item"
@@ -125,17 +132,15 @@
                         <div class="task-info">
                           <p class="task-title">
                             <span
-                              class="w-3 h-3 bg-[#f56c6c] rounded-full"
-                            ></span
-                            >{{ task.contentMajor }}
+                              v-if="task.status === '0'"
+                              class="inline-block h-2 w-2 bg-[#f56c6c] rounded-full"
+                            ></span>
+                            {{ task.title }}
                           </p>
                           <p class="message-desc">
-                            {{ timestampToDateTime(task.createTime) }}
+                            <span>{{ task.oaCreateTime }}</span>
                           </p>
                         </div>
-                        <el-tag :type="task.priorityTag" size="small">{{
-                          task.priorityText
-                        }}</el-tag>
                       </div>
                       <div v-if="!oaMessagesList.length" class="no-tasks">
                         暂无新消息
@@ -346,7 +351,7 @@
 
 <script setup lang="ts">
 import { Icon } from "@iconify/vue";
-import { ref, computed, onMounted } from "vue";
+import { ref, computed, onMounted, onBeforeUnmount } from "vue";
 import { useRouter } from "vue-router";
 import logo from "@/assets/images/logo.png";
 import person from "@/assets/images/person.png";
@@ -357,6 +362,9 @@ import {
   getNotifyMessageList,
   markMessageAsRead,
   getUnreadNotifyMessageCount,
+  getOANotifyMessages,
+  getOANotifyMessageList,
+  markOAMessageAsRead,
 } from "@api/user";
 
 import {
@@ -367,35 +375,12 @@ import {
 } from "@utils/auth";
 
 import { deleteUserCache } from "@hooks/useCache";
+import { manualLogoutKey, reloginCancelKey } from "@/config/axios/service";
 
 // 新增消息中心状态
 const activeTab = ref("messages");
 const messages = ref([]);
 
-const tasks = ref([
-  {
-    title: "审批申请",
-    desc: "部门采购申请等待您审批",
-    dueTime: "今天 17:00",
-    priorityText: "高",
-    priorityTag: "danger",
-  },
-  {
-    title: "项目汇报",
-    desc: "月度项目进度报告待提交",
-    dueTime: "明天",
-    priorityText: "中",
-    priorityTag: "warning",
-  },
-  {
-    title: "会议安排",
-    desc: "准备下周团队会议材料",
-    dueTime: "后天",
-    priorityText: "低",
-    priorityTag: "info",
-  },
-]);
-
 const isLoggedIn = computed(
   () => !!userStore.isSetUser || !!userStore.user?.id,
 );
@@ -406,44 +391,74 @@ const userName = computed(() => userStore.user?.nickname || "");
 const hasUnreadMessages = computed(() => {
   return messages.value.some((msg) => msg.status === "0");
 });
+// oa是否有未读
+const oaHasUnreadCount = computed(() => {
+  return oaMessagesList.value.some((msg) => msg.status === "0");
+});
 
 // 未读消息数量
 const unreadMessageCount = computed(() => {
   return messages.value.filter((msg) => msg.status === "0").length;
 });
-
+// oa未读消息数量
+const oaUnreadCount = computed(() => {
+  return oaMessagesList.value.filter((msg) => msg.status === "0").length;
+});
 // oa未读
 const oaMessagesList = ref([]);
 
 const unreadCount = ref(0); // 未读消息数量
 const getUnreadCount = async () => {
-  getUnreadNotifyMessageCount().then((data) => {
-    unreadCount.value = data;
-  });
+  if (!getAccessToken()) {
+    unreadCount.value = 0;
+    return;
+  }
+
+  const data = await getUnreadNotifyMessageCount();
+  unreadCount.value = data;
 };
+let messageTimer: ReturnType<typeof setInterval> | undefined;
+let unreadTimer: ReturnType<typeof setInterval> | undefined;
 onMounted(async () => {
   if (isLoggedIn.value) {
+    getUnreadCount();
     await getNotifyMessages(userStore.getUser.username);
     const messageList = await getNotifyMessageList(userStore.getUser.username);
-    messages.value = messageList;
+    messages.value = messageList.filter((msg: any) => msg.status === "0");
+
+    // oa消息
+    await getOANotifyMessages(userStore.getUser.username);
+    const oaMessageList = await getOANotifyMessageList(
+      userStore.getUser.username,
+    );
+    oaMessagesList.value = oaMessageList.filter((msg) => msg.status === "0");
   }
 
-  setInterval(
+  messageTimer = setInterval(
     async () => {
       if (isLoggedIn.value) {
         await getNotifyMessages(userStore.getUser.username);
         const messageList = await getNotifyMessageList(
           userStore.getUser.username,
         );
-        messages.value = messageList;
+        messages.value = messageList.filter((msg: any) => msg.status === "0");
+
+        // oa消息
+        await getOANotifyMessages(userStore.getUser.username);
+        const oaMessageList = await getOANotifyMessageList(
+          userStore.getUser.username,
+        );
+        oaMessagesList.value = oaMessageList.filter(
+          (msg: any) => msg.status === "0",
+        );
       }
     },
-    1000 * 60 * 1,
+    1000 * 60 * 5,
   );
 
-  setInterval(
+  unreadTimer = setInterval(
     () => {
-      if (userStore.getIsSetUser) {
+      if (userStore.getIsSetUser && getAccessToken()) {
         console.log("轮询刷新小红点");
         getUnreadCount();
       } else {
@@ -454,6 +469,15 @@ onMounted(async () => {
   );
 });
 
+onBeforeUnmount(() => {
+  if (messageTimer) {
+    clearInterval(messageTimer);
+  }
+  if (unreadTimer) {
+    clearInterval(unreadTimer);
+  }
+});
+
 function timestampToDateTime(timestamp) {
   // 兼容 10位(秒) / 13位(毫秒)
   const len = String(timestamp).length;
@@ -483,7 +507,15 @@ const markAllAsRead = async () => {
   await markMessageAsRead(userStore.getUser.username);
   // 刷新消息列表
   const messageList = await getNotifyMessageList(userStore.getUser.username);
-  messages.value = messageList;
+  messages.value = messageList.filter((msg: any) => msg.status === "0");
+};
+
+// oa全部标为已读
+const oaMarkAllAsRead = async () => {
+  await markOAMessageAsRead(userStore.getUser.username);
+  // 刷新消息列表
+  const messageList = await getOANotifyMessageList(userStore.getUser.username);
+  oaMessagesList.value = messageList.filter((msg: any) => msg.status === "0");
 };
 
 const goHome = () => {
@@ -505,8 +537,10 @@ const onUserCommand = async (command: string) => {
     // await userStore.loginOut();
 
     deleteUserCache(); // 删除用户缓存
+    sessionStorage.setItem(manualLogoutKey, "true");
+    sessionStorage.removeItem(reloginCancelKey);
     removeToken();
-    window.location.reload();
+    window.location.href = "/login";
   }
 };
 </script>

+ 19 - 3
src/config/axios/service.ts

@@ -28,6 +28,8 @@ const ignoreMsgs = [
 ];
 // 是否显示重新登录
 export const isRelogin = { show: false };
+export const reloginCancelKey = "reloginCancel";
+export const manualLogoutKey = "manualLogout";
 // Axios 无感知刷新令牌,参考 https://www.dashingdog.cn/article/11 与 https://segmentfault.com/a/1190000020210980 实现
 // 请求队列
 let requestList: any[] = [];
@@ -203,13 +205,25 @@ const refreshToken = async () => {
   );
 };
 const handleAuthorized = () => {
+  const isManualLogout = sessionStorage.getItem(manualLogoutKey) === "true";
+  const isReloginCanceled = sessionStorage.getItem(reloginCancelKey) === "true";
+
+  if (isManualLogout || isReloginCanceled) {
+    deleteUserCache();
+    removeToken();
+    if (!window.location.href.includes("login")) {
+      window.location.href = "/login";
+    }
+    return Promise.reject("登录超时,请重新登录");
+  }
+
   if (!isRelogin.show) {
     if (window.location.href.includes("login")) {
-      return;
+      return Promise.reject("登录超时,请重新登录");
     }
     isRelogin.show = true;
     ElMessageBox.confirm("登录超时,请重新登录", "确定", {
-      showCancelButton: true,
+      showCancelButton: false,
       closeOnClickModal: false,
       showClose: false,
       closeOnPressEscape: false,
@@ -218,16 +232,18 @@ const handleAuthorized = () => {
       type: "warning",
     })
       .then(async () => {
+        sessionStorage.removeItem(reloginCancelKey);
         deleteUserCache(); // 删除用户缓存
         removeToken();
         isRelogin.show = false;
         window.location.href = "/login";
       })
       .catch(() => {
+        sessionStorage.setItem(reloginCancelKey, "true");
         deleteUserCache(); // 删除用户缓存
         removeToken();
         isRelogin.show = false; // 重置显示状态
-        window.location.href = "/";
+        window.location.href = "/login";
       });
   }
   return Promise.reject("登录超时,请重新登录");

+ 3 - 1
src/router/index.ts

@@ -11,7 +11,7 @@ import Login from "@/views/login.vue";
 import { getAccessToken } from "@utils/auth";
 import { socialLogin } from "@/api/user";
 import * as authUtil from "@/utils/auth";
-import { isRelogin } from "@/config/axios/service";
+import { isRelogin, manualLogoutKey, reloginCancelKey } from "@/config/axios/service";
 
 import { useUserStoreWithOut } from "@/stores/useUserStore";
 
@@ -169,6 +169,8 @@ router.beforeEach(async (to, from, next) => {
         );
 
         authUtil.setToken(res);
+        sessionStorage.removeItem(manualLogoutKey);
+        sessionStorage.removeItem(reloginCancelKey);
         next({ path: "/" });
       } else {
         next(); // 正常导航

+ 10 - 3
src/views/flow/index.vue

@@ -117,7 +117,7 @@
               <p class="item-desc">{{ item.remark || "暂无描述" }}</p>
             </div>
 
-            <div class="flex justify-between">
+            <!-- <div class="flex justify-between">
               <div class="item-time flex items-center gap-2">
                 <svg
                   xmlns="http://www.w3.org/2000/svg"
@@ -140,10 +140,10 @@
                     ></path>
                   </g>
                 </svg>
-                <span class="text-[12px] text-[#babdd1]">85人使用</span>
+                <span class="text-[12px] text-[#babdd1]">提交流程</span>
               </div>
               <Icon icon="mdi-light:chevron-right" class="item-arrow w-6 h-6" />
-            </div>
+            </div> -->
           </div>
         </div>
       </div>
@@ -163,6 +163,7 @@ import { useUserStore } from "@/stores/useUserStore";
 import { getAccessToken } from "@/utils/auth";
 import * as echarts from "echarts";
 import { useRouter } from "vue-router";
+import dd from "dingtalk-jsapi";
 const router = useRouter();
 
 const userStore = useUserStore();
@@ -396,6 +397,9 @@ const go = async (item) => {
       if (res) {
         const ua = window.navigator.userAgent.toLowerCase();
         if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
+          console.log(
+            "现在是钉钉。。。。。。。。。。。。。。。。。。。。。。。。。",
+          );
           const targetUrl1 = item.indexUrl + "?ssoToken=" + res + "#/main";
           const targetUrl2 = item.flowUrl;
           dd.biz.util.openLink({
@@ -406,6 +410,9 @@ const go = async (item) => {
                 dd.biz.util.openLink({ url: targetUrl2 });
               }, 100);
             },
+            onFail: (err) => {
+              console.log("钉钉err>>>>>>>>>>>>>>>>>>>>> ", err);
+            },
           });
         } else {
           const newTab = window.open("", "_blank");

+ 3 - 0
src/views/login.vue

@@ -80,6 +80,7 @@ import logo from "@/assets/images/logo.png";
 import bgImage from "@/assets/images/bg.png";
 import { login } from "@/api/user";
 import * as authUtil from "@/utils/auth";
+import { manualLogoutKey, reloginCancelKey } from "@/config/axios/service";
 
 type LoginForm = {
   username: string;
@@ -112,6 +113,8 @@ const onSubmit = async () => {
       });
 
       authUtil.setToken(res);
+      sessionStorage.removeItem(manualLogoutKey);
+      sessionStorage.removeItem(reloginCancelKey);
 
       if (form.remember) {
         authUtil.setLoginForm(form);