Browse Source

srm流程

yanghao 1 tuần trước cách đây
mục cha
commit
9efc1e5bfa
6 tập tin đã thay đổi với 973 bổ sung187 xóa
  1. 13 0
      src/api/user.ts
  2. 18 0
      src/router/index.ts
  3. 70 183
      src/views/flow/index.vue
  4. 412 0
      src/views/flow/srmDone.vue
  5. 412 0
      src/views/flow/srmTodo.vue
  6. 48 4
      src/views/index.vue

+ 13 - 0
src/api/user.ts

@@ -129,6 +129,19 @@ export const getCRMTasks = async (params) => {
   });
 };
 
+// srm的待办及已办
+export const getSRMTasks = async (params) => {
+  return await request.get({
+    url:
+      "/admin-api/portal/todo/srm?workcode=" +
+      params.id +
+      "&pageNo=" +
+      params.pageNum +
+      "&pageSize=" +
+      params.pageSize,
+  });
+};
+
 // CMR消息通知
 export const getNotifyMessages = async (id) => {
   return await request.get({

+ 18 - 0
src/router/index.ts

@@ -79,6 +79,24 @@ const routes: RouteRecordRaw[] = [
     },
   },
 
+  {
+    path: "/srm-todo-list",
+    name: "SRMTodoList",
+    component: () => import("@/views/flow/srmTodo.vue"),
+    meta: {
+      title: "DeepOil 智慧经营平台 | SRM待办列表",
+    },
+  },
+
+  {
+    path: "/srm-done-list",
+    name: "SRMDoneList",
+    component: () => import("@/views/flow/srmDone.vue"),
+    meta: {
+      title: "DeepOil 智慧经营平台 | SRM已办列表",
+    },
+  },
+
   {
     path: "/drive",
     name: "Drive",

+ 70 - 183
src/views/flow/index.vue

@@ -218,23 +218,21 @@ import Header from "@components/home/header.vue";
 import Footer from "@components/home/Footer.vue";
 import { computed, ref, onMounted, onBeforeUnmount, nextTick } from "vue";
 import { Icon } from "@iconify/vue";
-import { getFlows, ssoLogin, getOATasks, getCRMTasks } from "@/api/user";
+import {
+  getFlows,
+  ssoLogin,
+  getOATasks,
+  getCRMTasks,
+  getSRMTasks,
+} from "@/api/user";
 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();
 import { ElLoading, ElMessage } from "element-plus";
 const userStore = useUserStore();
 
-const lineChartInstance = ref(null);
-let lineChartRef = ref(null);
-let pieChartRef = ref(null);
-const pieChartInstance = ref(null);
-let chartResizeObserver = null;
-let chartInitTimer = null;
-
 // 1. 定义 Ref
 const tabsContainerRef = ref(null);
 const isLeftDisabled = ref(true);
@@ -276,31 +274,6 @@ const handleTabScroll = () => {
   updateArrowState();
 };
 
-const initChartsSafe = (attempt = 0) => {
-  const lineDom = lineChartRef.value;
-  const pieDom = pieChartRef.value;
-
-  if (!lineDom || !pieDom) return;
-
-  const lineRect = lineDom.getBoundingClientRect();
-  const pieRect = pieDom.getBoundingClientRect();
-  const isLineReady = lineRect.width > 0 && lineRect.height > 0;
-  const isPieReady = pieRect.width > 0 && pieRect.height > 0;
-
-  if (isLineReady && isPieReady) {
-    initLineChart();
-    initPieChart();
-    handleResize();
-    return;
-  }
-
-  if (attempt < 8) {
-    chartInitTimer = window.setTimeout(() => {
-      initChartsSafe(attempt + 1);
-    }, 120);
-  }
-};
-
 const getGreeting = () => {
   const hour = new Date().getHours();
   if (hour < 12) return "早上好";
@@ -308,24 +281,6 @@ const getGreeting = () => {
   return "晚上好";
 };
 
-// 模拟数据 - 请根据实际 API 返回的数据调整
-const lineChartData = {
-  title: "流程处理趋势 (30天)",
-  xAxis: ["03-27", "03-28", "03-29", "03-30", "03-31", "04-01", "04-02"],
-  yAxis: [12, 18, 15, 20, 27, 24, 31],
-};
-
-const pieChartData = {
-  title: "流程类型占比",
-  seriesData: [
-    { name: "财务报销", value: 35, itemStyle: { color: "#409eff" } },
-    { name: "行政办公", value: 25, itemStyle: { color: "#f56c6c" } },
-    { name: "IT技术", value: 20, itemStyle: { color: "#9a66ff" } },
-    { name: "人力资源", value: 15, itemStyle: { color: "#e6a23c" } },
-    { name: "业务申请", value: 5, itemStyle: { color: "#50c878" } },
-  ],
-};
-
 const getDetailList = (index) => {
   switch (index) {
     case 0: // 我的待办
@@ -340,113 +295,6 @@ const getDetailList = (index) => {
       return [];
   }
 };
-// 初始化图表
-const initLineChart = () => {
-  const chartDom = lineChartRef.value;
-  if (!chartDom) return;
-
-  const chart = echarts.init(chartDom);
-  lineChartInstance.value = chart; // 保存实例
-
-  chart.setOption({
-    title: {
-      text: lineChartData.title,
-      left: "10",
-      top: 20,
-
-      textStyle: {
-        fontSize: 16,
-        fontWeight: "bold",
-        color: "#333",
-      },
-    },
-    // ... 原有的 option 配置保持不变 ...
-    tooltip: {
-      trigger: "axis",
-      axisPointer: { type: "shadow" },
-    },
-    grid: {
-      left: "3%",
-      right: "4%",
-      bottom: "10%",
-      containLabel: true,
-    },
-    xAxis: {
-      type: "category",
-      data: lineChartData.xAxis,
-      axisLabel: { formatter: (value) => value },
-    },
-    yAxis: {
-      type: "value",
-      splitLine: { show: true, lineStyle: { color: "#eee" } },
-    },
-    series: [
-      {
-        name: "处理数量",
-        type: "line",
-        smooth: true,
-        areaStyle: {
-          opacity: 0.3,
-          color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
-            { offset: 0, color: "#409eff" },
-            { offset: 1, color: "#b3d8ff" },
-          ]),
-        },
-        lineStyle: { width: 3, color: "#2563eb" },
-        symbol: "circle",
-        symbolSize: 8,
-        data: lineChartData.yAxis,
-      },
-    ],
-  });
-};
-
-const initPieChart = () => {
-  const chartDom = pieChartRef.value;
-  if (!chartDom) return;
-
-  const chart = echarts.init(chartDom);
-  pieChartInstance.value = chart; // 保存实例
-
-  chart.setOption({
-    title: {
-      text: pieChartData.title,
-      left: "10",
-      top: 20,
-
-      textStyle: {
-        fontSize: 16,
-        fontWeight: "bold",
-        color: "#333",
-      },
-    },
-    // ... 原有的 option 配置保持不变 ...
-    tooltip: {
-      trigger: "item",
-      formatter: "{a} <br/>{b}: {c} ({d}%)",
-    },
-    legend: { show: false },
-    series: [
-      {
-        name: "流程类型",
-        type: "pie",
-        radius: ["50%", "70%"],
-        avoidLabelOverlap: false,
-        label: { show: false, position: "center" },
-        emphasis: {
-          label: { show: true, fontSize: "14", fontWeight: "bold" },
-        },
-        labelLine: { show: false },
-        data: pieChartData.seriesData,
-      },
-    ],
-  });
-};
-
-const handleResize = () => {
-  lineChartInstance.value?.resize();
-  pieChartInstance.value?.resize();
-};
 
 const tabs = ref([]);
 
@@ -734,10 +582,25 @@ const handleDetailClick = (task, categoryTitle) => {
       query: { type: task.name.toLowerCase() },
     });
   }
+
+  if (task.name === "SRM" && categoryTitle === "我的待办") {
+    router.push({
+      path: "/srm-todo-list",
+      query: { type: task.name.toLowerCase() },
+    });
+  }
+
+  if (task.name === "SRM" && categoryTitle === "已办事项") {
+    router.push({
+      path: "/srm-done-list",
+      query: { type: task.name.toLowerCase() },
+    });
+  }
 };
 
 let oaTasks = ref([]);
 let crmTasks = ref([]);
+let srmTasks = ref([]);
 const statsLoading = ref(true);
 
 const stats = ref([
@@ -761,12 +624,14 @@ const stats = ref([
 const todoCount = ref([
   { name: "OA", value: 0 },
   { name: "CRM", value: 0 },
+  { name: "SRM", value: 0 },
 ]);
 
 // 已办事项
 const doneCount = ref([
   { name: "OA", value: 0 },
   { name: "CRM", value: 0 },
+  { name: "SRM", value: 0 },
 ]);
 
 onMounted(async () => {
@@ -778,19 +643,6 @@ onMounted(async () => {
   if (tabsContainerRef.value) {
     tabsContainerRef.value.addEventListener("scroll", handleTabScroll);
   }
-  requestAnimationFrame(() => {
-    initChartsSafe();
-    // 添加监听
-    window.addEventListener("resize", handleResize);
-    // 使用 ResizeObserver 监听容器尺寸变化(移动端更稳定)
-    if (typeof ResizeObserver !== "undefined") {
-      chartResizeObserver = new ResizeObserver(() => {
-        handleResize();
-      });
-      if (lineChartRef.value) chartResizeObserver.observe(lineChartRef.value);
-      if (pieChartRef.value) chartResizeObserver.observe(pieChartRef.value);
-    }
-  });
 
   if (userStore.getUser.username) {
     try {
@@ -809,12 +661,24 @@ onMounted(async () => {
       });
       crmTasks.value = crmRes;
 
+      const srmRes = await getSRMTasks({
+        id: userStore.getUser.username,
+
+        pageNum: 1,
+        pageSize: 10,
+      });
+
+      srmTasks.value = srmRes;
+
       stats.value[0].number =
-        Number(oaTasks.value.todoCount) + Number(crmTasks.value.todoCount);
+        Number(oaTasks.value.todoCount) +
+        Number(crmTasks.value.todoCount) +
+        Number(srmTasks.value.todoCount);
 
       todoCount.value = [
         { name: "OA", value: oaTasks.value.todoCount ?? 0 },
         { name: "CRM", value: crmTasks.value.todoCount ?? 0 },
+        { name: "SRM", value: srmTasks.value.todoCount ?? 0 },
       ];
 
       // *****************已办事项统计*************************
@@ -826,12 +690,22 @@ onMounted(async () => {
         pageSize: 10,
       });
 
+      const srmDoneRes = await getSRMTasks({
+        id: userStore.getUser.username,
+
+        pageNum: 1,
+        pageSize: 10,
+      });
+
       stats.value[1].number =
-        Number(oaTasks.value.doneCount) + Number(crmDoneRes.todoCount);
+        Number(oaTasks.value.doneCount) +
+        Number(crmDoneRes.todoCount) +
+        Number(srmDoneRes.doneCount);
 
       doneCount.value = [
         { name: "OA", value: oaTasks.value.doneCount ?? 0 },
         { name: "CRM", value: crmDoneRes.todoCount ?? 0 },
+        { name: "SRM", value: srmDoneRes.doneCount ?? 0 },
       ];
     } finally {
       statsLoading.value = false;
@@ -854,12 +728,23 @@ onMounted(async () => {
         });
         crmTasks.value = crmRes;
 
+        const srmRes = await getSRMTasks({
+          id: userStore.getUser.username,
+          pageNum: 1,
+          pageSize: 10,
+        });
+
+        srmTasks.value = srmRes;
+
         stats.value[0].number =
-          Number(oaTasks.value.todoCount) + Number(crmTasks.value.todoCount);
+          Number(oaTasks.value.todoCount) +
+          Number(crmTasks.value.todoCount) +
+          Number(srmTasks.value.todoCount);
 
         todoCount.value = [
           { name: "OA", value: oaTasks.value.todoCount ?? 0 },
           { name: "CRM", value: crmTasks.value.todoCount ?? 0 },
+          { name: "SRM", value: srmTasks.value.todoCount ?? 0 },
         ];
 
         const crmDoneRes = await getCRMTasks({
@@ -869,12 +754,21 @@ onMounted(async () => {
           pageSize: 10,
         });
 
+        const srmDoneRes = await getSRMTasks({
+          id: userStore.getUser.username,
+          pageNum: 1,
+          pageSize: 10,
+        });
+
         stats.value[1].number =
-          Number(oaTasks.value.doneCount) + Number(crmDoneRes.todoCount);
+          Number(oaTasks.value.doneCount) +
+          Number(crmDoneRes.todoCount) +
+          Number(srmDoneRes.doneCount);
 
         doneCount.value = [
           { name: "OA", value: oaTasks.value.doneCount ?? 0 },
           { name: "CRM", value: crmDoneRes.todoCount ?? 0 },
+          { name: "SRM", value: srmDoneRes.doneCount ?? 0 },
         ];
       },
       10 * 60 * 1000,
@@ -886,13 +780,6 @@ onMounted(async () => {
 
 // 组件卸载时移除监听,防止内存泄漏
 onBeforeUnmount(() => {
-  window.removeEventListener("resize", handleResize);
-  chartResizeObserver?.disconnect();
-  if (chartInitTimer) window.clearTimeout(chartInitTimer);
-  // 可选:销毁 echarts 实例
-  lineChartInstance.value?.dispose();
-  pieChartInstance.value?.dispose();
-
   if (tabsContainerRef.value) {
     tabsContainerRef.value.removeEventListener("scroll", handleTabScroll);
   }

+ 412 - 0
src/views/flow/srmDone.vue

@@ -0,0 +1,412 @@
+<template>
+  <div class="todo-list">
+    <Header />
+
+    <div class="content-wrapper mt-15 max-w-[1200px] mx-auto">
+      <div
+        class="flex gap-5 items-center mb-4 bg-[#091126] py-2 pl-4 rounded-sm"
+      >
+        <p class="flex items-center text-white">
+          <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" class="table-wrapper">
+        <el-table
+          v-loading="loading"
+          :data="oaTasks"
+          style="width: 100%"
+          stripe
+          height="70vh"
+          element-loading-text="加载中..."
+          :empty-text="loading ? '' : '暂无数据'"
+          :header-cell-style="{
+            backgroundColor: '#091126',
+            color: '#b8bfd0',
+            fontWeight: '400',
+          }"
+          :cell-style="{
+            color: 'black',
+          }"
+        >
+          <el-table-column
+            type="index"
+            label="&#24207;&#21495;"
+            width="80"
+            fixed="left"
+            align="center"
+            :index="getIndex"
+          />
+          <el-table-column
+            prop="title"
+            label="请求标题"
+            min-width="250"
+            fixed="left"
+            align="center"
+          />
+          <el-table-column
+            prop="creatorName"
+            label="创建人"
+            width="140"
+            align="center"
+          />
+
+          <el-table-column label="创建日期" width="140" align="center">
+            <template #default="scope">
+              {{ scope.row.createdDate.substring(0, 10) }}
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="操作"
+            width="120"
+            fixed="right"
+            align="center"
+          >
+            <template #default="scope">
+              <span
+                class="text-[#1e90ff] cursor-pointer text-[13px]"
+                @click="goBackPage(scope.row)"
+                >&#22788;&#29702;</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 * as dd from "dingtalk-jsapi";
+import { ref, onMounted } from "vue";
+import { getSRMTasks, ssoLogin } from "@/api/user";
+import { useUserStore } from "@/stores/useUserStore";
+import { Icon } from "@iconify/vue";
+import router from "@/router";
+const userStore = useUserStore();
+import { ElLoading, ElMessage } from "element-plus";
+
+const oaTasks = ref([]);
+const loading = ref(false);
+
+const pagination = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0,
+});
+
+const goBackPage = async (row) => {
+  const res = await ssoLogin({
+    username: userStore.getUser.username,
+  });
+
+  if (res) {
+    const ua = window.navigator.userAgent.toLowerCase();
+    if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
+      dd.biz.util.openLink({
+        url:
+          "https://yfoa.keruioil.com/wui/index.html" +
+          "?ssoToken=" +
+          res +
+          "#/main", // 先跳你的 SSO 链接
+        onSuccess: () => {
+          // 延迟跳目标业务地址(和你原来 setTimeout 逻辑一致)
+          setTimeout(() => {
+            dd.biz.util.openLink({
+              url: `https://yfoa.keruioil.com/spa/workflow/static4form/index.html?_rdm=1776063595284#/main/workflow/req?requestid=${row.requestId}`,
+            });
+          }, 100);
+        },
+      });
+    } else {
+      const loading = ElLoading.service({
+        lock: true,
+        text: "正在跳转,请稍候...",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+      const newTab = window.open("", "_blank");
+      newTab.location.href =
+        "https://yfoa.keruioil.com/wui/index.html" +
+        "?ssoToken=" +
+        res +
+        "#/main";
+
+      setTimeout(function () {
+        newTab.location.href = `https://yfoa.keruioil.com/spa/workflow/static4form/index.html?_rdm=1776063595284#/main/workflow/req?requestid=${row.requestId}`;
+        setTimeout(() => {
+          loading.close();
+        }, 500);
+      }, 100);
+    }
+  }
+};
+
+const handleCurrentChange = async (page) => {
+  pagination.value.pageNum = page;
+  try {
+    const res = await getSRMTasks({
+      id: userStore.getUser.username,
+      pageNum: pagination.value.pageNum,
+      pageSize: pagination.value.pageSize,
+    });
+    oaTasks.value = res.doneList;
+    pagination.value.total = Number(res.doneCount);
+  } finally {
+    loading.value = false;
+  }
+};
+
+const handleSizeChange = async (size) => {
+  pagination.value.pageSize = size;
+  pagination.value.pageNum = 1;
+
+  try {
+    const res = await getSRMTasks({
+      id: userStore.getUser.username,
+      pageNum: pagination.value.pageNum,
+      pageSize: pagination.value.pageSize,
+    });
+    oaTasks.value = res.doneList;
+    pagination.value.total = Number(res.doneCount);
+  } finally {
+    loading.value = false;
+  }
+};
+
+onMounted(async () => {
+  if (userStore.getUser.username) {
+    loading.value = true;
+    try {
+      const res = await getSRMTasks({
+        id: userStore.getUser.username,
+        pageNum: pagination.value.pageNum,
+        pageSize: pagination.value.pageSize,
+      });
+      oaTasks.value = res.doneList;
+      pagination.value.total = Number(res.doneCount);
+    } finally {
+      loading.value = false;
+    }
+  }
+});
+</script>
+
+<style scoped>
+.todo-list {
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  /* background-color: #f5f7fa; */
+}
+
+.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: #091126 !important;
+  color: white !important;
+}
+
+:deep(.table-wrapper) {
+  background: #091126 !important;
+}
+
+:deep(.el-table__header-wrapper thead) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+:deep(.el-table__header-wrapper .el-table__header) {
+  border-bottom: none;
+}
+:deep(.el-table__inner-wrapper) {
+  background: #091126 !important;
+  color: white !important;
+}
+:deep(.el-table__body-wrapper .el-table__row) {
+  background: #091126;
+  color: white !important;
+}
+
+:deep(.el-table__body-wrapper .el-table__row .hover-row) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+:deep(.el-table__body-wrapper .el-table__row .el-table__cell) {
+  background: #091126 !important;
+  color: white !important;
+  border-bottom: 1px solid #313849;
+}
+
+:deep(.el-loading-mask) {
+  background-color: rgba(9, 17, 38, 0.8) !important; /* 半透明深色遮罩 */
+}
+
+:deep(.el-table__body-wrapper .el-table__row .el-table__cell) {
+  border-bottom: 1px solid #313849;
+}
+
+:deep(.el-pagination is-background) {
+  background: #091126 !important;
+}
+
+:deep(.el-pagination .el-pager li) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+:deep(.el-pagination .el-pager li.active) {
+  background: #2d8cf0 !important;
+}
+
+:deep(.el-select .el-select__wrapper) {
+  background: #091126 !important;
+  border: 1px solid #313849 !important;
+  outline: none !important;
+}
+
+:deep(.el-input) {
+  border: 1px solid #313849 !important;
+  outline: none !important;
+}
+
+:deep(.btn-next) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+:deep(.btn-prev) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+/* 下拉菜单弹出层的背景 */
+:deep(.el-select-dropdown) {
+  background-color: #091126 !important;
+  border: 1px solid #313849 !important;
+}
+
+/* 下拉菜单项 */
+:deep(.el-select-dropdown__item) {
+  color: #fff !important;
+}
+
+:deep(.el-select-dropdown__item.hover),
+:deep(.el-select-dropdown__item:hover) {
+  background-color: #111a35 !important; /* 悬停深色背景 */
+}
+
+/* 关键:修复下拉选择框 (PageSize) 的白色边框/背景 */
+:deep(.el-pagination .el-select .el-select__wrapper) {
+  background-color: #091126 !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: #091126 !important;
+  box-shadow: none !important; /* 去掉默认的白色/灰色阴影边框 */
+  border: 1px solid #313849 !important;
+}
+
+:deep(.el-input__inner) {
+  color: #fff !important;
+}
+</style>

+ 412 - 0
src/views/flow/srmTodo.vue

@@ -0,0 +1,412 @@
+<template>
+  <div class="todo-list">
+    <Header />
+
+    <div class="content-wrapper mt-15 max-w-[1200px] mx-auto">
+      <div
+        class="flex gap-5 items-center mb-4 bg-[#091126] py-2 pl-4 rounded-sm"
+      >
+        <p class="flex items-center text-white">
+          <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" class="table-wrapper">
+        <el-table
+          v-loading="loading"
+          :data="oaTasks"
+          style="width: 100%"
+          stripe
+          height="70vh"
+          element-loading-text="加载中..."
+          :empty-text="loading ? '' : '暂无数据'"
+          :header-cell-style="{
+            backgroundColor: '#091126',
+            color: '#b8bfd0',
+            fontWeight: '400',
+          }"
+          :cell-style="{
+            color: 'black',
+          }"
+        >
+          <el-table-column
+            type="index"
+            label="&#24207;&#21495;"
+            width="80"
+            fixed="left"
+            align="center"
+            :index="getIndex"
+          />
+          <el-table-column
+            prop="title"
+            label="请求标题"
+            min-width="250"
+            fixed="left"
+            align="center"
+          />
+          <el-table-column
+            prop="creatorName"
+            label="创建人"
+            width="140"
+            align="center"
+          />
+
+          <el-table-column label="创建日期" width="140" align="center">
+            <template #default="scope">
+              {{ scope.row.createdDate.substring(0, 10) }}
+            </template>
+          </el-table-column>
+
+          <el-table-column
+            label="操作"
+            width="120"
+            fixed="right"
+            align="center"
+          >
+            <template #default="scope">
+              <span
+                class="text-[#1e90ff] cursor-pointer text-[13px]"
+                @click="goBackPage(scope.row)"
+                >&#22788;&#29702;</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 * as dd from "dingtalk-jsapi";
+import { ref, onMounted } from "vue";
+import { getSRMTasks, ssoLogin } from "@/api/user";
+import { useUserStore } from "@/stores/useUserStore";
+import { Icon } from "@iconify/vue";
+import router from "@/router";
+const userStore = useUserStore();
+import { ElLoading, ElMessage } from "element-plus";
+
+const oaTasks = ref([]);
+const loading = ref(false);
+
+const pagination = ref({
+  pageNum: 1,
+  pageSize: 10,
+  total: 0,
+});
+
+const goBackPage = async (row) => {
+  const res = await ssoLogin({
+    username: userStore.getUser.username,
+  });
+
+  if (res) {
+    const ua = window.navigator.userAgent.toLowerCase();
+    if (ua.includes("dingtalk") || ua.includes("dingtalkwork")) {
+      dd.biz.util.openLink({
+        url:
+          "https://yfoa.keruioil.com/wui/index.html" +
+          "?ssoToken=" +
+          res +
+          "#/main", // 先跳你的 SSO 链接
+        onSuccess: () => {
+          // 延迟跳目标业务地址(和你原来 setTimeout 逻辑一致)
+          setTimeout(() => {
+            dd.biz.util.openLink({
+              url: `https://yfoa.keruioil.com/spa/workflow/static4form/index.html?_rdm=1776063595284#/main/workflow/req?requestid=${row.requestId}`,
+            });
+          }, 100);
+        },
+      });
+    } else {
+      const loading = ElLoading.service({
+        lock: true,
+        text: "正在跳转,请稍候...",
+        background: "rgba(0, 0, 0, 0.7)",
+      });
+      const newTab = window.open("", "_blank");
+      newTab.location.href =
+        "https://yfoa.keruioil.com/wui/index.html" +
+        "?ssoToken=" +
+        res +
+        "#/main";
+
+      setTimeout(function () {
+        newTab.location.href = `https://yfoa.keruioil.com/spa/workflow/static4form/index.html?_rdm=1776063595284#/main/workflow/req?requestid=${row.requestId}`;
+        setTimeout(() => {
+          loading.close();
+        }, 500);
+      }, 100);
+    }
+  }
+};
+
+const handleCurrentChange = async (page) => {
+  pagination.value.pageNum = page;
+  try {
+    const res = await getSRMTasks({
+      id: userStore.getUser.username,
+      pageNum: pagination.value.pageNum,
+      pageSize: pagination.value.pageSize,
+    });
+    oaTasks.value = res.todoList;
+    pagination.value.total = Number(res.todoCount);
+  } finally {
+    loading.value = false;
+  }
+};
+
+const handleSizeChange = async (size) => {
+  pagination.value.pageSize = size;
+  pagination.value.pageNum = 1;
+
+  try {
+    const res = await getSRMTasks({
+      id: userStore.getUser.username,
+      pageNum: pagination.value.pageNum,
+      pageSize: pagination.value.pageSize,
+    });
+    oaTasks.value = res.todoList;
+    pagination.value.total = Number(res.todoCount);
+  } finally {
+    loading.value = false;
+  }
+};
+
+onMounted(async () => {
+  if (userStore.getUser.username) {
+    loading.value = true;
+    try {
+      const res = await getSRMTasks({
+        id: userStore.getUser.username,
+        pageNum: pagination.value.pageNum,
+        pageSize: pagination.value.pageSize,
+      });
+      oaTasks.value = res.todoList;
+      pagination.value.total = Number(res.todoCount);
+    } finally {
+      loading.value = false;
+    }
+  }
+});
+</script>
+
+<style scoped>
+.todo-list {
+  min-height: 100vh;
+  display: flex;
+  flex-direction: column;
+  /* background-color: #f5f7fa; */
+}
+
+.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: #091126 !important;
+  color: white !important;
+}
+
+:deep(.table-wrapper) {
+  background: #091126 !important;
+}
+
+:deep(.el-table__header-wrapper thead) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+:deep(.el-table__header-wrapper .el-table__header) {
+  border-bottom: none;
+}
+:deep(.el-table__inner-wrapper) {
+  background: #091126 !important;
+  color: white !important;
+}
+:deep(.el-table__body-wrapper .el-table__row) {
+  background: #091126;
+  color: white !important;
+}
+
+:deep(.el-table__body-wrapper .el-table__row .hover-row) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+:deep(.el-table__body-wrapper .el-table__row .el-table__cell) {
+  background: #091126 !important;
+  color: white !important;
+  border-bottom: 1px solid #313849;
+}
+
+:deep(.el-loading-mask) {
+  background-color: rgba(9, 17, 38, 0.8) !important; /* 半透明深色遮罩 */
+}
+
+:deep(.el-table__body-wrapper .el-table__row .el-table__cell) {
+  border-bottom: 1px solid #313849;
+}
+
+:deep(.el-pagination is-background) {
+  background: #091126 !important;
+}
+
+:deep(.el-pagination .el-pager li) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+:deep(.el-pagination .el-pager li.active) {
+  background: #2d8cf0 !important;
+}
+
+:deep(.el-select .el-select__wrapper) {
+  background: #091126 !important;
+  border: 1px solid #313849 !important;
+  outline: none !important;
+}
+
+:deep(.el-input) {
+  border: 1px solid #313849 !important;
+  outline: none !important;
+}
+
+:deep(.btn-next) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+:deep(.btn-prev) {
+  background: #091126 !important;
+  color: white !important;
+}
+
+/* 下拉菜单弹出层的背景 */
+:deep(.el-select-dropdown) {
+  background-color: #091126 !important;
+  border: 1px solid #313849 !important;
+}
+
+/* 下拉菜单项 */
+:deep(.el-select-dropdown__item) {
+  color: #fff !important;
+}
+
+:deep(.el-select-dropdown__item.hover),
+:deep(.el-select-dropdown__item:hover) {
+  background-color: #111a35 !important; /* 悬停深色背景 */
+}
+
+/* 关键:修复下拉选择框 (PageSize) 的白色边框/背景 */
+:deep(.el-pagination .el-select .el-select__wrapper) {
+  background-color: #091126 !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: #091126 !important;
+  box-shadow: none !important; /* 去掉默认的白色/灰色阴影边框 */
+  border: 1px solid #313849 !important;
+}
+
+:deep(.el-input__inner) {
+  color: #fff !important;
+}
+</style>

+ 48 - 4
src/views/index.vue

@@ -128,6 +128,12 @@
                         <span>{{ crmtodo }}</span>
                       </div>
                     </el-dropdown-item>
+                    <el-dropdown-item command="todo-srm">
+                      <div class="p-2 flex items-center gap-3 text-[#e43c2f]!">
+                        <span>SRM</span>
+                        <span>{{ srmtodo }}</span>
+                      </div>
+                    </el-dropdown-item>
                   </el-dropdown-menu>
                 </template>
               </el-dropdown>
@@ -158,6 +164,13 @@
                         <span>{{ crmdone }}</span>
                       </div></el-dropdown-item
                     >
+
+                    <el-dropdown-item command="done-srm">
+                      <div class="p-2 flex items-center gap-3 text-[#2da04d]!">
+                        <span>SRM</span>
+                        <span>{{ srmdone }}</span>
+                      </div></el-dropdown-item
+                    >
                   </el-dropdown-menu>
                 </template>
               </el-dropdown>
@@ -219,7 +232,7 @@
 
             <div
               v-if="section.apps?.length"
-              class="grid grid-cols-[repeat(2,minmax(0,1fr))] gap-2 p-6 px-3 md:px-6 md:grid-cols-[repeat(3,minmax(0,1fr))] xl:grid-cols-[repeat(3,minmax(0,1fr))]"
+              class="grid grid-cols-[repeat(2,minmax(0,1fr))] gap-2 p-6 px-3 md:px-4 md:grid-cols-[repeat(3,minmax(0,1fr))] xl:grid-cols-[repeat(3,minmax(0,1fr))]"
             >
               <button
                 v-for="(app, appIndex) in section.apps"
@@ -401,6 +414,15 @@
                           <span>{{ crmtodo }}</span>
                         </div>
                       </el-dropdown-item>
+
+                      <el-dropdown-item command="todo-srm">
+                        <div
+                          class="p-2 flex items-center gap-3 text-[#e43c2f]!"
+                        >
+                          <span>SRM</span>
+                          <span>{{ srmtodo }}</span>
+                        </div>
+                      </el-dropdown-item>
                     </el-dropdown-menu>
                   </template>
                 </el-dropdown>
@@ -442,6 +464,15 @@
                           <span>{{ crmdone }}</span>
                         </div>
                       </el-dropdown-item>
+
+                      <el-dropdown-item command="done-srm">
+                        <div
+                          class="p-2 flex items-center gap-3 text-[#2d8767]!"
+                        >
+                          <span>SRM</span>
+                          <span>{{ srmdone }}</span>
+                        </div>
+                      </el-dropdown-item>
                     </el-dropdown-menu>
                   </template>
                 </el-dropdown>
@@ -558,6 +589,7 @@ import {
   zentaoSsoLogin,
   getOATasks,
   getCRMTasks,
+  getSRMTasks,
   getNotices,
   getRedHeadFiles,
   getNews,
@@ -728,6 +760,8 @@ const handleQuickAccessCommand = (command: string) => {
     "todo-crm": "/crm-todo-list?type=crm",
     "done-oa": "/oa-done-list?type=oa",
     "done-crm": "/crm-done-list?type=crm",
+    "todo-srm": "/srm-todo-list?type=srm",
+    "done-srm": "/srm-done-list?type=srm",
   };
 
   const target = routeMap[command];
@@ -805,12 +839,14 @@ let oatodo = ref(0);
 let oadone = ref(0);
 let crmtodo = ref(0);
 let crmdone = ref(0);
+let srmtodo = ref(0);
+let srmdone = ref(0);
 const loadHomeData = async () => {
   await loadNoticeList(activeNoticeTab.value);
 
   if (!userStore.getUser.username) return;
 
-  const [oaRes, crmRes, crmDoneRes, newsRes] = await Promise.all([
+  const [oaRes, crmRes, crmDoneRes, srmRes, newsRes] = await Promise.all([
     getOATasks({
       id: userStore.getUser.username,
       pageNum: 1,
@@ -828,6 +864,11 @@ const loadHomeData = async () => {
       pageNum: 1,
       pageSize: 10,
     }),
+    await getSRMTasks({
+      id: userStore.getUser.username,
+      pageNum: 1,
+      pageSize: 10,
+    }),
     getNews({
       pageNum: 1,
       pageSize: 10,
@@ -835,13 +876,16 @@ const loadHomeData = async () => {
   ]);
 
   oaTasks.value = oaRes.todoList.slice(0, 3);
-  todo.value = Number(oaRes.todoCount) + crmRes.todoCount;
-  done.value = Number(oaRes.doneCount) + crmDoneRes.todoCount;
+  todo.value = Number(oaRes.todoCount) + crmRes.todoCount + srmRes.todoCount;
+  done.value =
+    Number(oaRes.doneCount) + crmDoneRes.todoCount + srmRes.doneCount;
 
   oatodo.value = oaRes.todoCount;
   oadone.value = oaRes.doneCount;
   crmtodo.value = crmRes.todoCount;
   crmdone.value = crmDoneRes.todoCount;
+  srmtodo.value = srmRes.todoCount;
+  srmdone.value = srmRes.doneCount;
   newsList.value = newsRes.list.slice(0, 3);
 };