|
|
@@ -0,0 +1,225 @@
|
|
|
+<template>
|
|
|
+ <el-col class="dashboard-col">
|
|
|
+ <div class="dashboard-card">
|
|
|
+ <el-row class="h100">
|
|
|
+ <el-col :lg="16" class="left-part">
|
|
|
+ <div class="card-header">
|
|
|
+ <div class="card-header__text">收入报表</div>
|
|
|
+ <div class="legend earning">收入</div>
|
|
|
+ <div class="legend expense">支出</div>
|
|
|
+ </div>
|
|
|
+ <div class="card-body">
|
|
|
+ <div style="height: 230px">
|
|
|
+ <chart v-bind="{ ...chart }"></chart>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ <el-col :lg="8" class="right-part">
|
|
|
+ <el-select v-model="year" style="width: 100px">
|
|
|
+ <el-option label="2021" value="2021"></el-option>
|
|
|
+ </el-select>
|
|
|
+ <div class="num1">$25,852</div>
|
|
|
+ <div class="num2">预算: 56,800</div>
|
|
|
+ <div style="height: 180px; margin: 20px 0; width: calc(100% - 40px)">
|
|
|
+ <chart v-bind="{ ...chart1 }"></chart>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+ </el-row>
|
|
|
+ </div>
|
|
|
+ </el-col>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import chart from '@j-t-mcc/vue3-chartjs';
|
|
|
+let delayed = false;
|
|
|
+let chartData1 = Array.from({ length: 9 }, (_, i) => parseInt(Math.random() * 20 + 20));
|
|
|
+export default {
|
|
|
+ components: { chart },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ year: '2021',
|
|
|
+ chart: {
|
|
|
+ type: 'bar',
|
|
|
+ options: {
|
|
|
+ animation: {
|
|
|
+ onComplete: () => {
|
|
|
+ delayed = true;
|
|
|
+ },
|
|
|
+ delay: context => {
|
|
|
+ let delay = 0;
|
|
|
+ if (context.type === 'data' && context.mode === 'default' && !delayed) {
|
|
|
+ delay = context.dataIndex * 50 + context.datasetIndex * 50;
|
|
|
+ }
|
|
|
+ return delay;
|
|
|
+ }
|
|
|
+ },
|
|
|
+ responsive: true,
|
|
|
+ maintainAspectRatio: false,
|
|
|
+ plugins: {
|
|
|
+ legend: {
|
|
|
+ display: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ scales: {
|
|
|
+ xAxis: {
|
|
|
+ stacked: true,
|
|
|
+ grid: {
|
|
|
+ display: false,
|
|
|
+ drawBorder: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ grid: {
|
|
|
+ display: false,
|
|
|
+ drawBorder: false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data: {
|
|
|
+ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
|
|
|
+ datasets: [
|
|
|
+ {
|
|
|
+ label: 'Earning',
|
|
|
+ backgroundColor: ['#665df5', '#665df5', '#665df5', '#665df5', '#665df5'],
|
|
|
+ data: Array.from({ length: 12 }, (_, i) => parseInt(Math.random() * 30 + 30)),
|
|
|
+ barPercentage: 0.2,
|
|
|
+ borderRadius: 1000,
|
|
|
+ borderSkipped: 'start'
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: 'Expense',
|
|
|
+ backgroundColor: ['#ff9f43', '#ff9f43', '#ff9f43', '#ff9f43', '#ff9f43'],
|
|
|
+ data: Array.from({ length: 12 }, (_, i) => -parseInt(Math.random() * 30 + 30)),
|
|
|
+ barPercentage: 0.2,
|
|
|
+ borderRadius: 1000,
|
|
|
+ borderSkipped: 'start'
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ chart1: {
|
|
|
+ type: 'line',
|
|
|
+ options: {
|
|
|
+ maintainAspectRatio: false,
|
|
|
+ plugins: {
|
|
|
+ legend: {
|
|
|
+ display: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ scales: {
|
|
|
+ xAxis: {
|
|
|
+ display: false,
|
|
|
+ grid: {
|
|
|
+ display: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ yAxis: {
|
|
|
+ display: false,
|
|
|
+ grid: {
|
|
|
+ display: false
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+ data: {
|
|
|
+ labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep'],
|
|
|
+ datasets: [
|
|
|
+ {
|
|
|
+ label: 'Earning',
|
|
|
+ borderColor: '#665df5',
|
|
|
+ backgroundColor: '#665df5',
|
|
|
+ borderCapStyle: 'round',
|
|
|
+ pointRadius: 0,
|
|
|
+ tension: 0.4,
|
|
|
+ borderWidth: 2,
|
|
|
+ data: chartData1
|
|
|
+ },
|
|
|
+ {
|
|
|
+ label: 'Expense',
|
|
|
+ borderColor: '#b8c2cc',
|
|
|
+ backgroundColor: '#b8c2cc',
|
|
|
+ borderCapStyle: 'round',
|
|
|
+ pointRadius: 0,
|
|
|
+ tension: 0.4,
|
|
|
+ borderWidth: 2,
|
|
|
+ borderDash: chartData1.map(i => 10),
|
|
|
+ data: chartData1.map(i => i - 20)
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="less" scoped>
|
|
|
+@import url(./card.less);
|
|
|
+.left-part {
|
|
|
+ border-right: 1px solid var(--border-color-3);
|
|
|
+ .card-header {
|
|
|
+ display: flex;
|
|
|
+ align-items: center;
|
|
|
+ }
|
|
|
+ .card-header__text {
|
|
|
+ flex-grow: 1;
|
|
|
+ }
|
|
|
+ .legend {
|
|
|
+ color: var(--text-color-2);
|
|
|
+ font-size: 14px;
|
|
|
+ margin-left: 40px;
|
|
|
+ font-weight: 400;
|
|
|
+ position: relative;
|
|
|
+ &::before {
|
|
|
+ content: '';
|
|
|
+ position: absolute;
|
|
|
+ margin: auto;
|
|
|
+ left: -20px;
|
|
|
+ top: 0;
|
|
|
+ bottom: 0;
|
|
|
+ width: 14px;
|
|
|
+ height: 14px;
|
|
|
+ border-radius: 50%;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .earning {
|
|
|
+ &::before {
|
|
|
+ background-color: var(--primary-color);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ .expense {
|
|
|
+ &::before {
|
|
|
+ background-color: var(--orange);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+.right-part {
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ justify-content: center;
|
|
|
+ align-items: center;
|
|
|
+ .num1 {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: var(--text-color-2);
|
|
|
+ margin-top: 20px;
|
|
|
+ }
|
|
|
+ .num2 {
|
|
|
+ font-size: 14px;
|
|
|
+ margin-top: 4px;
|
|
|
+ color: var(--text-color-2);
|
|
|
+ }
|
|
|
+}
|
|
|
+.chart-title {
|
|
|
+ .name {
|
|
|
+ font-size: 14px;
|
|
|
+ font-weight: 500;
|
|
|
+ color: var(--text-color-2);
|
|
|
+ }
|
|
|
+ .value {
|
|
|
+ font-size: 24px;
|
|
|
+ font-weight: 600;
|
|
|
+ margin-top: 6px;
|
|
|
+ color: var(--text-color-2);
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|