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

484 lines
13 KiB
Vue
Raw Normal View History

2025-07-30 09:13:52 +08:00
<template>
<div class="app-container">
<a-card class="general-card" title="应用使用数据" :bordered="false">
<a-row :gutter="16">
<a-col :span="6" v-for="(stat, index) in appStatistics" :key="index">
<a-card class="stat-card">
<a-statistic
:title="stat.title"
:value="stat.value"
:precision="stat.precision || 0"
:suffix="stat.suffix || ''"
>
<template #prefix>
<component :is="stat.icon" />
2025-07-30 09:13:52 +08:00
</template>
</a-statistic>
</a-card>
</a-col>
</a-row>
<a-divider />
<a-row :gutter="16">
<a-col :span="12">
<a-card title="应用访问量趋势" :bordered="false">
<div ref="appVisitChart" style="height: 350px"></div>
</a-card>
</a-col>
<a-col :span="12">
<a-card title="应用使用时长分布" :bordered="false">
<div ref="appTimeChart" style="height: 350px"></div>
</a-card>
</a-col>
</a-row>
<a-divider />
<a-card title="应用使用详情" :bordered="false">
<a-tabs default-active-key="1">
<a-tab-pane key="1" tab="Web端">
<a-table :columns="appColumns" :data-source="webAppData" :pagination="{ pageSize: 5 }">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'usageRate'">
<a-progress :percent="record.usageRate" :stroke-color="getUsageRateColor(record.usageRate)" />
</template>
<template v-if="column.dataIndex === 'trend'">
<span :style="{ color: getTrendColor(record.trend) }">
{{ record.trend >= 0 ? '+' : '' }}{{ record.trend }}%
<icon-up v-if="record.trend > 0" style="color: #52c41a" />
<icon-down v-if="record.trend < 0" style="color: #ff4d4f" />
<icon-minus v-if="record.trend === 0" style="color: #1890ff" />
</span>
</template>
2025-07-30 09:13:52 +08:00
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="2" tab="移动端">
<a-table :columns="appColumns" :data-source="mobileAppData" :pagination="{ pageSize: 5 }">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'usageRate'">
<a-progress :percent="record.usageRate" :stroke-color="getUsageRateColor(record.usageRate)" />
</template>
<template v-if="column.dataIndex === 'trend'">
<span :style="{ color: getTrendColor(record.trend) }">
{{ record.trend >= 0 ? '+' : '' }}{{ record.trend }}%
<icon-up v-if="record.trend > 0" style="color: #52c41a" />
<icon-down v-if="record.trend < 0" style="color: #ff4d4f" />
<icon-minus v-if="record.trend === 0" style="color: #1890ff" />
</span>
</template>
2025-07-30 09:13:52 +08:00
</template>
</a-table>
</a-tab-pane>
<a-tab-pane key="3" tab="微信小程序">
<a-table :columns="appColumns" :data-source="miniAppData" :pagination="{ pageSize: 5 }">
<template #bodyCell="{ column, record }">
<template v-if="column.dataIndex === 'usageRate'">
<a-progress :percent="record.usageRate" :stroke-color="getUsageRateColor(record.usageRate)" />
</template>
<template v-if="column.dataIndex === 'trend'">
<span :style="{ color: getTrendColor(record.trend) }">
{{ record.trend >= 0 ? '+' : '' }}{{ record.trend }}%
<icon-up v-if="record.trend > 0" style="color: #52c41a" />
<icon-down v-if="record.trend < 0" style="color: #ff4d4f" />
<icon-minus v-if="record.trend === 0" style="color: #1890ff" />
</span>
</template>
2025-07-30 09:13:52 +08:00
</template>
</a-table>
</a-tab-pane>
</a-tabs>
</a-card>
<a-divider />
<a-row :gutter="16">
<a-col :span="24">
<a-card title="终端设备分布" :bordered="false">
<div ref="deviceDistributionChart" style="height: 400px"></div>
</a-card>
</a-col>
</a-row>
2025-07-30 09:13:52 +08:00
</a-card>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, reactive, nextTick } from 'vue'
import { Statistic } from '@arco-design/web-vue'
import * as echarts from 'echarts'
import {
IconApps,
IconMobile,
IconUser,
IconClockCircle,
IconUp,
IconDown,
IconMinus
} from '@arco-design/web-vue/es/icon'
const appVisitChart = ref(null)
const appTimeChart = ref(null)
const deviceDistributionChart = ref(null)
// 应用统计数据
const appStatistics = reactive([
{
title: '应用总数',
value: 12,
icon: IconApps
},
{
title: '活跃应用',
value: 8,
icon: IconApps
},
{
title: '日均访问量',
value: 1258,
icon: IconUser
},
{
title: '日均使用时长',
value: 3.5,
precision: 1,
suffix: '小时',
icon: IconClockCircle
}
])
// 应用使用详情表格列定义
const appColumns = [
{
title: '应用名称',
dataIndex: 'appName',
key: 'appName',
},
{
title: '访问量',
dataIndex: 'visitCount',
key: 'visitCount',
sorter: (a, b) => a.visitCount - b.visitCount,
},
{
title: '用户数',
dataIndex: 'userCount',
key: 'userCount',
sorter: (a, b) => a.userCount - b.userCount,
},
{
title: '使用率',
dataIndex: 'usageRate',
key: 'usageRate',
sorter: (a, b) => a.usageRate - b.usageRate,
},
{
title: '平均使用时长',
dataIndex: 'averageTime',
key: 'averageTime',
},
{
title: '环比上月',
dataIndex: 'trend',
key: 'trend',
sorter: (a, b) => a.trend - b.trend,
}
]
// Web端应用数据
const webAppData = [
{
key: '1',
appName: '企业管理后台',
visitCount: 3560,
userCount: 320,
usageRate: 95,
averageTime: '2.5小时',
trend: 8.5
},
{
key: '2',
appName: '项目管理系统',
visitCount: 2980,
userCount: 285,
usageRate: 90,
averageTime: '3小时',
trend: 5.2
},
{
key: '3',
appName: '数据分析平台',
visitCount: 2450,
userCount: 210,
usageRate: 85,
averageTime: '2小时',
trend: 3.8
},
{
key: '4',
appName: '客户管理系统',
visitCount: 1980,
userCount: 180,
usageRate: 75,
averageTime: '1.5小时',
trend: -2.1
},
{
key: '5',
appName: '知识库系统',
visitCount: 1560,
userCount: 150,
usageRate: 65,
averageTime: '1小时',
trend: 0
}
]
// 移动端应用数据
const mobileAppData = [
{
key: '1',
appName: '移动办公APP',
visitCount: 4250,
userCount: 350,
usageRate: 98,
averageTime: '3.5小时',
trend: 12.5
},
{
key: '2',
appName: '外勤管理APP',
visitCount: 3680,
userCount: 320,
usageRate: 92,
averageTime: '4小时',
trend: 9.8
},
{
key: '3',
appName: '项目跟踪APP',
visitCount: 2850,
userCount: 260,
usageRate: 88,
averageTime: '3小时',
trend: 7.5
},
{
key: '4',
appName: '客户拜访APP',
visitCount: 2120,
userCount: 180,
usageRate: 72,
averageTime: '2小时',
trend: -1.5
}
]
// 微信小程序数据
const miniAppData = [
{
key: '1',
appName: '企业服务小程序',
visitCount: 5680,
userCount: 420,
usageRate: 96,
averageTime: '1.5小时',
trend: 15.8
},
{
key: '2',
appName: '客户自助小程序',
visitCount: 4850,
userCount: 380,
usageRate: 90,
averageTime: '1小时',
trend: 10.5
},
{
key: '3',
appName: '员工工具小程序',
visitCount: 3920,
userCount: 345,
usageRate: 85,
averageTime: '0.8小时',
trend: 8.2
}
]
// 颜色处理函数
const getUsageRateColor = (rate) => {
if (rate >= 90) return '#52c41a'
if (rate >= 70) return '#1890ff'
return '#faad14'
}
const getTrendColor = (trend) => {
if (trend > 0) return '#52c41a'
if (trend < 0) return '#ff4d4f'
return '#1890ff'
}
onMounted(() => {
// 使用 nextTick 确保 DOM 已完全渲染
nextTick(() => {
2025-07-30 09:13:52 +08:00
// 初始化应用访问量趋势图表
if (appVisitChart.value) {
const visitChart = echarts.init(appVisitChart.value)
visitChart.setOption({
tooltip: {
trigger: 'axis'
},
legend: {
data: ['Web端', '移动端', '小程序']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日']
},
yAxis: {
type: 'value'
},
series: [
{
name: 'Web端',
type: 'line',
data: [2500, 2800, 3200, 3100, 2950, 1800, 1200]
},
{
name: '移动端',
type: 'line',
data: [3200, 3500, 3800, 3600, 3400, 2800, 2500]
},
{
name: '小程序',
type: 'line',
data: [4500, 4800, 5200, 4900, 4700, 3900, 3500]
}
]
})
}
2025-07-30 09:13:52 +08:00
// 初始化应用使用时长分布图表
if (appTimeChart.value) {
const timeChart = echarts.init(appTimeChart.value)
timeChart.setOption({
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: '使用时长分布',
type: 'pie',
radius: '70%',
data: [
{ value: 35, name: 'Web端' },
{ value: 45, name: '移动端' },
{ value: 20, name: '小程序' }
],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
})
}
// 初始化终端设备分布图表
if (deviceDistributionChart.value) {
const deviceChart = echarts.init(deviceDistributionChart.value)
deviceChart.setOption({
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'value'
},
yAxis: {
type: 'category',
data: ['Windows PC', 'Mac', 'iOS', 'Android', '微信']
},
series: [
{
name: '访问量',
type: 'bar',
stack: 'total',
label: {
show: true
2025-07-30 09:13:52 +08:00
},
emphasis: {
focus: 'series'
},
data: [5200, 3800, 6500, 8200, 9500]
2025-07-30 09:13:52 +08:00
},
{
name: '用户数',
type: 'bar',
stack: 'total',
label: {
show: true
2025-07-30 09:13:52 +08:00
},
emphasis: {
focus: 'series'
2025-07-30 09:13:52 +08:00
},
data: [280, 220, 320, 380, 420]
}
]
})
}
2025-07-30 09:13:52 +08:00
// 监听窗口大小变化,调整图表大小
window.addEventListener('resize', () => {
if (appVisitChart.value) {
const visitChart = echarts.getInstanceByDom(appVisitChart.value)
visitChart?.resize()
}
if (appTimeChart.value) {
const timeChart = echarts.getInstanceByDom(appTimeChart.value)
timeChart?.resize()
}
if (deviceDistributionChart.value) {
const deviceChart = echarts.getInstanceByDom(deviceDistributionChart.value)
deviceChart?.resize()
}
})
2025-07-30 09:13:52 +08:00
})
})
</script>
2025-07-30 09:13:52 +08:00
<style scoped>
.general-card {
margin-bottom: 20px;
}
2025-07-30 09:13:52 +08:00
.stat-card {
margin-bottom: 20px;
text-align: center;
}
</style>