فهرست منبع

crm待办移动端适配

yanghao 2 روز پیش
والد
کامیت
891f8b3672
3فایلهای تغییر یافته به همراه711 افزوده شده و 2 حذف شده
  1. 9 0
      src/router/index.ts
  2. 700 0
      src/views/flow/crmTodoListMobile.vue
  3. 2 2
      src/views/index.vue

+ 9 - 0
src/router/index.ts

@@ -79,6 +79,15 @@ const routes: RouteRecordRaw[] = [
     },
   },
 
+  {
+    path: "/moblie-crm-todo-list",
+    name: "MobileCRMTodoList",
+    component: () => import("@/views/flow/crmTodoListMobile.vue"),
+    meta: {
+      title: "DeepOil 智慧经营平台 | CRM待办列表",
+    },
+  },
+
   {
     path: "/crm-done-list",
     name: "CRMDoneList",

+ 700 - 0
src/views/flow/crmTodoListMobile.vue

@@ -0,0 +1,700 @@
+<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-6 w-6"
+            color="#014099"
+          />CRM待办任务列表
+        </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"
+          />返回</el-button
+        >
+      </div>
+      <div v-loading="loading" class="table-wrapper">
+        <el-table
+          v-loading="loading"
+          :data="oaTasks"
+          style="width: 100%"
+          height="70vh"
+          stripe
+          element-loading-text="加载中..."
+          :empty-text="loading ? '' : '暂无数据'"
+          :header-cell-style="{
+            backgroundColor: 'var(--bg-table-head) !important',
+            color: 'var(--text-primary)',
+            fontWeight: '400',
+          }"
+        >
+          <el-table-column
+            type="index"
+            label="序号"
+            width="80"
+            fixed="left"
+            align="center"
+          />
+          <el-table-column
+            prop="instTitle"
+            label="流程标题"
+            min-width="220"
+            fixed="left"
+            align="center"
+          />
+          <el-table-column
+            prop="entityTypeId"
+            label="业务类型"
+            width="140"
+            align="center"
+          />
+          <el-table-column
+            prop="priority"
+            label="优先级别"
+            width="100"
+            align="center"
+          >
+            <template #default="scope">
+              <el-tag v-if="scope.row.priority == 50" type="warning" size="mini"
+                >一般</el-tag
+              >
+              <el-tag
+                v-else-if="scope.row.priority === 90"
+                type="danger"
+                size="mini"
+              >
+                紧急
+              </el-tag>
+
+              <span v-else></span>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            prop="createAt"
+            label="任务提交时间"
+            width="180"
+            align="center"
+          >
+            <template #default="scope">
+              {{ timestampToDateTime(scope.row.submitAt) }}
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            prop="createAt"
+            label="任务创建时间"
+            width="180"
+            align="center"
+          >
+            <template #default="scope">
+              {{ timestampToDateTime(scope.row.createdAt) }}
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            prop="endAt"
+            label="任务完成时间"
+            width="180"
+            align="center"
+          >
+            <template #default="scope">
+              {{ timestampToDateTime(scope.row.endAt) }}
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            prop="userName"
+            label="任务提交人"
+            width="120"
+            align="center"
+          />
+
+          <el-table-column
+            prop="status"
+            label="任务状态"
+            width="100"
+            align="center"
+          >
+            <template #default="scope">
+              <el-tag v-if="scope.row.status === 1" type="info" size="mini"
+                >待提交</el-tag
+              >
+              <el-tag
+                v-else-if="scope.row.status === 2"
+                type="info"
+                size="mini"
+              >
+                待重新提交
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 3"
+                type="info"
+                size="mini"
+              >
+                待提交到退回节点
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 4"
+                type="primary"
+                size="mini"
+              >
+                已提交
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 5"
+                type="info"
+                size="mini"
+              >
+                待办理
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 6"
+                type="success"
+                size="mini"
+              >
+                已同意
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 7"
+                type="danger"
+                size="mini"
+              >
+                已拒绝
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 8"
+                type="danger"
+                size="mini"
+              >
+                已转办
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 9"
+                type="primary"
+                size="mini"
+              >
+                已抄送
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 10"
+                type="warning"
+                size="mini"
+              >
+                加签挂起
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 11"
+                type="warning"
+                size="mini"
+              >
+                任务挂起
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 12"
+                type="warning"
+                size="mini"
+              >
+                已收回
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 13"
+                type="warning"
+                size="mini"
+              >
+                已移交
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 14"
+                type="warning"
+                size="mini"
+              >
+                已委托
+              </el-tag>
+
+              <el-tag
+                v-else-if="scope.row.status === 99"
+                type="success"
+                size="mini"
+              >
+                无需办理
+              </el-tag>
+              <span v-else></span>
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="操作"
+            width="120"
+            fixed="right"
+            align="center"
+          >
+            <template #default="scope">
+              <span
+                class="text-[#1e90ff] cursor-pointer"
+                @click="goBackPage(scope.row)"
+                >处理</span
+              >
+            </template>
+          </el-table-column>
+        </el-table>
+      </div>
+
+      <div class="pagination-container">
+        <el-pagination
+          v-model:current-page="pagination.pageNum"
+          v-model:page-size="pagination.pageSize"
+          :total="pagination.total"
+          :page-sizes="[10, 20, 50, 100]"
+          layout="total, sizes, prev, pager, next"
+          background
+          @current-change="handleCurrentChange"
+          @size-change="handleSizeChange"
+        />
+      </div>
+    </div>
+
+    <Footer />
+  </div>
+</template>
+
+<script setup>
+import Header from "@components/home/header.vue";
+import { ref, onMounted } from "vue";
+import { getCRMTasks, ssoLogin } from "@/api/user";
+import { useUserStore } from "@/stores/useUserStore";
+import { getAccessToken } from "@/utils/auth";
+import * as dd from "dingtalk-jsapi";
+import { Icon } from "@iconify/vue";
+import router from "@/router";
+const userStore = useUserStore();
+
+const oaTasks = ref([]);
+const loading = ref(false);
+
+const pagination = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0,
+});
+
+const handleCurrentChange = async (page) => {
+  pagination.value.pageNum = page;
+  loading.value = true;
+  try {
+    const res = await getCRMTasks({
+      id: userStore.getUser.username,
+      type: "pending",
+      pageNum: pagination.value.pageNum,
+      pageSize: pagination.value.pageSize,
+    });
+    oaTasks.value = res.todoList;
+    pagination.value.total = res.todoCount;
+  } finally {
+    loading.value = false;
+  }
+};
+
+const handleSizeChange = async (size) => {
+  pagination.value.pageSize = size;
+  pagination.value.pageNum = 1;
+  loading.value = true;
+  try {
+    const res = await getCRMTasks({
+      id: userStore.getUser.username,
+      type: "pending",
+      pageNum: pagination.value.pageNum,
+      pageSize: pagination.value.pageSize,
+    });
+    oaTasks.value = res.todoList;
+    pagination.value.total = res.todoCount;
+  } finally {
+    loading.value = false;
+  }
+};
+
+const goBackPage = async (row) => {
+  if (userStore.getUser.username && getAccessToken()) {
+    const ua = window.navigator.userAgent; // const ua = navigator.userAgent;
+    const isDesktop =
+      ua.includes("DingTalk") &&
+      (ua.includes("Windows") || ua.includes("Macintosh"));
+
+    let ua2 = navigator.userAgent.toLowerCase();
+    var isMobile = ua2.indexOf("dingtalk") > -1;
+    if (ua2.includes("dingtalk") || ua2.includes("dingtalkwork")) {
+      if (isMobile && !isDesktop) {
+        const originPath =
+          "/bff/spa/crmh5/index.html#/home?platform=H5&deviceType=0";
+        // 连续三次encodeURIComponent
+        let e1 = encodeURIComponent(originPath);
+        let e2 = encodeURIComponent(e1);
+        let e3 = encodeURIComponent(e2);
+        dd.biz.util.openLink({
+          url: `https://crm-tencent.xiaoshouyi.com/global/sso/callback/00APEB9EEEA9B2E338B686B7ECFA8585808C.action?token=${getAccessToken()}&returnUri=${e3}`,
+
+          onSuccess: () => {},
+        });
+      } else if (isDesktop) {
+        const originPath = "/bff/neoweb#/approval_workbench";
+        // 连续三次encodeURIComponent
+        let e1 = encodeURIComponent(originPath);
+        let e2 = encodeURIComponent(e1);
+        let e3 = encodeURIComponent(e2);
+        dd.biz.util.openLink({
+          url: `https://crm-tencent.xiaoshouyi.com/global/sso/callback/00APEB9EEEA9B2E338B686B7ECFA8585808C.action?token=${getAccessToken()}&returnUri=${e3}`,
+          onSuccess: () => {},
+        });
+      }
+    } else {
+      const newTab = window.open("", "_blank");
+      const originPath = "/bff/neoweb#/approval_workbench";
+      // 连续三次encodeURIComponent
+      let e1 = encodeURIComponent(originPath);
+      let e2 = encodeURIComponent(e1);
+      let e3 = encodeURIComponent(e2);
+      newTab.location.href = `https://crm-tencent.xiaoshouyi.com/global/sso/callback/00APEB9EEEA9B2E338B686B7ECFA8585808C.action?token=${getAccessToken()}&returnUri=${e3}`;
+    }
+  } else {
+    router.push("/login");
+  }
+};
+
+function timestampToDateTime(timestamp) {
+  // 兼容 10位(秒) / 13位(毫秒)
+  const len = String(timestamp).length;
+  const date = new Date(Number(timestamp) * (len === 10 ? 1000 : 1));
+
+  // 年
+  const year = date.getFullYear();
+  // 月(0~11 → +1)
+  const month = String(date.getMonth() + 1).padStart(2, "0");
+  // 日
+  const day = String(date.getDate()).padStart(2, "0");
+  // 时
+  const hours = String(date.getHours()).padStart(2, "0");
+  // 分
+  const minutes = String(date.getMinutes()).padStart(2, "0");
+  // 秒
+  const seconds = String(date.getSeconds()).padStart(2, "0");
+
+  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
+}
+onMounted(async () => {
+  if (userStore.getUser.username) {
+    loading.value = true;
+    try {
+      const res = await getCRMTasks({
+        id: userStore.getUser.username,
+        type: "pending",
+        pageNum: pagination.value.pageNum,
+        pageSize: pagination.value.pageSize,
+      });
+      oaTasks.value = res.todoList;
+      pagination.value.total = res.todoCount;
+    } finally {
+      loading.value = false;
+    }
+  }
+});
+</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;
+  /* margin: 0 auto; */
+  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: 400px;
+  background: #fff;
+  padding: 20px;
+  border-radius: 4px;
+}
+
+.table-title {
+  font-weight: 500;
+  color: #303133;
+}
+
+.table-summary {
+  color: #606266;
+  font-size: 13px;
+}
+
+.pagination-container {
+  display: flex;
+  justify-content: center;
+  margin-top: 0px;
+  padding: 20px 0;
+}
+
+:deep(.el-table) {
+  background-color: var(--bg-table) !important;
+  color: var(--text-primary) !important;
+}
+
+:deep(.table-wrapper) {
+  background: var(--bg-table) !important;
+}
+
+:deep(.el-table__header-wrapper thead) {
+  background: var(--bg-table) !important;
+  color: var(--text-primary) !important;
+}
+
+:deep(.el-table__header-wrapper .el-table__header) {
+  border-bottom: none;
+}
+:deep(.el-table__inner-wrapper) {
+  background: var(--bg-table) !important;
+  color: var(--text-primary) !important;
+}
+:deep(.el-table__body-wrapper .el-table__row) {
+  background: var(--bg-table);
+  color: var(--text-primary) !important;
+}
+
+:deep(.el-table__body-wrapper .el-table__row .hover-row) {
+  background: var(--bg-table) !important;
+  color: var(--text-primary) !important;
+}
+
+:deep(.el-table__body-wrapper .el-table__row .el-table__cell) {
+  background: var(--bg-table) !important;
+  color: var(--text-primary) !important;
+  border-bottom: 1px solid var(--border-color) !important;
+}
+
+:deep(.el-loading-mask) {
+  background-color: var(--bg-table) !important; /* 半透明深色遮罩 */
+}
+
+:deep(.el-table__body-wrapper .el-table__row .el-table__cell) {
+  border-bottom: 1px solid #313849;
+}
+
+:deep(.el-pagination is-background) {
+  background: var(--bg-table) !important;
+}
+
+:deep(.el-pagination .el-pager li) {
+  background: var(--bg-table) !important;
+  color: var(--text-tertiary) !important;
+}
+
+:deep(.el-pagination .el-pager li.is-active) {
+  /* background: #2d8cf0 !important; */
+  color: var(--portal-accent) !important;
+}
+
+:deep(.el-select .el-select__wrapper) {
+  background: var(--bg-table) !important;
+  border: 1px solid #313849 !important;
+  outline: none !important;
+}
+
+:deep(.el-input) {
+  border: 1px solid #313849 !important;
+  outline: none !important;
+}
+
+:deep(.btn-next) {
+  background: var(--bg-table) !important;
+  color: var(--text-tertiary) !important;
+}
+
+:deep(.btn-prev) {
+  background: var(--bg-table) !important;
+  color: var(--text-tertiary) !important;
+}
+
+/* 下拉菜单弹出层的背景 */
+:deep(.el-select-dropdown) {
+  background-color: var(--bg-table) !important;
+  border: 1px solid #313849 !important;
+}
+
+/* 下拉菜单项 */
+:deep(.el-select-dropdown__item) {
+  color: var(--bg-table) !important;
+}
+
+:deep(.el-select-dropdown__item.hover),
+:deep(.el-select-dropdown__item:hover) {
+  background-color: var(--bg-table) !important; /* 悬停深色背景 */
+}
+
+/* 关键:修复下拉选择框 (PageSize) 的白色边框/背景 */
+:deep(.el-pagination .el-select .el-select__wrapper) {
+  background-color: var(--bg-table) !important;
+  box-shadow: none !important; /* 去掉可能的阴影 */
+  border: 1px solid #313849 !important; /* 统一边框颜色 */
+}
+
+/* 去掉聚焦时的白色/蓝色轮廓 */
+:deep(.el-pagination .el-select .el-select__wrapper.is-focused),
+:deep(.el-pagination .el-select .el-select__wrapper:hover) {
+  box-shadow: none !important;
+  border-color: #409eff !important; /* 聚焦时变为主题蓝,或者保持 #313849 */
+}
+
+/* 通用输入框边框修复 (如果其他地方也有) */
+:deep(.el-input__wrapper) {
+  background-color: var(--bg-table) !important;
+  box-shadow: none !important; /* 去掉默认的白色/灰色阴影边框 */
+  border: 1px solid #313849 !important;
+}
+
+:deep(.el-input__inner) {
+  color: var(--bg-primary) !important;
+}
+</style>

+ 2 - 2
src/views/index.vue

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