From 9b8563141470990db2905f27ab5e893324afeba1 Mon Sep 17 00:00:00 2001
From: zhangwencui <1064582902@qq.com>
Date: 星期四, 26 三月 2026 17:02:24 +0800
Subject: [PATCH] 销售统计看板重构
---
src/views/reportAnalysis/salesStatistics/index.vue | 1136 ++++++++++++++++++++++++++++++++++++++++++----------------
1 files changed, 814 insertions(+), 322 deletions(-)
diff --git a/src/views/reportAnalysis/salesStatistics/index.vue b/src/views/reportAnalysis/salesStatistics/index.vue
index 4991649..c18972b 100644
--- a/src/views/reportAnalysis/salesStatistics/index.vue
+++ b/src/views/reportAnalysis/salesStatistics/index.vue
@@ -47,22 +47,26 @@
<!-- 宸︿笂锛氶攢閲忚秼鍔� -->
<div class="bi-panel bi-panel-top-left">
<PanelHeader :isFullscreen="true"
- title="閿�鍞垎鏋�-鐮屽潡" />
+ title="閿�閲忓垎鏋愯秼鍔垮浘" />
<div class="panel-tabs">
- <span class="tab-item active">骞�</span>
- <span class="tab-item">鏈�</span>
+ <span class="tab-item"
+ :class="{ active: blockTimeDimension === 'year' }"
+ @click="handleBlockTimeDimensionChange('year')">骞�</span>
+ <span class="tab-item"
+ :class="{ active: blockTimeDimension === 'month' }"
+ @click="handleBlockTimeDimensionChange('month')">鏈�</span>
+ </div>
+ <div class="panel-tabs2">
+ <span class="tab-item"
+ :class="{ active: blockProductType === '鐮屽潡' }"
+ @click="handleBlockProductTypeChange('鐮屽潡')">鐮屽潡</span>
+ <span class="tab-item"
+ :class="{ active: blockProductType === '鏉挎潗' }"
+ @click="handleBlockProductTypeChange('鏉挎潗')">鏉挎潗</span>
</div>
<div class="bi-panel-body">
- <div class="chart-filter-tabs">
- <span class="cf-tab active">***閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- </div>
<div class="chart-unit-row">
<span>鍗曚綅锛氱珛鏂圭背</span>
- <span class="dot-legend">鏉挎潗</span>
</div>
<div ref="salesVolumeChart"
class="echart-fill"></div>
@@ -71,22 +75,26 @@
<!-- 鍙充笂锛氶攢鍞噾棰� -->
<div class="bi-panel bi-panel-top-right">
<PanelHeader :isFullscreen="true"
- title="閿�鍞垎鏋�-鏉挎潗" />
+ title="閿�鍞噾棰濆垎鏋�" />
<div class="panel-tabs">
- <span class="tab-item active">骞�</span>
- <span class="tab-item">鏈�</span>
+ <span class="tab-item"
+ :class="{ active: boardTimeDimension === 'year' }"
+ @click="handleBoardTimeDimensionChange('year')">骞�</span>
+ <span class="tab-item"
+ :class="{ active: boardTimeDimension === 'month' }"
+ @click="handleBoardTimeDimensionChange('month')">鏈�</span>
+ </div>
+ <div class="panel-tabs2">
+ <span class="tab-item"
+ :class="{ active: boardProductType === '鐮屽潡' }"
+ @click="handleBoardProductTypeChange('鐮屽潡')">鐮屽潡</span>
+ <span class="tab-item"
+ :class="{ active: boardProductType === '鏉挎潗' }"
+ @click="handleBoardProductTypeChange('鏉挎潗')">鏉挎潗</span>
</div>
<div class="bi-panel-body">
- <div class="chart-filter-tabs">
- <span class="cf-tab active">***閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- </div>
<div class="chart-unit-row">
- <span>鍗曚綅锛氫欢</span>
- <span class="dot-legend">鏉挎潗</span>
+ <span>鍗曚綅锛氬厓</span>
</div>
<div ref="salesAmountChart"
class="echart-fill"></div>
@@ -94,37 +102,11 @@
</div>
<!-- 涓棿涓績鐜� -->
<div class="center-ring">
- <!-- <img class="center-ring-bg"
- src="@/assets/BI/zonghetongbingtubiankuang@2x.png"
- alt="" /> -->
- <!-- <div class="center-ring-content"> -->
- <!-- <div class="center-ring-title">閿�鍞�<br />涓績</div>
- <div class="center-metric m1">
- <div class="center-metric-label">鏂板瀹㈡埛</div>
- <div class="center-metric-value">{{ centerNewCustomerCount }}</div>
- <div class="center-metric-unit">浜�</div>
- </div>
- <div class="center-metric m2">
- <div class="center-metric-label">鎴愪氦鎬昏鍗�</div>
- <div class="center-metric-value">{{ completedOrders }}</div>
- <div class="center-metric-unit">鍗�</div>
- </div>
- <div class="center-metric m3">
- <div class="center-metric-label">鏂板璁㈠崟</div>
- <div class="center-metric-value">{{ salesOrderCount }}</div>
- <div class="center-metric-unit">鍗�</div>
- </div>
- <div class="center-metric m4">
- <div class="center-metric-label">鎬婚攢鍞尯</div>
- <div class="center-metric-value">{{ totalSalesAreaCount }}</div>
- <div class="center-metric-unit">鍖�</div>
- </div> -->
- <!-- </div> -->
<div class="center-ring-box">
<div class="center-metric m1">
- <div class="center-metric-label">鏂板瀹㈡埛</div>
- <div class="center-metric-value">{{ centerNewCustomerCount }}</div>
- <div class="center-metric-unit">浜�</div>
+ <div class="center-metric-label">鎬婚攢鍞噾棰�</div>
+ <div class="center-metric-value">{{ totalSalesAmount.toFixed(0) }}</div>
+ <div class="center-metric-unit">涓囧厓</div>
</div>
<div class="center-metric m2">
<div class="center-metric-label">鎴愪氦鎬昏鍗�</div>
@@ -132,9 +114,9 @@
<div class="center-metric-unit">鍗�</div>
</div>
<div class="center-metric m3">
- <div class="center-metric-label">鏂板璁㈠崟</div>
- <div class="center-metric-value">{{ salesOrderCount }}</div>
- <div class="center-metric-unit">鍗�</div>
+ <div class="center-metric-label">绱瀹㈡埛</div>
+ <div class="center-metric-value">{{ centerNewCustomerCount }}</div>
+ <div class="center-metric-unit">瀹�</div>
</div>
<div class="center-metric m4">
<div class="center-metric-label">鎬婚攢鍞尯</div>
@@ -146,21 +128,61 @@
<!-- 宸︿笅锛氫骇鍝佺被鍨嬮攢閲� -->
<div class="bi-panel bi-panel-bottom-left">
<PanelHeader :isFullscreen="true"
- title="瀹㈡埛閿�閲忔帓鍚嶅垎鏋�-鐮屽潡" />
+ title="閿�閲忔暟鎹�-鎺掑悕鍒嗘瀽" />
<div class="panel-tabs">
- <span class="tab-item active">骞�</span>
- <span class="tab-item">鏈�</span>
+ <span class="tab-item"
+ :class="{ active: blockTimeDimension === 'year' }"
+ @click="handleBlockTimeDimensionChange('year')">骞�</span>
+ <span class="tab-item"
+ :class="{ active: blockTimeDimension === 'month' }"
+ @click="handleBlockTimeDimensionChange('month')">鏈�</span>
+ </div>
+ <div class="panel-tabs2">
+ <span class="tab-item"
+ :class="{ active: blockProductType === '鐮屽潡' }"
+ @click="handleBlockProductTypeChange('鐮屽潡')">鐮屽潡</span>
+ <span class="tab-item"
+ :class="{ active: blockProductType === '鏉挎潗' }"
+ @click="handleBlockProductTypeChange('鏉挎潗')">鏉挎潗</span>
</div>
<div class="bi-panel-body">
<div class="chart-filter-tabs">
- <span class="cf-tab active">***閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
+ <span v-for="area in salesAreas"
+ :key="area"
+ class="cf-tab"
+ :class="{ active: blockSelectedArea === area }"
+ @click="handleBlockAreaChange(area)">{{ area }}</span>
</div>
- <div ref="productTypeChart"
- class="echart-fill"></div>
+ <div class="scroll-table-container">
+ <table class="scroll-table">
+ <thead>
+ <tr>
+ <th>鎺掑悕</th>
+ <th>浜у搧绫诲瀷</th>
+ <th>骞存湀</th>
+ <th>閿�鍞尯</th>
+ <th>閿�閲忥紙m鲁锛�</th>
+ </tr>
+ </thead>
+ <div class="scroll-table-content">
+ <tbody ref="blockTableBody">
+ <tr :class="item.sort % 2 === 0 ? 'evenTableTr' : 'oddTableTr'"
+ v-for="(item, index) in blockSalesData"
+ :key="item.period + item.area + index">
+ <td>{{ item.sort }}</td>
+ <td>{{ item.productType }}</td>
+ <td>{{ item.period }}</td>
+ <td>{{ item.area }}</td>
+ <td>{{ item.sales }}</td>
+ </tr>
+ </tbody>
+ </div>
+ </table>
+ </div>
+ <div class="panel-summary-row">
+ <div class="summary-label">鍚堣</div>
+ <div class="summary-value">127384 m鲁</div>
+ </div>
</div>
</div>
<!-- 涓笅锛氭柊澧炲鎴峰垎鏋愶紙鍒嗕骇鍝佺被鍨嬭秼鍔匡級 -->
@@ -168,14 +190,14 @@
<PanelHeader :isFullscreen="true"
title="鏂板瀹㈡埛瓒嬪娍鍒嗘瀽" />
<div class="panel-tabs">
- <span class="tab-item active">骞�</span>
- <span class="tab-item">鏈�</span>
+ <span class="tab-item"
+ :class="{ active: customerTimeDimension === 'year' }"
+ @click="handleCustomerTimeDimensionChange('year')">骞�</span>
+ <span class="tab-item"
+ :class="{ active: customerTimeDimension === 'month' }"
+ @click="handleCustomerTimeDimensionChange('month')">鏈�</span>
</div>
<div class="bi-panel-body">
- <div class="chart-mini-title">
- <span class="diamond"></span>
- <span>鏂板瀹㈡埛鏁�</span>
- </div>
<div class="chart-unit-row chart-unit-single">
<span>鍗曚綅锛氫汉</span>
</div>
@@ -186,21 +208,59 @@
<!-- 鍙充笅锛氶攢鍞尯鍩熼攢閲� -->
<div class="bi-panel bi-panel-bottom-right">
<PanelHeader :isFullscreen="true"
- title="瀹㈡埛閿�閲忔帓鍚嶅垎鏋�-鏉挎潗" />
+ title="閿�鍞鏁版嵁-鎺掑悕鍒嗘瀽" />
<div class="panel-tabs">
- <span class="tab-item active">骞�</span>
- <span class="tab-item">鏈�</span>
+ <span class="tab-item"
+ :class="{ active: boardTimeDimension === 'year' }"
+ @click="handleBoardTimeDimensionChange('year')">骞�</span>
+ <span class="tab-item"
+ :class="{ active: boardTimeDimension === 'month' }"
+ @click="handleBoardTimeDimensionChange('month')">鏈�</span>
+ </div>
+ <div class="panel-tabs2">
+ <span class="tab-item"
+ :class="{ active: boardProductType === '鐮屽潡' }"
+ @click="handleBoardProductTypeChange('鐮屽潡')">鐮屽潡</span>
+ <span class="tab-item"
+ :class="{ active: boardProductType === '鏉挎潗' }"
+ @click="handleBoardProductTypeChange('鏉挎潗')">鏉挎潗</span>
</div>
<div class="bi-panel-body">
<div class="chart-filter-tabs">
- <span class="cf-tab active">***閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
- <span class="cf-tab">xxx閿�鍞尯</span>
+ <span v-for="area in salesAreas"
+ :key="area"
+ class="cf-tab"
+ :class="{ active: boardSelectedArea === area }"
+ @click="handleBoardAreaChange(area)">{{ area }}</span>
</div>
- <div ref="salesAreaChart"
- class="echart-fill"></div>
+ <div class="scroll-table-container">
+ <table class="scroll-table">
+ <thead>
+ <tr>
+ <th>鎺掑悕</th>
+ <th>骞存湀</th>
+ <th>閿�鍞尯</th>
+ <th>閿�鍞锛堜竾鍏冿級</th>
+ </tr>
+ </thead>
+ <div class="scroll-table-content">
+ <tbody ref="boardTableBody">
+ <tr :class="item.sort % 2 === 0 ? 'evenTableTr' : 'oddTableTr'"
+ v-for="(item, index) in boardSalesData"
+ :key="item.period + item.area + index">
+ <td>{{ item.sort }}</td>
+ <td>{{ item.period }}</td>
+ <td>{{ item.area }}</td>
+ <td>{{ item.sales }}</td>
+ </tr>
+ </tbody>
+ </div>
+ </table>
+ </div>
+ <div class="panel-summary-row">
+ <div class="summary-label">鍚堣</div>
+ <div class="summary-value2">127384 涓囧厓</div>
+ </div>
</div>
</div>
</div>
@@ -220,6 +280,7 @@
import * as echarts from "echarts";
import dayjs from "dayjs";
import PanelHeader from "@/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue";
+ import { findAllQualifiedStockOutRecordTypeOptions } from "../../../api/basicData/enum";
const router = useRouter();
const screenRoot = ref(null);
@@ -275,6 +336,53 @@
const productTypeChart = ref(null);
const salesAreaChart = ref(null);
const productTypeTrendChart = ref(null);
+ const blockTableBody = ref(null);
+ const boardTableBody = ref(null);
+
+ // 閫夋嫨鍣ㄦ暟鎹�
+ const blockTimeDimension = ref("year");
+ const blockSelectedArea = ref("鍏ㄩ儴");
+ const blockProductType = ref("鐮屽潡");
+ const boardTimeDimension = ref("year");
+ const boardSelectedArea = ref("鍏ㄩ儴");
+ const boardProductType = ref("鏉挎潗");
+ const customerTimeDimension = ref("year");
+
+ const salesAreas = [
+ "鍏ㄩ儴",
+ "A閿�鍞尯",
+ "B閿�鍞尯",
+ "C閿�鍞尯",
+ "D閿�鍞尯",
+ "E閿�鍞尯",
+ ];
+
+ // 琛ㄦ牸鏁版嵁
+ const blockSalesData = ref([
+ { period: "2024-01", area: "***閿�鍞尯", sales: 1250, sort: 1 },
+ { period: "2024-02", area: "xxx閿�鍞尯", sales: 1180, sort: 2 },
+ { period: "2024-03", area: "xxx閿�鍞尯", sales: 1050, sort: 3 },
+ { period: "2024-04", area: "xxx閿�鍞尯", sales: 980, sort: 4 },
+ { period: "2024-05", area: "xxx閿�鍞尯", sales: 920, sort: 5 },
+ { period: "2024-06", area: "***閿�鍞尯", sales: 880, sort: 6 },
+ { period: "2024-07", area: "xxx閿�鍞尯", sales: 850, sort: 7 },
+ { period: "2024-08", area: "***閿�鍞尯", sales: 820, sort: 8 },
+ { period: "2024-09", area: "xxx閿�鍞尯", sales: 790, sort: 9 },
+ { period: "2024-10", area: "***閿�鍞尯", sales: 750, sort: 10 },
+ ]);
+
+ const boardSalesData = ref([
+ { period: "2024-01", area: "***閿�鍞尯", sales: 980, sort: 1 },
+ { period: "2024-02", area: "xxx閿�鍞尯", sales: 920, sort: 2 },
+ { period: "2024-03", area: "***閿�鍞尯", sales: 880, sort: 3 },
+ { period: "2024-04", area: "xxx閿�鍞尯", sales: 850, sort: 4 },
+ { period: "2024-05", area: "xxx閿�鍞尯", sales: 820, sort: 5 },
+ { period: "2024-06", area: "***閿�鍞尯", sales: 790, sort: 6 },
+ { period: "2024-07", area: "xxx閿�鍞尯", sales: 750, sort: 7 },
+ { period: "2024-08", area: "xxx閿�鍞尯", sales: 720, sort: 8 },
+ { period: "2024-09", area: "***閿�鍞尯", sales: 690, sort: 9 },
+ { period: "2024-10", area: "xxx閿�鍞尯", sales: 650, sort: 10 },
+ ]);
const cumulativeSalesVolumeChart = ref(null);
const cumulativeSalesAmountChart = ref(null);
@@ -541,11 +649,7 @@
return filteredData.value.reduce((sum, item) => sum + item.salesVolume, 0);
});
- const totalSalesAmount = computed(() => {
- return filteredData.value
- .reduce((sum, item) => sum + item.salesAmount, 0)
- .toFixed(2);
- });
+ const totalSalesAmount = ref(1299);
const newCustomerCount = computed(() => {
return filteredData.value.reduce((sum, item) => sum + item.newCustomers, 0);
@@ -594,8 +698,70 @@
// 閿�閲忚秼鍔垮浘琛ㄩ厤缃�
const salesVolumeChartOption = computed(() => {
- const periods = ["6/9", "6/10", "6/11", "6/12", "6/12", "6/13"];
- const values = [132, 168, 168, 198, 168, 198];
+ // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
+ const salesAreas = [
+ "鍏ㄩ儴",
+ "A閿�鍞尯",
+ "B閿�鍞尯",
+ "C閿�鍞尯",
+ "D閿�鍞尯",
+ "E閿�鍞尯",
+ ];
+ const colors = [
+ "#00A4ED",
+ "#34D8F7",
+ "#4A8BFF",
+ "#8A6BFF",
+ "#C8C447",
+ "#FF6B6B",
+ ];
+ const year = 2024;
+ const periodType = blockTimeDimension.value;
+
+ // 鐢熸垚鏃堕棿娈�
+ let periods = [];
+ if (periodType === "year") {
+ // 骞村害鏁版嵁锛�12涓湀
+ for (let month = 1; month <= 12; month++) {
+ periods.push(`${year}-${month.toString().padStart(2, "0")}`);
+ }
+ } else {
+ // 鏈堝害鏁版嵁锛�30澶�
+ const month = 1;
+ for (let day = 1; day <= 30; day++) {
+ periods.push(
+ `${year}-${month.toString().padStart(2, "0")}-${day
+ .toString()
+ .padStart(2, "0")}`
+ );
+ }
+ }
+
+ // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
+ const series = salesAreas.map((area, index) => {
+ const data = periods.map(() => {
+ return periodType === "year"
+ ? Math.floor(Math.random() * 500) + 800
+ : Math.floor(Math.random() * 50) + 20;
+ });
+
+ return {
+ name: area,
+ data: data,
+ type: "line",
+ smooth: false,
+ // symbolSize: getResponsiveValue(8),
+ lineStyle: { width: getResponsiveValue(1), color: colors[index] },
+ itemStyle: { color: colors[index] },
+ areaStyle: {
+ opacity: 0.4,
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: colors[index] + "80" },
+ { offset: 1, color: colors[index] + "00" },
+ ]),
+ },
+ };
+ });
return {
backgroundColor: "transparent",
@@ -605,12 +771,29 @@
borderColor: "rgba(64,158,255,0.25)",
borderWidth: getResponsiveValue(1),
textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
- formatter: "{b}: {c} 绔嬫柟绫�",
+ formatter: function (params) {
+ let result = params[0].name + "<br/>";
+ params.forEach(param => {
+ result += `${param.marker}${param.seriesName}: ${param.value} 绔嬫柟绫�<br/>`;
+ });
+ return result;
+ },
+ },
+ legend: {
+ data: salesAreas,
+ top: "10%",
+ right: "1%",
+ textStyle: {
+ color: "#B8C8E0",
+ fontSize: getResponsiveValue(9),
+ },
+ itemWidth: getResponsiveValue(10),
+ itemHeight: getResponsiveValue(10),
},
grid: {
- left: "10%",
- right: "4%",
- bottom: "16%",
+ left: "1%",
+ right: "1%",
+ bottom: "1%",
top: "28%",
containLabel: true,
},
@@ -637,30 +820,75 @@
},
splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
},
- series: [
- {
- data: values,
- type: "line",
- smooth: true,
- symbolSize: getResponsiveValue(8),
- lineStyle: { width: getResponsiveValue(3), color: "#00A4ED" },
- itemStyle: { color: "#00A4ED" },
- areaStyle: {
- opacity: 1,
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: "rgba(0,164,237,0.35)" },
- { offset: 1, color: "rgba(0,164,237,0)" },
- ]),
- },
- },
- ],
+ series: series,
};
});
// 閿�鍞噾棰濊秼鍔垮浘琛ㄩ厤缃�
const salesAmountChartOption = computed(() => {
- const periods = ["6/9", "6/10", "6/11", "6/12", "6/12", "6/13"];
- const values = [132, 168, 168, 198, 168, 198];
+ // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
+ const salesAreas = [
+ "鍏ㄩ儴",
+ "A閿�鍞尯",
+ "B閿�鍞尯",
+ "C閿�鍞尯",
+ "D閿�鍞尯",
+ "E閿�鍞尯",
+ ];
+ const colors = [
+ "#00A4ED",
+ "#34D8F7",
+ "#4A8BFF",
+ "#8A6BFF",
+ "#C8C447",
+ "#FF6B6B",
+ ];
+ const year = 2024;
+ const periodType = boardTimeDimension.value;
+
+ // 鐢熸垚鏃堕棿娈�
+ let periods = [];
+ if (periodType === "year") {
+ // 骞村害鏁版嵁锛�12涓湀
+ for (let month = 1; month <= 12; month++) {
+ periods.push(`${year}-${month.toString().padStart(2, "0")}`);
+ }
+ } else {
+ // 鏈堝害鏁版嵁锛�30澶�
+ const month = 1;
+ for (let day = 1; day <= 30; day++) {
+ periods.push(
+ `${year}-${month.toString().padStart(2, "0")}-${day
+ .toString()
+ .padStart(2, "0")}`
+ );
+ }
+ }
+
+ // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
+ const series = salesAreas.map((area, index) => {
+ const data = periods.map(() => {
+ return periodType === "year"
+ ? Math.floor(Math.random() * 50000) + 80000
+ : Math.floor(Math.random() * 5000) + 2000;
+ });
+
+ return {
+ name: area,
+ data: data,
+ type: "bar",
+ smooth: true,
+ lineStyle: { width: getResponsiveValue(3), color: colors[index] },
+ itemStyle: { color: colors[index] },
+ areaStyle: {
+ opacity: 0.2,
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ { offset: 0, color: colors[index] + "80" },
+ { offset: 1, color: colors[index] + "00" },
+ ]),
+ },
+ };
+ });
return {
backgroundColor: "transparent",
@@ -670,12 +898,29 @@
borderColor: "rgba(64,158,255,0.25)",
borderWidth: getResponsiveValue(1),
textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
- formatter: "{b}: {c} 涓囧厓",
+ formatter: function (params) {
+ let result = params[0].name + "<br/>";
+ params.forEach(param => {
+ result += `${param.marker}${param.seriesName}: ${param.value} 鍏�<br/>`;
+ });
+ return result;
+ },
+ },
+ legend: {
+ data: salesAreas,
+ top: "10%",
+ right: "1%",
+ textStyle: {
+ color: "#B8C8E0",
+ fontSize: getResponsiveValue(9),
+ },
+ itemWidth: getResponsiveValue(10),
+ itemHeight: getResponsiveValue(10),
},
grid: {
- left: "10%",
- right: "4%",
- bottom: "16%",
+ left: "1%",
+ right: "1%",
+ bottom: "1%",
top: "28%",
containLabel: true,
},
@@ -689,6 +934,7 @@
fontSize: getResponsiveValue(11),
margin: getResponsiveValue(10),
},
+ splitLine: { show: false },
},
yAxis: {
type: "value",
@@ -701,25 +947,7 @@
},
splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
},
- series: [
- {
- data: values,
- type: "line",
- smooth: true,
- symbolSize: getResponsiveValue(8),
- itemStyle: {
- color: "#00A4ED",
- },
- lineStyle: { width: getResponsiveValue(3), color: "#00A4ED" },
- areaStyle: {
- opacity: 1,
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: "rgba(0,164,237,0.35)" },
- { offset: 1, color: "rgba(0,164,237,0)" },
- ]),
- },
- },
- ],
+ series: series,
};
});
@@ -862,83 +1090,97 @@
};
});
- // 鏂板瀹㈡埛瓒嬪娍鍥捐〃閰嶇疆锛堟寜浜у搧绫诲瀷澶氭姌绾匡級
+ // 鏂板瀹㈡埛瓒嬪娍鍥捐〃閰嶇疆锛堟寜閿�鍞尯鍜屽勾鏈堢淮搴︼級
const productTypeTrendChartOption = computed(() => {
- const typeOrder = ["AAA閿�鍞尯", "BBB閿�鍞尯", "CCC閿�鍞尯", "DDD閿�鍞尯"];
- const colorMap = {
- AAA閿�鍞尯: "#65A0FF",
- BBB閿�鍞尯: "#33F5FF",
- CCC閿�鍞尯: "#FFD54A",
- DDD閿�鍞尯: "#EE52FF",
- };
- const areaColorMap = {
- AAA閿�鍞尯: "rgba(101,160,255,0.28)",
- BBB閿�鍞尯: "rgba(51,245,255,0.30)",
- CCC閿�鍞尯: "rgba(255,213,74,0.25)",
- DDD閿�鍞尯: "rgba(238,82,255,0.25)",
- };
- const periods = [
- "6/9",
- "6/10",
- "6/11",
- "6/12",
- "6/12",
- "6/13",
- "6/14",
- "6/15",
+ // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
+ const salesAreas = [
+ "鍏ㄩ儴",
+ "A閿�鍞尯",
+ "B閿�鍞尯",
+ "C閿�鍞尯",
+ "D閿�鍞尯",
+ "E閿�鍞尯",
];
- const map = {
- AAA閿�鍞尯: [85, 112, 112, 112, 140, 112, 112, 140],
- BBB閿�鍞尯: [140, 180, 180, 180, 230, 180, 180, 230],
- CCC閿�鍞尯: [112, 140, 140, 140, 180, 140, 140, 180],
- DDD閿�鍞尯: [200, 165, 200, 200, 165, 165, 140, 140],
- };
+ const colors = [
+ "#00A4ED",
+ "#34D8F7",
+ "#4A8BFF",
+ "#8A6BFF",
+ "#C8C447",
+ "#FF6B6B",
+ ];
+ const year = 2024;
+ const periodType = customerTimeDimension.value;
- const series = typeOrder.map(t => ({
- name: t,
- type: "line",
- smooth: true,
- symbolSize: getResponsiveValue(7),
- showSymbol: true,
- data: map[t] || [],
- lineStyle: { width: getResponsiveValue(3), color: colorMap[t] },
- itemStyle: { color: colorMap[t] },
- areaStyle: {
- opacity: 0.25,
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
- { offset: 0, color: areaColorMap[t] },
- { offset: 1, color: "rgba(0,0,0,0)" },
- ]),
- },
- }));
+ // 鐢熸垚鏃堕棿娈�
+ let periods = [];
+ if (periodType === "year") {
+ // 骞村害鏁版嵁锛�12涓湀
+ for (let month = 1; month <= 12; month++) {
+ periods.push(`${year}-${month.toString().padStart(2, "0")}`);
+ }
+ } else {
+ // 鏈堝害鏁版嵁锛�30澶�
+ const month = 1;
+ for (let day = 1; day <= 30; day++) {
+ periods.push(
+ `${year}-${month.toString().padStart(2, "0")}-${day
+ .toString()
+ .padStart(2, "0")}`
+ );
+ }
+ }
+
+ // 涓烘瘡涓攢鍞尯鐢熸垚鏁版嵁
+ const series = salesAreas.map((area, index) => {
+ const data = periods.map(() => {
+ return periodType === "year"
+ ? Math.floor(Math.random() * 10) + 2
+ : Math.floor(Math.random() * 3) + 1;
+ });
+
+ return {
+ name: area,
+ data: data,
+ type: "line",
+ smooth: false,
+ lineStyle: { width: getResponsiveValue(1), color: colors[index] },
+ itemStyle: { color: colors[index] },
+ };
+ });
return {
backgroundColor: "transparent",
-
- legend: {
- top: getResponsiveValue(10),
- left: "center",
- textStyle: {
- color: "#B8C8E0",
- fontSize: getResponsiveValue(11),
- padding: [0, 0, 0, getResponsiveValue(2)],
- },
- itemWidth: getResponsiveValue(12),
- itemHeight: getResponsiveValue(10),
- itemGap: getResponsiveValue(18),
- },
tooltip: {
trigger: "axis",
backgroundColor: "rgba(0,0,0,0.55)",
borderColor: "rgba(64,158,255,0.25)",
borderWidth: getResponsiveValue(1),
textStyle: { color: "#B8C8E0", fontSize: getResponsiveValue(11) },
+ formatter: function (params) {
+ let result = params[0].name + "<br/>";
+ params.forEach(param => {
+ result += `${param.marker}${param.seriesName}: ${param.value} 浜�<br/>`;
+ });
+ return result;
+ },
+ },
+ legend: {
+ data: salesAreas,
+ top: "10%",
+ right: "1%",
+ textStyle: {
+ color: "#B8C8E0",
+ fontSize: getResponsiveValue(9),
+ },
+ itemWidth: getResponsiveValue(10),
+ itemHeight: getResponsiveValue(10),
},
grid: {
- left: "10%",
- right: "6%",
- bottom: "14%",
- top: "26%",
+ left: "1%",
+ right: "1%",
+ bottom: "1%",
+ top: "28%",
containLabel: true,
},
xAxis: {
@@ -951,6 +1193,7 @@
fontSize: getResponsiveValue(11),
margin: getResponsiveValue(10),
},
+ splitLine: { show: false },
},
yAxis: {
type: "value",
@@ -963,125 +1206,10 @@
},
splitLine: { lineStyle: { color: "rgba(184,200,224,0.12)" } },
},
- series,
+ series: series,
};
});
- // 绱閿�閲忚秼鍔垮浘琛ㄩ厤缃�
- const cumulativeSalesVolumeChartOption = computed(() => {
- // 鎸夊懆鏈熷垎缁�
- const periodMap = {};
- let cumulativeValue = 0;
-
- // 鎸夊懆鏈熸帓搴�
- const sortedData = [...filteredData.value].sort((a, b) =>
- a.period.localeCompare(b.period)
- );
-
- sortedData.forEach(item => {
- cumulativeValue += item.salesVolume;
- periodMap[item.period] = cumulativeValue;
- });
-
- const periods = Object.keys(periodMap).sort();
- const values = periods.map(period => periodMap[period]);
-
- return {
- tooltip: {
- trigger: "axis",
- formatter: "{b}: {c} 绔嬫柟绫�",
- textStyle: { fontSize: getResponsiveValue(11) },
- },
- xAxis: {
- type: "category",
- data: periods,
- axisLabel: { fontSize: getResponsiveValue(11) },
- },
- yAxis: {
- type: "value",
- name: "绱閿�閲忥紙绔嬫柟绫筹級",
- axisLabel: { fontSize: getResponsiveValue(11) },
- },
- series: [
- {
- data: values,
- type: "line",
- smooth: true,
- areaStyle: {
- opacity: 0.3,
- },
- itemStyle: {
- color: "#E6A23C",
- },
- lineStyle: {
- width: getResponsiveValue(3),
- },
- },
- ],
- };
- });
-
- // 绱閿�鍞噾棰濊秼鍔垮浘琛ㄩ厤缃�
- const cumulativeSalesAmountChartOption = computed(() => {
- // 鎸夊懆鏈熷垎缁�
- const periodMap = {};
- let cumulativeValue = 0;
-
- // 鎸夊懆鏈熸帓搴�
- const sortedData = [...filteredData.value].sort((a, b) =>
- a.period.localeCompare(b.period)
- );
-
- sortedData.forEach(item => {
- cumulativeValue += item.salesAmount;
- periodMap[item.period] = cumulativeValue;
- });
-
- const periods = Object.keys(periodMap).sort();
- const values = periods.map(period => periodMap[period]);
-
- return {
- tooltip: {
- trigger: "axis",
- formatter: "{b}: {c} 涓囧厓",
- textStyle: { fontSize: getResponsiveValue(11) },
- },
- xAxis: {
- type: "category",
- data: periods,
- axisLabel: { fontSize: getResponsiveValue(11) },
- },
- yAxis: {
- type: "value",
- name: "绱閿�鍞噾棰濓紙涓囧厓锛�",
- axisLabel: { fontSize: getResponsiveValue(11) },
- },
- series: [
- {
- data: values,
- type: "bar",
- itemStyle: {
- color: "#F56C6C",
- },
- },
- ],
- };
- });
-
- // 鏂规硶
- const goBack = () => {
- router.back();
- };
-
- const handleDateChange = () => {
- // 澶勭悊鏃ユ湡鍙樺寲
- updateCharts();
- };
-
- const handleFilterChange = () => {
- // 澶勭悊绛涢�夋潯浠跺彉鍖�
- updateCharts();
- };
const baseWidth = ref(1650);
// 璁$畻鍝嶅簲寮忓��
const getResponsiveValue = baseValue => {
@@ -1175,6 +1303,198 @@
}
};
+ // 琛ㄦ牸鍔ㄧ敾鎺у埗
+ let blockScrollTimer = null;
+ let boardScrollTimer = null;
+ let blockCurrentIndex = 0;
+ let boardCurrentIndex = 0;
+
+ const startBlockTableScroll = () => {
+ if (blockScrollTimer) {
+ clearInterval(blockScrollTimer);
+ }
+
+ const scrollTable = () => {
+ if (!blockTableBody.value || blockSalesData.value.length === 0) return;
+
+ const rows = blockTableBody.value.querySelectorAll("tr");
+ if (rows.length === 0) return;
+
+ const rowHeight = rows[0].offsetHeight;
+
+ blockTableBody.value.style.transition = "transform 0.5s ease-in-out";
+ blockTableBody.value.style.transform = `translateY(-${rowHeight}px)`;
+
+ setTimeout(() => {
+ blockTableBody.value.style.transition = "none";
+ blockTableBody.value.style.transform = "translateY(0)";
+
+ const firstItem = blockSalesData.value[0];
+ blockSalesData.value.shift();
+ blockSalesData.value.push(firstItem);
+ }, 500);
+ };
+
+ blockScrollTimer = setInterval(scrollTable, 2000);
+ };
+
+ const startBoardTableScroll = () => {
+ if (boardScrollTimer) {
+ clearInterval(boardScrollTimer);
+ }
+
+ const scrollTable = () => {
+ if (!boardTableBody.value || boardSalesData.value.length === 0) return;
+
+ const rows = boardTableBody.value.querySelectorAll("tr");
+ if (rows.length === 0) return;
+
+ const rowHeight = rows[0].offsetHeight;
+
+ boardTableBody.value.style.transition = "transform 0.5s ease-in-out";
+ boardTableBody.value.style.transform = `translateY(-${rowHeight}px)`;
+
+ setTimeout(() => {
+ boardTableBody.value.style.transition = "none";
+ boardTableBody.value.style.transform = "translateY(0)";
+
+ const firstItem = boardSalesData.value[0];
+ boardSalesData.value.shift();
+ boardSalesData.value.push(firstItem);
+ }, 500);
+ };
+
+ boardScrollTimer = setInterval(scrollTable, 2000);
+ };
+
+ const stopTableScroll = () => {
+ if (blockScrollTimer) {
+ clearInterval(blockScrollTimer);
+ blockScrollTimer = null;
+ }
+ if (boardScrollTimer) {
+ clearInterval(boardScrollTimer);
+ boardScrollTimer = null;
+ }
+ };
+
+ // 澶勭悊鏃堕棿缁村害閫夋嫨
+ const handleBlockTimeDimensionChange = dimension => {
+ blockTimeDimension.value = dimension;
+ generateBlockSalesData();
+ };
+
+ const handleBoardTimeDimensionChange = dimension => {
+ boardTimeDimension.value = dimension;
+ generateBoardSalesData();
+ };
+
+ // 澶勭悊浜у搧绫诲瀷閫夋嫨
+ const handleBlockProductTypeChange = type => {
+ blockProductType.value = type;
+ generateBlockSalesData();
+ };
+
+ const handleBoardProductTypeChange = type => {
+ boardProductType.value = type;
+ generateBoardSalesData();
+ };
+
+ // 澶勭悊閿�鍞尯閫夋嫨
+ const handleBlockAreaChange = area => {
+ blockSelectedArea.value = area;
+ generateBlockSalesData();
+ };
+
+ const handleBoardAreaChange = area => {
+ boardSelectedArea.value = area;
+ generateBoardSalesData();
+ };
+
+ // 澶勭悊鏂板瀹㈡埛瓒嬪娍鏃堕棿缁村害鍒囨崲
+ const handleCustomerTimeDimensionChange = dimension => {
+ customerTimeDimension.value = dimension;
+ updateCharts();
+ };
+
+ // 鐢熸垚鐮屽潡閿�鍞暟鎹�
+ const generateBlockSalesData = () => {
+ const data = [];
+ const year = 2024;
+
+ if (blockTimeDimension.value === "year") {
+ // 骞村害鏁版嵁锛�12涓湀
+ for (let month = 1; month <= 12; month++) {
+ const period = `${year}-${month.toString().padStart(2, "0")}`;
+ data.push({
+ period: period,
+ area: blockSelectedArea.value,
+ productType: blockProductType.value,
+ sales: Math.floor(Math.random() * 500) + 800,
+ sort: month,
+ });
+ }
+ } else {
+ // 鏈堝害鏁版嵁锛�30澶�
+ const month = 1;
+ for (let day = 1; day <= 30; day++) {
+ const period = `${year}-${month.toString().padStart(2, "0")}-${day
+ .toString()
+ .padStart(2, "0")}`;
+ data.push({
+ period: period,
+ area: blockSelectedArea.value,
+ productType: blockProductType.value,
+ sales: Math.floor(Math.random() * 50) + 20,
+ sort: day,
+ });
+ }
+ }
+
+ blockSalesData.value = data;
+ // 鏇存柊鍥捐〃
+ updateCharts();
+ };
+
+ // 鐢熸垚鏉挎潗閿�鍞暟鎹�
+ const generateBoardSalesData = () => {
+ const data = [];
+ const year = 2024;
+
+ if (boardTimeDimension.value === "year") {
+ // 骞村害鏁版嵁锛�12涓湀
+ for (let month = 1; month <= 12; month++) {
+ const period = `${year}-${month.toString().padStart(2, "0")}`;
+ data.push({
+ period: period,
+ area: boardSelectedArea.value,
+ productType: boardProductType.value,
+ sales: Math.floor(Math.random() * 400) + 600,
+ sort: month,
+ });
+ }
+ } else {
+ // 鏈堝害鏁版嵁锛�30澶�
+ const month = 1;
+ for (let day = 1; day <= 30; day++) {
+ const period = `${year}-${month.toString().padStart(2, "0")}-${day
+ .toString()
+ .padStart(2, "0")}`;
+ data.push({
+ period: period,
+ area: boardSelectedArea.value,
+ productType: boardProductType.value,
+ sales: Math.floor(Math.random() * 40) + 15,
+ sort: day,
+ });
+ }
+ }
+
+ boardSalesData.value = data;
+ // 鏇存柊鍥捐〃
+ updateCharts();
+ };
+
// 鐩戝惉绐楀彛澶у皬鍙樺寲
const handleResize = () => {
console.log("resize");
@@ -1221,9 +1541,16 @@
endDate.format("YYYY-MM-DD"),
];
+ // 鐢熸垚鍒濆鏁版嵁
+ generateBlockSalesData();
+ generateBoardSalesData();
+
// 绛夊緟DOM鏇存柊鍚庡垵濮嬪寲鍥捐〃
nextTick(() => {
initCharts();
+ // 鍚姩琛ㄦ牸婊氬姩鍔ㄧ敾
+ startBlockTableScroll();
+ startBoardTableScroll();
});
// 娣诲姞绐楀彛澶у皬鍙樺寲鐩戝惉
@@ -1463,15 +1790,22 @@
border-bottom: 0.1vh solid rgba(64, 158, 255, 0.25);
}
- .panel-tabs {
+ .panel-tabs,
+ .panel-tabs2 {
position: absolute;
top: 0.8vh;
- right: 1.2vh;
display: flex;
gap: 0.6vh;
z-index: 4;
}
+ .panel-tabs {
+ right: 1.2vh;
+ }
+
+ .panel-tabs2 {
+ right: 8vh;
+ }
.tab-item {
font-size: 1.2vh;
color: rgba(184, 200, 224, 0.75);
@@ -1479,6 +1813,7 @@
border: 0.1vh solid rgba(64, 158, 255, 0.25);
border-radius: 0.3vh;
line-height: 1.4;
+ cursor: pointer;
}
.tab-item.active {
@@ -1490,6 +1825,76 @@
.bi-panel-body {
flex: 1;
padding: 0.8vh 1vh;
+ position: relative;
+ }
+
+ .scroll-table-container {
+ height: 33vh;
+ overflow: hidden;
+ position: relative;
+ }
+
+ .scroll-table {
+ width: 100%;
+ border-collapse: collapse;
+ color: #b8c8e0;
+ }
+
+ .scroll-table th {
+ /* background-color: #0e2a54; */
+ padding: 1.2vh;
+ text-align: left;
+ font-size: 1.2vh;
+ font-weight: bold;
+ border: 1px solid rgba(184, 200, 224, 0.2);
+ }
+
+ .scroll-table td {
+ padding: 1vh;
+ font-size: 1.1vh;
+ border-bottom: 1px solid rgba(184, 200, 224, 0.1);
+ }
+
+ .scroll-table tbody {
+ display: block;
+ height: 35vh;
+ overflow: hidden;
+ }
+
+ .scroll-table thead,
+ .scroll-table tbody tr {
+ display: table;
+ width: 100%;
+ table-layout: fixed;
+ }
+
+ .scroll-table th,
+ .scroll-table td {
+ width: 25%;
+ box-sizing: border-box;
+ font-size: 1.4vh;
+ }
+
+ .scroll-table tbody tr {
+ transition: all 0.5s ease-in-out;
+ }
+
+ /* .scroll-table tbody tr:nth-child(odd) {
+ background-color: rgba(64, 158, 255, 0.05);
+ }
+
+ .scroll-table tbody tr:nth-child(even) {
+ background-color: rgba(64, 158, 255, 0.1);
+ } */
+ .oddTableTr {
+ background-color: rgba(64, 158, 255, 0.05);
+ }
+ .evenTableTr {
+ background-color: rgba(64, 158, 255, 0.1);
+ }
+
+ .scroll-table-container:hover tbody {
+ overflow: hidden;
}
.echart-fill {
@@ -1501,6 +1906,7 @@
display: flex;
gap: 0.6vh;
margin: 0 0 0.5vh 0;
+ justify-self: end;
}
.cf-tab {
@@ -1510,6 +1916,7 @@
border: 0.1vh solid rgba(64, 158, 255, 0.25);
padding: 0.3vh 0.9vh;
line-height: 1;
+ cursor: pointer;
}
.cf-tab.active {
@@ -1542,11 +1949,44 @@
gap: 0.8vh;
font-size: 1.8vh;
color: #d9ecff;
- font-weight: 700;
- margin: 0 0 0.8vh 0;
- line-height: 1;
}
+ /* 闈㈡澘搴曢儴鍚堣琛� */
+ .panel-summary-row {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 0.8vh 1.2vh;
+ /* margin-top: 0.8vh; */
+ background: #041e3c;
+ border-top: 0.1vh solid rgba(64, 158, 255, 0.25);
+ border-radius: 0 0 0.4vh 0.4vh;
+ width: 100%;
+ position: absolute;
+ bottom: 0;
+ }
+
+ .summary-label {
+ font-size: 1.3vh;
+ font-weight: 700;
+ color: #b8c8e0;
+ }
+
+ .summary-value {
+ font-size: 1.4vh;
+ font-weight: 800;
+ color: #00a4ed;
+ margin-right: 3.8vh;
+ text-shadow: 0 0 1vh rgba(0, 164, 237, 0.5);
+ }
+
+ .summary-value2 {
+ font-size: 1.4vh;
+ font-weight: 800;
+ color: #00a4ed;
+ margin-right: 5.8vh;
+ text-shadow: 0 0 1vh rgba(0, 164, 237, 0.5);
+ }
.diamond {
width: 1vh;
height: 1vh;
@@ -1589,6 +2029,11 @@
.bi-panel-bottom-left {
grid-column: 1;
grid-row: 2;
+ overflow-y: auto;
+ }
+ .bi-panel-bottom-left::-webkit-scrollbar {
+ width: 0vh;
+ height: 0vh;
}
.bi-panel-bottom-center {
@@ -1599,6 +2044,11 @@
.bi-panel-bottom-right {
grid-column: 3;
grid-row: 2;
+ overflow-y: auto;
+ }
+ .bi-panel-bottom-right::-webkit-scrollbar {
+ width: 0vh;
+ height: 0vh;
}
/* 涓績鐜诞灞傦紙缁濆瀹氫綅鍦ㄧ綉鏍间笂鏂癸級 */
@@ -1630,7 +2080,7 @@
width: 100%;
height: 100%;
object-fit: contain;
- filter: drop-shadow(0 0 20px rgba(0, 164, 237, 0.35));
+ filter: drop-shadow(0 0 2vh rgba(0, 164, 237, 0.35));
}
.center-ring-content {
@@ -1730,13 +2180,13 @@
.m1 {
top: 2.5vh;
- left: 2.3vw;
+ left: 4.8vh;
text-align: left;
}
.m2 {
top: 4.1vh;
- right: 4.3vw;
+ right: 8.6vh;
text-align: right;
}
@@ -1787,4 +2237,46 @@
right: 4.4vh;
}
}
-</style>
\ No newline at end of file
+ .scroll-table-content {
+ height: 39vh;
+ overflow: auto;
+ }
+ .scroll-table-content::-webkit-scrollbar {
+ width: 0;
+ height: 0;
+ background-color: transparent;
+ }
+ .total-row {
+ position: absolute;
+ bottom: 0vh;
+ left: 0;
+ width: 100%;
+ display: flex;
+ height: 3.5vh;
+ justify-content: space-around;
+ align-items: center;
+ background-color: #081843;
+ }
+
+ .total-cell {
+ width: 20%;
+ font-size: 1.4vh;
+ margin-bottom: 0.5vh;
+ line-height: 3.5vh;
+ padding-left: 0.8vh;
+ color: #eaf6ff;
+ text-shadow: 0 0 0.8vh rgba(0, 229, 255, 0.22);
+ text-align: left;
+ color: #c3c3c3;
+ }
+ .total-cell2 {
+ width: 20%;
+ font-size: 1.4vh;
+ margin-bottom: 0.5vh;
+ line-height: 3.5vh;
+ color: #eaf6ff;
+ text-shadow: 0 0 0.8vh rgba(0, 229, 255, 0.22);
+ text-align: left;
+ color: #c3c3c3;
+ }
+</style>
--
Gitblit v1.9.3