更新首页柱状图

This commit is contained in:
2025-09-09 20:33:33 +08:00
parent 83b8cfd6b3
commit a8956a1e5d
6 changed files with 154 additions and 23 deletions

View File

@@ -73,7 +73,7 @@
<el-card shadow="never" class="mt-8px">
<div style="display: flex; width: 50%;"
<!-- <div style="display: flex; width: 50%;"
v-if="wsCache.get('roleRouters').find(item => item.id === 1)?.children.find(item => item.id === 100)">
<el-select v-model="allocationUser" :placeholder="t('newHosts.placeAllocationUser')" clearable
@@ -81,24 +81,32 @@
<el-option v-for="(user, index) in allocationUserList" :key="index" :label="user.label"
:value="user.value" />
</el-select>
</div>
</div> -->
<el-skeleton :loading="loading" animated>
<el-row :gutter="20" justify="space-between">
<el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
<!-- <el-col :xl="10" :lg="10" :md="24" :sm="24" :xs="24">
<el-card shadow="hover" class="mb-8px">
<el-skeleton :loading="loading" animated>
<Echart :options="pieOptionsData" :height="280" />
</el-skeleton>
</el-card>
</el-col>
<!-- <el-col :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
</el-col> -->
<el-col
v-if="wsCache.get('roleRouters').find(item => item.id === 1)?.children.find(item => item.id === 100)"
:xl="14" :lg="20" :md="24" :sm="24" :xs="24">
<el-card shadow="hover" class="mb-8px">
<el-skeleton :loading="loading" animated>
<Echart :options="barOptionsData" :height="280" />
</el-skeleton>
</el-card>
</el-col> -->
</el-col>
<el-col v-else :xl="14" :lg="14" :md="24" :sm="24" :xs="24">
<el-card shadow="hover" class="mb-8px">
<div>当日建联数量</div>
{{ HostsOperationNum }}
</el-card>
</el-col>
</el-row>
</el-skeleton>
</el-card>
@@ -106,7 +114,7 @@
<el-col :xl="8" :lg="8" :md="24" :sm="24" :xs="24" class="mb-8px">
<!-- 快捷入口 -->
<!-- <el-card shadow="never">
<template #header>
<template #header>
<div class="h-3 flex justify-between">
<span>{{ t('workplace.shortcutOperation') }}</span>
</div>
@@ -169,6 +177,27 @@ import { useRouter } from 'vue-router'
import { getComplete, getEmployeeComplete } from '@/api/system/user'
import { useCache } from '@/hooks/web/useCache'
import { getSimpleUserListPage, getSimpleUserList } from '@/api/system/user'
import { EmployeeHostsApi } from '@/api/server/employeehosts'
import { ref, reactive, onMounted, onActivated } from 'vue'
let HostsOperationNum = ref(0)
onMounted(async () => {
await getAllApi()
await getAllocationList()
if (wsCache.get('roleRouters').find(item => item.id === 1)?.children.find(item => item.id === 100)) {
await fetchAllHostsCount()
} else {
await fetchDailyHostsCount()
}
})
// 每次页面“再次显示”时都会触发(前提:该路由组件被 keep-alive 缓存)
onActivated(async () => {
await fetchDailyHostsCount()
})
// import { useGlobalWebSocket } from '@/components/useGlobalWebSocket'
// let messageList = useGlobalWebSocket().messageList
// console.log(messageList.value)
@@ -186,6 +215,8 @@ let allocationUserList = ref([
// }
defineOptions({ name: 'Index' })
// console.log(data)
// const { open } = useGlobalWebSocket()
const { t } = useI18n()
const router = useRouter()
@@ -369,17 +400,68 @@ const getUserAccessSource = async (id) => {
})
}
const barOptionsData = reactive<EChartsOption>(barOptions) as EChartsOption
type EmpBarItem = {
userId: number
finishedNum: number | null
totalNum: number | null
unfinishedNum: number | null
}
// 传入希望展示的用户 id 列表 + 后端原始返回,补齐未返回的用户为 0
function mergeZeroUsers(ids: number[], resList: EmpBarItem[]): EmpBarItem[] {
const map = new Map<number, EmpBarItem>(resList.map(it => [it.userId, it]))
return ids.map(id => {
const it = map.get(id)
const finished = it?.finishedNum ?? 0
// 未建联:优先用后端给的 unfinishedNum若没有且提供了 totalNum则用 totalNum - finished否则 0
const total = it?.totalNum ?? 0
const unfinished = it?.unfinishedNum ?? (it?.totalNum != null && it?.finishedNum != null
? Math.max(Number(total) - Number(finished), 0)
: 0)
// 周活跃量
return {
userId: id,
finishedNum: Number(finished),
totalNum: Number(total),
unfinishedNum: Number(unfinished)
}
})
}
// 把后端返回的数据渲染到柱状图
function updateEmployeeBarChart(list: EmpBarItem[]) {
// 建立 id -> 昵称 的映射
const id2label = new Map(allocationUserList.value.map(u => [u.value, u.label]))
const labels = list.map(it => id2label.get(it.userId) || String(it.userId))
const finished = list.map(it => it.finishedNum ?? 0)
const unfinished = list.map(it => it.unfinishedNum ?? 0)
// legend
const legendNames = []
set(barOptionsData, 'legend.data', legendNames)
set(barOptionsData, 'xAxis.data', labels)
set(barOptionsData, 'series', [
{
name: t('analysis.alreadyJianlian'),
type: 'bar',
data: finished
},
// {
// name: t('analysis.noAlliance'),
// type: 'bar',
// data: unfinished
// }
])
}
// 周活跃量 图表数据
const getWeeklyUserActivity = async () => {
const data = [
{ value: 13253, name: 'analysis.monday' },
{ value: 34235, name: 'analysis.tuesday' },
{ value: 26321, name: 'analysis.wednesday' },
{ value: 12340, name: 'analysis.thursday' },
{ value: 24643, name: 'analysis.friday' },
{ value: 1322, name: 'analysis.saturday' },
{ value: 1324, name: 'analysis.sunday' }
{ value: HostsOperationNum.value, name: 'analysis.monday' },
]
set(
barOptionsData,
@@ -439,6 +521,37 @@ const getAllocationList = async () => {
loading.value = false
}
}
getAllApi()
getAllocationList()
// 获取当前日期,格式为 YYYY-MM-DD
const getFormattedDate = () => {
const now = new Date()
return now.toISOString().split('T')[0] + ' 00:00:00'
}
// ✅ 抽成函数:每天数量
async function fetchDailyHostsCount() {
const res = await EmployeeHostsApi.getEmployeeHostsPage({
operationStatus: 1,
pageNo: 1,
pageSize: 10,
updateTime: getFormattedDate()
})
HostsOperationNum.value = res.total ?? 0
// 如果柱状图依赖这个值,顺便刷新一次图表数据
}
// ✅ 抽成函数:每天所有员工数量(用于多人柱状图)
async function fetchAllHostsCount() {
// 以“传入的用户 id”为准展示顺序也按这里来
const ids = allocationUserList.value.map(item => item.value)
const res = await EmployeeHostsApi.employeeCompleteBarChart(ids)
const rawList: EmpBarItem[] = Array.isArray(res) ? res : (res?.data ?? [])
// 补齐后端未返回的用户为 0
const list = mergeZeroUsers(ids, rawList)
// 渲染
updateEmployeeBarChart(list)
}
</script>