更新首页柱状图
This commit is contained in:
@@ -22,6 +22,8 @@ export interface EmployeeHostsVO {
|
||||
uid: string // 用户id
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 员工分配主播 API
|
||||
export const EmployeeHostsApi = {
|
||||
// 查询员工分配主播分页
|
||||
@@ -32,6 +34,10 @@ export const EmployeeHostsApi = {
|
||||
getEmployeeHostsPage: async (params: any) => {
|
||||
return await request.get({ url: `/server/employee-hosts/self_page`, params })
|
||||
},
|
||||
// 查询员工分配主播分页
|
||||
employeeCompleteBarChart: async (params: number[]) => {
|
||||
return await request.post({ url: `/server/employee-hosts/employeeCompleteBarChart`, data: params })
|
||||
},
|
||||
// 查询管理员工分配主播分页
|
||||
getMeangeEmployeeHostsPage: async (params: any) => {
|
||||
return await request.get({ url: `server/employee-hosts/page`, params })
|
||||
|
||||
@@ -290,6 +290,7 @@ export default {
|
||||
title: 'Title',
|
||||
author: 'Author',
|
||||
createTime: 'Create time',
|
||||
updateTime: 'Update Time',
|
||||
action: 'Action',
|
||||
pagination: 'pagination',
|
||||
reserveIndex: 'Reserve index',
|
||||
@@ -428,7 +429,8 @@ export default {
|
||||
sex: 'Sex',
|
||||
man: 'Man',
|
||||
woman: 'Woman',
|
||||
createTime: 'Created Date'
|
||||
createTime: 'Created Date',
|
||||
updateTime: 'Update Time',
|
||||
},
|
||||
info: {
|
||||
title: 'Basic Information',
|
||||
@@ -488,6 +490,7 @@ export default {
|
||||
sortName:'Sort Name',
|
||||
placeIsAssigned: 'Please select assignment status',
|
||||
createTime: 'Created Time',
|
||||
updateTime: 'Update Time',
|
||||
invitationType: 'Invitation Type',
|
||||
placeInvitationType: 'Please select invitation type',
|
||||
allocationUser: 'Assigned Employee',
|
||||
@@ -524,7 +527,7 @@ export default {
|
||||
isAssigned: 'Assignment Status',
|
||||
placeIsAssigned: 'Please select assignment status',
|
||||
createTime: 'Created Time',
|
||||
updateTime: 'update Time',
|
||||
updataTime: 'Update Time',
|
||||
userId: 'User ID',
|
||||
placeAllocationUser: 'Please select assigned employee',
|
||||
invitationType: 'Invitation Type',
|
||||
|
||||
@@ -199,8 +199,8 @@ export default {
|
||||
allianceAdvertising: '联盟广告',
|
||||
videoAdvertising: '视频广告',
|
||||
searchEngines: '搜索引擎',
|
||||
weeklyUserActivity: '每周用户活跃量',
|
||||
activeQuantity: '活跃量',
|
||||
weeklyUserActivity: '当日建联数',
|
||||
activeQuantity: '建联数',
|
||||
alreadyJianlian:'已建联',
|
||||
noAlliance:'未建联',
|
||||
monday: '周一',
|
||||
@@ -297,6 +297,7 @@ export default {
|
||||
title: '标题',
|
||||
author: '作者',
|
||||
createTime: '创建时间',
|
||||
updateTime: '更新时间',
|
||||
action: '操作',
|
||||
pagination: '分页',
|
||||
reserveIndex: '叠加序号',
|
||||
@@ -488,6 +489,7 @@ export default {
|
||||
sortName:'排序名字',
|
||||
placeIsAssigned: '请选择是否已经分配给员工',
|
||||
createTime: '创建时间',
|
||||
updateTime: '更新时间',
|
||||
invitationType: '邀请类型',
|
||||
placeInvitationType: '请选择邀请类型',
|
||||
allocationUser: '分配员工',
|
||||
@@ -524,7 +526,7 @@ export default {
|
||||
isAssigned: '分配情况',
|
||||
placeIsAssigned: '请选择是否已经分配给员工',
|
||||
createTime: '创建时间',
|
||||
updateTime: '更新时间',
|
||||
updataTime: '更新时间',
|
||||
userId: '用户 Id',
|
||||
placeAllocationUser: '请选择分配的员工',
|
||||
invitationType: '邀请类型',
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -108,6 +108,8 @@ export const pieOptions: EChartsOption = {
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const barOptions: EChartsOption = {
|
||||
title: {
|
||||
text: t('analysis.weeklyUserActivity'),
|
||||
|
||||
@@ -65,6 +65,10 @@
|
||||
<el-date-picker v-model="queryParams.createTime" value-format="YYYY-MM-DD HH:mm:ss" type="date"
|
||||
class="!w-240px" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('employee.updataTime')" prop="updataTime">
|
||||
<el-date-picker v-model="queryParams.updateTime" value-format="YYYY-MM-DD HH:mm:ss" type="date"
|
||||
class="!w-240px" />
|
||||
</el-form-item>
|
||||
<el-form-item label="旗帜" prop="flag">
|
||||
<el-select v-model="queryParams.flag" placeholder="请选择状态" clearable class="!w-240px" style="width: 50px">
|
||||
<el-option label="请选择" :value="''" />
|
||||
@@ -216,7 +220,7 @@
|
||||
<div class="card-row"><b>{{ $t('employee.updateTime') }}:</b>{{ formatTimestamp(item.updateTime) }}</div>
|
||||
<div class="card-row action-row">
|
||||
<el-button link type="primary" @click="openForm('update', item.id, index)">{{ $t('employee.edit')
|
||||
}}</el-button>
|
||||
}}</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -278,6 +282,7 @@ const queryParams = reactive({
|
||||
sortName: "createTime", //排序字段
|
||||
sort: 'desc', //排序方式
|
||||
createTime: [],
|
||||
updateTime: [],
|
||||
userId: undefined,
|
||||
operationStatus: undefined,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user