Files
prop-data-guard/frontend/src/views/report/Report.vue
T

196 lines
5.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="page-container">
<div class="page-header">
<h2 class="page-title">报表统计</h2>
<el-select v-model="selectedProject" placeholder="选择项目生成报告" clearable style="width: 260px">
<el-option v-for="p in projects" :key="p.id" :label="p.name" :value="p.id" />
</el-select>
<el-button type="primary" :disabled="!selectedProject" @click="downloadReport">
<el-icon><Download /></el-icon>下载报告
</el-button>
</div>
<el-row :gutter="16" class="chart-row">
<el-col :xs="24" :md="12">
<div class="chart-card card-shadow">
<div class="chart-title">数据分级分布</div>
<v-chart class="chart" :option="levelOption" autoresize />
</div>
</el-col>
<el-col :xs="24" :md="12">
<div class="chart-card card-shadow">
<div class="chart-title">项目进度</div>
<v-chart class="chart" :option="projectOption" autoresize />
</div>
</el-col>
</el-row>
<el-row :gutter="16" class="chart-row">
<el-col :xs="24" :md="12">
<div class="chart-card card-shadow">
<div class="chart-title">识别来源占比</div>
<v-chart class="chart" :option="sourceOption" autoresize />
</div>
</el-col>
<el-col :xs="24" :md="12">
<div class="chart-card card-shadow">
<div class="chart-title">敏感数据趋势近7天</div>
<v-chart class="chart" :option="trendOption" autoresize />
</div>
</el-col>
</el-row>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { use } from 'echarts/core'
import { CanvasRenderer } from 'echarts/renderers'
import { PieChart, BarChart, LineChart } from 'echarts/charts'
import { TooltipComponent, LegendComponent, GridComponent } from 'echarts/components'
import VChart from 'vue-echarts'
import { Download } from '@element-plus/icons-vue'
import { getProjects } from '@/api/project'
use([CanvasRenderer, PieChart, BarChart, LineChart, TooltipComponent, LegendComponent, GridComponent])
const selectedProject = ref<number | undefined>(undefined)
const projects = ref<any[]>([])
const levelOption = ref({
tooltip: { trigger: 'item' },
legend: { bottom: '0%', left: 'center' },
color: ['#67c23a', '#409eff', '#e6a23c', '#f56c6c', '#909399'],
series: [
{
type: 'pie',
radius: ['40%', '70%'],
avoidLabelOverlap: false,
itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 2 },
label: { show: false },
data: [
{ value: 35000, name: 'L1 公开级' },
{ value: 62000, name: 'L2 内部级' },
{ value: 48000, name: 'L3 敏感级' },
{ value: 22000, name: 'L4 重要级' },
{ value: 6931, name: 'L5 核心级' },
],
},
],
})
const projectOption = ref({
tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' } },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: { type: 'category', data: ['项目A', '项目B', '项目C', '项目D'] },
yAxis: { type: 'value', max: 100 },
series: [
{
type: 'bar',
data: [68, 92, 25, 45],
itemStyle: { borderRadius: [4, 4, 0, 0], color: '#409eff' },
label: { show: true, position: 'top', formatter: '{c}%' },
},
],
})
const sourceOption = ref({
tooltip: { trigger: 'item' },
legend: { bottom: '0%', left: 'center' },
color: ['#e6a23c', '#67c23a'],
series: [
{
type: 'pie',
radius: ['40%', '70%'],
itemStyle: { borderRadius: 6, borderColor: '#fff', borderWidth: 2 },
label: { show: false },
data: [
{ value: 124500, name: '自动识别' },
{ value: 27840, name: '人工打标' },
],
},
],
})
const trendOption = ref({
tooltip: { trigger: 'axis' },
grid: { left: '3%', right: '4%', bottom: '3%', containLabel: true },
xAxis: { type: 'category', data: ['周一', '周二', '周三', '周四', '周五', '周六', '周日'] },
yAxis: { type: 'value' },
series: [
{
type: 'line',
data: [120, 132, 101, 134, 90, 230, 210],
smooth: true,
itemStyle: { color: '#f56c6c' },
areaStyle: { color: 'rgba(245,108,108,0.1)' },
},
],
})
function downloadReport() {
if (!selectedProject.value) return
const token = localStorage.getItem('pdg_token')
const url = `/api/v1/reports/projects/${selectedProject.value}/download`
const a = document.createElement('a')
a.href = url
a.download = `report_project_${selectedProject.value}.docx`
if (token) {
a.setAttribute('data-token', token)
}
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
async function fetchProjects() {
try {
const res: any = await getProjects({ page: 1, page_size: 100 })
projects.value = res?.data || []
} catch (e) {
// ignore
}
}
onMounted(fetchProjects)
</script>
<style scoped lang="scss">
.page-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
flex-wrap: wrap;
.page-title {
font-size: 20px;
font-weight: 600;
color: #303133;
margin-right: auto;
}
}
.chart-row {
margin-bottom: 16px;
}
.chart-card {
padding: 20px;
background: #fff;
border-radius: 8px;
.chart-title {
font-size: 16px;
font-weight: 600;
margin-bottom: 16px;
color: #303133;
}
.chart {
width: 100%;
height: 300px;
}
}
</style>