فهرست منبع

srm待办移动端

yanghao 2 روز پیش
والد
کامیت
ac24b546c9
3فایلهای تغییر یافته به همراه560 افزوده شده و 6 حذف شده
  1. 9 0
      src/router/index.ts
  2. 545 0
      src/views/flow/srmTodoMoblie.vue
  3. 6 6
      src/views/index.vue

+ 9 - 0
src/router/index.ts

@@ -97,6 +97,15 @@ const routes: RouteRecordRaw[] = [
     },
   },
 
+  {
+    path: "/mobile-srm-todo-list",
+    name: "MobileSRMTodoList",
+    component: () => import("@/views/flow/srmTodoMoblie.vue"),
+    meta: {
+      title: "DeepOil 智慧经营平台 | SRM待办列表",
+    },
+  },
+
   {
     path: "/srm-done-list",
     name: "SRMDoneList",

+ 545 - 0
src/views/flow/srmTodoMoblie.vue

@@ -0,0 +1,545 @@
+<template>
+  <div class="todo-list">
+    <Header />
+
+    <div class="content-wrapper mt-15 max-w-[1200px] mx-auto">
+      <div class="nav flex gap-5 items-center mb-4 py-2 pl-4 rounded-sm">
+        <p class="flex items-center text-var(--text-primary)">
+          <Icon
+            icon="mynaui:arrow-up-down"
+            class="icon pr-1 h-8 w-8"
+            color="#014099"
+          />SRM待办任务列表
+        </p>
+
+        <el-button
+          type="primary"
+          round
+          size="small"
+          color="#02409b"
+          @click="router.back()"
+          ><Icon
+            icon="mynaui:corner-up-left"
+            class="icon pr-1"
+            width="20"
+            height="20"
+          />&#36820;&#22238;</el-button
+        >
+      </div>
+
+      <div v-loading="loading && oaTasks.length === 0" class="table-wrapper">
+        <div class="table-summary mb-4 text-var(--text-secondary)!">
+          共 {{ pagination.total }} 条待办
+        </div>
+
+        <div class="task-scroll-list">
+          <div
+            v-for="(item, index) in oaTasks"
+            :key="item.requestId || `${item.requestName}-${index}`"
+            class="task-card"
+          >
+            <div class="task-card__header">
+              <span class="task-card__index">{{ index + 1 }}</span>
+              <span class="task-card__status">{{
+                item.status || "待处理"
+              }}</span>
+            </div>
+
+            <div class="task-card__title">
+              {{ item.requestName || "--" }}
+            </div>
+
+            <div class="task-card__grid">
+              <div class="task-card__field">
+                <span class="task-card__label">流程类型</span>
+                <span class="task-card__value">{{
+                  item.workflowBaseInfo?.workflowTypeName || "--"
+                }}</span>
+              </div>
+              <div class="task-card__field">
+                <span class="task-card__label">紧急程度</span>
+                <span class="task-card__value">{{
+                  item.requestLevel || "--"
+                }}</span>
+              </div>
+              <div class="task-card__field">
+                <span class="task-card__label">系统名称</span>
+                <span class="task-card__value">{{ item.sysName || "--" }}</span>
+              </div>
+              <div class="task-card__field">
+                <span class="task-card__label">当前节点</span>
+                <span class="task-card__value">{{
+                  item.currentNodeName || "--"
+                }}</span>
+              </div>
+              <div class="task-card__field">
+                <span class="task-card__label">创建人</span>
+                <span class="task-card__value">{{
+                  item.creatorName || "--"
+                }}</span>
+              </div>
+              <div class="task-card__field">
+                <span class="task-card__label">最后处理人</span>
+                <span class="task-card__value">{{
+                  item.lastOperatorName || "--"
+                }}</span>
+              </div>
+              <div class="task-card__field task-card__field--full">
+                <span class="task-card__label">流程名称</span>
+                <span class="task-card__value">{{
+                  item.workflowBaseInfo?.workflowName || "--"
+                }}</span>
+              </div>
+              <div class="task-card__field task-card__field--full">
+                <span class="task-card__label">创建时间</span>
+                <span class="task-card__value">{{
+                  item.createTime || "--"
+                }}</span>
+              </div>
+              <div class="task-card__field task-card__field--full">
+                <span class="task-card__label">最后操作时间</span>
+                <span class="task-card__value">{{
+                  item.lastOperateTime || "--"
+                }}</span>
+              </div>
+              <div class="task-card__field task-card__field--full">
+                <span class="task-card__label">接收时间</span>
+                <span class="task-card__value">{{
+                  item.receiveTime || "--"
+                }}</span>
+              </div>
+            </div>
+
+            <div class="task-card__footer">
+              <span class="task-card__action" @click="goBackPage(item)"
+                >处理</span
+              >
+            </div>
+          </div>
+
+          <InfiniteLoading
+            :identifier="infiniteId"
+            spinner="spiral"
+            @infinite="loadMore"
+          >
+            <template #no-more>
+              <div class="infinite-status">没有更多数据了</div>
+            </template>
+            <template #no-results>
+              <div class="infinite-status">没有更多数据了</div>
+            </template>
+            <template #error>
+              <div class="infinite-status">加载失败,请稍后重试</div>
+            </template>
+          </InfiniteLoading>
+        </div>
+      </div>
+    </div>
+
+    <Footer />
+  </div>
+</template>
+
+<script setup>
+import Header from "@components/home/header.vue";
+import * as dd from "dingtalk-jsapi";
+import { onMounted, ref } from "vue";
+// import { getOATasks, ssoLogin } from "@/api/user";
+import { getSRMTasks, srmLogin } from "@/api/user";
+import { useUserStore } from "@/stores/useUserStore";
+import { Icon } from "@iconify/vue";
+import router from "@/router";
+import { ElLoading } from "element-plus";
+import InfiniteLoading from "vue-infinite-loading";
+
+const userStore = useUserStore();
+
+const oaTasks = ref([]);
+const loading = ref(false);
+const infiniteId = ref(Date.now());
+
+const pagination = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0,
+});
+
+const goBackPage = async (row) => {
+  const res = await srmLogin({
+    username: userStore.getUser.username,
+  });
+  if (JSON.parse(res).msg === "账号未授权") {
+    dialogVisible.value = true;
+    return;
+  }
+  if (res) {
+    const ua = window.navigator.userAgent.toLowerCase();
+    if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
+      dd.biz.util.openLink({
+        url: `https://srm.deepoil.cc/#/mixed-page/view/MXP00048?Authorization=${JSON.parse(res).msg}`,
+        onSuccess: () => {
+          setTimeout(() => {
+            dd.biz.util.openLink({
+              url: `https://srm.deepoil.cc/#/workflow-process/request-${row.requestId}`,
+            });
+          }, SRM_LOGIN_DELAY);
+        },
+      });
+    } else {
+      const loading = ElLoading.service({
+        lock: true,
+        text: "正在跳转,请稍候...",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+      const newTab = window.open("", "_blank");
+      newTab.location.href = `https://srm.deepoil.cc/#/mixed-page/view/MXP00048?Authorization=${JSON.parse(res).msg}`;
+      setTimeout(function () {
+        setTimeout(() => {
+          loading.close();
+        }, 500);
+        newTab.location.href = `https://srm.deepoil.cc/#/workflow-process/request-${row.requestId}`;
+      }, SRM_LOGIN_DELAY);
+    }
+  }
+};
+
+const loadTaskPage = async () => {
+  const res = await getSRMTasks({
+    id: userStore.getUser.username,
+    pageNum: pagination.value.pageNum,
+    pageSize: pagination.value.pageSize,
+  });
+
+  pagination.value.total = Number(res?.todoCount || 0);
+  return Array.isArray(res?.todoList) ? res.todoList : [];
+};
+
+const resetList = () => {
+  oaTasks.value = [];
+  pagination.value.pageNum = 1;
+  pagination.value.total = 0;
+  infiniteId.value = Date.now();
+};
+
+const loadMore = async ($state) => {
+  if (!userStore.getUser.username) {
+    $state.complete();
+    return;
+  }
+
+  loading.value = pagination.value.pageNum === 1;
+
+  try {
+    const list = await loadTaskPage();
+
+    if (pagination.value.pageNum === 1) {
+      oaTasks.value = list;
+    } else {
+      oaTasks.value = [...oaTasks.value, ...list];
+    }
+
+    const loadedCount = oaTasks.value.length;
+    const hasMore =
+      list.length === pagination.value.pageSize &&
+      loadedCount < pagination.value.total;
+
+    if (hasMore) {
+      pagination.value.pageNum += 1;
+      $state.loaded();
+    } else {
+      $state.complete();
+    }
+  } catch (error) {
+    $state.error();
+  } finally {
+    loading.value = false;
+  }
+};
+
+onMounted(() => {
+  if (userStore.getUser.username) {
+    resetList();
+  }
+});
+</script>
+
+<style scoped>
+.todo-list {
+  --portal-text: #17345f;
+  --portal-text-muted: #5f6f83;
+  --portal-text-soft: #7f8fa6;
+  --portal-title: #163867;
+  --portal-subtitle: rgba(61, 92, 135, 0.86);
+  --portal-line: rgba(126, 156, 201, 0.24);
+  --portal-card: rgba(255, 255, 255, 0.82);
+  --portal-card-2: rgba(248, 251, 255, 0.94);
+  --portal-card-3: rgba(240, 246, 255, 0.88);
+  --portal-card-4: rgba(231, 239, 251, 0.92);
+  --portal-nav-bg: rgba(255, 255, 255, 0.72);
+  --portal-nav-hover: rgba(219, 232, 252, 0.8);
+  --portal-input-bg: rgba(255, 255, 255, 0.7);
+  --portal-input-hover: rgba(255, 255, 255, 0.92);
+  --portal-shadow: 0 18px 40px rgba(23, 52, 95, 0.12);
+  --portal-shadow-strong: 0 24px 60px rgba(23, 52, 95, 0.16);
+  --portal-accent: #245edb;
+  --portal-accent-2: #4e8cff;
+  --portal-accent-soft: rgba(36, 94, 219, 0.14);
+  --portal-todo-bg: rgba(242, 247, 255, 0.94);
+  --portal-todo-hover: rgba(228, 238, 252, 0.95);
+  --portal-number-todo: #e15a5a;
+  --portal-number-done: #2da04d;
+  color: var(--portal-text);
+  background:
+    radial-gradient(
+      circle at 18% 12%,
+      rgba(83, 126, 255, 0.14),
+      transparent 22%
+    ),
+    radial-gradient(
+      circle at 82% 20%,
+      rgba(71, 148, 255, 0.14),
+      transparent 20%
+    ),
+    radial-gradient(
+      circle at 50% 100%,
+      rgba(97, 142, 247, 0.12),
+      transparent 28%
+    ),
+    linear-gradient(180deg, #eef3f9 0%, #f7faff 46%, #eef3f9 100%);
+}
+
+:global([data-theme="dark"] .todo-list) {
+  --portal-text: #eaf1ff;
+  --portal-text-muted: rgba(234, 241, 255, 0.95);
+  --portal-text-soft: #8a9ab0;
+  --portal-title: #f4f7ff;
+  --portal-subtitle: rgba(188, 205, 255, 0.82);
+  --portal-line: rgba(97, 129, 206, 0.28);
+  --portal-card: rgba(10, 19, 43, 0.8);
+  --portal-card-2: rgba(12, 24, 52, 0.92);
+  --portal-card-3: rgba(17, 25, 48, 0.8);
+  --portal-card-4: rgba(15, 24, 45, 0.82);
+  --portal-nav-bg: rgba(10, 19, 43, 0.8);
+  --portal-nav-hover: rgba(28, 40, 72, 0.8);
+  --portal-input-bg: rgba(255, 255, 255, 0.08);
+  --portal-input-hover: rgba(255, 255, 255, 0.12);
+  --portal-shadow: 0 16px 34px rgba(0, 0, 0, 0.22);
+  --portal-shadow-strong: 0 24px 60px rgba(0, 0, 0, 0.38);
+  --portal-accent: #6e7dff;
+  --portal-accent-2: #8d4dff;
+  --portal-accent-soft: rgba(110, 125, 255, 0.16);
+  --portal-todo-bg: #070e20;
+  --portal-todo-hover: rgba(28, 40, 72, 0.8);
+  --portal-number-todo: #f56c6c;
+  --portal-number-done: #ffffff;
+  --bg-table: #091126;
+  color: var(--portal-text);
+  background:
+    radial-gradient(
+      circle at 18% 12%,
+      rgba(79, 82, 221, 0.34),
+      transparent 22%
+    ),
+    radial-gradient(circle at 82% 20%, rgba(28, 95, 255, 0.2), transparent 20%),
+    radial-gradient(
+      circle at 50% 100%,
+      rgba(103, 46, 255, 0.16),
+      transparent 28%
+    ),
+    linear-gradient(180deg, #040814 0%, #060d1d 46%, #040814 100%);
+}
+
+.nav {
+  background-color: var(--bg-table);
+}
+
+.todo-list {
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+}
+
+.content {
+  padding: 16px 20px;
+  margin-top: 100px;
+}
+
+.pagination-wrap {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 16px;
+}
+
+.news-container {
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  background-color: #f5f7fa;
+}
+
+.content-wrapper {
+  flex: 1;
+  max-width: 1200px;
+  padding: 20px;
+  width: 100%;
+  box-sizing: border-box;
+}
+
+.page-title {
+  margin-bottom: 20px;
+  color: #303133;
+  border-left: 5px solid #409eff;
+  padding-left: 10px;
+}
+
+.table-wrapper {
+  min-height: 300px;
+  background: #fff;
+  padding: 20px;
+  border-radius: 4px;
+}
+
+.table-title {
+  font-weight: 500;
+  color: #303133;
+}
+
+.table-summary {
+  font-size: 13px;
+}
+
+.task-scroll-list {
+  padding-right: 4px;
+  background-color: transparent;
+}
+
+.task-card {
+  background: transparent !important;
+  border: 1px solid var(--portal-line);
+  border-radius: 18px;
+  padding: 16px;
+  margin-bottom: 14px;
+  box-shadow: var(--portal-shadow);
+}
+
+.task-card__header {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  margin-bottom: 12px;
+  gap: 12px;
+}
+
+.task-card__index {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  width: 28px;
+  height: 28px;
+  border-radius: 999px;
+  background: var(--portal-accent-soft);
+  color: var(--portal-accent);
+  font-size: 13px;
+  font-weight: 600;
+  flex-shrink: 0;
+}
+
+.task-card__status {
+  color: var(--portal-accent);
+  font-size: 12px;
+  background: var(--portal-accent-soft);
+  padding: 4px 10px;
+  border-radius: 999px;
+}
+
+.task-card__title {
+  font-size: 16px;
+  font-weight: 600;
+  line-height: 1.5;
+  color: var(--portal-title);
+  margin-bottom: 14px;
+  word-break: break-word;
+}
+
+.task-card__grid {
+  display: grid;
+  grid-template-columns: repeat(2, minmax(0, 1fr));
+  gap: 12px;
+}
+
+.task-card__field {
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+  min-width: 0;
+}
+
+.task-card__field--full {
+  grid-column: 1 / -1;
+}
+
+.task-card__label {
+  font-size: 12px;
+  color: var(--portal-text-soft);
+}
+
+.task-card__value {
+  font-size: 13px;
+  line-height: 1.5;
+  color: var(--portal-text);
+  word-break: break-all;
+}
+
+.task-card__footer {
+  display: flex;
+  justify-content: flex-end;
+  margin-top: 16px;
+  padding-top: 12px;
+  border-top: 1px solid var(--portal-line);
+}
+
+.task-card__action {
+  color: #1e90ff;
+  cursor: pointer;
+  font-size: 14px;
+  font-weight: 500;
+}
+
+.infinite-status {
+  color: var(--portal-text-soft);
+  text-align: center;
+  padding: 12px 0;
+  font-size: 13px;
+}
+
+:deep(.table-wrapper) {
+  background: var(--bg-table) !important;
+}
+
+:deep(.el-loading-mask) {
+  background-color: var(--bg-table) !important;
+}
+
+@media (max-width: 640px) {
+  .content-wrapper {
+    padding: 16px;
+  }
+
+  .table-wrapper {
+    padding: 16px;
+  }
+
+  .task-card {
+    padding: 14px;
+    border-radius: 16px;
+  }
+
+  .task-card__grid {
+    grid-template-columns: 1fr;
+  }
+
+  .task-card__field--full {
+    grid-column: auto;
+  }
+}
+</style>

+ 6 - 6
src/views/index.vue

@@ -745,7 +745,7 @@ const handleQuickAccessCommand = (command: string) => {
   let ua2 = navigator.userAgent.toLowerCase();
   let isMobile = ua2.indexOf("dingtalk") > -1;
   const routeMap: Record<string, string> = {
-    "todo-oa": "/mobile-todo-list?type=oa",
+    "todo-oa": "/todo-list?type=oa",
     "todo-crm": "/crm-todo-list?type=crm",
     "done-oa": "/oa-done-list?type=oa",
     "done-crm": "/crm-done-list?type=crm",
@@ -755,11 +755,11 @@ const handleQuickAccessCommand = (command: string) => {
 
   const routeMap2: Record<string, string> = {
     "todo-oa": "/mobile-todo-list?type=oa",
-    "done-oa": "/oa-done-list?type=oa",
-    "todo-crm": "/crm-todo-list?type=crm",
-    "done-crm": "/crm-done-list?type=crm",
-    "todo-srm": "/srm-todo-list?type=srm",
-    "done-srm": "/srm-done-list?type=srm",
+    "done-oa": "/mobile-oa-done-list?type=oa",
+    "todo-crm": "/mobile-crm-todo-list?type=crm",
+    "done-crm": "/mobile-crm-done-list?type=crm",
+    "todo-srm": "/mobile-srm-todo-list?type=srm",
+    "done-srm": "/mobile-srm-done-list?type=srm",
   };
 
   // const target = routeMap[command];