<!-- src/views/statistics/case.vue -->
|
<template>
|
<div class="statistics-page">
|
<!-- 筛选面板 -->
|
<el-card class="filter-card">
|
<el-form :inline="true" :model="query" class="filter-form">
|
<el-form-item label="地区">
|
<el-select
|
v-model="query.region"
|
placeholder="请选择地区"
|
clearable
|
multiple
|
collapse-tags
|
style="width: 200px"
|
>
|
<el-option
|
v-for="item in regionOptions"
|
:key="item.value"
|
:label="item.label"
|
:value="item.value"
|
/>
|
</el-select>
|
</el-form-item>
|
|
<el-form-item label="月份范围">
|
<el-date-picker
|
v-model="query.monthRange"
|
type="monthrange"
|
range-separator="至"
|
start-placeholder="开始月份"
|
end-placeholder="结束月份"
|
value-format="yyyy-MM"
|
style="width: 300px"
|
/>
|
</el-form-item>
|
|
<el-form-item>
|
<el-button type="primary" icon="el-icon-search" @click="handleSearch">查询</el-button>
|
<el-button icon="el-icon-refresh" @click="handleReset">重置</el-button>
|
<el-button type="success" icon="el-icon-download" @click="handleExport">导出</el-button>
|
</el-form-item>
|
</el-form>
|
</el-card>
|
|
<!-- 数据概览 -->
|
<el-row :gutter="20" class="overview-row">
|
<el-col :span="6" v-for="item in overviewData" :key="item.title">
|
<el-card class="overview-card">
|
<div class="overview-content">
|
<div class="overview-icon" :style="{ backgroundColor: item.color }">
|
<i :class="item.icon"></i>
|
</div>
|
<div class="overview-info">
|
<div class="overview-title">{{ item.title }}</div>
|
<div class="overview-value">{{ item.value }}</div>
|
<div class="overview-desc">{{ item.desc }}</div>
|
</div>
|
</div>
|
</el-card>
|
</el-col>
|
</el-row>
|
|
<!-- 图表区域 -->
|
<el-row :gutter="20" class="chart-row">
|
<el-col :span="12">
|
<el-card>
|
<div slot="header" class="clearfix">
|
<span>案例趋势分析</span>
|
<el-button
|
style="float: right; padding: 3px 0"
|
type="text"
|
@click="toggleChartType('trend')"
|
>
|
{{ chartTypes.trend === 'line' ? '柱状图' : '折线图' }}
|
</el-button>
|
</div>
|
<EChartsWrapper
|
:id="'trend-chart'"
|
:options="getTrendChartOptions()"
|
height="400px"
|
/>
|
</el-card>
|
</el-col>
|
|
<el-col :span="12">
|
<el-card>
|
<div slot="header" class="clearfix">
|
<span>地区分布对比</span>
|
</div>
|
<EChartsWrapper
|
:id="'region-chart'"
|
:options="getRegionChartOptions()"
|
height="400px"
|
/>
|
</el-card>
|
</el-col>
|
</el-row>
|
|
<!-- 数据表格 -->
|
<el-card>
|
<div slot="header" class="clearfix">
|
<span>案例统计明细</span>
|
<el-button
|
style="float: right;"
|
type="primary"
|
icon="el-icon-zoom-in"
|
@click="showDetail = true"
|
>
|
查看案例明细
|
</el-button>
|
</div>
|
|
<el-table
|
v-loading="loading"
|
:data="tableData"
|
style="width: 100%"
|
border
|
stripe
|
>
|
<el-table-column label="地区" prop="region" align="center" />
|
<el-table-column label="月份" prop="month" align="center" >
|
<template slot-scope="{ row }">
|
{{ formatMonth(row.month) }}
|
</template>
|
</el-table-column>
|
<el-table-column label="潜在捐献案例数" prop="potentialCount" align="center" />
|
<el-table-column label="完成捐献数量" prop="completedCount" align="center" />
|
<el-table-column label="完成率" prop="completionRate" align="center" >
|
<template slot-scope="{ row }">
|
<el-progress
|
:percentage="row.completionRate"
|
:color="getProgressColor(row.completionRate)"
|
:show-text="false"
|
/>
|
<span>{{ row.completionRate }}%</span>
|
</template>
|
</el-table-column>
|
<el-table-column label="案例明细" align="center" >
|
<template slot-scope="{ row }">
|
<el-button
|
type="text"
|
size="mini"
|
@click="viewCaseDetail(row)"
|
>
|
查看({{ row.caseCount || 0 }})
|
</el-button>
|
</template>
|
</el-table-column>
|
</el-table>
|
|
<el-pagination
|
v-show="total > 0"
|
:total="total"
|
:page.sync="query.page"
|
:limit.sync="query.limit"
|
@pagination="handlePagination"
|
style="margin-top: 20px;"
|
layout="total, sizes, prev, pager, next, jumper"
|
:page-sizes="[10, 20, 50, 100]"
|
/>
|
</el-card>
|
|
<!-- 案例明细弹窗 -->
|
<el-dialog
|
title="案例明细"
|
:visible.sync="showDetail"
|
|
append-to-body
|
>
|
<case-detail
|
:query="detailQuery"
|
@close="showDetail = false"
|
/>
|
</el-dialog>
|
</div>
|
</template>
|
|
<script>
|
import EChartsWrapper from '@/components/charts/EChartsWrapper.vue';
|
import CaseDetail from './components/CaseDetail.vue';
|
|
export default {
|
name: 'CaseStatistics',
|
components: {
|
EChartsWrapper,
|
CaseDetail
|
},
|
data() {
|
return {
|
// 查询参数
|
query: {
|
region: [],
|
monthRange: [],
|
page: 1,
|
limit: 10
|
},
|
|
// 地区选项
|
regionOptions: [
|
{ label: '青岛地区', value: 'qingdao' },
|
{ label: '日照地区', value: 'rizhao' },
|
{ label: '济南地区', value: 'jinan' },
|
{ label: '烟台地区', value: 'yantai' },
|
{ label: '威海地区', value: 'weihai' },
|
{ label: '潍坊地区', value: 'weifang' },
|
{ label: '临沂地区', value: 'linyi' }
|
],
|
|
// 加载状态
|
loading: false,
|
|
// 表格数据
|
tableData: [],
|
total: 0,
|
|
// 概览数据
|
overviewData: [
|
{ title: '总潜在捐献案例', value: 0, desc: '统计周期内', icon: 'el-icon-s-flag', color: '#409EFF' },
|
{ title: '总完成捐献数量', value: 0, desc: '统计周期内', icon: 'el-icon-circle-check', color: '#67C23A' },
|
{ title: '平均完成率', value: '0%', desc: '统计周期内', icon: 'el-icon-s-data', color: '#E6A23C' },
|
{ title: '涉及案例数', value: 0, desc: '统计周期内', icon: 'el-icon-document', color: '#F56C6C' }
|
],
|
|
// 图表类型
|
chartTypes: {
|
trend: 'line'
|
},
|
|
// 图表数据
|
chartData: {
|
trend: [],
|
region: []
|
},
|
|
// 弹窗控制
|
showDetail: false,
|
detailQuery: {},
|
|
// 模拟数据
|
mockData: {
|
table: [
|
{ id: 1, region: '青岛地区', month: '2024-01', potentialCount: 15, completedCount: 8, completionRate: 53.3, caseCount: 5 },
|
{ id: 2, region: '青岛地区', month: '2024-02', potentialCount: 18, completedCount: 10, completionRate: 55.6, caseCount: 6 },
|
{ id: 3, region: '日照地区', month: '2024-01', potentialCount: 8, completedCount: 4, completionRate: 50.0, caseCount: 3 },
|
{ id: 4, region: '日照地区', month: '2024-02', potentialCount: 10, completedCount: 6, completionRate: 60.0, caseCount: 4 },
|
{ id: 5, region: '济南地区', month: '2024-01', potentialCount: 20, completedCount: 12, completionRate: 60.0, caseCount: 7 },
|
{ id: 6, region: '济南地区', month: '2024-02', potentialCount: 22, completedCount: 14, completionRate: 63.6, caseCount: 8 }
|
],
|
trend: [
|
{ month: '2024-01', potential: 55, completed: 31 },
|
{ month: '2024-02', potential: 64, completed: 39 },
|
{ month: '2024-03', potential: 58, completed: 35 },
|
{ month: '2024-04', potential: 62, completed: 40 },
|
{ month: '2024-05', potential: 68, completed: 45 },
|
{ month: '2024-06', potential: 72, completed: 50 }
|
],
|
region: [
|
{ region: '青岛地区', potential: 150, completed: 85 },
|
{ region: '日照地区', potential: 80, completed: 45 },
|
{ region: '济南地区', potential: 200, completed: 120 },
|
{ region: '烟台地区', potential: 100, completed: 60 }
|
]
|
}
|
};
|
},
|
created() {
|
this.loadData();
|
},
|
methods: {
|
// 加载数据
|
async loadData() {
|
this.loading = true;
|
try {
|
// 模拟接口调用
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
// 处理表格数据
|
let filteredData = [...this.mockData.table];
|
|
if (this.query.region.length > 0) {
|
filteredData = filteredData.filter(item =>
|
this.query.region.includes(item.region.replace('地区', '').toLowerCase())
|
);
|
}
|
|
if (this.query.monthRange && this.query.monthRange.length === 2) {
|
const [start, end] = this.query.monthRange;
|
filteredData = filteredData.filter(item =>
|
item.month >= start && item.month <= end
|
);
|
}
|
|
this.tableData = filteredData;
|
this.total = filteredData.length;
|
|
// 更新概览数据
|
this.updateOverviewData(filteredData);
|
|
// 更新图表数据
|
this.chartData.trend = [...this.mockData.trend];
|
this.chartData.region = [...this.mockData.region];
|
|
} catch (error) {
|
console.error('加载数据失败:', error);
|
this.$message.error('数据加载失败');
|
} finally {
|
this.loading = false;
|
}
|
},
|
|
// 更新概览数据
|
updateOverviewData(data) {
|
if (data.length === 0) return;
|
|
const totalPotential = data.reduce((sum, item) => sum + item.potentialCount, 0);
|
const totalCompleted = data.reduce((sum, item) => sum + item.completedCount, 0);
|
const avgRate = data.length > 0
|
? (data.reduce((sum, item) => sum + item.completionRate, 0) / data.length).toFixed(1)
|
: 0;
|
const totalCases = data.reduce((sum, item) => sum + (item.caseCount || 0), 0);
|
|
this.overviewData[0].value = totalPotential;
|
this.overviewData[1].value = totalCompleted;
|
this.overviewData[2].value = `${avgRate}%`;
|
this.overviewData[3].value = totalCases;
|
},
|
|
// 获取趋势图表配置
|
getTrendChartOptions() {
|
const isLine = this.chartTypes.trend === 'line';
|
|
return {
|
tooltip: {
|
trigger: 'axis',
|
axisPointer: {
|
type: 'shadow'
|
}
|
},
|
legend: {
|
data: ['潜在捐献数', '完成捐献数']
|
},
|
grid: {
|
left: '3%',
|
right: '4%',
|
bottom: '3%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
data: this.chartData.trend.map(item => this.formatMonth(item.month))
|
},
|
yAxis: {
|
type: 'value',
|
name: '数量(个)'
|
},
|
series: [
|
{
|
name: '潜在捐献数',
|
type: isLine ? 'line' : 'bar',
|
data: this.chartData.trend.map(item => item.potential),
|
itemStyle: { color: '#409EFF' },
|
smooth: isLine,
|
lineStyle: isLine ? { width: 3 } : {}
|
},
|
{
|
name: '完成捐献数',
|
type: isLine ? 'line' : 'bar',
|
data: this.chartData.trend.map(item => item.completed),
|
itemStyle: { color: '#67C23A' },
|
smooth: isLine,
|
lineStyle: isLine ? { width: 3 } : {}
|
}
|
]
|
};
|
},
|
|
// 获取地区图表配置
|
getRegionChartOptions() {
|
return {
|
tooltip: {
|
trigger: 'axis',
|
axisPointer: {
|
type: 'shadow'
|
}
|
},
|
legend: {
|
data: ['潜在捐献数', '完成捐献数']
|
},
|
grid: {
|
left: '3%',
|
right: '4%',
|
bottom: '3%',
|
containLabel: true
|
},
|
xAxis: {
|
type: 'category',
|
data: this.chartData.region.map(item => item.region)
|
},
|
yAxis: {
|
type: 'value',
|
name: '数量(个)'
|
},
|
series: [
|
{
|
name: '潜在捐献数',
|
type: 'bar',
|
data: this.chartData.region.map(item => item.potential),
|
itemStyle: { color: '#409EFF' }
|
},
|
{
|
name: '完成捐献数',
|
type: 'bar',
|
data: this.chartData.region.map(item => item.completed),
|
itemStyle: { color: '#67C23A' }
|
}
|
]
|
};
|
},
|
|
// 获取进度条颜色
|
getProgressColor(percentage) {
|
if (percentage >= 60) return '#67C23A';
|
if (percentage >= 50) return '#E6A23C';
|
return '#F56C6C';
|
},
|
|
// 格式化月份显示
|
formatMonth(month) {
|
if (!month) return '';
|
return month.replace('-', '年') + '月';
|
},
|
|
// 处理查询
|
handleSearch() {
|
this.query.page = 1;
|
this.loadData();
|
},
|
|
// 处理重置
|
handleReset() {
|
this.query = {
|
region: [],
|
monthRange: [],
|
page: 1,
|
limit: 10
|
};
|
this.loadData();
|
},
|
|
// 处理分页
|
handlePagination({ page, limit }) {
|
this.query.page = page;
|
this.query.limit = limit;
|
this.loadData();
|
},
|
|
// 处理导出
|
handleExport() {
|
this.$message.info('导出功能开发中...');
|
// 这里可以调用导出接口
|
},
|
|
// 切换图表类型
|
toggleChartType(type) {
|
this.chartTypes[type] = this.chartTypes[type] === 'line' ? 'bar' : 'line';
|
},
|
|
// 查看案例详情
|
viewCaseDetail(row) {
|
this.detailQuery = {
|
region: row.region,
|
month: row.month
|
};
|
this.showDetail = true;
|
}
|
}
|
};
|
</script>
|
|
<style scoped>
|
.statistics-page {
|
padding: 20px;
|
}
|
|
.filter-card {
|
margin-bottom: 20px;
|
}
|
|
.filter-form {
|
margin-bottom: 0;
|
}
|
|
.overview-row {
|
margin-bottom: 20px;
|
}
|
|
.overview-card {
|
height: 100%;
|
}
|
|
.overview-content {
|
display: flex;
|
align-items: center;
|
}
|
|
.overview-icon {
|
width: 50px;
|
height: 50px;
|
border-radius: 8px;
|
display: flex;
|
align-items: center;
|
justify-content: center;
|
margin-right: 15px;
|
}
|
|
.overview-icon i {
|
font-size: 24px;
|
color: white;
|
}
|
|
.overview-info {
|
flex: 1;
|
}
|
|
.overview-title {
|
font-size: 14px;
|
color: #909399;
|
margin-bottom: 4px;
|
}
|
|
.overview-value {
|
font-size: 24px;
|
font-weight: bold;
|
color: #303133;
|
margin-bottom: 4px;
|
}
|
|
.overview-desc {
|
font-size: 12px;
|
color: #C0C4CC;
|
}
|
|
.chart-row {
|
margin-bottom: 20px;
|
}
|
</style>
|