丁烨烨 2 месяцев назад
Родитель
Сommit
b9a885a21c
3 измененных файлов с 426 добавлено и 79 удалено
  1. 1 1
      next-env.d.ts
  2. 2 1
      package.json
  3. 423 77
      src/components/about/ContactUs.tsx

+ 1 - 1
next-env.d.ts

@@ -1,6 +1,6 @@
 /// <reference types="next" />
 /// <reference types="next/image-types/global" />
-import "./.next/dev/types/routes.d.ts";
+import "./.next/types/routes.d.ts";
 
 // NOTE: This file should not be edited
 // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.

+ 2 - 1
package.json

@@ -12,7 +12,8 @@
     "@ant-design/nextjs-registry": "^1.1.0",
     "@ant-design/v5-patch-for-react-19": "^1.0.3",
     "antd": "^5.27.2",
-    "axios": "^1.11.0",
+    "axios": "1.13.5",
+    "echarts": "^6.0.0",
     "framer-motion": "^12.23.19",
     "lucide-react": "^0.542.0",
     "next": "16.1.5",

+ 423 - 77
src/components/about/ContactUs.tsx

@@ -1,84 +1,430 @@
 'use client'
-import React, {useEffect} from 'react';
+import React, { useEffect, useRef, useState } from 'react';
 import SubTitle from "@/components/subTitle";
-// import {BDMapGL} from "@/utils/BDMap";
 import Image from "next/image";
+// 引入 ECharts
+import * as echarts from 'echarts';
 
-function ContactUs({basicInfo, locationInfoList}: { basicInfo: BasicInfo, locationInfoList: LocationInfo[] }) {
-  const BASE_URL: string = process.env.NEXT_PUBLIC_BASE_URL as string;
-
-  // const BDMapInit = () => {
-  //   BDMapGL('94KOPB1NRjoXmLvlJN6HMi7eVC50z09K').then((BMapGL: any) => {
-  //     const map = new BMapGL.Map('container')
-  //     locationInfoList.forEach(point => {
-  //       const bmapPoint = new BMapGL.Point(point.longitude, point.latitude);
-  //       const marker = new BMapGL.Marker(bmapPoint);
-  //
-  //       // 创建信息窗口(内容可自定义 HTML)
-  //       const infoWindow = new BMapGL.InfoWindow(`
-  //           <div>
-  //             <h4>姓名:${point.name}</h4>
-  //             <p style="margin: 5px 0 0; color: #666;">区域:${point.marker}</p>
-  //             <p style="margin: 5px 0 10px; color: #666;">联系方式:${point.phone}</p>
-  //           </div>
-  //         `);
-  //
-  //       // 绑定点击事件:点击标记点显示信息窗口
-  //       marker.addEventListener("click", () => {
-  //         map.openInfoWindow(infoWindow, bmapPoint); // 在点位坐标处打开窗口
-  //       });
-  //
-  //       map.centerAndZoom(bmapPoint, 7)
-  //       map.enableScrollWheelZoom(true) //设置鼠标放大缩小
-  //       map.addControl(new BMapGL.ScaleControl()) //卡尺
-  //       map.addOverlay(marker)
-  //     });
-  //
-  //   })
-  // }
-  const qrCodeUrl = BASE_URL + basicInfo.qrCodeUrl
-  useEffect(() => {
-    // BDMapInit()
-  }, []);
-  return (
-    <>
-      {/* 联系我们 */}
-      <section id="section-4" className="scroll-mt-10 py-12 px-4">
-        <div className="w-4/5 mx-auto my-10 sm:my-6">
-          <SubTitle title="联系我们"/>
-        </div>
-        <div className="w-full sm:w-[80%] mx-auto">
-          <Image
-            src="/assets/about/25.jpg"
-            alt="contact"
-            width={1000}
-            height={1000}
-            className="w-full h-auto block sm:hidden"
-            unoptimized
-          />
-          <Image
-            src="/assets/about/24.jpg"
-            alt="contact"
-            width={1000}
-            height={1000}
-            className="w-full h-auto hidden sm:block"
-            unoptimized
-          />
-        </div>
-        {/* <div className="grid sm:grid-cols-1 md:grid-cols-2 gap-6">
-          <div className="h-88" id="container"></div>
-          <div className="space-y-4">
-            <div className="bg-gray-300 w-60 h-60">
-              <Image src={qrCodeUrl} alt={'qrcode'} width={500} height={500}/>
-            </div>
-            <p>电话:{basicInfo.telephone}</p>
-            <p>邮箱:{basicInfo.email}</p>
-            <p>地址:{basicInfo.address}</p>
-          </div>
-        </div> */}
-      </section>
-    </>
-  );
+// 定义类型接口
+interface BasicInfo {
+    qrCodeUrl: string;
+    telephone: string;
+    email: string;
+    address: string;
+}
+
+interface LocationInfo {
+    longitude: number;
+    latitude: number;
+    name: string;
+    marker: string;
+    phone: string;
+}
+
+// 定义需要响应交互的省份白名单(和data中的省份对应)
+const ALLOWED_PROVINCES = ["北京", "上海", "湖南", "四川", "广东"];
+
+function ContactUs({ basicInfo, locationInfoList }: { basicInfo: BasicInfo, locationInfoList: LocationInfo[] }) {
+    const BASE_URL: string = process.env.NEXT_PUBLIC_BASE_URL as string;
+    // 创建 ECharts 容器引用
+    const chartRef = useRef<HTMLDivElement>(null);
+    // 存储 ECharts 实例
+    let myChart: echarts.ECharts | null = null;
+    // 存储中国地图 GeoJSON 数据
+    const [chinaMapData, setChinaMapData] = useState<any>(null);
+
+    // 第一步:加载中国地图 GeoJSON 数据
+    useEffect(() => {
+        // 方式1:从公共 CDN 加载(推荐,无需本地文件)
+        fetch('https://cdn.jsdelivr.net/npm/echarts/map/json/china.json')
+            .then(res => res.json())
+            .then(data => {
+                setChinaMapData(data);
+            })
+            .catch(err => {
+                console.error('加载地图数据失败:', err);
+            });
+
+        // 方式2:如果想本地加载,把 china.json 放到 public 目录下,使用下面这行
+        // fetch('/china.json').then(res => res.json()).then(data => setChinaMapData(data));
+    }, []);
+
+    // 初始化 ECharts 中国地图
+    const initEchartsMap = () => {
+        if (!chartRef.current || !chinaMapData) return;
+
+        // 关键修复:手动注册中国地图
+        echarts.registerMap('china', chinaMapData);
+
+        // 初始化 ECharts 实例
+        myChart = echarts.init(chartRef.current);
+
+        // 地图数据定义
+        const mapName = 'china';
+        const data = [
+            { name: "北京", value: 100 },
+            { name: "上海", value: 100 },
+            { name: "湖南", value: 100 },
+            { name: "四川", value: 100 },
+            { name: "广东", value: 100 },
+        ];
+
+        const geoCoordMap: Record<string, number[]> = {};
+        const toolTipData = [
+            {
+                name: "北京", value: [
+                    { name: "刘经理", value: 17377770429 }
+                ]
+            },
+            {
+                name: "上海", value: [
+                    { name: "邹经理", value: 17747061438 }
+                ]
+            },
+            {
+                name: "湖南", value: [
+                    { name: "徐经理", value: 18888336871 }
+                ]
+            },
+            {
+                name: "四川", value: [
+                    { name: "刘经理", value: 17377770429 }
+                ]
+            },
+            {
+                name: "广东", value: [
+                    { name: "徐经理", value: 18888336871 }
+                ]
+            },
+        ];
+
+        // 修复:从加载的 GeoJSON 中获取地图特征(替代原来的 echarts.getMap)
+        const mapFeatures = chinaMapData.features || [];
+        mapFeatures.forEach(function (v: any) {
+            // 地区名称
+            const name = v.properties.name;
+            // 地区经纬度
+            geoCoordMap[name] = v.properties.cp;
+        });
+
+        // 数据转换函数
+        const convertData = function (data: any[]) {
+            const res: any[] = [];
+            for (let i = 0; i < data.length; i++) {
+                const geoCoord = geoCoordMap[data[i].name];
+                if (geoCoord) {
+                    res.push({
+                        name: data[i].name,
+                        value: geoCoord.concat(data[i].value),
+                    });
+                }
+            }
+            return res;
+        };
+
+        // 模拟 tooltipCharts 函数(如果需要实际功能,需补充实现)
+        const tooltipCharts = (name: string) => {
+            console.log('Tooltip charts for:', name);
+            // 这里可以添加 tooltip 内图表的渲染逻辑
+        };
+
+        // ECharts 配置项
+        const option = {
+            grid: {
+                left: '5%',    // 缩小左右边距,让地图占更多空间
+                right: '5%',
+                bottom: '5%',  // 缩小上下边距
+                top: '5%',
+            },
+            tooltip: {
+                padding: 10, // 增加内边距,提升美观度
+                enterable: true,
+                transitionDuration: 0.3, // 优化过渡动画
+                textStyle: {
+                    color: '#fff',
+                    fontSize: 14,
+                    decoration: 'none',
+                },
+                // 自定义tooltip样式
+                backgroundColor: 'rgba(22,80,158,0.9)',
+                borderColor: 'rgba(7,166,255,1)',
+                borderWidth: 1,
+                borderRadius: 6,
+                // 核心:精准匹配省份,展示「姓名 + 电话号码」格式
+                formatter: function (params: any) {
+                    // 非白名单省份直接返回空,不显示tooltip
+                    if (!ALLOWED_PROVINCES.includes(params.name)) return '';
+
+                    // 根据省份名称查找对应的联系方式
+                    const provinceData = toolTipData.find(item => item.name === params.name);
+                    if (!provinceData || !provinceData.value.length) {
+                        return `<div style="padding: 8px;">${params.name}:暂无联系方式</div>`;
+                    }
+
+                    // 拼接展示内容:名称 + 电话号码
+                    const contactInfo = provinceData.value[0];
+                    let tipHtml = `
+                        <div style="padding: 8px 0;">
+                            <div style="font-size: 16px; font-weight: 600; margin-bottom: 6px;">${params.name}</div>
+                            <div style="font-size: 14px; line-height: 1.5;">
+                                ${contactInfo.name}:${contactInfo.value}
+                            </div>
+                        </div>
+                    `;
+
+                    setTimeout(function () {
+                        tooltipCharts(params.name);
+                    }, 10);
+                    return tipHtml;
+                },
+                // 优化:只在鼠标移动时触发,移除点击触发(避免点击变色)
+                triggerOn: 'mousemove',
+                // 调整tooltip位置,避免遮挡
+                position: ['50%', '50%'],
+                confine: true // 限制tooltip在图表容器内显示
+            },
+            visualMap: {
+                show: false,
+                min: 0,
+                max: 200,
+                left: '10%',
+                top: 'bottom',
+                calculable: true,
+                seriesIndex: [1],
+                inRange: {
+                    color: ['#04387b', '#467bc0'] // 蓝绿
+                }
+            },
+            geo: {
+                show: true,
+                map: mapName,
+                // 核心:放大地图 - 设置地图中心和缩放级别
+                center: [105.00, 36.00], // 中国地理中心坐标(微调让地图居中)
+                zoom: 1.2, // 缩放级别(默认1,越大地图越大)
+                label: {
+                    normal: {
+                        show: false
+                    },
+                    emphasis: {
+                        show: false,
+                    }
+                },
+                roam: false,
+                itemStyle: {
+                    normal: {
+                        areaColor: '#023677',
+                        borderColor: '#1180c7',
+                    },
+                    // 核心修改1:移除悬停/点击变色效果,保持固定样式
+                    emphasis: {
+                        areaColor: '#023677', // 与normal状态一致,无变色
+                        borderColor: '#1180c7'
+                    }
+                },
+                // 调整地图的显示范围,进一步放大
+                boundingCoords: [
+                    [70, 15], // 西南角坐标
+                    [140, 55] // 东北角坐标
+                ],
+                // 保留geo层交互(用于tooltip),但移除样式变化
+                silent: false,
+                emphasis: {
+                    focus: 'none' // 移除焦点高亮效果
+                }
+            },
+            series: [{
+                name: '散点',
+                type: 'scatter',
+                coordinateSystem: 'geo',
+                data: convertData(data),
+                // 放大散点尺寸(从/10改为/8)
+                symbolSize: function (val: any[]) {
+                    return val[2] / 8;
+                },
+                label: {
+                    normal: {
+                        formatter: '{b}',
+                        position: 'right',
+                        show: true,
+                        fontSize: 14 // 放大文字大小
+                    },
+                    emphasis: {
+                        show: true
+                    }
+                },
+                itemStyle: {
+                    normal: {
+                        color: '#fff'
+                    }
+                },
+                // 禁用散点层交互
+                silent: true
+            },
+                {
+                    type: 'map',
+                    map: mapName,
+                    geoIndex: 0,
+                    aspectScale: 0.85, // 调整长宽比,让地图更舒展(原0.75)
+                    showLegendSymbol: false, // 存在legend时显示
+                    label: {
+                        normal: {
+                            show: true,
+                            fontSize: 13 // 放大省份名称文字
+                        },
+                        emphasis: {
+                            show: true, // 保持文字显示,不移除
+                            textStyle: {
+                                color: '#fff' // 文字颜色固定,不变色
+                            }
+                        }
+                    },
+                    roam: false, // 关闭地图拖拽缩放,避免误操作
+                    itemStyle: {
+                        normal: {
+                            areaColor: '#031525',
+                            borderColor: '#3B5077',
+                        },
+                        // 核心修改2:移除map层悬停/点击变色效果
+                        emphasis: {
+                            areaColor: '#031525', // 与normal状态一致
+                            borderColor: '#3B5077'
+                        }
+                    },
+                    animation: false,
+                    data: data,
+                    // 保留交互用于tooltip,但移除样式变化
+                    silent: false,
+                    // 启用tooltip但移除点击触发
+                    tooltip: {
+                        show: true,
+                        triggerOn: 'mousemove'
+                    }
+                },
+                {
+                    name: '点',
+                    type: 'scatter',
+                    coordinateSystem: 'geo',
+                    zlevel: 6,
+                    // 禁用空散点层的交互
+                    silent: true
+                },
+                {
+                    name: 'Top 5',
+                    type: 'effectScatter',
+                    coordinateSystem: 'geo',
+                    data: convertData(data.sort(function (a, b) {
+                        return b.value - a.value;
+                    }).slice(0, 10)),
+                    // 放大动态散点尺寸(从/10改为/8)
+                    symbolSize: function (val: any[]) {
+                        return val[2] / 8;
+                    },
+                    showEffectOn: 'render',
+                    rippleEffect: {
+                        brushType: 'stroke',
+                        scale: 2.0 // 放大涟漪效果
+                    },
+                    hoverAnimation: false, // 关闭悬停动画效果
+                    label: {
+                        normal: {
+                            formatter: '{b}',
+                            position: 'left',
+                            show: false
+                        }
+                    },
+                    itemStyle: {
+                        normal: {
+                            color: 'yellow',
+                            shadowBlur: 15, // 放大阴影效果
+                            shadowColor: 'yellow'
+                        }
+                    },
+                    zlevel: 1,
+                    // 禁用动态散点层交互
+                    silent: true
+                }]
+        };
+
+        // 设置并渲染配置项
+        myChart.setOption(option);
+
+        // 响应窗口大小变化
+        const resizeHandler = () => {
+            if (myChart) {
+                myChart.resize();
+            }
+        };
+
+        window.addEventListener('resize', resizeHandler);
+
+        // 核心修改3:手动禁用点击事件,确保点击无任何样式变化
+        myChart.off('click');
+        myChart.on('click', function (params) {
+            // 阻止点击事件的默认行为
+            return false;
+        });
+
+        // 返回清理函数
+        return () => {
+            window.removeEventListener('resize', resizeHandler);
+            if (myChart) {
+                myChart.dispose();
+                myChart = null;
+            }
+        };
+    };
+
+    // 处理 QR Code URL
+    const qrCodeUrl = BASE_URL + basicInfo.qrCodeUrl;
+
+    // 组件挂载时初始化(地图数据加载完成后才初始化)
+    useEffect(() => {
+        if (!chinaMapData) return;
+
+        // 初始化 ECharts 地图
+        const cleanupEcharts = initEchartsMap();
+
+        // 组件卸载时清理
+        return () => {
+            if (cleanupEcharts) cleanupEcharts();
+        };
+    }, [chinaMapData, locationInfoList, basicInfo.qrCodeUrl]);
+
+    return (
+        <>
+            {/* 联系我们 */}
+            <section id="section-4" className="scroll-mt-10 py-12 px-4">
+                <div className="w-4/5 mx-auto my-10 sm:my-6">
+                    <SubTitle title="联系我们" />
+                </div>
+                <div>
+                    <div className="w-4/5 mx-auto my-10 sm:my-6 grid sm:grid-cols-1 md:grid-cols-2 gap-6">
+                        {/* 核心:放大图表容器尺寸 */}
+                        <div
+                            className="w-full mx-auto my-10 sm:my-6 h-[500px]" // 宽度改为full,高度设为700px
+                            id="container"
+                            ref={chartRef}
+                            style={{ minWidth: '100%' }}
+                        ></div>
+                        <div className="w-4/5 mx-auto my-10 sm:my-6 space-y-4 flex flex-col justify-center">
+                            <div className="bg-gray-300 w-60 h-60">
+                                <Image
+                                    src={qrCodeUrl}
+                                    alt={'qrcode'}
+                                    width={500}
+                                    height={500}
+                                    className="w-full h-full object-contain"
+                                />
+                            </div>
+                            <p>电话:{basicInfo.telephone}</p>
+                            <p>邮箱:{basicInfo.email}</p>
+                            <p>地址:{basicInfo.address}</p>
+                        </div>
+                    </div>
+                </div>
+            </section>
+        </>
+    );
 }
 
 export default ContactUs;