feat(api): 更新知识库和文档接口路径
feat(views): 新增广告监控相关页面组件
This commit is contained in:
815
src/views/ads/summary/monitor/index.vue
Normal file
815
src/views/ads/summary/monitor/index.vue
Normal file
@@ -0,0 +1,815 @@
|
||||
<template>
|
||||
<div class="ads-summary-monitor">
|
||||
<el-card shadow="hover">
|
||||
<template #header
|
||||
><div class="card-header"><span>监控总表</span></div></template
|
||||
>
|
||||
<div class="search-container">
|
||||
<el-form :model="searchParams" :inline="true" class="search-form">
|
||||
<el-form-item label="时间范围">
|
||||
<el-date-picker
|
||||
v-model="searchParams.dateRange"
|
||||
type="daterange"
|
||||
range-separator="至"
|
||||
start-placeholder="开始日期"
|
||||
end-placeholder="结束日期"
|
||||
value-format="YYYY-MM-DD"
|
||||
:shortcuts="dateShortcuts"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item label="部门"
|
||||
><el-select v-model="searchParams.department" placeholder="选择部门"
|
||||
><el-option v-for="option in departmentOptions" :key="option.value || 'all'" :label="option.label" :value="option.value" /></el-select
|
||||
></el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="handleSearch">查询</el-button>
|
||||
<el-button @click="handleReset">重置</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</div>
|
||||
<div class="chart-container">
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="12">
|
||||
<el-card>
|
||||
<template #header><div class="card-header">预算执行趋势</div></template>
|
||||
<div ref="trendChartRef" class="chart"></div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card>
|
||||
<template #header><div class="card-header">部门达成率对比</div></template>
|
||||
<div ref="comparisonChartRef" class="chart"></div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
<el-row :gutter="20" style="margin-top: 20px">
|
||||
<el-col :span="12">
|
||||
<el-card>
|
||||
<template #header><div class="card-header">预算执行分布</div></template>
|
||||
<div ref="distributionChartRef" class="chart"></div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
<el-col :span="12">
|
||||
<el-card>
|
||||
<template #header><div class="card-header">月度预算执行</div></template>
|
||||
<div ref="monthlyChartRef" class="chart"></div>
|
||||
</el-card>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
<div class="data-container">
|
||||
<el-card>
|
||||
<template #header><div class="card-header">关键指标</div></template>
|
||||
<div class="stats-grid">
|
||||
<el-card shadow="hover" class="stats-card">
|
||||
<div class="stats-item">
|
||||
<div class="stats-label">总预算</div>
|
||||
<div class="stats-value">¥{{ totalStats.totalBudget }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card shadow="hover" class="stats-card">
|
||||
<div class="stats-item">
|
||||
<div class="stats-label">已执行</div>
|
||||
<div class="stats-value">¥{{ totalStats.executed }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card shadow="hover" class="stats-card">
|
||||
<div class="stats-item">
|
||||
<div class="stats-label">总达成率</div>
|
||||
<div class="stats-value">{{ totalStats.overallRate }}%</div>
|
||||
</div>
|
||||
</el-card>
|
||||
<el-card shadow="hover" class="stats-card">
|
||||
<div class="stats-item">
|
||||
<div class="stats-label">日均执行</div>
|
||||
<div class="stats-value">¥{{ totalStats.dailyAverage }}</div>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
<div class="table-container">
|
||||
<el-card>
|
||||
<template #header><div class="card-header">部门预算执行明细</div></template>
|
||||
<el-table :data="pagedData" style="width: 100%">
|
||||
<el-table-column prop="department" label="部门" />
|
||||
<el-table-column prop="monthlyBudget" label="月度任务" />
|
||||
<el-table-column prop="executed" label="已达成" />
|
||||
<el-table-column prop="achievementRate" label="达成率"
|
||||
><template #default="scope">{{ scope.row.achievementRate }}%</template></el-table-column
|
||||
>
|
||||
<el-table-column prop="surplusBudget" label="剩余任务" />
|
||||
<el-table-column prop="dailyAverage" label="剩余日均" />
|
||||
<el-table-column prop="yesterday" label="昨日" />
|
||||
<el-table-column prop="estimatedAchievement" label="预计达成" />
|
||||
<el-table-column prop="dailyDifference" label="日均差" />
|
||||
<el-table-column prop="previousDay" label="前日" />
|
||||
<el-table-column prop="sequentialRatio" label="环比" />
|
||||
<el-table-column prop="timeProgress" label="对比时间进度" />
|
||||
<el-table-column prop="januaryAchievement" label="1月达成" />
|
||||
<el-table-column prop="januarySequentialRatio" label="环比" />
|
||||
<el-table-column prop="differenceFromTarget" label="目标差" />
|
||||
</el-table>
|
||||
<div class="pagination-container">
|
||||
<el-pagination
|
||||
v-model:current-page="pagination.currentPage"
|
||||
v-model:page-size="pagination.pageSize"
|
||||
:page-sizes="[10, 20, 50, 100]"
|
||||
layout="total, sizes, prev, pager, next, jumper"
|
||||
:total="pagination.total"
|
||||
@size-change="handlePageSizeChange"
|
||||
@current-change="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, onMounted, reactive, ref } from 'vue';
|
||||
import * as echarts from 'echarts';
|
||||
|
||||
interface DepartmentData {
|
||||
department: string;
|
||||
monthlyBudget: string;
|
||||
executed: string;
|
||||
achievementRate: string;
|
||||
surplusBudget: string;
|
||||
surplusDays: string;
|
||||
dailyAverage: string;
|
||||
yesterday: string;
|
||||
estimatedAchievement: string;
|
||||
dailyDifference: string;
|
||||
previousDay: string;
|
||||
sequentialRatio: string;
|
||||
timeProgress: string;
|
||||
januaryAchievement: string;
|
||||
januarySequentialRatio: string;
|
||||
differenceFromTarget: string;
|
||||
}
|
||||
|
||||
const departmentOptions = [
|
||||
{ label: '全部', value: 'all' },
|
||||
{ label: '一区一部', value: '一区一部' },
|
||||
{ label: '一区二部', value: '一区二部' },
|
||||
{ label: '一区三部', value: '一区三部' },
|
||||
{ label: '一区四部', value: '一区四部' },
|
||||
{ label: '代理运营总', value: '代理运营总' },
|
||||
{ label: '渠道部', value: '渠道部' },
|
||||
{ label: '电商一部', value: '电商一部' },
|
||||
{ label: '电商二部', value: '电商二部' },
|
||||
{ label: '张哥自营', value: '张哥自营' },
|
||||
{ label: '电商合计', value: '电商合计' },
|
||||
{ label: '金牛总任务', value: '金牛总任务' },
|
||||
];
|
||||
|
||||
const searchParams = reactive({
|
||||
dateRange: [],
|
||||
department: '',
|
||||
});
|
||||
|
||||
const dateShortcuts = [
|
||||
{
|
||||
text: '最近7天',
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7);
|
||||
return [start, end];
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '最近30天',
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30);
|
||||
return [start, end];
|
||||
},
|
||||
},
|
||||
{
|
||||
text: '最近90天',
|
||||
value: () => {
|
||||
const end = new Date();
|
||||
const start = new Date();
|
||||
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90);
|
||||
return [start, end];
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const trendChartRef = ref();
|
||||
const comparisonChartRef = ref();
|
||||
const distributionChartRef = ref();
|
||||
const monthlyChartRef = ref();
|
||||
let trendChart: echarts.ECharts | null = null;
|
||||
let comparisonChart: echarts.ECharts | null = null;
|
||||
let distributionChart: echarts.ECharts | null = null;
|
||||
let monthlyChart: echarts.ECharts | null = null;
|
||||
|
||||
const totalStats = reactive({
|
||||
totalBudget: '0',
|
||||
executed: '0',
|
||||
overallRate: '0',
|
||||
dailyAverage: '0',
|
||||
});
|
||||
|
||||
const data = ref<DepartmentData[]>([]);
|
||||
const pagination = reactive({
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0,
|
||||
});
|
||||
|
||||
const pagedData = computed(() => {
|
||||
const start = (pagination.currentPage - 1) * pagination.pageSize;
|
||||
const end = start + pagination.pageSize;
|
||||
return data.value.slice(start, end);
|
||||
});
|
||||
|
||||
const getMockData = (): DepartmentData[] => {
|
||||
// 根据图片中的数据生成模拟数据
|
||||
const departments = [
|
||||
{
|
||||
name: '一区一部',
|
||||
monthlyBudget: '1300000',
|
||||
executed: '937947.12',
|
||||
achievementRate: '72.15',
|
||||
surplusBudget: '362052.88',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '17240.61',
|
||||
yesterday: '36129.91',
|
||||
estimatedAchievement: '130.51%',
|
||||
dailyDifference: '18889.30',
|
||||
previousDay: '47003.57',
|
||||
sequentialRatio: '-10873.66',
|
||||
timeProgress: '42%',
|
||||
januaryAchievement: '1547156.813',
|
||||
januarySequentialRatio: '-16%',
|
||||
differenceFromTarget: '-7%',
|
||||
},
|
||||
{
|
||||
name: '一区二部',
|
||||
monthlyBudget: '3500000',
|
||||
executed: '2338291.84',
|
||||
achievementRate: '66.81',
|
||||
surplusBudget: '1161708.16',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '55319.44',
|
||||
yesterday: '106494.91',
|
||||
estimatedAchievement: '130.71%',
|
||||
dailyDifference: '51175.47',
|
||||
previousDay: '105791.93',
|
||||
sequentialRatio: '702.97',
|
||||
timeProgress: '37%',
|
||||
januaryAchievement: '3789374.035',
|
||||
januarySequentialRatio: '-8%',
|
||||
differenceFromTarget: '2%',
|
||||
},
|
||||
{
|
||||
name: '一区三部',
|
||||
monthlyBudget: '2100000',
|
||||
executed: '1896655.41',
|
||||
achievementRate: '90.32',
|
||||
surplusBudget: '203344.59',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '9683.07',
|
||||
yesterday: '55613.03',
|
||||
estimatedAchievement: '145.93%',
|
||||
dailyDifference: '45928.43',
|
||||
previousDay: '53994.08',
|
||||
sequentialRatio: '1618.95',
|
||||
timeProgress: '60%',
|
||||
januaryAchievement: '2861643.583',
|
||||
januarySequentialRatio: '-27%',
|
||||
differenceFromTarget: '-19%',
|
||||
},
|
||||
{
|
||||
name: '一区四部',
|
||||
monthlyBudget: '1600000',
|
||||
executed: '1960555.94',
|
||||
achievementRate: '122.53',
|
||||
surplusBudget: '-360555.94',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '-17169.33',
|
||||
yesterday: '66458.76',
|
||||
estimatedAchievement: '209.76%',
|
||||
dailyDifference: '83628.09',
|
||||
previousDay: '79558.31',
|
||||
sequentialRatio: '-1309.55',
|
||||
timeProgress: '93%',
|
||||
januaryAchievement: '2216583.797',
|
||||
januarySequentialRatio: '-28%',
|
||||
differenceFromTarget: '-20%',
|
||||
},
|
||||
{
|
||||
name: '代理运营总',
|
||||
monthlyBudget: '8500000',
|
||||
executed: '7134418.26',
|
||||
achievementRate: '83.93',
|
||||
surplusBudget: '1365581.74',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '65027.70',
|
||||
yesterday: '264596.76',
|
||||
estimatedAchievement: '149.32%',
|
||||
dailyDifference: '199682.28',
|
||||
previousDay: '286347.89',
|
||||
sequentialRatio: '-21651.29',
|
||||
timeProgress: '54%',
|
||||
januaryAchievement: '10414758.23',
|
||||
januarySequentialRatio: '-18%',
|
||||
differenceFromTarget: '-10%',
|
||||
},
|
||||
{
|
||||
name: '渠道部',
|
||||
monthlyBudget: '3000000',
|
||||
executed: '29134092.68',
|
||||
achievementRate: '97.11',
|
||||
surplusBudget: '865907.32',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '41233.68',
|
||||
yesterday: '806116.365',
|
||||
estimatedAchievement: '153.54%',
|
||||
dailyDifference: '764882.68',
|
||||
previousDay: '844507.14',
|
||||
sequentialRatio: '-38390.78',
|
||||
timeProgress: '67%',
|
||||
januaryAchievement: '39078360.25',
|
||||
januarySequentialRatio: '-23%',
|
||||
differenceFromTarget: '-15%',
|
||||
},
|
||||
{
|
||||
name: '电商一部',
|
||||
monthlyBudget: '4700000',
|
||||
executed: '3993326.756',
|
||||
achievementRate: '83.88',
|
||||
surplusBudget: '706673.24',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '33651.11',
|
||||
yesterday: '125785.982',
|
||||
estimatedAchievement: '140.02%',
|
||||
dailyDifference: '89563.45',
|
||||
previousDay: '132741.39',
|
||||
sequentialRatio: '-6955.41',
|
||||
timeProgress: '54%',
|
||||
januaryAchievement: '4522665.91',
|
||||
januarySequentialRatio: '4%',
|
||||
differenceFromTarget: '15%',
|
||||
},
|
||||
{
|
||||
name: '电商二部',
|
||||
monthlyBudget: '2800000',
|
||||
executed: '1302679.056',
|
||||
achievementRate: '46.52',
|
||||
surplusBudget: '1497320.94',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '7130.10',
|
||||
yesterday: '26049.373',
|
||||
estimatedAchievement: '66.06%',
|
||||
dailyDifference: '-45251.62',
|
||||
previousDay: '27892.62',
|
||||
sequentialRatio: '-1843.24',
|
||||
timeProgress: '17%',
|
||||
januaryAchievement: '2776056.70',
|
||||
januarySequentialRatio: '1%',
|
||||
differenceFromTarget: '12%',
|
||||
},
|
||||
{
|
||||
name: '张哥自营',
|
||||
monthlyBudget: '6000000',
|
||||
executed: '9770673.61',
|
||||
achievementRate: '162.84',
|
||||
surplusBudget: '-3770673.61',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '-179555.89',
|
||||
yesterday: '392448.463',
|
||||
estimatedAchievement: '300.20%',
|
||||
dailyDifference: '572004.35',
|
||||
previousDay: '331376.53',
|
||||
sequentialRatio: '61071.93',
|
||||
timeProgress: '133%',
|
||||
januaryAchievement: '8310458.83',
|
||||
januarySequentialRatio: '-28%',
|
||||
differenceFromTarget: '-20%',
|
||||
},
|
||||
{
|
||||
name: '电商合计',
|
||||
monthlyBudget: '13500000',
|
||||
executed: '15012801.94',
|
||||
achievementRate: '111.21',
|
||||
surplusBudget: '-1512801.94',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '-72038.19',
|
||||
yesterday: '544283.818',
|
||||
estimatedAchievement: '195.87%',
|
||||
dailyDifference: '616316.17',
|
||||
previousDay: '492286.58',
|
||||
sequentialRatio: '5207.28',
|
||||
timeProgress: '81%',
|
||||
januaryAchievement: '15609181.44',
|
||||
januarySequentialRatio: '-14%',
|
||||
differenceFromTarget: '-4%',
|
||||
},
|
||||
{
|
||||
name: '金牛总任务',
|
||||
monthlyBudget: '52000000',
|
||||
executed: '51280190.4',
|
||||
achievementRate: '98.62',
|
||||
surplusBudget: '719809.60',
|
||||
surplusDays: '21',
|
||||
dailyAverage: '34276.65',
|
||||
yesterday: '1615096.78',
|
||||
estimatedAchievement: '163.84%',
|
||||
dailyDifference: '1622865.58',
|
||||
previousDay: '1622865.58',
|
||||
sequentialRatio: '-7768.79',
|
||||
timeProgress: '69%',
|
||||
januaryAchievement: '65108327.29',
|
||||
januarySequentialRatio: '-20%',
|
||||
differenceFromTarget: '-12%',
|
||||
},
|
||||
];
|
||||
|
||||
const mockData: DepartmentData[] = departments.map((dept) => ({
|
||||
department: dept.name,
|
||||
monthlyBudget: dept.monthlyBudget,
|
||||
executed: dept.executed,
|
||||
achievementRate: dept.achievementRate,
|
||||
surplusBudget: dept.surplusBudget,
|
||||
surplusDays: dept.surplusDays,
|
||||
dailyAverage: dept.dailyAverage,
|
||||
yesterday: dept.yesterday,
|
||||
estimatedAchievement: dept.estimatedAchievement,
|
||||
dailyDifference: dept.dailyDifference,
|
||||
previousDay: dept.previousDay,
|
||||
sequentialRatio: dept.sequentialRatio,
|
||||
timeProgress: dept.timeProgress,
|
||||
januaryAchievement: dept.januaryAchievement,
|
||||
januarySequentialRatio: dept.januarySequentialRatio,
|
||||
differenceFromTarget: dept.differenceFromTarget,
|
||||
}));
|
||||
|
||||
return mockData;
|
||||
};
|
||||
|
||||
const calculateTotalStats = (_data: DepartmentData[]) => {
|
||||
// 使用图片中的总数据
|
||||
totalStats.totalBudget = '52000000';
|
||||
totalStats.executed = '51280190.4';
|
||||
totalStats.overallRate = '98.62';
|
||||
totalStats.dailyAverage = '1654199.70';
|
||||
};
|
||||
|
||||
const initTrendChart = (_data: DepartmentData[]) => {
|
||||
if (!trendChartRef.value) return;
|
||||
|
||||
if (trendChart) trendChart.dispose();
|
||||
trendChart = echarts.init(trendChartRef.value);
|
||||
|
||||
// 使用图片中的2026年2月数据
|
||||
const dates = [
|
||||
'2026/2/1',
|
||||
'2026/2/2',
|
||||
'2026/2/3',
|
||||
'2026/2/4',
|
||||
'2026/2/5',
|
||||
'2026/2/6',
|
||||
'2026/2/7',
|
||||
'2026/2/8',
|
||||
'2026/2/9',
|
||||
'2026/2/10',
|
||||
'2026/2/11',
|
||||
'2026/2/12',
|
||||
'2026/2/13',
|
||||
'2026/2/14',
|
||||
'2026/2/15',
|
||||
'2026/2/16',
|
||||
];
|
||||
const executedData = [
|
||||
2149518.05, 1871119.64, 2088655.19, 1702786.8, 1770269.31, 1714822.74, 1649665.0, 1622865.58, 1615096.78, 1485551.17, 1407212.21, 1364826.0,
|
||||
1233123.83, 1089680.69, 1086898.47, 816321.92,
|
||||
];
|
||||
const targetData = dates.map(() => 1733333.33); // 52000000 / 30
|
||||
|
||||
trendChart.setOption({
|
||||
title: {
|
||||
text: '预算执行趋势',
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: '{b}<br/>{a}: ¥{c}',
|
||||
},
|
||||
legend: {
|
||||
data: ['实际执行', '目标'],
|
||||
bottom: 0,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: dates,
|
||||
axisLabel: {
|
||||
rotate: 45,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '金额',
|
||||
axisLabel: {
|
||||
formatter: '¥{value}',
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '实际执行',
|
||||
type: 'line',
|
||||
data: executedData,
|
||||
areaStyle: {},
|
||||
},
|
||||
{
|
||||
name: '目标',
|
||||
type: 'line',
|
||||
data: targetData,
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const initComparisonChart = (data: DepartmentData[]) => {
|
||||
if (!comparisonChartRef.value) return;
|
||||
|
||||
if (comparisonChart) comparisonChart.dispose();
|
||||
comparisonChart = echarts.init(comparisonChartRef.value);
|
||||
|
||||
const departments = data.map((item) => item.department);
|
||||
const achievementRates = data.map((item) => parseFloat(item.achievementRate));
|
||||
|
||||
comparisonChart.setOption({
|
||||
title: {
|
||||
text: '部门达成率对比',
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: '{b}<br/>{a}: {c}%',
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: departments,
|
||||
axisLabel: {
|
||||
rotate: 45,
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '达成率',
|
||||
axisLabel: {
|
||||
formatter: '{value}%',
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '达成率',
|
||||
type: 'bar',
|
||||
data: achievementRates,
|
||||
itemStyle: {
|
||||
color: function (params: any) {
|
||||
const rate = params.value;
|
||||
if (rate >= 80) return '#67c23a';
|
||||
if (rate >= 60) return '#e6a23c';
|
||||
return '#f56c6c';
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const initDistributionChart = (data: DepartmentData[]) => {
|
||||
if (!distributionChartRef.value) return;
|
||||
|
||||
if (distributionChart) distributionChart.dispose();
|
||||
distributionChart = echarts.init(distributionChartRef.value);
|
||||
|
||||
distributionChart.setOption({
|
||||
title: {
|
||||
text: '预算执行分布',
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{b}: ¥{c} ({d}%)',
|
||||
},
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
data: data.map((item) => item.department),
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '预算执行',
|
||||
type: 'pie',
|
||||
radius: '50%',
|
||||
data: data.map((item) => ({
|
||||
value: parseFloat(item.executed),
|
||||
name: item.department,
|
||||
})),
|
||||
emphasis: {
|
||||
itemStyle: {
|
||||
shadowBlur: 10,
|
||||
shadowOffsetX: 0,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const initMonthlyChart = (_data: DepartmentData[]) => {
|
||||
if (!monthlyChartRef.value) return;
|
||||
|
||||
if (monthlyChart) monthlyChart.dispose();
|
||||
monthlyChart = echarts.init(monthlyChartRef.value);
|
||||
|
||||
const months = ['1月', '2月', '3月', '4月', '5月', '6月'];
|
||||
const budgetData = months.map(() => (Math.random() * 10000000 + 5000000).toFixed(2));
|
||||
const executedData = months.map((_, index) => (parseFloat(budgetData[index]) * (Math.random() * 0.3 + 0.5)).toFixed(2));
|
||||
|
||||
monthlyChart.setOption({
|
||||
title: {
|
||||
text: '月度预算执行',
|
||||
left: 'center',
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
formatter: '{b}<br/>{a}: ¥{c}',
|
||||
},
|
||||
legend: {
|
||||
data: ['预算', '实际执行'],
|
||||
bottom: 0,
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
data: months,
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
name: '金额',
|
||||
axisLabel: {
|
||||
formatter: '¥{value}',
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: '预算',
|
||||
type: 'bar',
|
||||
data: budgetData.map(parseFloat),
|
||||
itemStyle: {
|
||||
color: '#909399',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: '实际执行',
|
||||
type: 'bar',
|
||||
data: executedData.map(parseFloat),
|
||||
itemStyle: {
|
||||
color: '#409eff',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
};
|
||||
|
||||
const handleSearch = () => {
|
||||
data.value = getMockData();
|
||||
pagination.total = data.value.length;
|
||||
calculateTotalStats(data.value);
|
||||
initTrendChart(data.value);
|
||||
initComparisonChart(data.value);
|
||||
initDistributionChart(data.value);
|
||||
initMonthlyChart(data.value);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
searchParams.dateRange = [];
|
||||
searchParams.department = '';
|
||||
pagination.currentPage = 1;
|
||||
handleSearch();
|
||||
};
|
||||
|
||||
const handlePageSizeChange = (size: number) => {
|
||||
pagination.pageSize = size;
|
||||
pagination.currentPage = 1;
|
||||
};
|
||||
|
||||
const handlePageChange = (page: number) => {
|
||||
pagination.currentPage = page;
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
handleSearch();
|
||||
window.addEventListener('resize', () => {
|
||||
trendChart?.resize();
|
||||
comparisonChart?.resize();
|
||||
distributionChart?.resize();
|
||||
monthlyChart?.resize();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.ads-summary-monitor {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.search-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.search-form {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.search-form :deep(.el-form-item) {
|
||||
margin-right: 12px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.ads-summary-monitor :deep(.el-select) {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
.ads-summary-monitor :deep(.el-select__wrapper),
|
||||
.ads-summary-monitor :deep(.el-select__selected-item),
|
||||
.ads-summary-monitor :deep(.el-select__placeholder) {
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.granularity-group {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.chart {
|
||||
width: 100%;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.data-container {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
.stats-card {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stats-item {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.stats-label {
|
||||
font-size: 14px;
|
||||
color: #606266;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stats-value {
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.table-container {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.pagination-container {
|
||||
margin-top: 16px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user