Sfoglia il codice sorgente

feat: 趋势模块开发

周玉环 10 ore fa
parent
commit
de8ba90358

BIN
xinkeaboard-admin/src/assets/bigscreen/bar-head.png


+ 19 - 0
xinkeaboard-admin/src/assets/bigscreen/bar-head.svg

@@ -0,0 +1,19 @@
+<svg width="15" height="14" viewBox="0 0 15 14" fill="none" xmlns="http://www.w3.org/2000/svg">
+<path d="M7.54688 4.90234L0.893555 8.70996V4.09668L7.54688 0.289062V4.90234Z" fill="#29F1FA" stroke="#28F1FA" stroke-width="0.336257" stroke-linejoin="round"/>
+<path d="M14.5576 4.09766V8.70996L7.89258 4.90234L7.88281 0.289062L14.5576 4.09766Z" fill="#29F1FA" stroke="#28F1FA" stroke-width="0.336257" stroke-linejoin="round"/>
+<path d="M7.72559 8.0415L14.7256 4.0415V9.0415L7.72559 13.0415V8.0415Z" fill="#29F1FA"/>
+<path d="M7.72559 8.0415L14.7256 4.0415V9.0415L7.72559 13.0415V8.0415Z" fill="url(#paint0_linear_417_19693)" fill-opacity="0.2"/>
+<path d="M0.725586 4.0415L7.72559 8.0415V13.0415L0.725586 9.0415V4.0415Z" fill="#29F1FA"/>
+<path d="M0.725586 4.0415L7.72559 8.0415V13.0415L0.725586 9.0415V4.0415Z" fill="url(#paint1_linear_417_19693)" fill-opacity="0.2"/>
+<path d="M7.72557 0.0414262L14.7256 4.0415L7.7256 8.04147L0.725586 4.04145L7.72557 0.0414262Z" fill="#29F1FA"/>
+<defs>
+<linearGradient id="paint0_linear_417_19693" x1="11.2091" y1="4.57666" x2="11.2091" y2="13.6117" gradientUnits="userSpaceOnUse">
+<stop/>
+<stop offset="1" stop-opacity="0"/>
+</linearGradient>
+<linearGradient id="paint1_linear_417_19693" x1="4.2201" y1="4.57666" x2="4.2201" y2="13.6117" gradientUnits="userSpaceOnUse">
+<stop/>
+<stop offset="1" stop-opacity="0"/>
+</linearGradient>
+</defs>
+</svg>

+ 100 - 0
xinkeaboard-admin/src/pages/statistics/bigscreen/components/BarChart.js

@@ -0,0 +1,100 @@
+import React from "react";
+import styles from "../styles/bar_chart.less";
+import * as echarts from "echarts";
+import topIcon from "../../../../assets/bigscreen/bar-head.svg";
+
+class BarChart extends React.Component {
+  constructor(props) {
+    super(props);
+    this.chartRef = React.createRef();
+    this.chartInstance = null;
+  }
+
+  componentDidMount() {
+    this.initChart();
+  }
+
+  componentDidUpdate(prevProps) {
+    this.initChart();
+  }
+
+  componentWillUnmount() {
+    if (this.chartInstance) {
+      this.chartInstance.dispose();
+    }
+  }
+
+  initChart() {
+    if (!this.chartInstance) {
+      this.chartInstance = echarts.init(this.chartRef.current);
+    }
+    const option = {
+      tooltip: {
+        trigger: "item", // 鼠标悬浮触发方式:'item' 或 'axis'
+      },
+      xAxis: {
+        type: "category",
+        data: this.props.xAxisdata,
+        axisLabel: {
+          show: true,
+          fontWeight: 400,
+          fontSize: "16px",
+          color: "#FFFFFF",
+        },
+      },
+      yAxis: {
+        type: "value",
+        axisLabel: {
+          show: true,
+          fontWeight: 400,
+          fontSize: "16px",
+          color: "#FFFFFF",
+        },
+        splitLine: {
+          // y 轴竖直方向虚线
+          show: true,
+          lineStyle: {
+            type: "dashed",
+            color: "#ccc",
+          },
+        },
+      },
+      series: [
+        {
+          data: this.props.seriesData,
+          type: "bar",
+          barWidth: 28,
+          itemStyle: {
+            color: new echarts.graphic.LinearGradient(
+              0,
+              0,
+              0,
+              1, // 0,0到0,1表示从上到下
+              [
+                { offset: 0, color: "#125CB2" }, // 顶部颜色
+                { offset: 1, color: "rgba(18,92,178,0)" }, // 底部透明
+              ]
+            ),
+          },
+        },
+        {
+          type: "pictorialBar",
+          symbol: `image://${topIcon}`, // 图片 URL
+          symbolSize: [30, 30], // 图片大小
+          symbolPosition: "end", // 关键:自动到柱子最高点
+
+          symbolOffset: [0, -15], // 向上偏移,让图片在柱子顶部
+          data: this.props.seriesData,
+          z: 4,
+        },
+      ],
+    };
+    this.chartInstance.setOption(option);
+  }
+
+  render() {
+    return <div className={styles.bar_chart} ref={this.chartRef} />;
+  }
+}
+
+export default BarChart;

+ 35 - 14
xinkeaboard-admin/src/pages/statistics/bigscreen/components/EnquirePieChart.js

@@ -1,13 +1,14 @@
 import React from "react";
 import * as echarts from "echarts";
 import styles from "../styles/enquire_pie_chart.less";
-import "echarts-gl"; // 如果要用真正的3D图
 
 class Pie3DChart extends React.Component {
   constructor(props) {
     super(props);
     this.chartRef = React.createRef();
     this.chartInstance = null;
+    this.startColor = [126, 206, 244]; // RGB 起点
+    this.endColor = [64, 50, 166]; // RGB 终点
   }
 
   componentDidMount() {
@@ -24,30 +25,48 @@ class Pie3DChart extends React.Component {
     }
   }
 
+  colorScale(index, total) {
+    const { startColor, endColor } = this;
+    return `rgb(${Math.round(
+      startColor[0] + ((endColor[0] - startColor[0]) * index) / (total - 1)
+    )}, 
+             ${Math.round(
+               startColor[1] +
+                 ((endColor[1] - startColor[1]) * index) / (total - 1)
+             )}, 
+             ${Math.round(
+               startColor[2] +
+                 ((endColor[2] - startColor[2]) * index) / (total - 1)
+             )})`;
+  }
+
   initChart() {
     if (!this.chartInstance) {
       this.chartInstance = echarts.init(this.chartRef.current);
     }
+
     const option = {
-      color: ["#7ECEF4", "#2EA7E0", "#036EB8", "#004E9D"], // 统一调色板
+      color: this.props.data.map((item, index) =>
+        this.colorScale(index, this.props.data.length)
+      ), // 自动生成渐变颜色
+      tooltip: {
+        trigger: "item",
+      },
       legend: {
-        itemGap: 30,
+        itemGap: 35,
         bottom: 0,
         textStyle: { color: "#fff" },
       },
       series: [
         {
-        //   name: "访问来源",
+          //   name: 'Access From',
           type: "pie",
-          radius: ["0", "60%"],
-          center: ["50%", "45%"],
+          radius: ["40%", "70%"],
           avoidLabelOverlap: false,
           itemStyle: {
-            borderRadius: 5,
-            borderColor: "#0b0c1b",
-            borderWidth: 3,
-            // shadowBlur: 20,
-            // shadowColor: "rgba(0, 0, 0, 0.5)",
+            borderRadius: 10,
+            // borderColor: "#fff",
+            borderWidth: 2,
           },
           label: {
             show: false,
@@ -56,12 +75,14 @@ class Pie3DChart extends React.Component {
           emphasis: {
             label: {
               show: true,
-              fontSize: "16",
+              fontSize: 16,
               fontWeight: "bold",
             },
           },
-          //   labelLine: { show: false },
-          data: this.props.data
+          labelLine: {
+            show: false,
+          },
+          data: this.props.data,
         },
       ],
     };

+ 38 - 0
xinkeaboard-admin/src/pages/statistics/bigscreen/components/addMemberTrend.js

@@ -0,0 +1,38 @@
+import React from "react";
+import { connect } from "dva";
+import PanelNav from "./PanelNav";
+import BarChart from "./BarChart";
+import styles from "../styles/add_member_trend.less";
+
+const AddMemberTrend = ({ data, loading, dispatch }) => {
+  const parseData = (barData) => {
+    const xAxisdata = [];
+    const seriesData = [];
+
+    barData.forEach((item) => {
+      xAxisdata.push(item.month);
+      seriesData.push(item.newMemberNum);
+    });
+
+    return {
+      xAxisdata,
+      seriesData,
+    };
+  };
+
+  return (
+    <div className={styles.member}>
+      <div className={styles.member_header}>
+        <PanelNav title="新增会员趋势" />
+      </div>
+      <div className={styles.member_content}>
+        <BarChart { ...parseData(data) }/>
+      </div>
+    </div>
+  );
+};
+
+export default connect(({ bigscreen }) => ({
+  data: bigscreen.memberAddTrendData.data,
+  loading: bigscreen.memberAddTrendData.loading,
+}))(AddMemberTrend);

+ 37 - 0
xinkeaboard-admin/src/pages/statistics/bigscreen/components/addProductTrend.js

@@ -0,0 +1,37 @@
+import React from "react";
+import { connect } from "dva";
+import PanelNav from "./PanelNav";
+import BarChart from "./BarChart";
+import styles from "../styles/add_product_trend.less";
+
+const AddProductTrend = ({ data, loading, dispatch }) => {
+  const parseData = (barData) => {
+    const xAxisdata = [];
+    const seriesData = [];
+
+    barData.forEach((item) => {
+      xAxisdata.push(item.month);
+      seriesData.push(item.newGoodsNum);
+    });
+
+    return {
+      xAxisdata,
+      seriesData,
+    };
+  };
+  return (
+    <div className={styles.product}>
+      <div className={styles.product_header}>
+        <PanelNav title="新增商品趋势" />
+      </div>
+      <div className={styles.product_content}>
+        <BarChart {...parseData(data)} />
+      </div>
+    </div>
+  );
+};
+
+export default connect(({ bigscreen }) => ({
+  data: bigscreen.productAddTrendData.data,
+  loading: bigscreen.productAddTrendData.loading,
+}))(AddProductTrend);

+ 12 - 6
xinkeaboard-admin/src/pages/statistics/bigscreen/index.js

@@ -8,7 +8,9 @@ import OverView from "./components/Overview";
 import PortalTraffic from "./components/PortalTraffic";
 import Enquire from "./components/Enquire";
 import OverseasEnquireLocation from "./components/OverseasEnquireLocation";
-import DistributorEnquireLocation from './components/DistributorEnquireLocation';
+import DistributorEnquireLocation from "./components/DistributorEnquireLocation";
+import AddMemberTrend from "./components/addMemberTrend";
+import AddProductTrend from "./components/addProductTrend";
 
 @connect(({ bigscreen }) => ({
   bigscreen,
@@ -153,12 +155,12 @@ class BigScreen extends React.Component {
               <PanelBlock>
                 <Enquire />
               </PanelBlock>
-              <PanelBlock flexDirection='row'>
+              <PanelBlock flexDirection="row">
                 <PanelBlock>
-                  <OverseasEnquireLocation></OverseasEnquireLocation>
+                  <OverseasEnquireLocation />
                 </PanelBlock>
                 <PanelBlock>
-                  <DistributorEnquireLocation></DistributorEnquireLocation>
+                  <DistributorEnquireLocation />
                 </PanelBlock>
               </PanelBlock>
             </div>
@@ -170,8 +172,12 @@ class BigScreen extends React.Component {
               </PanelBlock>
               <PanelBlock />
               <PanelBlock height="500px" flexDirection="row">
-                <PanelBlock />
-                <PanelBlock />
+                <PanelBlock>
+                  <AddMemberTrend />
+                </PanelBlock>
+                <PanelBlock>
+                  <AddProductTrend />
+                </PanelBlock>
               </PanelBlock>
             </div>
 

+ 34 - 0
xinkeaboard-admin/src/pages/statistics/bigscreen/styles/add_member_trend.less

@@ -0,0 +1,34 @@
+.member {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+.member_header {
+  position: relative;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
+  height: 52px;
+  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+
+  &::after {
+    content: "";
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 112px;
+    height: 4px;
+    background: #06f7ff;
+  }
+}
+
+.member_content {
+  flex: 1;
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+}

+ 34 - 0
xinkeaboard-admin/src/pages/statistics/bigscreen/styles/add_product_trend.less

@@ -0,0 +1,34 @@
+.product {
+  position: relative;
+  width: 100%;
+  height: 100%;
+  display: flex;
+  flex-direction: column;
+}
+
+.product_header {
+  position: relative;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  width: 100%;
+  height: 52px;
+  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
+
+  &::after {
+    content: "";
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 112px;
+    height: 4px;
+    background: #06f7ff;
+  }
+}
+
+.product_content {
+  flex: 1;
+  width: 100%;
+  height: 100%;
+  padding: 20px;
+}

+ 4 - 0
xinkeaboard-admin/src/pages/statistics/bigscreen/styles/bar_chart.less

@@ -0,0 +1,4 @@
+.bar_chart {
+  width: 100%;
+  height: 100%;
+}

+ 72 - 0
xinkeaboard-admin/src/pages/statistics/models/bigscreen.js

@@ -83,6 +83,14 @@ export default {
       loading: false,
       data: [],
     },
+    memberAddTrendData: {
+      loading: false,
+      data: [],
+    },
+    productAddTrendData: {
+      loading: false,
+      data: [],
+    },
   },
 
   effects: {
@@ -194,6 +202,42 @@ export default {
       });
     },
 
+    // 新增会员趋势
+    *load_add_member_trend({ payload }, { put, call }) {
+      yield put({
+        type: "setMemberAddTrendData",
+        payload: { loading: true },
+      });
+      const response = yield call(
+        sldCommonService,
+        payload,
+        "get",
+        "v3/statistics/screen/analysis/memberTrend"
+      );
+      yield put({
+        type: "setMemberAddTrendData",
+        payload: { data: response.data, loading: false },
+      });
+    },
+
+    // 新增商品趋势
+    *load_add_product_trend({ payload }, { put, call }) {
+      yield put({
+        type: "setProductAddTrendData",
+        payload: { loading: true },
+      });
+      const response = yield call(
+        sldCommonService,
+        payload,
+        "get",
+        "v3/statistics/screen/analysis/goodsTrend"
+      );
+      yield put({
+        type: "setProductAddTrendData",
+        payload: { data: response.data, loading: false },
+      });
+    },
+
     // 初始化数据
     *load_data({ payload }, { put, call }) {
       // 调用 load_data
@@ -220,6 +264,16 @@ export default {
       yield put.resolve({
         type: "load_distributor_enquire_location",
       });
+
+      // 新增会员趋势
+      yield put.resolve({
+        type: "load_add_member_trend",
+      });
+
+      // 新增商品趋势 load_add_product_trend
+      yield put.resolve({
+        type: "load_add_product_trend",
+      });
     },
   },
 
@@ -269,6 +323,24 @@ export default {
         },
       };
     },
+    setMemberAddTrendData(state, { payload }) {
+      return {
+        ...state,
+        memberAddTrendData: {
+          ...state.memberAddTrendData,
+          ...payload,
+        },
+      };
+    },
+    setProductAddTrendData(state, { payload }) {
+      return {
+        ...state,
+        productAddTrendData: {
+          ...state.productAddTrendData,
+          ...payload,
+        },
+      };
+    },
   },
 
   subscriptions: {