WebApp【公共组件库】@前端(For Git Submodule)
‘chensiAb’
2025-04-10 15138a2ae174a53f3f4a1b319cd7659781a696e9
plugins/baiduMap/CBaiduMap.weapp.vue
@@ -28,7 +28,7 @@
                    type="primary"
                    size="small"
                    :onClick="evt => handleChooseLocation(evt)"
                >选择位置</AtButton>
                >选择地点</AtButton>
                <AtButton
                    type="primary"
                    size="small"
@@ -41,7 +41,7 @@
                    size="small"
                    class="btn-info"
                    :onClick="evt => handleSaveLocation(evt)"
                >保存</AtButton>
                >确认</AtButton>
            </view>
        </view>
    </view>
@@ -51,6 +51,7 @@
import Taro from '@tarojs/taro';
import { AtButton } from 'taro-ui-vue';
import { BAIDU_MAP, BMapWX } from './index';
import './cBaiduMap.scss';
export default {
    name: 'CBaiduMap',
@@ -69,68 +70,82 @@
    },
    data() {
        return {
            // 地图上下文
            mapCtx: null,
            // 地图是否准备就绪
            isMapReady: false,
            // 当前位置
            currentLocation: null,
            // 标记点id
            selectedMarkerId: 0,
            // 标记点列表
            markers: [],
            // 本地维护的坐标
            localLatitude: this.latitude,
            localLongitude: this.longitude,
            // 地图坐标
            mapLatitude: this.latitude,
            mapLongitude: this.longitude,
            // 地图缩放级别
            mapScale: 14,
            // 是否由chooseLocation触发移动
            isFromChooseLocation: false,
        };
    },
    watch: {
        latitude: {
            handler(newVal) {
                console.log(newVal, '纬度');
                if (newVal && this.longitude && this.isValidLatitude(newVal)) {
                    this.mapLatitude = newVal;
                    // 只在回显时更新本地坐标
                    this.localLatitude = newVal;
                    this.moveToLocation(newVal, this.longitude);
                    this.initLocation();
                }
            },
            immediate: true,
            immediate: false,
        },
        longitude: {
            handler(newVal) {
                console.log(newVal, '经度');
                if (newVal && this.latitude && this.isValidLongitude(newVal)) {
                    this.mapLongitude = newVal;
                    // 只在回显时更新本地坐标
                    this.localLongitude = newVal;
                    this.moveToLocation(this.latitude, newVal);
                    this.initLocation();
                }
            },
            immediate: true,
            immediate: false,
        },
    },
    mounted() {
        // 初始化地图
        this.initMap();
        // 如果有初始经纬度,添加标记点
        if (
            this.latitude &&
            this.longitude &&
            this.isValidLatitude(this.latitude) &&
            this.isValidLongitude(this.longitude)
        ) {
            this.initLocation();
        }
        // 设置一个延时,确保地图组件已完全加载
        setTimeout(() => {
            // 使用默认值处理可能的undefined或null
            const latitude = this.latitude || 39.90886;
            const longitude = this.longitude || 116.39739;
            // 确保坐标有效
            if (this.isValidLatitude(latitude) && this.isValidLongitude(longitude)) {
                this.localLatitude = latitude;
                this.localLongitude = longitude;
                this.initLocation();
            }
        }, 800);
    },
    methods: {
        // 验证纬度是否有效
        isValidLatitude(lat) {
            return lat >= -90 && lat <= 90;
        },
        // 验证经度是否有效
        isValidLongitude(lng) {
            return lng >= -180 && lng <= 180;
        },
        // 初始化地图
        initMap() {
            try {
                // 初始化地图上下文
                this.mapCtx = Taro.createMapContext('map', this);
                // 检查地图是否准备就绪
                this.checkMapReady();
            } catch (error) {
@@ -154,26 +169,34 @@
        // 地图区域改变事件
        async handleRegionChange(evt) {
            // 如果是由chooseLocation触发的移动,则不处理
            if (this.isFromChooseLocation) {
                return;
            }
            if (!evt.detail || !evt.detail.centerLocation) {
                return;
            }
            const { latitude, longitude } = evt.detail.centerLocation;
            if (!latitude || !longitude) {
                return;
            }
            try {
                // 将 GCJ-02 坐标转换为百度坐标用于获取地址
                const baiduCoords = this.gcj02ToBaidu(latitude, longitude);
                // 获取地址信息
                const address = await this.getAddressFromLocation(latitude, longitude);
                const address = await this.getAddressFromLocation(
                    baiduCoords.lat,
                    baiduCoords.lng,
                );
                if (!address || !address.address) {
                    return;
                }
                // 更新当前位置信息
                this.currentLocation = {
                    latitude,
                    longitude,
                    latitude: baiduCoords.lat,
                    longitude: baiduCoords.lng,
                    gcjLatitude: latitude,
                    gcjLongitude: longitude,
                    address: address.address,
                    province: address.province,
                    city: address.city,
@@ -181,7 +204,6 @@
                    street: address.street,
                    streetNumber: address.streetNumber,
                };
                // 添加标记点并显示地址信息
                this.addMarker(latitude, longitude, address.address);
                // 通知父组件位置已更新
@@ -204,7 +226,7 @@
                width: 20,
                height: 20,
                callout: {
                    content: title,
                    content: title || '未知位置',
                    color: '#000000',
                    fontSize: 14,
                    borderRadius: 4,
@@ -224,16 +246,21 @@
            if (!e || !e.detail) {
                return;
            }
            const { latitude, longitude } = e.detail;
            if (!latitude || !longitude) {
                return;
            }
            try {
                // 更新本地坐标
                this.localLatitude = latitude;
                this.localLongitude = longitude;
                // 将 GCJ-02 坐标转换为百度坐标用于获取地址
                const baiduCoords = this.gcj02ToBaidu(latitude, longitude);
                // 获取地址信息
                const address = await this.getAddressFromLocation(latitude, longitude);
                const address = await this.getAddressFromLocation(
                    baiduCoords.lat,
                    baiduCoords.lng,
                );
                if (!address || !address.address) {
                    Taro.showToast({
                        title: '获取地址失败',
@@ -241,10 +268,11 @@
                    });
                    return;
                }
                this.currentLocation = {
                    latitude,
                    longitude,
                    latitude: baiduCoords.lat,
                    longitude: baiduCoords.lng,
                    gcjLatitude: latitude,
                    gcjLongitude: longitude,
                    address: address.address,
                    province: address.province,
                    city: address.city,
@@ -252,7 +280,6 @@
                    street: address.street,
                    streetNumber: address.streetNumber,
                };
                // 添加标记点
                this.addMarker(latitude, longitude, address.address);
                this.$emit('locationSelected', this.currentLocation);
@@ -270,14 +297,18 @@
            const { markerId } = e.detail;
            const marker = this.markers.find(m => m.id === markerId);
            if (marker) {
                // 转换为百度坐标
                const baiduCoords = this.gcj02ToBaidu(marker.latitude, marker.longitude);
                // 获取地址信息
                const address = await this.getAddressFromLocation(
                    marker.latitude,
                    marker.longitude,
                    baiduCoords.lat,
                    baiduCoords.lng,
                );
                this.currentLocation = {
                    latitude: marker.latitude,
                    longitude: marker.longitude,
                    latitude: baiduCoords.lat,
                    longitude: baiduCoords.lng,
                    gcjLatitude: marker.latitude,
                    gcjLongitude: marker.longitude,
                    address: address.address,
                    province: address.province,
                    city: address.city,
@@ -291,36 +322,72 @@
        // 移动到指定位置
        moveToLocation(latitude, longitude) {
            // 更新地图位置
            // 更新地图位置数据
            this.mapLatitude = latitude;
            this.mapLongitude = longitude;
            this.mapScale = 16; // 设置合适的缩放级别
            // 更新标记点位置
            if (this.currentLocation) {
                this.addMarker(latitude, longitude, this.currentLocation.address);
            // 使用地图上下文移动到指定位置
            if (this.mapCtx) {
                this.mapCtx.moveToLocation({
                    latitude: latitude,
                    longitude: longitude,
                    success: () => {
                        // 更新标记点位置
                        if (this.currentLocation) {
                            this.addMarker(
                                latitude,
                                longitude,
                                this.currentLocation.address,
                            );
                        }
                    },
                    fail: err => {
                        console.error('移动失败:', err);
                        // 失败时也要尝试更新标记点
                        if (this.currentLocation) {
                            this.addMarker(
                                latitude,
                                longitude,
                                this.currentLocation.address,
                            );
                        }
                    },
                });
            } else {
                // 地图上下文不可用时,直接更新标记点
                if (this.currentLocation) {
                    this.addMarker(latitude, longitude, this.currentLocation.address);
                }
            }
        },
        // 获取当前位置按钮点击事件
        async handleGetLocation(e) {
            try {
                // 显示加载中提示
                Taro.showLoading({
                    title: '获取位置中...',
                });
                const res = await Taro.getLocation({
                    type: 'gcj02',
                });
                // 将GCJ-02坐标转换为百度坐标
                const baiduLocation = this.gcj02ToBaidu(res.latitude, res.longitude);
                // 更新本地坐标
                this.localLatitude = res.latitude;
                this.localLongitude = res.longitude;
                // 设置标志,防止handleRegionChange触发时覆盖地址
                this.isFromChooseLocation = true;
                // 将 GCJ-02 坐标转换为百度坐标用于获取地址
                const baiduCoords = this.gcj02ToBaidu(res.latitude, res.longitude);
                // 获取地址信息
                const address = await this.getAddressFromLocation(
                    baiduLocation.lat,
                    baiduLocation.lng,
                    baiduCoords.lat,
                    baiduCoords.lng,
                );
                this.currentLocation = {
                    latitude: baiduLocation.lat,
                    longitude: baiduLocation.lng,
                    latitude: baiduCoords.lat,
                    longitude: baiduCoords.lng,
                    gcjLatitude: res.latitude,
                    gcjLongitude: res.longitude,
                    address: address.address,
                    province: address.province,
                    city: address.city,
@@ -328,12 +395,24 @@
                    street: address.street,
                    streetNumber: address.streetNumber,
                };
                // 移动到当前位置(使用原始GCJ-02坐标)
                this.moveToLocation(res.latitude, res.longitude);
                // 直接更新地图位置
                this.mapLatitude = res.latitude;
                this.mapLongitude = res.longitude;
                this.mapScale = 16;
                // 添加标记点
                this.addMarker(res.latitude, res.longitude, address.address);
                // 通知父组件位置已更新
                this.$emit('locationSelected', this.currentLocation);
                // 完成后隐藏加载提示
                Taro.hideLoading();
                // 使用延时恢复标志
                setTimeout(() => {
                    this.isFromChooseLocation = false;
                }, 800);
            } catch (error) {
                console.error('获取位置失败:', error);
                Taro.hideLoading();
                this.isFromChooseLocation = false;
                Taro.showToast({
                    title: '获取位置失败',
                    icon: 'none',
@@ -345,26 +424,56 @@
        async handleChooseLocation(e) {
            try {
                const res = await Taro.chooseLocation();
                // 将GCJ-02坐标转换为百度坐标
                const baiduLocation = this.gcj02ToBaidu(res.latitude, res.longitude);
                // 设置标志,防止handleRegionChange触发时覆盖地址
                this.isFromChooseLocation = true;
                // 更新本地坐标
                this.localLatitude = res.latitude;
                this.localLongitude = res.longitude;
                // 转换为百度坐标
                const baiduCoords = this.gcj02ToBaidu(res.latitude, res.longitude);
                this.currentLocation = {
                    latitude: baiduLocation.lat,
                    longitude: baiduLocation.lng,
                    latitude: baiduCoords.lat,
                    longitude: baiduCoords.lng,
                    gcjLatitude: res.latitude,
                    gcjLongitude: res.longitude,
                    address: res.address,
                    name: res.name || '',
                    province: '',
                    city: '',
                    district: '',
                    street: '',
                    streetNumber: '',
                };
                // 移动到选择的位置(使用原始GCJ-02坐标)
                this.moveToLocation(res.latitude, res.longitude);
                // 直接更新地图位置和添加标记点
                this.mapLatitude = res.latitude;
                this.mapLongitude = res.longitude;
                this.mapScale = 16;
                // 添加标记点
                this.addMarker(res.latitude, res.longitude, res.address);
                // 使用地图上下文移动到选择的位置
                if (this.mapCtx) {
                    this.mapCtx.moveToLocation({
                        latitude: res.latitude,
                        longitude: res.longitude,
                        success: () => {
                            // 再次确保标记点显示
                            setTimeout(() => {
                                // 重置标志
                                this.isFromChooseLocation = false;
                            }, 800);
                        },
                        fail: err => {
                            console.error('移动失败:', err);
                            // 重置标志
                            this.isFromChooseLocation = false;
                        },
                    });
                }
                this.$emit('locationSelected', this.currentLocation);
            } catch (error) {
                console.error('选择位置失败:', error);
                // 重置标志
                this.isFromChooseLocation = false;
                Taro.showToast({
                    title: '选择位置失败',
                    icon: 'none',
@@ -397,11 +506,9 @@
                    },
                    timeout: 10000,
                });
                if (!res.data) {
                    throw new Error('百度地图API返回数据为空');
                }
                if (res.data.status === 0) {
                    const result = res.data.result;
                    return {
@@ -430,116 +537,135 @@
        // GCJ-02坐标转百度坐标
        gcj02ToBaidu(lat, lng) {
            const x_pi = (3.14159265358979324 * 3000.0) / 180.0;
            const x = lng;
            const y = lat;
            const z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
            const theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
            const lngs = z * Math.cos(theta);
            const lats = z * Math.sin(theta);
            const PI = 3.14159265358979324;
            const x_pi = (PI * 3000.0) / 180.0;
            const z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_pi);
            const theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_pi);
            const bd_lng = z * Math.cos(theta) + 0.0065;
            const bd_lat = z * Math.sin(theta) + 0.006;
            return {
                lat: lats,
                lng: lngs,
                lat: bd_lat,
                lng: bd_lng,
            };
        },
        // 百度坐标转腾讯坐标
        baiduToGcj02(lat, lng) {
            const x_pi = (3.14159265358979324 * 3000.0) / 180.0;
            const PI = 3.14159265358979324;
            const x_pi = (PI * 3000.0) / 180.0;
            const x = lng - 0.0065;
            const y = lat - 0.006;
            const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
            const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
            const lngs = z * Math.cos(theta);
            const lats = z * Math.sin(theta);
            const gg_lng = z * Math.cos(theta);
            const gg_lat = z * Math.sin(theta);
            return {
                lat: lats,
                lng: lngs,
                lat: gg_lat,
                lng: gg_lng,
            };
        },
        // 初始化位置信息
        async initLocation() {
            try {
                // 获取地址信息
                const address = await this.getAddressFromLocation(
                    this.latitude,
                    this.longitude,
                );
                if (!address || !address.address) {
                    return;
                // 设置标志,防止handleRegionChange触发时覆盖地址
                this.isFromChooseLocation = true;
                // 显示加载提示
                Taro.showLoading({
                    title: '加载位置信息...',
                });
                try {
                    // 使用本地坐标(初始默认值或props传入值)获取地址信息
                    const address = await this.getAddressFromLocation(
                        this.localLatitude,
                        this.localLongitude,
                    );
                    if (!address || !address.address) {
                        console.warn('获取地址信息失败');
                        Taro.hideLoading();
                        this.isFromChooseLocation = false;
                        return;
                    }
                    // 将百度坐标转换为腾讯坐标
                    const gcjCoords = this.baiduToGcj02(
                        this.localLatitude,
                        this.localLongitude,
                    );
                    // 更新当前位置信息
                    this.currentLocation = {
                        latitude: this.localLatitude,
                        longitude: this.localLongitude,
                        gcjLatitude: gcjCoords.lat,
                        gcjLongitude: gcjCoords.lng,
                        address: address.address,
                        province: address.province,
                        city: address.city,
                        district: address.district,
                        street: address.street,
                        streetNumber: address.streetNumber,
                    };
                    // 使用腾讯坐标更新地图位置
                    this.mapLatitude = gcjCoords.lat;
                    this.mapLongitude = gcjCoords.lng;
                    this.mapScale = 16;
                    // 添加标记点
                    this.markers = [
                        {
                            id: this.selectedMarkerId++,
                            latitude: gcjCoords.lat,
                            longitude: gcjCoords.lng,
                            title: address.address,
                            width: 30,
                            height: 30,
                            callout: {
                                content: address.address || '未知位置',
                                color: '#000000',
                                fontSize: 14,
                                borderRadius: 4,
                                padding: 8,
                                display: 'ALWAYS',
                                bgColor: '#ffffff',
                                borderWidth: 1,
                                borderColor: '#cccccc',
                                textAlign: 'center',
                                anchorY: -10,
                            },
                        },
                    ];
                    // 通知父组件位置已更新
                    this.$emit('locationSelected', this.currentLocation);
                    // 隐藏加载提示
                    Taro.hideLoading();
                    // 使用地图上下文移动到位置中心
                    if (this.mapCtx) {
                        this.mapCtx.moveToLocation({
                            latitude: gcjCoords.lat,
                            longitude: gcjCoords.lng,
                            success: () => {
                                // 延迟重置标志
                                setTimeout(() => {
                                    this.isFromChooseLocation = false;
                                }, 800);
                            },
                            fail: err => {
                                console.error('地图移动失败:', err);
                                this.isFromChooseLocation = false;
                            },
                        });
                    } else {
                        this.isFromChooseLocation = false;
                    }
                } catch (error) {
                    console.error('处理位置信息失败:', error);
                    Taro.hideLoading();
                    this.isFromChooseLocation = false;
                }
                // 更新当前位置信息
                this.currentLocation = {
                    latitude: this.latitude,
                    longitude: this.longitude,
                    address: address.address,
                    province: address.province,
                    city: address.city,
                    district: address.district,
                    street: address.street,
                    streetNumber: address.streetNumber,
                };
                // 添加标记点
                this.addMarker(this.latitude, this.longitude, address.address);
                // 通知父组件位置已更新
                this.$emit('locationSelected', this.currentLocation);
            } catch (error) {
                console.error('初始化位置信息失败:', error);
                console.error('初始化位置信息失败:', error);
                Taro.hideLoading();
                this.isFromChooseLocation = false;
            }
        },
    },
};
</script>
<style lang="scss">
.c-baidu-map {
    width: 100%;
    height: 100%;
    position: relative;
    display: block;
    .map {
        width: 100%;
        height: 100%;
        display: block;
    }
    .map-controls {
        position: absolute;
        bottom: 0;
        left: 0;
        right: 0;
        background: rgba(255, 255, 255, 0.9);
        z-index: 100;
        .map-controls-top {
            display: flex;
            justify-content: space-between;
            align-items: center;
            height: 100px;
            padding: 0 20px;
            .at-button {
                width: 45%;
                height: 76px !important;
                line-height: 72px;
                font-size: 40px;
            }
        }
        .map-controls-bottom {
            display: flex;
            align-items: center;
            height: 100px;
            padding: 0 20px;
            .at-button {
                width: 95%;
                height: 76px !important;
                line-height: 72px;
                font-size: 40px;
            }
        }
    }
}
</style>
</script>