123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- <script lang="ts" setup>
- import * as echarts from 'echarts';
- import { onBeforeUnmount, onMounted, ref } from 'vue';
- import { getChartData } from '/src/views/score-statistics/api';
- let chartObj: any;
- const chartRef = ref(null);
- const loading = ref(false);
- const newAverageScores = ref([]);
- const oldAverageScores = ref([]);
- const newStarRatings = ref<number[][]>([]);
- const oldStarRatings = ref<number[][]>([]);
- // 初始化 ECharts 图表
- onMounted(() => {
- addResize();
- initLine();
- });
- // 组件卸载前清理
- onBeforeUnmount(() => {
- if (chartObj) {
- chartObj.dispose();
- chartObj = null;
- }
- removeResize();
- });
- // ECharts 配置项
- const option: any = {
- // dataset: {
- // source: [],
- // },
- title: {
- left: '0%',
- text: '每月平均评分',
- textStyle: {
- fontSize: '16px',
- fontWeight: '500',
- },
- },
- tooltip: {
- trigger: 'axis',
- },
- legend: {
- top: '10%',
- align: 'right',
- },
- grid: {
- top: '30%',
- left: '5%',
- right: '5%',
- bottom: '5%',
- containLabel: true,
- },
- xAxis: {
- type: 'category',
- data: [],
- },
- yAxis: [
- {
- type: 'value',
- name: '平均评分',
- min: 2,
- max: 5,
- interval: 0.5,
- position: 'left',
- axisLine: {
- show: true,
- lineStyle: {
- color: '#70b6e3',
- },
- },
- axisLabel: {
- formatter: '{value} 分',
- },
- },
- {
- type: 'value',
- name: '评分数量',
- min: 0,
- position: 'right',
- splitLine: {
- show: false,
- },
- axisLine: {
- show: true,
- lineStyle: {
- color: '#5470c6',
- },
- },
- axisLabel: {
- formatter: '{value} 个',
- },
- },
- ],
- series: [
- {
- id: 0,
- name: '新品平均评分',
- type: 'line',
- yAxisIndex: 0,
- itemStyle: {
- color: '#70b6e3', //改变折线点的颜色
- lineStyle: {
- color: '#70b6e3', //改变折线颜色
- },
- },
- data: [],
- },
- {
- id: 1,
- name: '旧品平均评分',
- type: 'line',
- yAxisIndex: 0,
- itemStyle: {
- color: '#8170cc', //改变折线点的颜色
- lineStyle: {
- color: '#3f3da4', //改变折线颜色
- },
- },
- data: [],
- },
- {
- name: '新品一星',
- type: 'bar',
- stack: 'stack1',
- yAxisIndex: 1,
- barGap: 0,
- barMaxWidth: '14px',
- itemStyle: {
- color: '#e7b3b3',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '旧品一星',
- type: 'bar',
- stack: 'stack1',
- yAxisIndex: 1,
- barGap: 0,
- barMaxWidth: '14px',
- itemStyle: {
- color: 'rgba(231,179,179,0.73)',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '新品二星',
- type: 'bar',
- stack: 'stack2',
- yAxisIndex: 1,
- barMaxWidth: '14px',
- itemStyle: {
- color: '#fdba74',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '旧品二星',
- type: 'bar',
- stack: 'stack2',
- yAxisIndex: 1,
- barMaxWidth: '14px',
- itemStyle: {
- color: 'rgba(253,186,116,0.79)',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '新品三星',
- type: 'bar',
- stack: 'stack3',
- yAxisIndex: 1,
- barMaxWidth: '14px',
- itemStyle: {
- color: '#eae09e',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '旧品三星',
- type: 'bar',
- stack: 'stack3',
- yAxisIndex: 1,
- barMaxWidth: '14px',
- itemStyle: {
- color: 'rgba(234,224,158,0.76)',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '新品四星',
- type: 'bar',
- yAxisIndex: 1,
- stack: 'stack4',
- barMaxWidth: '14px',
- itemStyle: {
- color: '#bae6fd',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '旧品四星',
- type: 'bar',
- yAxisIndex: 1,
- stack: 'stack4',
- barMaxWidth: '14px',
- itemStyle: {
- color: 'rgba(186,230,253,0.76)',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '新品五星',
- type: 'bar',
- stack: 'stack5',
- yAxisIndex: 1,
- barMaxWidth: '14px',
- itemStyle: {
- color: '#a6e3a1',
- //borderRadius: 4,
- },
- data: [],
- },
- {
- name: '旧品五星',
- type: 'bar',
- stack: 'stack5',
- yAxisIndex: 1,
- barMaxWidth: '14px',
- itemStyle: {
- color: 'rgba(166,227,161,0.66)',
- //borderRadius: 4,
- },
- data: [],
- },
- ],
- };
- // 初始化 ECharts 图表的函数
- async function initLine() {
- await loadData();
- chartObj = echarts.init(chartRef.value);
- chartObj.setOption(option, true);
- }
- // 加载数据
- async function loadData() {
- try {
- loading.value = true;
- const query = {};
- const resp = await getChartData(query);
- const trendData = resp.data;
- newAverageScores.value = trendData.new_avg_score.map((item) => item.avg_val);
- oldAverageScores.value = trendData.old_avg_score.map((item) => item.avg_val);
- option.xAxis.data = trendData.new_avg_score.map((item) => item.date);
- option.series[0].data = newAverageScores.value;
- option.series[1].data = oldAverageScores.value;
- trendData.reviews_items.forEach((item) => {
- const ratings = [item.reviews1_sum || 0, item.reviews2_sum || 0, item.reviews3_sum || 0, item.reviews4_sum || 0, item.reviews5_sum || 0];
- if (item.is_new_sku) {
- newStarRatings.value.push(ratings);
- } else {
- oldStarRatings.value.push(ratings);
- }
- });
- const starRatings = [newStarRatings, oldStarRatings];
- starRatings.forEach((ratings, i) => {
- ratings.value.forEach((rating, j) => {
- rating.forEach((value, k) => {
- option.series[2 * k + i + 2].data = option.series[2 * k + i + 2].data || [];
- option.series[2 * k + i + 2].data[j] = value;
- });
- });
- });
- } catch (e) {
- ElMessage.error('加载数据失败,请稍后再试');
- } finally {
- loading.value = false;
- }
- }
- // 处理窗口大小变化
- function resizeChart() {
- chartObj.resize();
- }
- // 添加窗口大小变化事件监听
- function addResize() {
- window.addEventListener('resize', resizeChart);
- }
- // 移除窗口大小变化事件监听
- function removeResize() {
- window.removeEventListener('resize', resizeChart);
- }
- </script>
- <template>
- <div v-loading="loading">
- <!-- 图表区域 -->
- <div ref="chartRef" style="width: 100%; height: 520px; background: #fff"></div>
- </div>
- </template>
- <style scoped></style>
|