|
|
@@ -3,7 +3,7 @@
|
|
|
<Header />
|
|
|
<section class="hero">
|
|
|
<div class="hero-inner">
|
|
|
- <h1 class="hero-title">下午好,晓华</h1>
|
|
|
+ <h1 class="hero-title">下午好,{{ userStore.getUser.nickname }}</h1>
|
|
|
<p class="hero-desc">
|
|
|
今天是 {{ new Date().toLocaleDateString() }}。您有 5 条流程待处理。
|
|
|
</p>
|
|
|
@@ -24,16 +24,43 @@
|
|
|
<!-- 任务统计 -->
|
|
|
<section class="total">
|
|
|
<div class="total-card" v-for="(item, index) in stats" :key="index">
|
|
|
- <div class="card-icon" :style="{ backgroundColor: item.bgcolor }">
|
|
|
- <Icon :icon="item.icon" :color="item.color" />
|
|
|
- </div>
|
|
|
- <div class="card-content">
|
|
|
- <p class="card-title">{{ item.title }}</p>
|
|
|
- <p class="card-number">{{ oaTasks.todoCount }}</p>
|
|
|
- </div>
|
|
|
- <div v-if="item.extra" class="card-extra">
|
|
|
- {{ item.extra }}
|
|
|
- </div>
|
|
|
+ <el-popover
|
|
|
+ placement="top"
|
|
|
+ :width="200"
|
|
|
+ trigger="hover"
|
|
|
+ popper-class="glass-popover"
|
|
|
+ :disabled="getDetailList(index).length === 0"
|
|
|
+ raw-content
|
|
|
+ transition="el-zoom-in-top"
|
|
|
+ >
|
|
|
+ <template #reference>
|
|
|
+ <div class="card-wrapper">
|
|
|
+ <!-- ... 图标和内容 ... -->
|
|
|
+ <div class="card-icon" :style="{ backgroundColor: item.bgcolor }">
|
|
|
+ <Icon :icon="item.icon" :color="item.color" />
|
|
|
+ </div>
|
|
|
+ <div class="card-content">
|
|
|
+ <p class="card-title">{{ item.title }}</p>
|
|
|
+ <p class="card-number">{{ item.number }}</p>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </template>
|
|
|
+
|
|
|
+ <div class="detail-list">
|
|
|
+ <div
|
|
|
+ v-for="(task, idx) in getDetailList(index)"
|
|
|
+ :key="idx"
|
|
|
+ class="detail-item"
|
|
|
+ @click="handleDetailClick(task, item.title)"
|
|
|
+ >
|
|
|
+ <span class="detail-name">{{ task.name }}</span>
|
|
|
+ <span class="detail-val">{{ task.value }}</span>
|
|
|
+ </div>
|
|
|
+ <div v-if="getDetailList(index).length === 0" class="empty-tip">
|
|
|
+ 暂无详细数据
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-popover>
|
|
|
</div>
|
|
|
</section>
|
|
|
|
|
|
@@ -101,7 +128,7 @@ 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 } from "@/api/user";
|
|
|
+import { getFlows, ssoLogin, getOATasks, getCRMTasks } from "@/api/user";
|
|
|
import { useUserStore } from "@/stores/useUserStore";
|
|
|
import { getAccessToken } from "@/utils/auth";
|
|
|
import * as echarts from "echarts";
|
|
|
@@ -158,6 +185,20 @@ const pieChartData = {
|
|
|
],
|
|
|
};
|
|
|
|
|
|
+const getDetailList = (index) => {
|
|
|
+ switch (index) {
|
|
|
+ case 0: // 我的待办
|
|
|
+ return todoCount.value;
|
|
|
+ case 1: // 已办事项
|
|
|
+ return doneCount.value;
|
|
|
+ case 2: // 发起流程
|
|
|
+ return startCount.value;
|
|
|
+ case 3: // 草稿箱
|
|
|
+ return drafts.value;
|
|
|
+ default:
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+};
|
|
|
// 初始化图表
|
|
|
const initLineChart = () => {
|
|
|
const chartDom = lineChartRef.value;
|
|
|
@@ -289,39 +330,6 @@ const activeTab = computed(() => {
|
|
|
);
|
|
|
});
|
|
|
|
|
|
-const stats = [
|
|
|
- {
|
|
|
- icon: "mdi:clock-outline",
|
|
|
- title: "我的待办",
|
|
|
- number: "05",
|
|
|
- extra: "+2 今日",
|
|
|
- bgcolor: "#fff7ed",
|
|
|
- color: "#f59e0b",
|
|
|
- },
|
|
|
- {
|
|
|
- icon: "mdi:check-circle-outline",
|
|
|
- title: "已办事项",
|
|
|
- number: "128",
|
|
|
- bgcolor: "#eff6ff",
|
|
|
- color: "#2563eb",
|
|
|
- },
|
|
|
- {
|
|
|
- icon: "mdi:arrow-right-bold-box-outline",
|
|
|
- title: "发起流程",
|
|
|
- number: "42",
|
|
|
- extra: "85% 准时",
|
|
|
- bgcolor: "#eff6ff",
|
|
|
- color: "#2563eb",
|
|
|
- },
|
|
|
- {
|
|
|
- icon: "mdi:file-document-outline",
|
|
|
- title: "草箱箱",
|
|
|
- number: "03",
|
|
|
- bgcolor: "#f8fafc",
|
|
|
- color: "#475569",
|
|
|
- },
|
|
|
-];
|
|
|
-
|
|
|
const getAll = async () => {
|
|
|
const res = await getFlows({
|
|
|
pageNo: 1,
|
|
|
@@ -374,7 +382,73 @@ const go = async (item) => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+const handleDetailClick = (task, categoryTitle) => {
|
|
|
+ console.log(`点击了 ${categoryTitle} 中的 ${task.name}: ${task.value}`);
|
|
|
+ // 示例:根据类型跳转
|
|
|
+ // if (categoryTitle === '我的待办') {
|
|
|
+ // router.push({ path: '/flow/todo', query: { type: task.name.toLowerCase() } });
|
|
|
+ // }
|
|
|
+};
|
|
|
+
|
|
|
let oaTasks = ref([]);
|
|
|
+let crmTasks = ref([]);
|
|
|
+
|
|
|
+const stats = ref([
|
|
|
+ {
|
|
|
+ icon: "mdi:clock-outline",
|
|
|
+ title: "我的待办",
|
|
|
+ number: 0,
|
|
|
+ extra: "+2 今日",
|
|
|
+ bgcolor: "#fff7ed",
|
|
|
+ color: "#f59e0b",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: "mdi:check-circle-outline",
|
|
|
+ title: "已办事项",
|
|
|
+ number: 0,
|
|
|
+ bgcolor: "#eff6ff",
|
|
|
+ color: "#2563eb",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: "mdi:arrow-right-bold-box-outline",
|
|
|
+ title: "发起流程",
|
|
|
+ number: 0,
|
|
|
+ extra: "85% 准时",
|
|
|
+ bgcolor: "#eff6ff",
|
|
|
+ color: "#2563eb",
|
|
|
+ },
|
|
|
+ {
|
|
|
+ icon: "mdi:file-document-outline",
|
|
|
+ title: "草稿箱",
|
|
|
+ number: 0,
|
|
|
+ bgcolor: "#f8fafc",
|
|
|
+ color: "#475569",
|
|
|
+ },
|
|
|
+]);
|
|
|
+
|
|
|
+const todoCount = ref([
|
|
|
+ { name: "OA", value: 0 },
|
|
|
+ { name: "CRM", value: 0 },
|
|
|
+]);
|
|
|
+
|
|
|
+// 已办事项
|
|
|
+const doneCount = ref([
|
|
|
+ { name: "OA", value: 0 },
|
|
|
+ { name: "CRM", value: 0 },
|
|
|
+]);
|
|
|
+
|
|
|
+// 发起流程
|
|
|
+const startCount = ref([
|
|
|
+ { name: "OA", value: 0 },
|
|
|
+ { name: "CRM", value: 0 },
|
|
|
+]);
|
|
|
+
|
|
|
+// 草稿箱
|
|
|
+const drafts = ref([
|
|
|
+ { name: "OA", value: 0 },
|
|
|
+ { name: "CRM", value: 0 },
|
|
|
+]);
|
|
|
+
|
|
|
onMounted(async () => {
|
|
|
getAll();
|
|
|
// 等待 DOM 与样式生效,避免移动端首屏尺寸为 0
|
|
|
@@ -396,7 +470,18 @@ onMounted(async () => {
|
|
|
if (userStore.getUser.username) {
|
|
|
const res = await getOATasks(userStore.getUser.username);
|
|
|
oaTasks.value = res;
|
|
|
+
|
|
|
+ const crmRes = await getCRMTasks(userStore.getUser.username);
|
|
|
+ crmTasks.value = crmRes;
|
|
|
}
|
|
|
+
|
|
|
+ stats.value[0].number =
|
|
|
+ Number(oaTasks.value.todoCount) + Number(crmTasks.value.todoCount);
|
|
|
+
|
|
|
+ todoCount.value = [
|
|
|
+ { name: "OA", value: oaTasks.value.todoCount },
|
|
|
+ { name: "CRM", value: crmTasks.value.todoCount },
|
|
|
+ ];
|
|
|
});
|
|
|
|
|
|
// 组件卸载时移除监听,防止内存泄漏
|
|
|
@@ -710,11 +795,13 @@ onBeforeUnmount(() => {
|
|
|
cursor: pointer;
|
|
|
/* border: 1px solid #e5e7eb; */
|
|
|
/* border-top: solid 5px #02409b; */
|
|
|
+ overflow: visible;
|
|
|
}
|
|
|
|
|
|
.total-card:hover {
|
|
|
transform: translateY(-4px);
|
|
|
box-shadow: 0 12px 24px rgba(0, 0, 0, 0.1);
|
|
|
+ color: #02409b !important;
|
|
|
}
|
|
|
|
|
|
.card-icon {
|
|
|
@@ -748,7 +835,7 @@ onBeforeUnmount(() => {
|
|
|
.card-number {
|
|
|
font-size: 28px;
|
|
|
font-weight: 600;
|
|
|
- color: #111827;
|
|
|
+ /* color: #111827; */
|
|
|
}
|
|
|
|
|
|
.card-extra {
|
|
|
@@ -780,4 +867,73 @@ onBeforeUnmount(() => {
|
|
|
overflow: hidden;
|
|
|
position: relative;
|
|
|
}
|
|
|
+
|
|
|
+:global(.glass-popover) {
|
|
|
+ background: rgba(0, 0, 0, 0.6) !important;
|
|
|
+ backdrop-filter: blur(10px);
|
|
|
+ -webkit-backdrop-filter: blur(10px);
|
|
|
+ height: 200px !important;
|
|
|
+ width: 100px !important;
|
|
|
+ overflow-y: auto !important;
|
|
|
+ box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1) !important;
|
|
|
+ border-radius: 8px !important;
|
|
|
+ padding: 10px !important;
|
|
|
+ color: #fff !important;
|
|
|
+ z-index: 2000 !important; /* 确保在最上层 */
|
|
|
+ top: 15% !important; /* 根据需要调整位置 */
|
|
|
+}
|
|
|
+
|
|
|
+:global(.glass-popover .el-popper__arrow::before) {
|
|
|
+ background: transparent !important;
|
|
|
+ /* border: 1px solid rgba(255, 255, 255, 0.1); */
|
|
|
+ border: none !important;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-list {
|
|
|
+ padding: 5px 0;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-item {
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+ margin-bottom: 8px;
|
|
|
+ font-size: 14px;
|
|
|
+ color: #e0e0e0; /* 浅色文字 */
|
|
|
+ line-height: 1.5;
|
|
|
+ padding: 6px 8px;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer; /* 鼠标变成手型 */
|
|
|
+ transition: background-color 0.2s ease;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-item:last-child {
|
|
|
+ margin-bottom: 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* 鼠标悬浮背景变灰 */
|
|
|
+.detail-item:hover {
|
|
|
+ background-color: rgba(
|
|
|
+ 255,
|
|
|
+ 255,
|
|
|
+ 255,
|
|
|
+ 0.15
|
|
|
+ ); /* 半透明白色,视觉上为灰色高亮 */
|
|
|
+}
|
|
|
+
|
|
|
+.detail-name {
|
|
|
+ color: #ccc;
|
|
|
+}
|
|
|
+
|
|
|
+.detail-val {
|
|
|
+ font-weight: bold;
|
|
|
+ color: #fff;
|
|
|
+}
|
|
|
+
|
|
|
+.empty-tip {
|
|
|
+ text-align: center;
|
|
|
+ color: #aaa;
|
|
|
+ font-size: 12px;
|
|
|
+ padding: 10px 0;
|
|
|
+}
|
|
|
</style>
|