|
|
@@ -28,53 +28,51 @@
|
|
|
<!-- 任务统计 -->
|
|
|
<section class="total">
|
|
|
<div class="total-card" v-for="(item, index) in stats" :key="index">
|
|
|
- <el-skeleton
|
|
|
- :rows="1"
|
|
|
- :animated="true"
|
|
|
- class="w-full"
|
|
|
- v-if="item.number === 0"
|
|
|
+ <el-popover
|
|
|
+ placement="top"
|
|
|
+ :width="200"
|
|
|
+ trigger="hover"
|
|
|
+ popper-class="glass-popover"
|
|
|
+ :disabled="getDetailList(index).length === 0"
|
|
|
+ raw-content
|
|
|
+ transition="el-zoom-in-top"
|
|
|
>
|
|
|
- <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>
|
|
|
+ <template #reference>
|
|
|
+ <div class="card-wrapper">
|
|
|
+ <!-- ... 图标和内容 ... -->
|
|
|
+ <div class="card-icon" :style="{ backgroundColor: item.bgcolor }">
|
|
|
+ <Icon :icon="item.icon" :color="item.color" />
|
|
|
</div>
|
|
|
- <div v-if="getDetailList(index).length === 0" class="empty-tip">
|
|
|
- 暂无详细数据
|
|
|
+ <div class="card-content">
|
|
|
+ <p class="card-title">{{ item.title }}</p>
|
|
|
+ <el-skeleton :rows="1" :animated="true" :loading="statsLoading">
|
|
|
+ <template #template>
|
|
|
+ <el-skeleton-item
|
|
|
+ variant="text"
|
|
|
+ style="width: 60%; height: 32px; border-radius: 50px"
|
|
|
+ />
|
|
|
+ </template>
|
|
|
+ <p class="card-number">{{ item.number }}</p>
|
|
|
+ </el-skeleton>
|
|
|
</div>
|
|
|
</div>
|
|
|
- </el-popover>
|
|
|
- </el-skeleton>
|
|
|
+ </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>
|
|
|
|
|
|
@@ -462,6 +460,7 @@ const handleDetailClick = (task, categoryTitle) => {
|
|
|
|
|
|
let oaTasks = ref([]);
|
|
|
let crmTasks = ref([]);
|
|
|
+const statsLoading = ref(true);
|
|
|
|
|
|
const stats = ref([
|
|
|
{
|
|
|
@@ -538,11 +537,24 @@ onMounted(async () => {
|
|
|
});
|
|
|
|
|
|
if (userStore.getUser.username) {
|
|
|
- const res = await getOATasks(userStore.getUser.username);
|
|
|
- oaTasks.value = res;
|
|
|
+ try {
|
|
|
+ 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 ?? 0 },
|
|
|
+ { name: "CRM", value: crmTasks.value.todoCount ?? 0 },
|
|
|
+ ];
|
|
|
+ } finally {
|
|
|
+ statsLoading.value = false;
|
|
|
+ }
|
|
|
|
|
|
- const crmRes = await getCRMTasks(userStore.getUser.username);
|
|
|
- crmTasks.value = crmRes;
|
|
|
setInterval(
|
|
|
async () => {
|
|
|
const res = await getOATasks(userStore.getUser.username);
|
|
|
@@ -550,18 +562,20 @@ onMounted(async () => {
|
|
|
|
|
|
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 ?? 0 },
|
|
|
+ { name: "CRM", value: crmTasks.value.todoCount ?? 0 },
|
|
|
+ ];
|
|
|
},
|
|
|
5 * 60 * 1000,
|
|
|
); // 每5分钟刷新一次
|
|
|
+ } else {
|
|
|
+ statsLoading.value = false;
|
|
|
}
|
|
|
-
|
|
|
- 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 },
|
|
|
- ];
|
|
|
});
|
|
|
|
|
|
// 组件卸载时移除监听,防止内存泄漏
|