xiongzhu il y a 4 ans
Parent
commit
ebc1ff45c5

+ 80 - 0
src/components/dashboard/Goal.vue

@@ -0,0 +1,80 @@
+<template>
+    <el-col class="dashboard-col">
+        <div class="dashboard-card card-goal">
+            <div class="card-header">
+                <div class="card-header__text">目标进度</div>
+            </div>
+            <div class="card-body">
+                <div class="progress">
+                    <el-progress type="dashboard" :percentage="82" :stroke-width="8" :width="180" color="#20c997">
+                        <template #default="{ percentage }">
+                            <div class="percentage-value">{{ percentage }}%</div>
+                        </template>
+                    </el-progress>
+                </div>
+                <div class="row">
+                    <div class="col">
+                        <div class="label">已完成</div>
+                        <div class="value">786,617</div>
+                    </div>
+                    <div class="col">
+                        <div class="label">进行中</div>
+                        <div class="value">13,561</div>
+                    </div>
+                </div>
+            </div>
+        </div>
+    </el-col>
+</template>
+<script>
+export default {
+    data() {
+        return {};
+    }
+};
+</script>
+<style lang="less" scoped>
+@import url(./card.less);
+.percentage-value {
+    font-weight: 500;
+    font-size: 32px;
+}
+.card-goal {
+    .card-body {
+        display: flex;
+        flex-direction: column;
+        justify-content: center;
+        .progress {
+            display: flex;
+            justify-content: center;
+            flex-grow: 1;
+        }
+        .row {
+            margin: 20px -20px -20px -20px;
+            display: flex;
+            .col {
+                flex-basis: 0;
+                flex-grow: 1;
+                display: flex;
+                flex-direction: column;
+                align-items: center;
+                justify-content: center;
+                border-top: 1px solid var(--border-color-3);
+                padding: 15px 0;
+                &:nth-child(2) {
+                    border-left: 1px solid var(--border-color-3);
+                }
+                .label {
+                    font-size: 14px;
+                    color: var(--text-color-2);
+                }
+                .value {
+                    font-size: 22px;
+                    font-weight: 700;
+                    color: var(--text-color-2);
+                }
+            }
+        }
+    }
+}
+</style>

+ 2 - 2
src/components/dashboard/OrderChart.vue

@@ -58,7 +58,7 @@ export default {
                     }
                 },
                 data: {
-                    labels: ['VueJs', 'EmberJs', 'ReactJs', 'AngularJs', 'AngularJs'],
+                    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
                     datasets: [
                         {
                             label: 'My First Dataset',
@@ -69,7 +69,7 @@ export default {
                                 'rgba(255, 159, 67, 0.85)',
                                 'rgba(255, 159, 67, 0.85)'
                             ],
-                            data: [40, 20, 50, 45, 55],
+                            data: Array.from({ length: 7 }, (_, i) => parseInt(Math.random() * 50 + 50)),
                             barPercentage: 0.2,
                             borderRadius: 1000,
                             borderSkipped: 0

+ 123 - 0
src/components/dashboard/OrderTrend.vue

@@ -0,0 +1,123 @@
+<template>
+    <el-col class="dashboard-col">
+        <div class="dashboard-card">
+            <div class="user-trend-body">
+                <div class="chart-title">
+                    <div class="icon-bg">
+                        <feather-icon name="box"></feather-icon>
+                    </div>
+                    <div class="value">1237</div>
+                    <div class="name">新增订单</div>
+                </div>
+                <div style="height: 100px">
+                    <chart v-bind="{ ...chart }"></chart>
+                </div>
+            </div>
+        </div>
+    </el-col>
+</template>
+<script>
+import chart from '@j-t-mcc/vue3-chartjs';
+
+export default {
+    components: { chart },
+    data() {
+        return {
+            chart: {
+                type: 'line',
+                data: {
+                    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
+                    datasets: [
+                        {
+                            label: 'Profit',
+                            data: Array.from({ length: 7 }, (_, i) => parseInt(Math.random() * 30 + 30)),
+                            borderColor: '#665df5',
+                            pointRadius: 0,
+                            borderWidth: 3,
+                            tension: 0.4,
+                            backgroundColor(context) {
+                                const chart = context.chart;
+                                const { ctx, chartArea } = chart;
+
+                                if (!chartArea) {
+                                    // This case happens on initial chart load
+                                    return null;
+                                }
+                                const chartWidth = chartArea.right - chartArea.left;
+                                const chartHeight = chartArea.bottom - chartArea.top;
+                                let width, height, gradient;
+                                if (gradient === null || width !== chartWidth || height !== chartHeight) {
+                                    // Create the gradient because this is either the first render
+                                    // or the size of the chart has changed
+                                    width = chartWidth;
+                                    height = chartHeight;
+                                    gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top);
+                                    gradient.addColorStop(0, 'rgba(115, 103, 240, 0)');
+                                    gradient.addColorStop(1, 'rgba(115, 103, 240, 0.6)');
+                                }
+
+                                return gradient;
+                            },
+                            fill: 'origin'
+                        }
+                    ]
+                },
+                options: {
+                    maintainAspectRatio: false,
+                    plugins: {
+                        legend: {
+                            display: false
+                        }
+                    },
+                    scales: {
+                        xAxis: {
+                            display: false,
+                            grid: {
+                                display: false
+                            }
+                        },
+                        yAxis: {
+                            min: 10,
+                            display: false,
+                            grid: {
+                                display: false
+                            }
+                        }
+                    }
+                }
+            }
+        };
+    }
+};
+</script>
+<style lang="less" scoped>
+@import url(./card.less);
+.user-trend-body {
+    padding: 0;
+}
+.chart-title {
+    padding: 20px 20px 0 20px;
+    .icon-bg {
+        width: 48px;
+        height: 48px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        background: rgba(115, 103, 240, 0.12);
+        border-radius: 50%;
+        margin-bottom: 20px;
+        /deep/ svg {
+            color: var(--primary-color);
+        }
+    }
+    .name {
+        font-size: 14px;
+        color: var(--text-color-2);
+    }
+    .value {
+        font-size: 24px;
+        font-weight: 600;
+        color: var(--text-color-2);
+    }
+}
+</style>

+ 2 - 2
src/components/dashboard/ProfitChart.vue

@@ -26,11 +26,11 @@ export default {
                     datasets: [
                         {
                             label: 'Profit',
-                            data: [65, 55, 80, 60, 85, 65, 95],
+                            data: Array.from({ length: 7 }, (_, i) => parseInt(Math.random() * 50 + 10)),
                             fill: false,
                             borderColor: 'rgba(0, 207, 232, 0.85)',
                             backgroundColor: 'rgba(0, 207, 232, 0.85)',
-                            borderWidth: 4
+                            borderWidth: 3
                         }
                     ]
                 },

+ 225 - 0
src/components/dashboard/RevenueChart.vue

@@ -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>

+ 123 - 0
src/components/dashboard/UserTrend.vue

@@ -0,0 +1,123 @@
+<template>
+    <el-col class="dashboard-col">
+        <div class="dashboard-card">
+            <div class="user-trend-body">
+                <div class="chart-title">
+                    <div class="icon-bg">
+                        <feather-icon name="user"></feather-icon>
+                    </div>
+                    <div class="value">4578</div>
+                    <div class="name">新增用户</div>
+                </div>
+                <div style="height: 100px">
+                    <chart v-bind="{ ...chart }"></chart>
+                </div>
+            </div>
+        </div>
+    </el-col>
+</template>
+<script>
+import chart from '@j-t-mcc/vue3-chartjs';
+
+export default {
+    components: { chart },
+    data() {
+        return {
+            chart: {
+                type: 'line',
+                data: {
+                    labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
+                    datasets: [
+                        {
+                            label: 'Profit',
+                            data: Array.from({ length: 7 }, (_, i) => parseInt(Math.random() * 30 + 30)),
+                            borderColor: '#ff9f43',
+                            pointRadius: 0,
+                            borderWidth: 3,
+                            tension: 0.4,
+                            backgroundColor(context) {
+                                const chart = context.chart;
+                                const { ctx, chartArea } = chart;
+
+                                if (!chartArea) {
+                                    // This case happens on initial chart load
+                                    return null;
+                                }
+                                const chartWidth = chartArea.right - chartArea.left;
+                                const chartHeight = chartArea.bottom - chartArea.top;
+                                let width, height, gradient;
+                                if (gradient === null || width !== chartWidth || height !== chartHeight) {
+                                    // Create the gradient because this is either the first render
+                                    // or the size of the chart has changed
+                                    width = chartWidth;
+                                    height = chartHeight;
+                                    gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top);
+                                    gradient.addColorStop(0, 'rgba(255, 159, 67, 0)');
+                                    gradient.addColorStop(1, 'rgba(255, 159, 67, 0.6)');
+                                }
+
+                                return gradient;
+                            },
+                            fill: 'origin'
+                        }
+                    ]
+                },
+                options: {
+                    maintainAspectRatio: false,
+                    plugins: {
+                        legend: {
+                            display: false
+                        }
+                    },
+                    scales: {
+                        xAxis: {
+                            display: false,
+                            grid: {
+                                display: false
+                            }
+                        },
+                        yAxis: {
+                            min: 10,
+                            display: false,
+                            grid: {
+                                display: false
+                            }
+                        }
+                    }
+                }
+            }
+        };
+    }
+};
+</script>
+<style lang="less" scoped>
+@import url(./card.less);
+.user-trend-body {
+    padding: 0;
+}
+.chart-title {
+    padding: 20px 20px 0 20px;
+    .icon-bg {
+        width: 48px;
+        height: 48px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        background: rgba(255, 159, 67, 0.12);
+        border-radius: 50%;
+        margin-bottom: 20px;
+        /deep/ svg {
+            color: var(--orange);
+        }
+    }
+    .name {
+        font-size: 14px;
+        color: var(--text-color-2);
+    }
+    .value {
+        font-size: 24px;
+        font-weight: 600;
+        color: var(--text-color-2);
+    }
+}
+</style>

+ 22 - 0
src/style/app.less

@@ -1,3 +1,25 @@
+:root {
+    --blue: #00cfe8;
+    --indigo: #6610f2;
+    --purple: #7367f0;
+    --pink: #e83e8c;
+    --red: #ea5455;
+    --orange: #ff9f43;
+    --yellow: #ffc107;
+    --green: #28c76f;
+    --teal: #20c997;
+    --cyan: #17a2b8;
+    --white: #fff;
+    --gray: #b8c2cc;
+    --gray-dark: #1e1e1e;
+    --secondary: #82868b;
+    --success: #28c76f;
+    --info: #00cfe8;
+    --warning: #ff9f43;
+    --danger: #ea5455;
+    --light: #f6f6f6;
+    --dark: #4b4b4b;
+}
 :root[theme='light'] {
     --background-color-1: #ffffff;
     --background-color-2: #f8f8f8;

+ 13 - 1
src/views/Dashboard.vue

@@ -7,6 +7,14 @@
         <el-row :gutter="20">
             <order-chart :xs="12" :sm="12"></order-chart><profit-chart :xs="12" :sm="12"></profit-chart>
         </el-row>
+        <el-row :gutter="20">
+            <user-trend :span="12"></user-trend>
+            <order-trend :span="12"></order-trend>
+        </el-row>
+        <el-row :gutter="20">
+            <goal :sm="6"></goal>
+            <revenue-chart :lg="18"></revenue-chart>
+        </el-row>
     </div>
 </template>
 <script>
@@ -14,8 +22,12 @@ import Statistics from '../components/dashboard/Statistics.vue';
 import Award from '../components/dashboard/Award.vue';
 import OrderChart from '../components/dashboard/OrderChart.vue';
 import ProfitChart from '../components/dashboard/ProfitChart.vue';
+import Goal from '../components/dashboard/Goal.vue';
+import RevenueChart from '../components/dashboard/RevenueChart.vue';
+import UserTrend from '../components/dashboard/UserTrend.vue';
+import OrderTrend from '../components/dashboard/OrderTrend.vue';
 export default {
-    components: { Statistics, Award, OrderChart, ProfitChart },
+    components: { Statistics, Award, OrderChart, ProfitChart, Goal, RevenueChart, UserTrend, OrderTrend },
     data() {
         return {};
     }

+ 6 - 3
src/views/Index.vue

@@ -157,6 +157,9 @@ export default {
             .avatar__wrapper {
                 position: relative;
                 cursor: pointer;
+                display: flex;
+                align-items: center;
+                justify-content: center;
                 .avatar {
                     width: 40px;
                     height: 40px;
@@ -166,12 +169,12 @@ export default {
                 &::after {
                     content: '';
                     position: absolute;
-                    right: 0;
-                    bottom: 1px;
+                    right: -1px;
+                    bottom: -1px;
                     width: 9px;
                     height: 9px;
                     border-radius: 7px;
-                    border: 1px solid #ffffff;
+                    border: 1.5px solid #ffffff;
                     background-color: #28c76f;
                 }
             }