|
@@ -218,23 +218,21 @@ import Header from "@components/home/header.vue";
|
|
|
import Footer from "@components/home/Footer.vue";
|
|
import Footer from "@components/home/Footer.vue";
|
|
|
import { computed, ref, onMounted, onBeforeUnmount, nextTick } from "vue";
|
|
import { computed, ref, onMounted, onBeforeUnmount, nextTick } from "vue";
|
|
|
import { Icon } from "@iconify/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 { useUserStore } from "@/stores/useUserStore";
|
|
|
import { getAccessToken } from "@/utils/auth";
|
|
import { getAccessToken } from "@/utils/auth";
|
|
|
-import * as echarts from "echarts";
|
|
|
|
|
import { useRouter } from "vue-router";
|
|
import { useRouter } from "vue-router";
|
|
|
import dd from "dingtalk-jsapi";
|
|
import dd from "dingtalk-jsapi";
|
|
|
const router = useRouter();
|
|
const router = useRouter();
|
|
|
import { ElLoading, ElMessage } from "element-plus";
|
|
import { ElLoading, ElMessage } from "element-plus";
|
|
|
const userStore = useUserStore();
|
|
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
|
|
// 1. 定义 Ref
|
|
|
const tabsContainerRef = ref(null);
|
|
const tabsContainerRef = ref(null);
|
|
|
const isLeftDisabled = ref(true);
|
|
const isLeftDisabled = ref(true);
|
|
@@ -276,31 +274,6 @@ const handleTabScroll = () => {
|
|
|
updateArrowState();
|
|
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 getGreeting = () => {
|
|
|
const hour = new Date().getHours();
|
|
const hour = new Date().getHours();
|
|
|
if (hour < 12) return "早上好";
|
|
if (hour < 12) return "早上好";
|
|
@@ -308,24 +281,6 @@ const getGreeting = () => {
|
|
|
return "晚上好";
|
|
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) => {
|
|
const getDetailList = (index) => {
|
|
|
switch (index) {
|
|
switch (index) {
|
|
|
case 0: // 我的待办
|
|
case 0: // 我的待办
|
|
@@ -340,113 +295,6 @@ const getDetailList = (index) => {
|
|
|
return [];
|
|
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([]);
|
|
const tabs = ref([]);
|
|
|
|
|
|
|
@@ -734,10 +582,25 @@ const handleDetailClick = (task, categoryTitle) => {
|
|
|
query: { type: task.name.toLowerCase() },
|
|
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 oaTasks = ref([]);
|
|
|
let crmTasks = ref([]);
|
|
let crmTasks = ref([]);
|
|
|
|
|
+let srmTasks = ref([]);
|
|
|
const statsLoading = ref(true);
|
|
const statsLoading = ref(true);
|
|
|
|
|
|
|
|
const stats = ref([
|
|
const stats = ref([
|
|
@@ -761,12 +624,14 @@ const stats = ref([
|
|
|
const todoCount = ref([
|
|
const todoCount = ref([
|
|
|
{ name: "OA", value: 0 },
|
|
{ name: "OA", value: 0 },
|
|
|
{ name: "CRM", value: 0 },
|
|
{ name: "CRM", value: 0 },
|
|
|
|
|
+ { name: "SRM", value: 0 },
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
// 已办事项
|
|
// 已办事项
|
|
|
const doneCount = ref([
|
|
const doneCount = ref([
|
|
|
{ name: "OA", value: 0 },
|
|
{ name: "OA", value: 0 },
|
|
|
{ name: "CRM", value: 0 },
|
|
{ name: "CRM", value: 0 },
|
|
|
|
|
+ { name: "SRM", value: 0 },
|
|
|
]);
|
|
]);
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
onMounted(async () => {
|
|
@@ -778,19 +643,6 @@ onMounted(async () => {
|
|
|
if (tabsContainerRef.value) {
|
|
if (tabsContainerRef.value) {
|
|
|
tabsContainerRef.value.addEventListener("scroll", handleTabScroll);
|
|
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) {
|
|
if (userStore.getUser.username) {
|
|
|
try {
|
|
try {
|
|
@@ -809,12 +661,24 @@ onMounted(async () => {
|
|
|
});
|
|
});
|
|
|
crmTasks.value = crmRes;
|
|
crmTasks.value = crmRes;
|
|
|
|
|
|
|
|
|
|
+ const srmRes = await getSRMTasks({
|
|
|
|
|
+ id: userStore.getUser.username,
|
|
|
|
|
+
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ srmTasks.value = srmRes;
|
|
|
|
|
+
|
|
|
stats.value[0].number =
|
|
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 = [
|
|
todoCount.value = [
|
|
|
{ name: "OA", value: oaTasks.value.todoCount ?? 0 },
|
|
{ name: "OA", value: oaTasks.value.todoCount ?? 0 },
|
|
|
{ name: "CRM", value: crmTasks.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,
|
|
pageSize: 10,
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+ const srmDoneRes = await getSRMTasks({
|
|
|
|
|
+ id: userStore.getUser.username,
|
|
|
|
|
+
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
stats.value[1].number =
|
|
stats.value[1].number =
|
|
|
- Number(oaTasks.value.doneCount) + Number(crmDoneRes.todoCount);
|
|
|
|
|
|
|
+ Number(oaTasks.value.doneCount) +
|
|
|
|
|
+ Number(crmDoneRes.todoCount) +
|
|
|
|
|
+ Number(srmDoneRes.doneCount);
|
|
|
|
|
|
|
|
doneCount.value = [
|
|
doneCount.value = [
|
|
|
{ name: "OA", value: oaTasks.value.doneCount ?? 0 },
|
|
{ name: "OA", value: oaTasks.value.doneCount ?? 0 },
|
|
|
{ name: "CRM", value: crmDoneRes.todoCount ?? 0 },
|
|
{ name: "CRM", value: crmDoneRes.todoCount ?? 0 },
|
|
|
|
|
+ { name: "SRM", value: srmDoneRes.doneCount ?? 0 },
|
|
|
];
|
|
];
|
|
|
} finally {
|
|
} finally {
|
|
|
statsLoading.value = false;
|
|
statsLoading.value = false;
|
|
@@ -854,12 +728,23 @@ onMounted(async () => {
|
|
|
});
|
|
});
|
|
|
crmTasks.value = crmRes;
|
|
crmTasks.value = crmRes;
|
|
|
|
|
|
|
|
|
|
+ const srmRes = await getSRMTasks({
|
|
|
|
|
+ id: userStore.getUser.username,
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ srmTasks.value = srmRes;
|
|
|
|
|
+
|
|
|
stats.value[0].number =
|
|
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 = [
|
|
todoCount.value = [
|
|
|
{ name: "OA", value: oaTasks.value.todoCount ?? 0 },
|
|
{ name: "OA", value: oaTasks.value.todoCount ?? 0 },
|
|
|
{ name: "CRM", value: crmTasks.value.todoCount ?? 0 },
|
|
{ name: "CRM", value: crmTasks.value.todoCount ?? 0 },
|
|
|
|
|
+ { name: "SRM", value: srmTasks.value.todoCount ?? 0 },
|
|
|
];
|
|
];
|
|
|
|
|
|
|
|
const crmDoneRes = await getCRMTasks({
|
|
const crmDoneRes = await getCRMTasks({
|
|
@@ -869,12 +754,21 @@ onMounted(async () => {
|
|
|
pageSize: 10,
|
|
pageSize: 10,
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
|
|
+ const srmDoneRes = await getSRMTasks({
|
|
|
|
|
+ id: userStore.getUser.username,
|
|
|
|
|
+ pageNum: 1,
|
|
|
|
|
+ pageSize: 10,
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
stats.value[1].number =
|
|
stats.value[1].number =
|
|
|
- Number(oaTasks.value.doneCount) + Number(crmDoneRes.todoCount);
|
|
|
|
|
|
|
+ Number(oaTasks.value.doneCount) +
|
|
|
|
|
+ Number(crmDoneRes.todoCount) +
|
|
|
|
|
+ Number(srmDoneRes.doneCount);
|
|
|
|
|
|
|
|
doneCount.value = [
|
|
doneCount.value = [
|
|
|
{ name: "OA", value: oaTasks.value.doneCount ?? 0 },
|
|
{ name: "OA", value: oaTasks.value.doneCount ?? 0 },
|
|
|
{ name: "CRM", value: crmDoneRes.todoCount ?? 0 },
|
|
{ name: "CRM", value: crmDoneRes.todoCount ?? 0 },
|
|
|
|
|
+ { name: "SRM", value: srmDoneRes.doneCount ?? 0 },
|
|
|
];
|
|
];
|
|
|
},
|
|
},
|
|
|
10 * 60 * 1000,
|
|
10 * 60 * 1000,
|
|
@@ -886,13 +780,6 @@ onMounted(async () => {
|
|
|
|
|
|
|
|
// 组件卸载时移除监听,防止内存泄漏
|
|
// 组件卸载时移除监听,防止内存泄漏
|
|
|
onBeforeUnmount(() => {
|
|
onBeforeUnmount(() => {
|
|
|
- window.removeEventListener("resize", handleResize);
|
|
|
|
|
- chartResizeObserver?.disconnect();
|
|
|
|
|
- if (chartInitTimer) window.clearTimeout(chartInitTimer);
|
|
|
|
|
- // 可选:销毁 echarts 实例
|
|
|
|
|
- lineChartInstance.value?.dispose();
|
|
|
|
|
- pieChartInstance.value?.dispose();
|
|
|
|
|
-
|
|
|
|
|
if (tabsContainerRef.value) {
|
|
if (tabsContainerRef.value) {
|
|
|
tabsContainerRef.value.removeEventListener("scroll", handleTabScroll);
|
|
tabsContainerRef.value.removeEventListener("scroll", handleTabScroll);
|
|
|
}
|
|
}
|