|
|
@@ -1,39 +1,79 @@
|
|
|
<script setup lang="ts">
|
|
|
-import chroma from 'chroma-js'
|
|
|
-import { Chart } from '@antv/g2';
|
|
|
-import { NNumberAnimation } from 'naive-ui'
|
|
|
+import { Chart, type G2Spec, type Mark, type Composition, type TooltipTitle } from '@antv/g2';
|
|
|
import { onMounted, watch, ref, computed, onUnmounted } from 'vue'
|
|
|
|
|
|
+import InfoCard, { type InfoCardData } from './component/infoCard.vue'
|
|
|
+
|
|
|
import { usePersonalization } from '@/composable/usePersonalization'
|
|
|
import thc from '@/utils/themeColor'
|
|
|
|
|
|
+import type { ShutdownStatisticsInfo } from '@/service/dashboard/interface'
|
|
|
+import { it } from 'node:test';
|
|
|
+
|
|
|
defineOptions({
|
|
|
name: 'Dashboard',
|
|
|
})
|
|
|
|
|
|
const { isDark, color } = usePersonalization()
|
|
|
|
|
|
-const cardList = ref(generateCardData())
|
|
|
+// const cardList = ref(generateCardData())
|
|
|
+const cardList = computed<InfoCardData>(() => {
|
|
|
+ const date = new Date(shutdownStatisticsInfo.value.date);
|
|
|
+ // const year = date.getFullYear();
|
|
|
+ const month = date.getMonth() + 1; // getMonth() 返回 0-11,需要 +1
|
|
|
+ // const day = date.getDate();
|
|
|
|
|
|
-const revenueChart = ref<HTMLDivElement | null>(null)
|
|
|
-let revenueChartInstance: Chart | null = null
|
|
|
-let revenueChartResizeHandler: (() => void) | null = null
|
|
|
+ const dayTotal = shutdownStatisticsInfo.value.dayTotal
|
|
|
+ const usTotal = shutdownStatisticsInfo.value.usTotal
|
|
|
+ const auTotal = shutdownStatisticsInfo.value.auTotal
|
|
|
|
|
|
-const revenueBarChart = ref<HTMLDivElement | null>(null)
|
|
|
-let revenueBarChartInstance: Chart | null = null
|
|
|
-let revenueBarChartResizeHandler: (() => void) | null = null
|
|
|
+ return [
|
|
|
+ {
|
|
|
+ title: 'Shutdown总数',
|
|
|
+ value: dayTotal.count,
|
|
|
+ growth: dayTotal.growth,
|
|
|
+ iconClass: 'i-ph:smiley-x-eyes-bold',
|
|
|
+ backgroundColor: 'indigo',
|
|
|
+ precision: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '北美地区总数',
|
|
|
+ value: usTotal.count,
|
|
|
+ growth: usTotal.growth,
|
|
|
+ iconClass: 'i-circle-flags:us',
|
|
|
+ backgroundColor: 'indigo',
|
|
|
+ precision: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: '澳洲地区总数',
|
|
|
+ value: auTotal.count,
|
|
|
+ growth: auTotal.growth,
|
|
|
+ iconClass: 'i-circle-flags:au',
|
|
|
+ backgroundColor: 'indigo',
|
|
|
+ precision: 0
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: `${month}月总数`,
|
|
|
+ value: dayTotal.monthCount,
|
|
|
+ growth: dayTotal.monthGrowth,
|
|
|
+ iconClass: 'i-ph:calendar-dots-bold',
|
|
|
+ backgroundColor: 'indigo',
|
|
|
+ precision: 0
|
|
|
+ },
|
|
|
+ ]
|
|
|
+})
|
|
|
|
|
|
-const revenueBarChart2 = ref<HTMLDivElement | null>(null)
|
|
|
-let revenueBarChart2Instance: Chart | null = null
|
|
|
-let revenueBarChart2ResizeHandler: (() => void) | null = null
|
|
|
+const shutdownWeeklyChart = ref<HTMLDivElement | null>(null)
|
|
|
+let shutdownWeeklyChartInstance: Chart | null = null
|
|
|
+let shutdownWeeklyChartResizeHandler: (() => void) | null = null
|
|
|
|
|
|
-const monthlyRadarChart = ref<HTMLDivElement | null>(null)
|
|
|
-let monthlyRadarChartInstance: Chart | null = null
|
|
|
-let monthlyRadarChartResizeHandler: (() => void) | null = null
|
|
|
+const shutdownYearChart = ref<HTMLDivElement | null>(null)
|
|
|
+let shutdownYearChartInstance: Chart | null = null
|
|
|
+let shutdownYearChartResizeHandler: (() => void) | null = null
|
|
|
|
|
|
-const highestRevenueChart = ref<HTMLDivElement | null>(null)
|
|
|
-let highestRevenueChartInstance: Chart | null = null
|
|
|
-let highestRevenueChartResizeHandler: (() => void) | null = null
|
|
|
+// const shutdownYearChart2 = ref<HTMLDivElement | null>(null)
|
|
|
+// let shutdownYearChart2Instance: Chart | null = null
|
|
|
+// let shutdownYearChart2ResizeHandler: (() => void) | null = null
|
|
|
|
|
|
const CHART_CONFIG = {
|
|
|
MONTHS: Array.from({ length: 12 }, (_, i) => `${i + 1}月`),
|
|
|
@@ -69,61 +109,6 @@ const getBusinessLinesConfig = () => [
|
|
|
|
|
|
const barChartSelectedLegend = ref(getBusinessLinesConfig()[0].name)
|
|
|
|
|
|
-function generateCardData() {
|
|
|
- const now = new Date()
|
|
|
- const currentMonth = now.getMonth() + 1
|
|
|
-
|
|
|
- const baseUserCount = 10000 + Math.floor(Math.random() * 5000)
|
|
|
- const todayVisits = Math.floor(
|
|
|
- 5000 + Math.random() * 8000 + Math.sin((now.getHours() / 24) * Math.PI) * 2000,
|
|
|
- )
|
|
|
- const monthlySales = Math.floor(1500000 + Math.random() * 1000000 + (currentMonth / 12) * 500000)
|
|
|
- const pendingOrders = Math.floor(150 + Math.random() * 200)
|
|
|
-
|
|
|
- return [
|
|
|
- {
|
|
|
- title: '用户总数',
|
|
|
- value: baseUserCount,
|
|
|
- percentage: parseFloat((3.2 + Math.random() * 4).toFixed(2)),
|
|
|
- iconClass: 'i-ph:users-bold text-indigo-50 dark:text-indigo-150',
|
|
|
- iconBgClass:
|
|
|
- 'text-indigo-500/5 bg-indigo-400 ring-4 ring-indigo-200 duration-300 dark:bg-indigo-650 dark:ring-indigo-500/30',
|
|
|
- precision: 0,
|
|
|
- description: `${currentMonth}月新增 ${Math.floor(100 + Math.random() * 200)} 人`,
|
|
|
- },
|
|
|
- {
|
|
|
- title: '今日访问',
|
|
|
- value: todayVisits,
|
|
|
- percentage: parseFloat((-2 + Math.random() * 20).toFixed(2)),
|
|
|
- iconClass: 'i-ph:eye-bold text-blue-50 dark:text-blue-150',
|
|
|
- iconBgClass:
|
|
|
- 'text-blue-500/5 bg-blue-400 ring-4 ring-blue-200 duration-300 dark:bg-blue-650 dark:ring-blue-500/30',
|
|
|
- precision: 0,
|
|
|
- description: '较昨日变化',
|
|
|
- },
|
|
|
- {
|
|
|
- title: `${currentMonth}月销售额`,
|
|
|
- value: monthlySales,
|
|
|
- percentage: parseFloat((5 + Math.random() * 10).toFixed(2)),
|
|
|
- iconClass: 'i-ph:currency-dollar-bold text-emerald-50 dark:text-emerald-150',
|
|
|
- iconBgClass:
|
|
|
- 'text-emerald-500/5 bg-emerald-400 ring-4 ring-emerald-200 duration-300 dark:bg-emerald-650 dark:ring-emerald-500/30',
|
|
|
- precision: 2,
|
|
|
- description: '本月累计收入',
|
|
|
- },
|
|
|
- {
|
|
|
- title: '待处理订单',
|
|
|
- value: pendingOrders,
|
|
|
- percentage: parseFloat((-8 + Math.random() * 6).toFixed(2)),
|
|
|
- iconClass: 'i-ph:shopping-cart-bold text-orange-50 dark:text-orange-150',
|
|
|
- iconBgClass:
|
|
|
- 'text-orange-500/5 bg-orange-400 ring-4 ring-orange-200 duration-300 dark:bg-orange-650 dark:ring-orange-500/30',
|
|
|
- precision: 0,
|
|
|
- description: '需要及时处理',
|
|
|
- },
|
|
|
- ]
|
|
|
-}
|
|
|
-
|
|
|
const generateRandomData = (
|
|
|
baseMin: number,
|
|
|
baseMax: number,
|
|
|
@@ -215,242 +200,335 @@ const chartDataManager = {
|
|
|
},
|
|
|
}
|
|
|
|
|
|
-function initRevenueChart() {
|
|
|
- if (!revenueChart.value) return
|
|
|
-
|
|
|
- // 初始化图表实例
|
|
|
- const chart = new Chart({
|
|
|
- container: revenueChart.value,
|
|
|
- });
|
|
|
-
|
|
|
- // 设置数据
|
|
|
- const data = businessLinesWithData.value.map((line, idx) => ({
|
|
|
- name: line.name,
|
|
|
- data: line.data,
|
|
|
- color: line.color,
|
|
|
- }));
|
|
|
-
|
|
|
- chart.data(data)
|
|
|
-
|
|
|
- revenueChartInstance = chart
|
|
|
- // revenueChartResizeHandler = () => chart.resize()
|
|
|
- // window.addEventListener('resize', revenueChartResizeHandler, { passive: true })
|
|
|
+interface ShutdownWeeklyChartData {
|
|
|
+ type: '总数' | '北美' | '澳洲'
|
|
|
+ date: string
|
|
|
+ value: number
|
|
|
}
|
|
|
|
|
|
-function initRevenueBarChart() {
|
|
|
- if (!revenueBarChart.value) return
|
|
|
+function initShutdownWeeklyChart() {
|
|
|
+ if (!shutdownWeeklyChart.value) return
|
|
|
|
|
|
// 初始化图表实例
|
|
|
const chart = new Chart({
|
|
|
- container: revenueBarChart.value,
|
|
|
+ container: shutdownWeeklyChart.value,
|
|
|
+ height: 340,
|
|
|
});
|
|
|
|
|
|
- revenueBarChartInstance = chart
|
|
|
- // revenueBarChartResizeHandler = () => chart.resize()
|
|
|
- // window.addEventListener('resize', revenueBarChartResizeHandler, { passive: true })
|
|
|
+ const data = shutdownStatisticsInfo.value
|
|
|
+
|
|
|
+ // 生成日期与数值对应数据
|
|
|
+ const weeklyDateList = Array.from<void, string>({ length: 7 }, (_, i) => {
|
|
|
+ const baseDate = new Date(data.date)
|
|
|
+ const date = new Date(data.date)
|
|
|
+ date.setDate(baseDate.getDate() - (6 - i)) // 倒推 6 天
|
|
|
+ const dateStr = date.toISOString().slice(0, 10)
|
|
|
+ return dateStr
|
|
|
+ })
|
|
|
+
|
|
|
+ chart.options({
|
|
|
+ type: 'view',
|
|
|
+ autoFit: true,
|
|
|
+ title: {
|
|
|
+ title: "Shutdown周曲线",
|
|
|
+ align: 'center'
|
|
|
+ },
|
|
|
+ data: {
|
|
|
+ type: 'inline',
|
|
|
+ value: data,
|
|
|
+ transform: [{
|
|
|
+ type: 'custom',
|
|
|
+ callback: (data: ShutdownStatisticsInfo): ShutdownWeeklyChartData[] => {
|
|
|
+ let chartData: ShutdownWeeklyChartData[] = []
|
|
|
+ data.dayTotal.weekly.map((item, idx) => {
|
|
|
+ chartData.push({
|
|
|
+ type: '总数', // 日总数据
|
|
|
+ date: weeklyDateList[idx] ?? "",
|
|
|
+ value: item
|
|
|
+ })
|
|
|
+ })
|
|
|
+ data.usTotal.weekly.map((item, idx) => {
|
|
|
+ chartData.push({
|
|
|
+ type: '北美', // 北美总数据
|
|
|
+ date: weeklyDateList[idx] ?? "",
|
|
|
+ value: item
|
|
|
+ })
|
|
|
+ })
|
|
|
+ data.auTotal.weekly.map((item, idx) => {
|
|
|
+ chartData.push({
|
|
|
+ type: '澳洲', // 澳洲总数据
|
|
|
+ date: weeklyDateList[idx] ?? "",
|
|
|
+ value: item
|
|
|
+ })
|
|
|
+ })
|
|
|
+ return chartData
|
|
|
+ }
|
|
|
+ }]
|
|
|
+ },
|
|
|
+ encode: {
|
|
|
+ x: 'date',
|
|
|
+ y: 'value',
|
|
|
+ color: 'type',
|
|
|
+ shape: 'smooth' // 圆滑曲线
|
|
|
+ },
|
|
|
+ axis: {
|
|
|
+ x: false,
|
|
|
+ y: {
|
|
|
+ title: false
|
|
|
+ }
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ color: {
|
|
|
+ itemMarker: 'rect'
|
|
|
+ }
|
|
|
+ },
|
|
|
+ children: [
|
|
|
+ {
|
|
|
+ type: 'area',
|
|
|
+ style: { fill: 'l(270) 0:#ffffff 0.9:#7ec2f3 1:#1890ff', fillOpacity: 0.3 },
|
|
|
+ animate: { enter: { type: 'fadeIn' as const, duration: 1000 } }
|
|
|
+ },
|
|
|
+ {
|
|
|
+ type: 'line',
|
|
|
+ style: { strokeWidth: 2 },
|
|
|
+ animate: { enter: { type: 'pathIn' as const, duration: 1500, delay: 100, easing: 'out-cubic' as const } },
|
|
|
+ tooltip: false
|
|
|
+ }
|
|
|
+ ]
|
|
|
+ })
|
|
|
+
|
|
|
+ chart.render()
|
|
|
+
|
|
|
+ shutdownWeeklyChartInstance = chart
|
|
|
+ shutdownWeeklyChartResizeHandler = () => chart.resize()
|
|
|
+ window.addEventListener('resize', shutdownWeeklyChartResizeHandler, { passive: true })
|
|
|
}
|
|
|
|
|
|
-function initRevenueBarChart2() {
|
|
|
- if (!revenueBarChart2.value) return
|
|
|
-
|
|
|
- // 初始化图表实例
|
|
|
- const chart = new Chart({
|
|
|
- container: revenueBarChart2.value,
|
|
|
- });
|
|
|
-
|
|
|
- revenueBarChart2Instance = chart
|
|
|
- // revenueBarChart2ResizeHandler = () => chart.resize()
|
|
|
- // window.addEventListener('resize', revenueBarChart2ResizeHandler, { passive: true })
|
|
|
+interface ShutdownYearChartData {
|
|
|
+ type: '总数' | '北美' | '澳洲'
|
|
|
+ month: string
|
|
|
+ value: number
|
|
|
}
|
|
|
|
|
|
-function initMonthlyRadarChart() {
|
|
|
- if (!monthlyRadarChart.value) return
|
|
|
-
|
|
|
- const now = new Date()
|
|
|
- const currentMonth = now.getMonth()
|
|
|
+// 记录当前选择的Legend
|
|
|
+let currentLegend = '总数'
|
|
|
|
|
|
- const currentMonthData = chartDataManager.getCurrentMonthData(currentMonth)
|
|
|
+function initShutdownYearChart() {
|
|
|
+ if (!shutdownYearChart.value) return
|
|
|
|
|
|
// 初始化图表实例
|
|
|
const chart = new Chart({
|
|
|
- container: monthlyRadarChart.value,
|
|
|
+ container: shutdownYearChart.value
|
|
|
});
|
|
|
|
|
|
- monthlyRadarChartInstance = chart
|
|
|
- // monthlyRadarChartResizeHandler = () => chart.resize()
|
|
|
- // window.addEventListener('resize', monthlyRadarChartResizeHandler, { passive: true })
|
|
|
-}
|
|
|
-
|
|
|
-function initHighestRevenueChart() {
|
|
|
- if (!highestRevenueChart.value) return
|
|
|
-
|
|
|
- const highestLine = chartDataManager.getHighestRevenueLine()
|
|
|
- const lowestLine = chartDataManager.getLowestRevenueLine()
|
|
|
-
|
|
|
- const chartData = [
|
|
|
- {
|
|
|
- legendName: '最高',
|
|
|
- legendValue: 'max',
|
|
|
- businessName: highestLine.name,
|
|
|
- color: highestLine.color,
|
|
|
- data: highestLine.data,
|
|
|
+ const data = shutdownStatisticsInfo.value
|
|
|
+
|
|
|
+ chart.options({
|
|
|
+ type: 'interval',
|
|
|
+ autoFit: true,
|
|
|
+ data: {
|
|
|
+ type: 'inline',
|
|
|
+ value: data,
|
|
|
+ transform: [{
|
|
|
+ type: 'custom',
|
|
|
+ callback: (data: ShutdownStatisticsInfo): ShutdownYearChartData[] => {
|
|
|
+ let chartData: ShutdownYearChartData[] = []
|
|
|
+ data.dayTotal.year.map((item, idx) => {
|
|
|
+ if (idx >= 12) return
|
|
|
+ chartData.push({
|
|
|
+ type: '总数', // 月总数据
|
|
|
+ month: `${idx + 1}月`,
|
|
|
+ value: item
|
|
|
+ })
|
|
|
+ })
|
|
|
+ data.usTotal.year.map((item, idx) => {
|
|
|
+ if (idx >= 12) return
|
|
|
+ chartData.push({
|
|
|
+ type: '北美', // 北美总数据
|
|
|
+ month: `${idx + 1}月`,
|
|
|
+ value: item
|
|
|
+ })
|
|
|
+ })
|
|
|
+ data.auTotal.year.map((item, idx) => {
|
|
|
+ if (idx >= 12) return
|
|
|
+ chartData.push({
|
|
|
+ type: '澳洲', // 澳洲总数据
|
|
|
+ month: `${idx + 1}月`,
|
|
|
+ value: item
|
|
|
+ })
|
|
|
+ })
|
|
|
+ console.log({ chartData })
|
|
|
+ return chartData
|
|
|
+ }
|
|
|
+ }]
|
|
|
},
|
|
|
- {
|
|
|
- legendName: '最低',
|
|
|
- legendValue: 'min',
|
|
|
- businessName: lowestLine.name,
|
|
|
- color: lowestLine.color,
|
|
|
- data: lowestLine.data,
|
|
|
+ encode: {
|
|
|
+ x: 'month',
|
|
|
+ y: 'value',
|
|
|
+ color: 'type',
|
|
|
},
|
|
|
- ]
|
|
|
-
|
|
|
- // 初始化图表实例
|
|
|
- const chart = new Chart({
|
|
|
- container: highestRevenueChart.value,
|
|
|
- });
|
|
|
+ axis: {
|
|
|
+ x: { title: false },
|
|
|
+ y: { title: false }
|
|
|
+ },
|
|
|
+ legend: {
|
|
|
+ color: {
|
|
|
+ itemMarker: 'rect',
|
|
|
+ defaultSelect: [currentLegend]
|
|
|
+ }
|
|
|
+ },
|
|
|
+ tooltip: {
|
|
|
+ title: (d: ShutdownYearChartData): TooltipTitle => `${d.type} - ${d.month}`
|
|
|
+ }
|
|
|
+ })
|
|
|
|
|
|
- const legendSelected: Record<string, boolean> = { max: true, min: false }
|
|
|
+ chart.render()
|
|
|
|
|
|
- highestRevenueChartInstance = chart
|
|
|
- // highestRevenueChartResizeHandler = () => chart.resize()
|
|
|
- // window.addEventListener('resize', highestRevenueChartResizeHandler, { passive: true })
|
|
|
-}
|
|
|
+ const setLegend = (legends: string[]) => {
|
|
|
+ chart.emit('legend:filter', {
|
|
|
+ data: { channel: 'color', values: legends },
|
|
|
+ });
|
|
|
+ }
|
|
|
|
|
|
-onMounted(() => {
|
|
|
- initRevenueChart()
|
|
|
- initRevenueBarChart()
|
|
|
- initRevenueBarChart2()
|
|
|
- initMonthlyRadarChart()
|
|
|
- initHighestRevenueChart()
|
|
|
-})
|
|
|
|
|
|
-onUnmounted(() => {
|
|
|
- if (revenueChartInstance) {
|
|
|
- if (revenueChartResizeHandler) {
|
|
|
- window.removeEventListener('resize', revenueChartResizeHandler)
|
|
|
- revenueChartResizeHandler = null
|
|
|
+ // 监听图例点击事件 - 当用户通过图例进行筛选时触发
|
|
|
+ chart.on('legend:filter', (e) => {
|
|
|
+ const { nativeEvent, data } = e;
|
|
|
+ if (!nativeEvent) return;
|
|
|
+ const selectLegends = data.values as string[]
|
|
|
+ if (selectLegends.length === 0) {
|
|
|
+ setLegend([currentLegend])
|
|
|
+ } else if (selectLegends.length > 1) {
|
|
|
+ const legends = (data.values as string[]).filter(item => item !== currentLegend)
|
|
|
+ currentLegend = legends[0]
|
|
|
+ setLegend(legends)
|
|
|
}
|
|
|
- revenueChartInstance.destroy()
|
|
|
- revenueChartInstance = null
|
|
|
- }
|
|
|
+ });
|
|
|
|
|
|
- if (revenueBarChartInstance) {
|
|
|
- if (revenueBarChartResizeHandler) {
|
|
|
- window.removeEventListener('resize', revenueBarChartResizeHandler)
|
|
|
- revenueBarChartResizeHandler = null
|
|
|
- }
|
|
|
- revenueBarChartInstance.destroy()
|
|
|
- revenueBarChartInstance = null
|
|
|
- }
|
|
|
+ shutdownYearChartInstance = chart
|
|
|
+ shutdownYearChartResizeHandler = () => chart.resize()
|
|
|
+ window.addEventListener('resize', shutdownYearChartResizeHandler, { passive: true })
|
|
|
+}
|
|
|
|
|
|
- if (revenueBarChart2Instance) {
|
|
|
- if (revenueBarChart2ResizeHandler) {
|
|
|
- window.removeEventListener('resize', revenueBarChart2ResizeHandler)
|
|
|
- revenueBarChart2ResizeHandler = null
|
|
|
- }
|
|
|
- revenueBarChart2Instance.destroy()
|
|
|
- revenueBarChart2Instance = null
|
|
|
+// function initShutdownYearChart2() {
|
|
|
+// if (!shutdownYearChart2.value) return
|
|
|
+
|
|
|
+// // 初始化图表实例
|
|
|
+// const chart = new Chart({
|
|
|
+// container: shutdownYearChart2.value,
|
|
|
+// });
|
|
|
+
|
|
|
+// shutdownYearChart2Instance = chart
|
|
|
+// shutdownYearChart2ResizeHandler = () => chart.resize()
|
|
|
+// window.addEventListener('resize', shutdownYearChart2ResizeHandler, { passive: true })
|
|
|
+// }
|
|
|
+
|
|
|
+// 模拟数据
|
|
|
+const shutdownStatisticsInfo = ref<ShutdownStatisticsInfo>({
|
|
|
+ date: "2025-10-16",
|
|
|
+ dayTotal: {
|
|
|
+ count: 687,
|
|
|
+ growth: 14,
|
|
|
+ weekly: [0, 0, 456, 234, 103, 43, 100],
|
|
|
+
|
|
|
+ monthCount: 6800,
|
|
|
+ monthGrowth: 340,
|
|
|
+ year: [0, 0, 0, 0, 0, 0, 0, 5867, 3245, 6780, 3400, 5800],
|
|
|
+ },
|
|
|
+ usTotal: {
|
|
|
+ count: 580,
|
|
|
+ growth: 32,
|
|
|
+ weekly: [0, 0, 234, 123, 98, 23, 55],
|
|
|
+
|
|
|
+ monthCount: 6800,
|
|
|
+ monthGrowth: 340,
|
|
|
+ year: [0, 0, 0, 0, 0, 0, 0, 5867, 3245, 6780, 3400, 5800],
|
|
|
+ },
|
|
|
+ auTotal: {
|
|
|
+ count: 120,
|
|
|
+ growth: 9,
|
|
|
+ weekly: [0, 0, 44, 21, 5, 12, 36],
|
|
|
+
|
|
|
+ monthCount: 6800,
|
|
|
+ monthGrowth: 340,
|
|
|
+ year: [0, 0, 0, 0, 0, 0, 0, 5867, 3245, 6780, 3400, 5800],
|
|
|
}
|
|
|
+})
|
|
|
|
|
|
- if (monthlyRadarChartInstance) {
|
|
|
- if (monthlyRadarChartResizeHandler) {
|
|
|
- window.removeEventListener('resize', monthlyRadarChartResizeHandler)
|
|
|
- monthlyRadarChartResizeHandler = null
|
|
|
- }
|
|
|
- monthlyRadarChartInstance.destroy()
|
|
|
- monthlyRadarChartInstance = null
|
|
|
- }
|
|
|
+onMounted(() => {
|
|
|
+ // TODO 请求数据
|
|
|
|
|
|
- if (highestRevenueChartInstance) {
|
|
|
- if (highestRevenueChartResizeHandler) {
|
|
|
- window.removeEventListener('resize', highestRevenueChartResizeHandler)
|
|
|
- highestRevenueChartResizeHandler = null
|
|
|
- }
|
|
|
- highestRevenueChartInstance.destroy()
|
|
|
- highestRevenueChartInstance = null
|
|
|
- }
|
|
|
+ initShutdownWeeklyChart()
|
|
|
+ initShutdownYearChart()
|
|
|
+ // initShutdownYearChart2()
|
|
|
})
|
|
|
|
|
|
-watch([isDark, color], () => {
|
|
|
- if (revenueChartInstance) {
|
|
|
- if (revenueChartResizeHandler) {
|
|
|
- window.removeEventListener('resize', revenueChartResizeHandler)
|
|
|
- revenueChartResizeHandler = null
|
|
|
+onUnmounted(() => {
|
|
|
+ if (shutdownWeeklyChartInstance) {
|
|
|
+ if (shutdownWeeklyChartResizeHandler) {
|
|
|
+ window.removeEventListener('resize', shutdownWeeklyChartResizeHandler)
|
|
|
+ shutdownWeeklyChartResizeHandler = null
|
|
|
}
|
|
|
- revenueChartInstance.destroy()
|
|
|
- revenueChartInstance = null
|
|
|
+ shutdownWeeklyChartInstance.destroy()
|
|
|
+ shutdownWeeklyChartInstance = null
|
|
|
}
|
|
|
|
|
|
- if (revenueBarChartInstance) {
|
|
|
- if (revenueBarChartResizeHandler) {
|
|
|
- window.removeEventListener('resize', revenueBarChartResizeHandler)
|
|
|
- revenueBarChartResizeHandler = null
|
|
|
+ if (shutdownYearChartInstance) {
|
|
|
+ if (shutdownYearChartResizeHandler) {
|
|
|
+ window.removeEventListener('resize', shutdownYearChartResizeHandler)
|
|
|
+ shutdownYearChartResizeHandler = null
|
|
|
}
|
|
|
- revenueBarChartInstance.destroy()
|
|
|
- revenueBarChartInstance = null
|
|
|
+ shutdownYearChartInstance.destroy()
|
|
|
+ shutdownYearChartInstance = null
|
|
|
}
|
|
|
|
|
|
- if (revenueBarChart2Instance) {
|
|
|
- if (revenueBarChart2ResizeHandler) {
|
|
|
- window.removeEventListener('resize', revenueBarChart2ResizeHandler)
|
|
|
- revenueBarChart2ResizeHandler = null
|
|
|
- }
|
|
|
- revenueBarChart2Instance.destroy()
|
|
|
- revenueBarChart2Instance = null
|
|
|
- }
|
|
|
+ // if (shutdownYearChart2Instance) {
|
|
|
+ // if (shutdownYearChart2ResizeHandler) {
|
|
|
+ // window.removeEventListener('resize', shutdownYearChart2ResizeHandler)
|
|
|
+ // shutdownYearChart2ResizeHandler = null
|
|
|
+ // }
|
|
|
+ // shutdownYearChart2Instance.destroy()
|
|
|
+ // shutdownYearChart2Instance = null
|
|
|
+ // }
|
|
|
+})
|
|
|
|
|
|
- if (monthlyRadarChartInstance) {
|
|
|
- if (monthlyRadarChartResizeHandler) {
|
|
|
- window.removeEventListener('resize', monthlyRadarChartResizeHandler)
|
|
|
- monthlyRadarChartResizeHandler = null
|
|
|
+watch([isDark, color], () => {
|
|
|
+ if (shutdownWeeklyChartInstance) {
|
|
|
+ if (shutdownWeeklyChartResizeHandler) {
|
|
|
+ window.removeEventListener('resize', shutdownWeeklyChartResizeHandler)
|
|
|
+ shutdownWeeklyChartResizeHandler = null
|
|
|
}
|
|
|
- monthlyRadarChartInstance.destroy()
|
|
|
- monthlyRadarChartInstance = null
|
|
|
+ shutdownWeeklyChartInstance.destroy()
|
|
|
+ shutdownWeeklyChartInstance = null
|
|
|
}
|
|
|
|
|
|
- if (highestRevenueChartInstance) {
|
|
|
- if (highestRevenueChartResizeHandler) {
|
|
|
- window.removeEventListener('resize', highestRevenueChartResizeHandler)
|
|
|
- highestRevenueChartResizeHandler = null
|
|
|
+ if (shutdownYearChartInstance) {
|
|
|
+ if (shutdownYearChartResizeHandler) {
|
|
|
+ window.removeEventListener('resize', shutdownYearChartResizeHandler)
|
|
|
+ shutdownYearChartResizeHandler = null
|
|
|
}
|
|
|
- highestRevenueChartInstance.destroy()
|
|
|
- highestRevenueChartInstance = null
|
|
|
+ shutdownYearChartInstance.destroy()
|
|
|
+ shutdownYearChartInstance = null
|
|
|
}
|
|
|
|
|
|
- initRevenueChart()
|
|
|
- initRevenueBarChart()
|
|
|
- initRevenueBarChart2()
|
|
|
- initMonthlyRadarChart()
|
|
|
- initHighestRevenueChart()
|
|
|
+ // if (shutdownYearChart2Instance) {
|
|
|
+ // if (shutdownYearChart2ResizeHandler) {
|
|
|
+ // window.removeEventListener('resize', shutdownYearChart2ResizeHandler)
|
|
|
+ // shutdownYearChart2ResizeHandler = null
|
|
|
+ // }
|
|
|
+ // shutdownYearChart2Instance.destroy()
|
|
|
+ // shutdownYearChart2Instance = null
|
|
|
+ // }
|
|
|
+
|
|
|
+ initShutdownWeeklyChart()
|
|
|
+ initShutdownYearChart()
|
|
|
+ // initShutdownYearChart2()
|
|
|
})
|
|
|
</script>
|
|
|
<template>
|
|
|
<div class="space-y-4 p-4">
|
|
|
- <!-- <div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
|
- <div v-for="item in cardList" :key="item.title"
|
|
|
- class="flex items-center justify-between gap-x-4 overflow-hidden rounded bg-[var(--card-color)] p-6 shadow-xs duration-300 transition-ease-in-out">
|
|
|
- <div class="flex-1">
|
|
|
- <span class="text-sm font-medium text-neutral-450">{{ item.title }}</span>
|
|
|
- <div class="mt-1 mb-1.5 flex gap-x-4 text-2xl text-neutral-700 dark:text-neutral-400">
|
|
|
- <NNumberAnimation :to="item.value" show-separator :precision="item.precision" />
|
|
|
- </div>
|
|
|
- <div class="flex items-center">
|
|
|
- <div class="flex items-center gap-x-0.5 rounded-xs px-1.5 py-0.5 text-xs duration-300" :class="item.percentage > 0
|
|
|
- ? 'bg-green-100 text-green-600 dark:bg-green-500/20 dark:text-green-400'
|
|
|
- : 'bg-rose-100 text-rose-600 dark:bg-rose-500/20 dark:text-rose-400'
|
|
|
- ">
|
|
|
- <span :class="item.percentage > 0 ? 'i-ph:arrow-up' : 'i-ph:arrow-down'"></span>
|
|
|
- <span class="font-medium">{{ Math.abs(item.percentage) }}%</span>
|
|
|
- </div>
|
|
|
- <span class="ml-2 text-neutral-500 dark:text-neutral-400">{{ item.description }}</span>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div>
|
|
|
- <div class="grid place-items-center rounded-full p-3" :class="item.iconBgClass">
|
|
|
- <span class="size-7" :class="item.iconClass" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div>
|
|
|
+ <div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
|
+ <InfoCard v-for="item in cardList" :key="item.title" :data="item" />
|
|
|
</div>
|
|
|
|
|
|
<div class="grid grid-cols-1 gap-4 overflow-hidden lg:grid-cols-12">
|
|
|
@@ -458,32 +536,17 @@ watch([isDark, color], () => {
|
|
|
<div
|
|
|
class="rounded bg-[var(--card-color)] px-5 pt-5 pb-4.5 shadow-xs transition-background-color-300 transition-ease-in-out"
|
|
|
style="height: 400px">
|
|
|
- <div ref="revenueChart" class="h-full" />
|
|
|
+ <div ref="shutdownWeeklyChart" class="h-full" />
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="col-span-1 lg:col-span-4">
|
|
|
<div
|
|
|
class="flex flex-col rounded bg-[var(--card-color)] px-5 pt-5 pb-4.5 shadow-xs transition-[background-color]-300 transition-ease-in-out"
|
|
|
style="height: 400px">
|
|
|
- <div ref="revenueBarChart" class="flex-1" />
|
|
|
- <div ref="revenueBarChart2" style="height: 150px" />
|
|
|
+ <div ref="shutdownYearChart" class="flex-1" />
|
|
|
+ <!-- <div ref="shutdownYearChart2" style="height: 150px" /> -->
|
|
|
</div>
|
|
|
</div>
|
|
|
</div>
|
|
|
- <div class="grid grid-cols-1 gap-4 overflow-hidden lg:grid-cols-12">
|
|
|
- <div class="col-span-1 lg:col-span-5">
|
|
|
- <div
|
|
|
- class="rounded bg-[var(--card-color)] px-5 pt-5 pb-3 shadow-xs transition-background-color-300 transition-ease-in-out"
|
|
|
- style="height: 340px">
|
|
|
- <div ref="monthlyRadarChart" class="h-full" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- <div class="col-span-1 lg:col-span-7">
|
|
|
- <div class="rounded bg-[var(--card-color)] p-5 shadow-xs transition-background-color-300 transition-ease-in-out"
|
|
|
- style="height: 340px; position: relative">
|
|
|
- <div ref="highestRevenueChart" class="h-full" />
|
|
|
- </div>
|
|
|
- </div>
|
|
|
- </div> -->
|
|
|
</div>
|
|
|
</template>
|