Merge branch 'main' of http://129.211.33.98:3210/hjq/mart-admin
This commit is contained in:
commit
6bea984e06
63
package-lock.json
generated
63
package-lock.json
generated
@ -13,6 +13,7 @@
|
|||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
|
"chart.js": "^4.4.6",
|
||||||
"countup.js": "^2.8.0",
|
"countup.js": "^2.8.0",
|
||||||
"cropperjs": "^1.6.1",
|
"cropperjs": "^1.6.1",
|
||||||
"echarts": "^5.5.0",
|
"echarts": "^5.5.0",
|
||||||
@ -23,6 +24,7 @@
|
|||||||
"js-table2excel": "^1.1.2",
|
"js-table2excel": "^1.1.2",
|
||||||
"jsplumb": "^2.15.6",
|
"jsplumb": "^2.15.6",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
|
"mockjs": "^1.1.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
@ -39,6 +41,8 @@
|
|||||||
"vue-router": "^4.3.0"
|
"vue-router": "^4.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/chart.js": "^2.9.41",
|
||||||
|
"@types/mockjs": "^1.0.10",
|
||||||
"@types/node": "^20.11.28",
|
"@types/node": "^20.11.28",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/sortablejs": "^1.15.8",
|
"@types/sortablejs": "^1.15.8",
|
||||||
@ -412,6 +416,11 @@
|
|||||||
"version": "1.4.15",
|
"version": "1.4.15",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@kurkle/color": {
|
||||||
|
"version": "0.3.4",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@kurkle/color/-/color-0.3.4.tgz",
|
||||||
|
"integrity": "sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w=="
|
||||||
|
},
|
||||||
"node_modules/@nodelib/fs.scandir": {
|
"node_modules/@nodelib/fs.scandir": {
|
||||||
"version": "2.1.5",
|
"version": "2.1.5",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -472,6 +481,15 @@
|
|||||||
"version": "0.0.7",
|
"version": "0.0.7",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/chart.js": {
|
||||||
|
"version": "2.9.41",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/chart.js/-/chart.js-2.9.41.tgz",
|
||||||
|
"integrity": "sha512-3dvkDvueckY83UyUXtJMalYoH6faOLkWQoaTlJgB4Djde3oORmNP0Jw85HtzTuXyliUHcdp704s0mZFQKio/KQ==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"moment": "^2.10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.5",
|
"version": "1.0.5",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -497,6 +515,12 @@
|
|||||||
"@types/lodash": "*"
|
"@types/lodash": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/mockjs": {
|
||||||
|
"version": "1.0.10",
|
||||||
|
"resolved": "https://registry.npmmirror.com/@types/mockjs/-/mockjs-1.0.10.tgz",
|
||||||
|
"integrity": "sha512-SXgrhajHG7boLv6oU93CcmdDm0HYRiceuz6b+7z+/2lCJPTWDv0V5YiwFHT2ejE4bQqgSXQiVPQYPWv7LGsK1g==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.11.28",
|
"version": "20.11.28",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -1245,6 +1269,17 @@
|
|||||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/chart.js": {
|
||||||
|
"version": "4.4.6",
|
||||||
|
"resolved": "https://registry.npmmirror.com/chart.js/-/chart.js-4.4.6.tgz",
|
||||||
|
"integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@kurkle/color": "^0.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"pnpm": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chokidar": {
|
"node_modules/chokidar": {
|
||||||
"version": "3.5.3",
|
"version": "3.5.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -1359,6 +1394,14 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "12.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/commander/-/commander-12.1.0.tgz",
|
||||||
|
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/compute-scroll-into-view": {
|
"node_modules/compute-scroll-into-view": {
|
||||||
"version": "1.0.20",
|
"version": "1.0.20",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
@ -2538,6 +2581,26 @@
|
|||||||
"mkdirp": "bin/cmd.js"
|
"mkdirp": "bin/cmd.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mockjs": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/mockjs/-/mockjs-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "*"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"random": "bin/random"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/moment": {
|
||||||
|
"version": "2.30.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/moment/-/moment-2.30.1.tgz",
|
||||||
|
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||||
|
"dev": true,
|
||||||
|
"engines": {
|
||||||
|
"node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-vue": "^5.1.12",
|
"@wangeditor/editor-for-vue": "^5.1.12",
|
||||||
"axios": "^1.6.8",
|
"axios": "^1.6.8",
|
||||||
|
"chart.js": "^4.4.6",
|
||||||
"countup.js": "^2.8.0",
|
"countup.js": "^2.8.0",
|
||||||
"cropperjs": "^1.6.1",
|
"cropperjs": "^1.6.1",
|
||||||
"echarts": "^5.5.0",
|
"echarts": "^5.5.0",
|
||||||
@ -25,6 +26,7 @@
|
|||||||
"js-table2excel": "^1.1.2",
|
"js-table2excel": "^1.1.2",
|
||||||
"jsplumb": "^2.15.6",
|
"jsplumb": "^2.15.6",
|
||||||
"mitt": "^3.0.1",
|
"mitt": "^3.0.1",
|
||||||
|
"mockjs": "^1.1.0",
|
||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
@ -42,6 +44,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/file-saver": "^2.0.7",
|
"@types/file-saver": "^2.0.7",
|
||||||
|
"@types/chart.js": "^2.9.41",
|
||||||
|
"@types/mockjs": "^1.0.10",
|
||||||
"@types/node": "^20.11.28",
|
"@types/node": "^20.11.28",
|
||||||
"@types/nprogress": "^0.2.3",
|
"@types/nprogress": "^0.2.3",
|
||||||
"@types/sortablejs": "^1.15.8",
|
"@types/sortablejs": "^1.15.8",
|
||||||
|
39
src/api/mock/index.ts
Normal file
39
src/api/mock/index.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
// src/api/mock/index.ts
|
||||||
|
import { Random } from 'mockjs';
|
||||||
|
|
||||||
|
interface StatisticsData {
|
||||||
|
todayVisits: number;
|
||||||
|
newUsers: number;
|
||||||
|
currentMonthSales: number;
|
||||||
|
currentMonthOrders: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface YearlySalesData {
|
||||||
|
monthlySales: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 模拟统计数据接口
|
||||||
|
export const getStatisticsData = async (): Promise<StatisticsData> => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// 模拟 API 延迟
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
todayVisits: Random.integer(500, 1500),
|
||||||
|
newUsers: Random.integer(20, 100),
|
||||||
|
currentMonthSales: Random.integer(3000, 15000),
|
||||||
|
currentMonthOrders: Random.integer(100, 500),
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 模拟年度销售数据接口
|
||||||
|
export const getYearlySalesData = async (): Promise<YearlySalesData> => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
// 模拟 API 延迟
|
||||||
|
setTimeout(() => {
|
||||||
|
const monthlySales = Array.from({ length: 12 }, () => Random.integer(5000, 20000));
|
||||||
|
resolve({ monthlySales });
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
};
|
@ -13,6 +13,7 @@ export default {
|
|||||||
article: 'article',
|
article: 'article',
|
||||||
message: 'message',
|
message: 'message',
|
||||||
order: 'order',
|
order: 'order',
|
||||||
|
statistics: 'statistics',
|
||||||
articleDetail: 'articleDetail',
|
articleDetail: 'articleDetail',
|
||||||
addArticle: 'addArticle',
|
addArticle: 'addArticle',
|
||||||
editArticle: 'editArticle',
|
editArticle: 'editArticle',
|
||||||
|
@ -13,6 +13,7 @@ export default {
|
|||||||
article: '文章管理',
|
article: '文章管理',
|
||||||
message: '留言管理',
|
message: '留言管理',
|
||||||
order: '订单管理',
|
order: '订单管理',
|
||||||
|
statistics: '统计分析',
|
||||||
articleDetail: '文章详情',
|
articleDetail: '文章详情',
|
||||||
addArticle: '新增文章',
|
addArticle: '新增文章',
|
||||||
editArticle: '编辑文章',
|
editArticle: '编辑文章',
|
||||||
|
@ -13,6 +13,7 @@ export default {
|
|||||||
article: '文章管理',
|
article: '文章管理',
|
||||||
message: '聯言管理',
|
message: '聯言管理',
|
||||||
order: '訂單管理',
|
order: '訂單管理',
|
||||||
|
statistics: '統計分析',
|
||||||
articleDetail: '文章詳情',
|
articleDetail: '文章詳情',
|
||||||
addArticle: '文章新增',
|
addArticle: '文章新增',
|
||||||
editArticle: '文章編輯',
|
editArticle: '文章編輯',
|
||||||
|
@ -295,6 +295,21 @@ export const dynamicRoutes: Array<RouteRecordRaw> = [
|
|||||||
icon: 'iconfont icon-shuju',
|
icon: 'iconfont icon-shuju',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/statistics',
|
||||||
|
name: 'statistics',
|
||||||
|
component: () => import('/@/views/statistics/index.vue'),
|
||||||
|
meta: {
|
||||||
|
title: 'message.router.statistics',
|
||||||
|
isLink: '',
|
||||||
|
isHide: false,
|
||||||
|
isKeepAlive: true,
|
||||||
|
isAffix: false,
|
||||||
|
isIframe: false,
|
||||||
|
roles: ['admin', 'common'],
|
||||||
|
icon: 'iconfont icon-ico_shuju',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/video',
|
path: '/video',
|
||||||
name: 'video',
|
name: 'video',
|
||||||
|
1
src/types/chartjs.d.ts
vendored
Normal file
1
src/types/chartjs.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
declare module 'chart.js';
|
118
src/views/statistics/index.vue
Normal file
118
src/views/statistics/index.vue
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
<template>
|
||||||
|
<div class="statistics">
|
||||||
|
<h1>统计分析</h1>
|
||||||
|
<div class="cards">
|
||||||
|
<div class="card" v-for="(item, index) in statistics" :key="index">
|
||||||
|
<h2>{{ item.title }}</h2>
|
||||||
|
<p class="val">{{ item.value }}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chart">
|
||||||
|
<h2>全年销售额分析图</h2>
|
||||||
|
<canvas ref="salesChart"></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import { ref, onMounted } from 'vue';
|
||||||
|
import { Chart, registerables } from 'chart.js';
|
||||||
|
import { getStatisticsData, getYearlySalesData } from '/@/api/mock';
|
||||||
|
|
||||||
|
// 定义统计项的类型
|
||||||
|
interface Statistic {
|
||||||
|
title: string;
|
||||||
|
value: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
Chart.register(...registerables);
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'Statistics',
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
const statistics = ref<Statistic[]>([]);
|
||||||
|
const salesChart = ref<HTMLCanvasElement | null>(null);
|
||||||
|
|
||||||
|
const fetchStatistics = async () => {
|
||||||
|
const data = await getStatisticsData();
|
||||||
|
statistics.value = [
|
||||||
|
{ title: '今日访问量', value: '+' + data.todayVisits },
|
||||||
|
{ title: '新增用户', value: '+' + data.newUsers },
|
||||||
|
{ title: '当月销售额', value: data.currentMonthSales },
|
||||||
|
{ title: '当月订单量', value: data.currentMonthOrders },
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchYearlySales = async () => {
|
||||||
|
if (salesChart.value) {
|
||||||
|
const ctx = salesChart.value.getContext('2d');
|
||||||
|
const data = await getYearlySalesData();
|
||||||
|
|
||||||
|
new Chart(ctx!, {
|
||||||
|
type: 'line',
|
||||||
|
data: {
|
||||||
|
labels: [
|
||||||
|
'一月', '二月', '三月', '四月', '五月', '六月',
|
||||||
|
'七月', '八月', '九月', '十月', '十一月', '十二月'
|
||||||
|
],
|
||||||
|
datasets: [{
|
||||||
|
label: '全年销售额',
|
||||||
|
data: data.monthlySales,
|
||||||
|
borderColor: 'rgba(75, 192, 192, 1)',
|
||||||
|
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||||
|
borderWidth: 1,
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
responsive: true,
|
||||||
|
scales: {
|
||||||
|
y: {
|
||||||
|
beginAtZero: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await fetchStatistics();
|
||||||
|
await fetchYearlySales();
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
statistics,
|
||||||
|
salesChart
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.val {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statistics {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cards {
|
||||||
|
display: flex;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
flex: 1;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 5px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user