Industrial-image-management.../src/views/enterprise-dashboard/member-data/index.vue

494 lines
12 KiB
Vue

<template>
<div class="app-container">
<a-card class="general-card" title="成员活跃数据" :bordered="false">
<a-tabs default-active-key="1">
<a-tab-pane key="1" tab="活跃度分析">
<a-row :gutter="16">
<a-col :span="24">
<a-card title="部门活跃度对比" :bordered="false">
<div ref="departmentActivityChart" style="height: 300px"></div>
</a-card>
</a-col>
</a-row>
<a-divider />
<a-row :gutter="16">
<a-col :span="12">
<a-card title="每日活跃用户数" :bordered="false">
<div ref="dailyActiveUsersChart" style="height: 300px"></div>
</a-card>
</a-col>
<a-col :span="12">
<a-card title="平均在线时长" :bordered="false">
<div ref="onlineTimeChart" style="height: 300px"></div>
</a-card>
</a-col>
</a-row>
</a-tab-pane>
<a-tab-pane key="2" tab="成员排行榜">
<a-card title="本月活跃度排名" :bordered="false">
<a-table :columns="rankColumns" :data-source="rankData" :pagination="{ pageSize: 10 }">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'rank'">
<a-tag :color="getRankColor(record.rank)">{{ record.rank }}</a-tag>
</template>
<template v-if="column.dataIndex === 'activityScore'">
<a-progress :percent="record.activityScore" :stroke-color="getScoreColor(record.activityScore)" />
</template>
</template>
</a-table>
</a-card>
</a-tab-pane>
<a-tab-pane key="3" tab="考勤数据">
<a-row :gutter="16">
<a-col :span="24">
<a-card title="部门考勤统计" :bordered="false">
<a-table :columns="attendanceColumns" :data-source="attendanceData" :pagination="{ pageSize: 5 }">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'attendanceRate'">
<a-progress :percent="record.attendanceRate" :stroke-color="getAttendanceColor(record.attendanceRate)" />
</template>
<template v-if="column.dataIndex === 'lateCount'">
<a-tag :color="getLateCountColor(record.lateCount)">{{ record.lateCount }}</a-tag>
</template>
</template>
</a-table>
</a-card>
</a-col>
</a-row>
<a-divider />
<a-row :gutter="16">
<a-col :span="24">
<a-card title="考勤趋势" :bordered="false">
<div ref="attendanceTrendChart" style="height: 300px"></div>
</a-card>
</a-col>
</a-row>
</a-tab-pane>
</a-tabs>
</a-card>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, nextTick } from 'vue'
import * as echarts from 'echarts'
const departmentActivityChart = ref(null)
const dailyActiveUsersChart = ref(null)
const onlineTimeChart = ref(null)
const attendanceTrendChart = ref(null)
// 排行榜数据
const rankColumns = [
{
title: '排名',
dataIndex: 'rank',
key: 'rank',
width: 80,
},
{
title: '姓名',
dataIndex: 'name',
key: 'name',
},
{
title: '部门',
dataIndex: 'department',
key: 'department',
},
{
title: '活跃度',
dataIndex: 'activityScore',
key: 'activityScore',
},
{
title: '登录次数',
dataIndex: 'loginCount',
key: 'loginCount',
},
{
title: '操作次数',
dataIndex: 'operationCount',
key: 'operationCount',
}
]
const rankData = [
{
key: '1',
rank: 1,
name: '张三',
department: '技术部',
activityScore: 98,
loginCount: 45,
operationCount: 532
},
{
key: '2',
rank: 2,
name: '李四',
department: '市场部',
activityScore: 95,
loginCount: 42,
operationCount: 498
},
{
key: '3',
rank: 3,
name: '王五',
department: '销售部',
activityScore: 92,
loginCount: 40,
operationCount: 475
},
{
key: '4',
rank: 4,
name: '赵六',
department: '人事部',
activityScore: 88,
loginCount: 38,
operationCount: 450
},
{
key: '5',
rank: 5,
name: '钱七',
department: '财务部',
activityScore: 85,
loginCount: 36,
operationCount: 420
},
{
key: '6',
rank: 6,
name: '孙八',
department: '技术部',
activityScore: 82,
loginCount: 34,
operationCount: 405
},
{
key: '7',
rank: 7,
name: '周九',
department: '市场部',
activityScore: 79,
loginCount: 32,
operationCount: 380
},
{
key: '8',
rank: 8,
name: '吴十',
department: '销售部',
activityScore: 76,
loginCount: 30,
operationCount: 365
},
{
key: '9',
rank: 9,
name: '郑十一',
department: '人事部',
activityScore: 73,
loginCount: 28,
operationCount: 350
},
{
key: '10',
rank: 10,
name: '王十二',
department: '财务部',
activityScore: 70,
loginCount: 26,
operationCount: 335
}
]
// 考勤数据
const attendanceColumns = [
{
title: '部门',
dataIndex: 'department',
key: 'department',
},
{
title: '人数',
dataIndex: 'memberCount',
key: 'memberCount',
},
{
title: '出勤率',
dataIndex: 'attendanceRate',
key: 'attendanceRate',
},
{
title: '迟到次数',
dataIndex: 'lateCount',
key: 'lateCount',
},
{
title: '早退次数',
dataIndex: 'earlyLeaveCount',
key: 'earlyLeaveCount',
},
{
title: '缺勤次数',
dataIndex: 'absentCount',
key: 'absentCount',
}
]
const attendanceData = [
{
key: '1',
department: '技术部',
memberCount: 45,
attendanceRate: 98,
lateCount: 3,
earlyLeaveCount: 1,
absentCount: 0
},
{
key: '2',
department: '市场部',
memberCount: 32,
attendanceRate: 96,
lateCount: 5,
earlyLeaveCount: 2,
absentCount: 1
},
{
key: '3',
department: '销售部',
memberCount: 38,
attendanceRate: 95,
lateCount: 6,
earlyLeaveCount: 3,
absentCount: 1
},
{
key: '4',
department: '人事部',
memberCount: 15,
attendanceRate: 97,
lateCount: 2,
earlyLeaveCount: 1,
absentCount: 0
},
{
key: '5',
department: '财务部',
memberCount: 12,
attendanceRate: 99,
lateCount: 1,
earlyLeaveCount: 0,
absentCount: 0
}
]
// 颜色处理函数
const getRankColor = (rank) => {
if (rank <= 3) return '#f50'
if (rank <= 10) return '#2db7f5'
return '#87d068'
}
const getScoreColor = (score) => {
if (score >= 90) return '#52c41a'
if (score >= 70) return '#1890ff'
return '#faad14'
}
const getAttendanceColor = (rate) => {
if (rate >= 95) return '#52c41a'
if (rate >= 90) return '#1890ff'
return '#faad14'
}
const getLateCountColor = (count) => {
if (count <= 2) return 'green'
if (count <= 5) return 'orange'
return 'red'
}
onMounted(() => {
// 使用 nextTick 确保 DOM 已完全渲染
nextTick(() => {
// 初始化部门活跃度对比图表
if (departmentActivityChart.value) {
const departmentChart = echarts.init(departmentActivityChart.value)
departmentChart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['技术部', '市场部', '销售部', '人事部', '财务部']
},
yAxis: {
type: 'value'
},
series: [
{
name: '活跃度',
type: 'bar',
data: [92, 85, 88, 79, 82]
},
{
name: '登录次数',
type: 'bar',
data: [320, 280, 310, 240, 260]
},
{
name: '操作次数',
type: 'bar',
data: [2800, 2100, 2400, 1800, 2000]
}
]
})
}
// 初始化每日活跃用户数图表
if (dailyActiveUsersChart.value) {
const dailyActiveChart = echarts.init(dailyActiveUsersChart.value)
dailyActiveChart.setOption({
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [
{
data: [120, 132, 145, 135, 128, 68, 42],
type: 'line',
areaStyle: {}
}
]
})
}
// 初始化平均在线时长图表
if (onlineTimeChart.value) {
const onlineChart = echarts.init(onlineTimeChart.value)
onlineChart.setOption({
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: ['技术部', '市场部', '销售部', '人事部', '财务部']
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value} 小时'
}
},
series: [
{
name: '平均在线时长',
type: 'bar',
data: [7.5, 6.8, 7.2, 6.5, 6.9]
}
]
})
}
// 初始化考勤趋势图表
if (attendanceTrendChart.value) {
const attendanceChart = echarts.init(attendanceTrendChart.value)
attendanceChart.setOption({
tooltip: {
trigger: 'axis'
},
legend: {
data: ['出勤率', '迟到率', '早退率']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月', '2月', '3月', '4月', '5月', '6月']
},
yAxis: {
type: 'value',
axisLabel: {
formatter: '{value}%'
}
},
series: [
{
name: '出勤率',
type: 'line',
data: [96.2, 97.1, 96.8, 97.5, 98.2, 97.8]
},
{
name: '迟到率',
type: 'line',
data: [2.8, 2.2, 2.5, 1.8, 1.2, 1.5]
},
{
name: '早退率',
type: 'line',
data: [1.0, 0.7, 0.7, 0.7, 0.6, 0.7]
}
]
})
}
// 监听窗口大小变化,调整图表大小
window.addEventListener('resize', () => {
if (departmentActivityChart.value) {
const departmentChart = echarts.getInstanceByDom(departmentActivityChart.value)
departmentChart?.resize()
}
if (dailyActiveUsersChart.value) {
const dailyActiveChart = echarts.getInstanceByDom(dailyActiveUsersChart.value)
dailyActiveChart?.resize()
}
if (onlineTimeChart.value) {
const onlineChart = echarts.getInstanceByDom(onlineTimeChart.value)
onlineChart?.resize()
}
if (attendanceTrendChart.value) {
const attendanceChart = echarts.getInstanceByDom(attendanceTrendChart.value)
attendanceChart?.resize()
}
})
})
})
</script>
<style scoped>
.general-card {
margin-bottom: 20px;
}
</style>