| | |
| | | title="æ°å¢å®¢æ·è¶å¿åæ" /> |
| | | <div class="panel-tabs"> |
| | | <span class="tab-item" |
| | | :class="{ active: customerTimeDimension === 'year' }" |
| | | @click="handleCustomerTimeDimensionChange('year')">å¹´</span> |
| | | :class="{ active: customerTimeDimension === 'å¹´' }" |
| | | @click="handleCustomerTimeDimensionChange('å¹´')">å¹´</span> |
| | | <span class="tab-item" |
| | | :class="{ active: customerTimeDimension === 'month' }" |
| | | @click="handleCustomerTimeDimensionChange('month')">æ</span> |
| | | :class="{ active: customerTimeDimension === 'æ' }" |
| | | @click="handleCustomerTimeDimensionChange('æ')">æ</span> |
| | | </div> |
| | | <div class="bi-panel-body"> |
| | | <div class="chart-unit-row chart-unit-single"> |
| | |
| | | import * as echarts from "echarts"; |
| | | import dayjs from "dayjs"; |
| | | import PanelHeader from "@/views/reportAnalysis/PSIDataAnalysis/components/PanelHeader.vue"; |
| | | import { findAllQualifiedStockOutRecordTypeOptions } from "../../../api/basicData/enum"; |
| | | import { |
| | | getDashboardStatistics, |
| | | getCustomerTrends, |
| | | } from "@/api/reportAnalysis/salesStatistics"; |
| | | |
| | | const router = useRouter(); |
| | | const screenRoot = ref(null); |
| | |
| | | const boardTimeDimension = ref("year"); |
| | | const boardSelectedArea = ref("å
¨é¨"); |
| | | const boardProductType = ref("æ¿æ"); |
| | | const customerTimeDimension = ref("year"); |
| | | const customerTimeDimension = ref("å¹´"); |
| | | |
| | | const salesAreas = [ |
| | | "å
¨é¨", |
| | |
| | | }); |
| | | |
| | | const totalSalesAmount = ref(1299); |
| | | const centerNewCustomerCount = ref(112); |
| | | const completedOrders = ref(1829); |
| | | const totalSalesAreaCount = ref(12); |
| | | |
| | | const newCustomerCount = computed(() => { |
| | | return filteredData.value.reduce((sum, item) => sum + item.newCustomers, 0); |
| | |
| | | return Object.values(customerMap).reduce((sum, count) => sum + count, 0); |
| | | }); |
| | | |
| | | // ä¸é´ä¸å¿ç¯ææ ï¼ç¨äºå¤§å±å±ç¤ºï¼ä½¿ç¨ç°æç»è®¡æ°æ®åæ å°ï¼ |
| | | const centerNewCustomerCount = computed(() => 112); |
| | | const completedOrders = computed(() => 1829); |
| | | const salesOrderCount = computed(() => 34); |
| | | const totalSalesAreaCount = computed(() => 12); |
| | | // 客æ·è¶å¿æ°æ® |
| | | const customerTrendsData = ref([]); |
| | | |
| | | // ååç计ç®ï¼æ¨¡æï¼ |
| | | const salesVolumeChange = ref("+5.2"); |
| | | const salesAmountChange = ref("+7.8"); |
| | | const customerCountChange = ref("+3.5"); |
| | | const totalCustomerChange = ref("+2.1"); |
| | | |
| | | // è·åä¸å¿çæ¿æ°æ® |
| | | const fetchDashboardData = async () => { |
| | | try { |
| | | const response = await getDashboardStatistics(); |
| | | if (response && response.data) { |
| | | totalSalesAmount.value = response.data.price || 0; |
| | | completedOrders.value = response.data.delivery || 0; |
| | | centerNewCustomerCount.value = response.data.customer || 0; |
| | | totalSalesAreaCount.value = response.data.totalSalesAreaCount || 0; |
| | | } |
| | | } catch (error) { |
| | | console.error("è·åä¸å¿çæ¿æ°æ®å¤±è´¥:", error); |
| | | } |
| | | }; |
| | | |
| | | // è·å客æ·è¶å¿æ°æ® |
| | | const fetchCustomerTrendsData = async () => { |
| | | try { |
| | | const response = await getCustomerTrends({ |
| | | days: customerTimeDimension.value, |
| | | }); |
| | | if (response && response.data) { |
| | | // APIè¿åçæ°æ®ç»æå¦ä¸ï¼ |
| | | // { |
| | | // "dates": ["2026-01-01", "2025-01-01", ...], |
| | | // "customerTrends": [{"ALLIN": 4, "é¶å·": 3, ...}, ...] |
| | | // } |
| | | customerTrendsData.value = response.data; |
| | | updateCharts(); |
| | | } |
| | | } catch (error) { |
| | | console.error("è·å客æ·è¶å¿æ°æ®å¤±è´¥:", error); |
| | | } |
| | | }; |
| | | |
| | | // è¡¨æ ¼æ°æ® |
| | | const tableData = computed(() => { |
| | |
| | | right: "1%", |
| | | textStyle: { |
| | | color: "#B8C8E0", |
| | | fontSize: getResponsiveValue(9), |
| | | fontSize: getResponsiveValue(10), |
| | | }, |
| | | itemWidth: getResponsiveValue(10), |
| | | itemHeight: getResponsiveValue(10), |
| | |
| | | right: "1%", |
| | | textStyle: { |
| | | color: "#B8C8E0", |
| | | fontSize: getResponsiveValue(9), |
| | | fontSize: getResponsiveValue(10), |
| | | }, |
| | | itemWidth: getResponsiveValue(10), |
| | | itemHeight: getResponsiveValue(10), |
| | |
| | | |
| | | // æ°å¢å®¢æ·è¶å¿å¾è¡¨é
ç½®ï¼æéå®åºåå¹´æç»´åº¦ï¼ |
| | | const productTypeTrendChartOption = computed(() => { |
| | | // 为æ¯ä¸ªéå®åºçææ°æ® |
| | | const salesAreas = [ |
| | | "å
¨é¨", |
| | | "Aéå®åº", |
| | | "Béå®åº", |
| | | "Céå®åº", |
| | | "Déå®åº", |
| | | "Eéå®åº", |
| | | ]; |
| | | const colors = [ |
| | | "#00A4ED", |
| | | "#34D8F7", |
| | |
| | | "#8A6BFF", |
| | | "#C8C447", |
| | | "#FF6B6B", |
| | | "#FF8B6B", |
| | | "#FFCB6B", |
| | | "#8BC34A", |
| | | "#4CAF50", |
| | | ]; |
| | | const year = 2024; |
| | | const periodType = customerTimeDimension.value; |
| | | |
| | | // çææ¶é´æ®µ |
| | | let periods = []; |
| | | let salesAreas = []; |
| | | let series = []; |
| | | |
| | | if ( |
| | | customerTrendsData.value && |
| | | customerTrendsData.value.dates && |
| | | customerTrendsData.value.customerTrends |
| | | ) { |
| | | // 使ç¨APIè¿åçæ°æ® |
| | | periods = customerTrendsData.value.dates; |
| | | |
| | | // æåææéå®åºå |
| | | const areaSet = new Set(); |
| | | customerTrendsData.value.customerTrends.forEach(item => { |
| | | Object.keys(item).forEach(key => { |
| | | areaSet.add(key); |
| | | }); |
| | | }); |
| | | salesAreas = Array.from(areaSet); |
| | | |
| | | // 为æ¯ä¸ªéå®åºåçææ°æ® |
| | | series = salesAreas.map((area, index) => { |
| | | const data = customerTrendsData.value.customerTrends.map((item, i) => { |
| | | return item[area] || 0; |
| | | }); |
| | | |
| | | return { |
| | | name: area, |
| | | data: data, |
| | | type: "line", |
| | | smooth: false, |
| | | lineStyle: { |
| | | width: getResponsiveValue(1), |
| | | color: colors[index % colors.length], |
| | | }, |
| | | itemStyle: { color: colors[index % colors.length] }, |
| | | }; |
| | | }); |
| | | } else { |
| | | // æ¨¡ææ°æ® |
| | | const year = 2024; |
| | | if (periodType === "year") { |
| | | // å¹´åº¦æ°æ®ï¼12个æ |
| | | for (let month = 1; month <= 12; month++) { |
| | |
| | | } |
| | | } |
| | | |
| | | // 为æ¯ä¸ªéå®åºçææ°æ® |
| | | const series = salesAreas.map((area, index) => { |
| | | salesAreas = []; |
| | | series = salesAreas.map((area, index) => { |
| | | const data = periods.map(() => { |
| | | return periodType === "year" |
| | | ? Math.floor(Math.random() * 10) + 2 |
| | |
| | | itemStyle: { color: colors[index] }, |
| | | }; |
| | | }); |
| | | } |
| | | |
| | | return { |
| | | backgroundColor: "transparent", |
| | |
| | | right: "1%", |
| | | textStyle: { |
| | | color: "#B8C8E0", |
| | | fontSize: getResponsiveValue(9), |
| | | fontSize: getResponsiveValue(10), |
| | | }, |
| | | itemWidth: getResponsiveValue(10), |
| | | itemHeight: getResponsiveValue(10), |
| | |
| | | // å¤çæ°å¢å®¢æ·è¶å¿æ¶é´ç»´åº¦åæ¢ |
| | | const handleCustomerTimeDimensionChange = dimension => { |
| | | customerTimeDimension.value = dimension; |
| | | updateCharts(); |
| | | fetchCustomerTrendsData(); |
| | | }; |
| | | |
| | | // çæç åé宿°æ® |
| | |
| | | }; |
| | | |
| | | // çå½å¨æ |
| | | onMounted(() => { |
| | | onMounted(async () => { |
| | | // å¯å¨é¡¶é¨æ æ¶é´å·æ° |
| | | if (!timeTicker) { |
| | | timeTicker = setInterval(() => { |
| | |
| | | generateBlockSalesData(); |
| | | generateBoardSalesData(); |
| | | |
| | | // è·åæ°æ® |
| | | await fetchDashboardData(); |
| | | await fetchCustomerTrendsData(); |
| | | |
| | | // çå¾
DOMæ´æ°ååå§åå¾è¡¨ |
| | | nextTick(() => { |
| | | initCharts(); |