12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418 |
- <template>
- <view class="map-container">
- <!-- 顶部导航栏 -->
- <view class="navbar">
- <view class="back-btn" @tap="goBack">
- <text class="back-icon">←</text>
- <text class="back-text">返回</text>
- </view>
- <view class="title">自定义行程</view>
- </view>
-
- <!-- 地图区域 -->
- <view class="map-view">
- <map
- class="map"
- :latitude="latitude"
- :longitude="longitude"
- :markers="markers"
- :scale="scale"
- :show-location="true"
- :enable-zoom="true"
- :enable-scroll="true"
- @markertap="onMarkerTap"
- :polyline="polylines"
- @loaded="onMapLoaded"
- :include-points="showAllMarkers ? includePoints : []"
- ></map>
-
- <!-- 地图上的搜索框 -->
- <view class="search-box">
- <view class="search-icon">🔍</view>
- <input
- class="search-input"
- type="text"
- placeholder="搜索景点、酒店、商场等"
- v-model="searchKeyword"
- @confirm="searchLocation"
- />
- </view>
-
- <!-- 测试按钮 -->
- <view class="debug-panel">
- <view class="debug-btn" @tap="addTestMarkerAndShow">
- <text>添加测试标记</text>
- </view>
- <view class="debug-btn" @tap="showMarkersInfo">
- <text>标记信息</text>
- </view>
- <view class="debug-btn" @tap="reloadMarkers">
- <text>重载标记</text>
- </view>
- <view class="debug-btn" @tap="showAllSpots">
- <text>显示所有景点</text>
- </view>
- <view class="debug-btn" @tap="resetView" v-if="showAllMarkers">
- <text>重置视图</text>
- </view>
- </view>
-
- <!-- 底部操作区 -->
- <view class="bottom-panel">
- <view class="panel-header">
- <text class="panel-title">添加到行程</text>
- <text class="panel-subtitle">已选择 {{selectedLocations.length}} 个地点</text>
- </view>
-
- <!-- 已选择的地点列表 -->
- <scroll-view class="location-list" scroll-y="true" v-if="selectedLocations.length > 0">
- <view
- class="location-item"
- v-for="(item, index) in selectedLocations"
- :key="index"
- :class="{'active': currentIndex === index}"
- @tap="selectLocation(index)"
- >
- <view class="location-index">{{index + 1}}</view>
- <view class="location-info">
- <text class="location-name">{{item.name}}</text>
- <text class="location-address">{{item.address}}</text>
- </view>
- <view class="location-actions">
- <view class="action-btn delete-btn" @tap.stop="removeLocation(index)">
- <text class="action-icon">×</text>
- </view>
- </view>
- </view>
- </scroll-view>
-
- <!-- 没有选择地点时的提示 -->
- <view class="empty-state" v-else>
- <view class="empty-icon">📍</view>
- <text class="empty-text">点击地图或搜索添加地点</text>
- </view>
-
- <!-- 底部按钮 -->
- <view class="action-buttons">
- <view class="action-btn secondary" @tap="clearAllLocations">
- <text>清空</text>
- </view>
- <view class="action-btn primary" @tap="saveTrip" :class="{'disabled': selectedLocations.length === 0}">
- <text>生成行程</text>
- </view>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script>
- // 导入景点查询API
- import { findalls } from '@/pages/api/luyou.js';
-
- export default {
- data() {
- return {
- latitude: 38.818143, // 保定理工的纬度
- longitude: 115.484621, // 保定理工的经度
- scale: 14,
- markers: [],
- polylines: [],
- includePoints: [], // 添加要包含在地图视野内的点
- showAllMarkers: false, // 是否显示所有景点
- searchKeyword: '',
- selectedLocations: [],
- currentIndex: -1,
- jingdian: [], // 存储景点数据
- targetSpotName: '', // 目标景点名称
- defaultBaodingSpots: [
- {
- id: 999,
- name: '保定古莲花池',
- pinyin: 'baodinggulianhuchi',
- description: '始建于唐代,是保定市著名的风景名胜区,国家AAAA级旅游景区',
- address: '河北省保定市莲池区牌坊街67号',
- city: '保定',
- category: '景区',
- latitude: 38.8743,
- longitude: 115.4646,
- image: '/static/default_attraction.jpg'
- },
- {
- id: 998,
- name: '保定直隶总督署',
- pinyin: 'baodingzhilizongedushu',
- description: '中国保存最完整的清代省级衙署,是河北省重点文物保护单位',
- address: '河北省保定市莲池区东风路1399号',
- city: '保定',
- category: '景区',
- latitude: 38.87346,
- longitude: 115.47486,
- image: '/static/default_attraction.jpg'
- },
- {
- id: 997,
- name: '保定野三坡景区',
- pinyin: 'baodingyesanpo',
- description: '国家AAAAA级景区,以奇峰、怪石、峡谷、溶洞和清泉著称',
- address: '河北省保定市涞水县野三坡镇',
- city: '保定',
- category: '景区',
- latitude: 39.46082,
- longitude: 115.61501,
- image: '/static/default_attraction.jpg'
- }
- ]
- }
- },
- onLoad(options) {
- // 检查是否有景点参数传入
- if (options.lat && options.lng && options.name) {
- this.latitude = parseFloat(options.lat);
- this.longitude = parseFloat(options.lng);
- this.targetSpotName = decodeURIComponent(options.name);
- this.scale = 15; // 放大一点
-
- console.log(`接收到景点定位参数: ${this.targetSpotName}, 坐标: ${this.latitude}, ${this.longitude}`);
-
- // 显示提示
- uni.showToast({
- title: `定位到: ${this.targetSpotName}`,
- icon: 'none',
- duration: 2000
- });
- }
-
- // 初始化地图
- this.initMap();
-
- // 查询景点数据并显示加载状态
- uni.showLoading({
- title: '加载景点数据...'
- });
-
- // 先加载默认保定景点
- this.setDefaultBaodingSpots();
-
- // 再查询API获取所有景点
- this.getJingdian();
- },
- methods: {
- // 设置默认保定景点
- setDefaultBaodingSpots() {
- // 预先设置默认的保定景点
- this.jingdian = [...this.defaultBaodingSpots];
-
- // 设置地图中心为第一个景点
- this.latitude = this.defaultBaodingSpots[0].latitude;
- this.longitude = this.defaultBaodingSpots[0].longitude;
-
- // 创建地图标记
- this.createMarkersFromJingdian();
- },
-
- // 查询景点数据
- getJingdian() {
- // 调用景点查询API
- findalls().then((res) => {
- console.log('API返回原始数据:', JSON.stringify(res));
-
- // 隐藏加载状态
- uni.hideLoading();
-
- if (res && res.code === 200) {
- // 保存API返回的原始数据
- this.apiResponse = res;
-
- // 确保获取到正确的数据位置
- let data = null;
-
- // 检查各种可能的数据位置
- if (res.obj) {
- data = res.obj;
- console.log('数据在res.obj中, 长度:', data.length);
- } else if (res.data && res.data.obj) {
- data = res.data.obj;
- console.log('数据在res.data.obj中, 长度:', data.length);
- } else if (res.data) {
- data = res.data;
- console.log('数据在res.data中, 长度:', data.length);
- } else {
- console.log('尝试解析完整响应');
- data = res;
- }
-
- let apiJingdian = [];
-
- // 如果数据是数组,则直接使用
- if (Array.isArray(data)) {
- apiJingdian = data;
- console.log('直接使用数组数据, 长度:', apiJingdian.length);
- } else {
- // 尝试找到数据中的数组
- for (const key in data) {
- if (Array.isArray(data[key]) && data[key].length > 0) {
- apiJingdian = data[key];
- console.log(`找到数组数据在${key}字段中, 长度:`, apiJingdian.length);
- break;
- }
- }
- }
-
- if (apiJingdian && apiJingdian.length > 0) {
- // 处理后端返回的景点数据
- const processedApiData = apiJingdian.map(item => {
- // 确保每个景点都有有效的坐标
- if (!item.latitude || !item.longitude) {
- console.log(`景点${item.name || '未命名'}没有坐标,尝试解析其他字段`);
-
- // 尝试从其他可能的字段中获取坐标
- if (item.latitudeStr && item.longitudeStr) {
- item.latitude = parseFloat(item.latitudeStr);
- item.longitude = parseFloat(item.longitudeStr);
- console.log(`从latitudeStr/longitudeStr字段获取到坐标: ${item.latitude}, ${item.longitude}`);
- } else if (item.lat && item.lng) {
- item.latitude = parseFloat(item.lat);
- item.longitude = parseFloat(item.lng);
- console.log(`从lat/lng字段获取到坐标: ${item.latitude}, ${item.longitude}`);
- }
- }
-
- // 确保坐标为数字类型
- if (item.latitude) item.latitude = Number(item.latitude);
- if (item.longitude) item.longitude = Number(item.longitude);
-
- return item;
- }).filter(item => {
- // 过滤掉没有有效坐标的景点
- const hasValidCoords = item.latitude && item.longitude &&
- !isNaN(Number(item.latitude)) && !isNaN(Number(item.longitude));
- if (!hasValidCoords) {
- console.log(`过滤掉无效坐标的景点: ${item.name || '未命名'}`);
- }
- return hasValidCoords;
- });
-
- console.log(`处理后的有效API景点数据: ${processedApiData.length}个`);
-
- // 合并数据(同时保持默认景点)
- this.jingdian = [...this.defaultBaodingSpots, ...processedApiData];
-
- console.log('合并后总景点数据:', this.jingdian.length);
- if (this.jingdian.length > 0) {
- console.log('第一条数据:', JSON.stringify(this.jingdian[0]));
- }
-
- uni.showToast({
- title: `成功加载${this.jingdian.length}个景点`,
- icon: 'success'
- });
-
- // 从景点数据创建地图标记
- this.createMarkersFromJingdian();
-
- // 检查是否需要选中目标景点
- if (this.targetSpotName) {
- this.selectTargetSpot();
- }
-
- // 调整地图视野以包含所有景点
- this.adjustMapViewToShowAllSpots();
- } else {
- console.log('API未返回有效景点数据,继续使用默认景点');
- uni.showToast({
- title: '使用默认景点数据',
- icon: 'none'
- });
-
- // 即使使用默认景点,也尝试选中目标景点
- if (this.targetSpotName) {
- this.selectTargetSpot();
- }
- }
- } else {
- console.error('API返回错误:', res);
- uni.showToast({
- title: res && res.message ? res.message : '查询失败,使用默认景点',
- icon: 'none'
- });
- }
- }).catch((error) => {
- uni.hideLoading();
- console.error('查询失败:', error);
- uni.showToast({
- title: '加载API景点失败,使用默认景点',
- icon: 'none'
- });
- });
- },
-
- // 调整地图视野以包含所有景点
- adjustMapViewToShowAllSpots() {
- if (!this.jingdian || this.jingdian.length === 0) return;
-
- console.log('调整地图视野以显示所有景点');
-
- // 保持当前的缩放级别,不要自动缩小
- // this.scale = 10; // 移除这行,不自动改变缩放级别
-
- // 找出所有景点的地理中心
- let latSum = 0;
- let lngSum = 0;
- let validSpots = 0;
-
- this.jingdian.forEach(spot => {
- if (spot.latitude && spot.longitude) {
- latSum += Number(spot.latitude);
- lngSum += Number(spot.longitude);
- validSpots++;
- }
- });
-
- if (validSpots > 0) {
- const centerLat = latSum / validSpots;
- const centerLng = lngSum / validSpots;
-
- console.log(`设置地图中心点为所有景点的地理中心: ${centerLat}, ${centerLng}`);
-
- this.latitude = centerLat;
- this.longitude = centerLng;
- }
- },
-
- // 从景点数据创建标记
- createMarkersFromJingdian() {
- // 检查景点数据
- if (!this.jingdian || this.jingdian.length === 0) {
- console.log('景点数据为空');
- uni.showToast({
- title: '景点数据为空',
- icon: 'none'
- });
- return;
- }
-
- console.log('开始创建标记,景点数据长度:', this.jingdian.length);
-
- // 先清空当前标记
- let currentMarkers = [...this.markers];
-
- // 将景点数据转换为标记数据
- const poiMarkers = this.jingdian.filter(poi => {
- if (!poi) {
- console.log('发现无效的景点数据(null或undefined)');
- return false;
- }
-
- const hasCoords = poi.latitude && poi.longitude;
- if (!hasCoords) {
- console.log(`景点${poi.name || '未命名'}没有有效的坐标`);
- return false;
- }
- return true;
- }).map((poi, index) => {
- try {
- const lat = Number(poi.latitude);
- const lng = Number(poi.longitude);
- console.log(`处理景点 ID=${poi.id}, 名称=${poi.name}, 坐标: ${lat}, ${lng}`);
-
- // 检查坐标是否为NaN
- if (isNaN(lat) || isNaN(lng)) {
- console.log(`景点${poi.name}的坐标转换为数字后不有效`);
- return null;
- }
-
- // 获取标记图标
- const iconType = poi.category || poi.type || 'attraction';
- const iconPath = this.getMarkerIcon(iconType);
-
- return {
- id: poi.id || index + 1,
- latitude: lat,
- longitude: lng,
- title: poi.name || poi.title,
- iconPath: iconPath,
- width: 36, // 增大标记尺寸以提高可见度
- height: 36,
- callout: {
- content: poi.name || poi.title,
- color: '#333333',
- fontSize: 12,
- borderRadius: 4,
- padding: 5,
- display: 'BYCLICK'
- }
- };
- } catch (error) {
- console.error(`处理景点${poi.name || '未命名'}时出错:`, error);
- return null;
- }
- }).filter(marker => marker !== null); // 过滤掉无效的标记
-
- console.log(`生成了${poiMarkers.length}个景点标记`);
- if (poiMarkers.length > 0) {
- console.log('示例标记:', JSON.stringify(poiMarkers[0]));
- } else {
- console.log('没有有效的景点标记生成');
- // 添加一个测试标记
- this.addTestMarker();
- return;
- }
-
- // 构建已选择的标记
- const selectedMarkers = this.selectedLocations.map((location, index) => {
- return {
- id: 1000 + index,
- latitude: Number(location.latitude),
- longitude: Number(location.longitude),
- title: location.name,
- iconPath: '/static/marker_selected.png', // 使用绝对路径
- width: 40,
- height: 40,
- label: {
- content: (index + 1).toString(),
- color: '#FFFFFF',
- fontSize: 14,
- textAlign: 'center',
- anchorX: 0,
- anchorY: -10
- }
- };
- });
-
- // 合并景点标记和已选择的标记
- this.markers = [...poiMarkers, ...selectedMarkers];
- console.log(`总共有${this.markers.length}个标记点`);
-
- // 延迟执行检查标记
- setTimeout(() => {
- this.checkMarkersVisibility();
- }, 1000);
- },
-
- // 检查标记可见性
- checkMarkersVisibility() {
- console.log('检查标记可见性');
- if (this.markers.length > 0) {
- console.log('标记数量:', this.markers.length);
- console.log('地图中心坐标:', this.latitude, this.longitude);
-
- // 如果没有可见的标记,尝试将地图中心移到第一个标记
- const firstMarker = this.markers[0];
- if (firstMarker && firstMarker.latitude && firstMarker.longitude) {
- console.log('移动地图到第一个标记:', firstMarker.latitude, firstMarker.longitude);
- this.latitude = firstMarker.latitude;
- this.longitude = firstMarker.longitude;
- this.scale = 14; // 调整缩放级别
- }
- }
- },
-
- // 初始化地图
- initMap() {
- // 获取当前位置
- uni.getLocation({
- type: 'gcj02',
- success: (res) => {
- this.latitude = res.latitude;
- this.longitude = res.longitude;
- },
- fail: () => {
- // 定位失败时使用默认坐标
- uni.showToast({
- title: '获取位置信息失败,使用默认位置',
- icon: 'none'
- });
- }
- });
- },
-
- // 根据POI类型获取不同的图标
- getMarkerIcon(type) {
- // 获取当前运行平台
- const systemInfo = uni.getSystemInfoSync();
- const platform = systemInfo.platform;
- console.log('当前运行平台:', platform);
-
- // 由于微信小程序的限制,使用特定格式的图标URL
- const baseUrl = '/static/';
-
- let iconName;
- switch(type) {
- case '景区':
- case '著名景点':
- case '历史遗迹':
- case 'attraction':
- iconName = 'marker_attraction.png';
- break;
- case '酒店':
- case '住宿':
- case 'hotel':
- iconName = 'marker_hotel.png';
- break;
- case '美食':
- case '餐厅':
- case 'restaurant':
- iconName = 'marker_restaurant.png';
- break;
- case '购物':
- case '商场':
- case 'shopping':
- iconName = 'marker_shopping.png';
- break;
- default:
- iconName = 'marker_default.png';
- }
-
- const iconPath = baseUrl + iconName;
- console.log(`选择的图标路径: ${iconPath}, 类型: ${type}`);
- return iconPath;
- },
-
- // 搜索位置
- searchLocation() {
- if (!this.searchKeyword.trim()) {
- return;
- }
-
- // 使用API数据进行搜索
- if (!this.jingdian || this.jingdian.length === 0) {
- uni.showToast({
- title: '景点数据未加载',
- icon: 'none'
- });
- return;
- }
-
- const result = this.jingdian.find(poi =>
- (poi.name || '').includes(this.searchKeyword) ||
- (poi.address || '').includes(this.searchKeyword) ||
- (poi.description || '').includes(this.searchKeyword)
- );
-
- if (result && result.latitude && result.longitude) {
- this.latitude = Number(result.latitude);
- this.longitude = Number(result.longitude);
- this.scale = 15;
-
- uni.showToast({
- title: `找到: ${result.name}`,
- icon: 'none'
- });
- } else {
- uni.showToast({
- title: '未找到相关位置',
- icon: 'none'
- });
- }
- },
-
- // 点击标记
- onMarkerTap(e) {
- const markerId = e.markerId;
- console.log('点击了标记:', markerId);
-
- // 处理选中的已添加地点标记
- if (markerId >= 1000) {
- const index = markerId - 1000;
- if (index >= 0 && index < this.selectedLocations.length) {
- this.currentIndex = index;
- return;
- }
- }
-
- // 使用API数据查找POI
- const poi = this.jingdian.find(item => item.id === markerId);
-
- if (poi) {
- // 构建景点详情内容
- let content = '';
- if (poi.description) {
- content += `描述: ${poi.description}\n`;
- }
- if (poi.address) {
- content += `地址: ${poi.address}\n`;
- }
- if (poi.category) {
- content += `类型: ${poi.category}\n`;
- }
- if (poi.city) {
- content += `城市: ${poi.city}\n`;
- }
- content += '是否添加到行程?';
-
- uni.showModal({
- title: poi.name,
- content: content,
- confirmText: '添加',
- cancelText: '取消',
- success: (res) => {
- if (res.confirm) {
- // 标准化POI数据格式
- const location = {
- id: poi.id,
- name: poi.name,
- latitude: Number(poi.latitude),
- longitude: Number(poi.longitude),
- address: poi.address || poi.city || '',
- type: poi.category || 'attraction',
- description: poi.description || ''
- };
- this.addLocation(location);
- }
- }
- });
- }
- },
-
- // 添加地点到行程
- addLocation(location) {
- // 检查是否已经添加过
- const exists = this.selectedLocations.some(item => item.id === location.id);
- if (exists) {
- uni.showToast({
- title: '该地点已在行程中',
- icon: 'none'
- });
- return;
- }
-
- // 确保经纬度是数值类型
- const standardizedLocation = {
- ...location,
- latitude: Number(location.latitude),
- longitude: Number(location.longitude)
- };
-
- console.log('添加标准化后的地点:', standardizedLocation);
-
- this.selectedLocations.push(standardizedLocation);
- this.currentIndex = this.selectedLocations.length - 1;
- this.updateSelectedMarkers();
-
- uni.showToast({
- title: '已添加到行程',
- icon: 'success'
- });
- },
-
- // 移除地点
- removeLocation(index) {
- this.selectedLocations.splice(index, 1);
-
- if (this.currentIndex >= this.selectedLocations.length) {
- this.currentIndex = this.selectedLocations.length - 1;
- }
-
- // 更新地图标记
- this.updateSelectedMarkers();
- },
-
- // 选择地点
- selectLocation(index) {
- this.currentIndex = index;
- const location = this.selectedLocations[index];
-
- // 移动地图到选中的位置
- this.latitude = location.latitude;
- this.longitude = location.longitude;
- },
-
- // 清空所有地点
- clearAllLocations() {
- if (this.selectedLocations.length === 0) return;
-
- uni.showModal({
- title: '确认清空',
- content: '确定要清空所有已添加的地点吗?',
- success: (res) => {
- if (res.confirm) {
- this.selectedLocations = [];
- this.currentIndex = -1;
- this.updateSelectedMarkers();
- }
- }
- });
- },
-
- // 保存行程
- saveTrip() {
- if (this.selectedLocations.length === 0) {
- uni.showToast({
- title: '请至少添加一个地点',
- icon: 'none'
- });
- return;
- }
-
- // 将选中的位置保存到本地存储中
- try {
- uni.setStorageSync('selectedLocations', JSON.stringify(this.selectedLocations));
-
- // 直接跳转到计划详情页面,不再显示弹窗
- uni.navigateTo({
- url: '/pages/custom-trip/plan-detail',
- success: () => {
- console.log('成功跳转到计划详情页');
- },
- fail: (err) => {
- console.error('跳转到计划详情页失败:', err);
- uni.showModal({
- title: '跳转失败',
- content: JSON.stringify(err),
- showCancel: false
- });
- }
- });
- } catch (e) {
- console.error('保存位置数据失败:', e);
- uni.showToast({
- title: '操作失败,请重试',
- icon: 'none'
- });
- }
- },
-
- // 返回上一页
- goBack() {
- uni.navigateBack();
- },
-
- // 更新选中的标记
- updateSelectedMarkers() {
- // 重新生成地图标记
- this.createMarkersFromJingdian();
-
- // 更新路线连线
- this.updatePolylines();
- },
-
- // 更新路线连线
- updatePolylines() {
- if (this.selectedLocations.length < 2) {
- this.polylines = [];
- this.markers = this.markers.filter(marker => marker.id < 2000 || marker.id >= 3000); // 移除距离标记
- return;
- }
-
- // 提取所有选中位置的坐标点
- const points = this.selectedLocations.map(location => {
- return {
- latitude: Number(location.latitude),
- longitude: Number(location.longitude)
- };
- });
-
- // 创建路线
- this.polylines = [{
- points: points,
- color: '#1aad19',
- width: 4,
- dottedLine: false,
- arrowLine: true,
- borderColor: '#ffffff',
- borderWidth: 1
- }];
-
- // 创建距离标记
- let distanceMarkers = [];
- for (let i = 0; i < points.length - 1; i++) {
- const startPoint = points[i];
- const endPoint = points[i + 1];
-
- // 计算两点之间的距离(单位:米)
- const distance = this.calculateDistance(
- startPoint.latitude,
- startPoint.longitude,
- endPoint.latitude,
- endPoint.longitude
- );
-
- // 显示格式:小于1公里显示米,大于等于1公里显示公里
- const distanceText = distance < 1000
- ? `${Math.round(distance)}米`
- : `${(distance / 1000).toFixed(1)}公里`;
-
- // 计算中点位置
- const midPoint = {
- latitude: (startPoint.latitude + endPoint.latitude) / 2,
- longitude: (startPoint.longitude + endPoint.longitude) / 2
- };
-
- // 创建距离标记
- distanceMarkers.push({
- id: 2000 + i, // 距离标记ID从2000开始
- latitude: midPoint.latitude,
- longitude: midPoint.longitude,
- iconPath: '/static/marker_default.png', // 使用默认图标
- width: 0, // 设置为0使图标不可见
- height: 0, // 设置为0使图标不可见
- callout: {
- content: distanceText,
- color: '#333333',
- fontSize: 12,
- borderRadius: 4,
- borderWidth: 1,
- borderColor: '#1aad19',
- bgColor: '#ffffff',
- padding: 5,
- display: 'ALWAYS'
- }
- });
- }
-
- // 更新所有标记,保留原有标记并添加距离标记
- // 先过滤掉旧的距离标记
- const otherMarkers = this.markers.filter(marker => marker.id < 2000 || marker.id >= 3000);
- this.markers = [...otherMarkers, ...distanceMarkers];
- },
-
- // 计算两点之间的距离(使用Haversine公式)
- calculateDistance(lat1, lon1, lat2, lon2) {
- const R = 6371000; // 地球半径(米)
- const dLat = this.deg2rad(lat2 - lat1);
- const dLon = this.deg2rad(lon2 - lon1);
- const a =
- Math.sin(dLat/2) * Math.sin(dLat/2) +
- Math.cos(this.deg2rad(lat1)) * Math.cos(this.deg2rad(lat2)) *
- Math.sin(dLon/2) * Math.sin(dLon/2);
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
- return R * c; // 距离(米)
- },
-
- // 角度转弧度
- deg2rad(deg) {
- return deg * (Math.PI/180);
- },
-
- // 选择目标景点(从热门目的地跳转来的)
- selectTargetSpot() {
- if (!this.targetSpotName || this.jingdian.length === 0) {
- return;
- }
-
- // 在景点数据中查找匹配的景点
- const targetSpot = this.jingdian.find(spot =>
- spot.name === this.targetSpotName ||
- spot.name.includes(this.targetSpotName) ||
- (this.targetSpotName.includes(spot.name) && spot.name.length > 2)
- );
-
- if (targetSpot) {
- // 模拟点击该景点的marker
- setTimeout(() => {
- const e = { markerId: targetSpot.id };
- this.onMarkerTap(e);
- }, 1000);
- } else {
- console.log(`未找到匹配的目标景点: ${this.targetSpotName}`);
- }
- },
-
- // 地图加载完成后的处理
- onMapLoaded() {
- console.log('地图加载完成');
-
- // 检查当前标记数据
- if (this.markers && this.markers.length > 0) {
- console.log('当前地图标记数量:', this.markers.length);
- console.log('第一个标记示例:', JSON.stringify(this.markers[0]));
- } else {
- console.log('当前无地图标记');
- }
-
- // 尝试重新加载标记
- this.refreshMarkers();
- },
-
- // 刷新地图标记
- refreshMarkers() {
- // 确保所有坐标都是有效的数字格式
- const validMarkers = this.markers.map(marker => {
- // 深拷贝,避免直接修改原对象
- const newMarker = {...marker};
-
- // 确保经纬度是有效数字
- if (typeof newMarker.latitude === 'string') {
- newMarker.latitude = parseFloat(newMarker.latitude);
- }
-
- if (typeof newMarker.longitude === 'string') {
- newMarker.longitude = parseFloat(newMarker.longitude);
- }
-
- // 检查是否有效
- if (isNaN(newMarker.latitude) || isNaN(newMarker.longitude)) {
- console.log(`忽略无效标记: ID=${newMarker.id}, 标题=${newMarker.title}`);
- return null;
- }
-
- // 将标记的宽高稍微增大,提高可见度
- newMarker.width = 36;
- newMarker.height = 36;
-
- return newMarker;
- }).filter(m => m !== null);
-
- console.log(`刷新后有效标记数量: ${validMarkers.length}`);
- if (validMarkers.length > 0) {
- console.log('刷新后第一个标记:', JSON.stringify(validMarkers[0]));
- }
-
- // 更新标记
- this.markers = validMarkers;
-
- // 如果标记刷新后仍然为空,使用默认坐标
- if (validMarkers.length === 0) {
- console.log('没有有效标记,添加一个默认测试标记');
- this.addTestMarker();
- }
- },
-
- // 添加测试标记
- addTestMarker() {
- console.log('添加测试标记');
-
- // 创建一个简单的红色点标记(不使用图片)
- const testMarker = {
- id: 9999,
- latitude: 38.8743,
- longitude: 115.4646,
- title: '测试标记',
- width: 20,
- height: 20,
- iconPath: '/static/marker_default.png',
- callout: {
- content: '测试标记',
- color: '#333333',
- fontSize: 12,
- borderRadius: 4,
- padding: 5,
- display: 'ALWAYS'
- }
- };
-
- this.markers = [testMarker];
- console.log('添加了测试标记:', JSON.stringify(testMarker));
-
- // 更新includePoints以显示测试标记
- this.includePoints = [
- {
- latitude: testMarker.latitude,
- longitude: testMarker.longitude
- }
- ];
- },
-
- // 添加测试标记并显示
- addTestMarkerAndShow() {
- console.log('手动添加测试标记');
-
- // 保存当前的缩放级别
- const currentScale = this.scale;
- console.log('当前缩放级别:', currentScale);
-
- this.addTestMarker();
-
- // 移动到标记位置,但保持当前缩放级别
- setTimeout(() => {
- if (this.markers.length > 0) {
- const marker = this.markers[0];
- this.latitude = marker.latitude;
- this.longitude = marker.longitude;
- // 保持原来的缩放级别不变
- this.scale = currentScale;
-
- uni.showToast({
- title: '已添加测试标记',
- icon: 'success'
- });
- }
- }, 300);
- },
-
- // 显示标记信息
- showMarkersInfo() {
- if (this.markers.length > 0) {
- const info = {
- 总标记数: this.markers.length,
- 第一个标记: this.markers[0]
- };
- uni.showModal({
- title: '标记信息',
- content: JSON.stringify(info, null, 2),
- showCancel: false
- });
- console.log('当前标记信息:', info);
- } else {
- uni.showToast({
- title: '当前没有标记',
- icon: 'none'
- });
- }
- },
-
- // 重新加载标记
- reloadMarkers() {
- console.log('重新加载标记');
- // 清空当前标记
- this.markers = [];
- // 重新加载
- this.createMarkersFromJingdian();
- uni.showToast({
- title: `已重载${this.markers.length}个标记`,
- icon: 'success'
- });
- },
-
- // 显示所有景点(手动方法)
- showAllSpots() {
- // 询问用户是否调整视图以显示所有景点
- uni.showModal({
- title: '显示所有景点',
- content: '调整地图视图以显示所有景点?这会改变地图缩放级别。',
- success: (res) => {
- if (res.confirm) {
- // 用户确认后才调整地图
- // 设置一个较小的缩放级别,以显示更多景点
- this.scale = 9;
-
- // 更新include-points以包含所有景点
- this.includePoints = this.markers.map(marker => ({
- latitude: marker.latitude,
- longitude: marker.longitude
- }));
-
- // 激活显示所有景点的模式
- this.showAllMarkers = true;
-
- // 移动到所有景点的中心
- if (this.markers.length > 0) {
- let latSum = 0, lngSum = 0;
- this.markers.forEach(marker => {
- latSum += marker.latitude;
- lngSum += marker.longitude;
- });
-
- this.latitude = latSum / this.markers.length;
- this.longitude = lngSum / this.markers.length;
-
- uni.showToast({
- title: '已显示所有景点',
- icon: 'success'
- });
- }
- }
- }
- });
- },
-
- // 重置地图视图
- resetView() {
- this.showAllMarkers = false;
- this.scale = 14; // 恢复默认缩放级别
-
- // 如果有默认景点,移动到第一个默认景点
- if (this.defaultBaodingSpots.length > 0) {
- this.latitude = this.defaultBaodingSpots[0].latitude;
- this.longitude = this.defaultBaodingSpots[0].longitude;
- }
-
- uni.showToast({
- title: '已重置地图视图',
- icon: 'success'
- });
- }
- }
- }
- </script>
- <style>
- .map-container {
- display: flex;
- flex-direction: column;
- height: 100vh;
- background-color: #f8f9fa;
- }
-
- /* 顶部导航栏 */
- .navbar {
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 50rpx 30rpx 20rpx;
- background-color: #ffffff;
- position: relative;
- z-index: 10;
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
- }
-
- .back-btn {
- display: flex;
- align-items: center;
- padding: 10rpx 20rpx;
- border-radius: 30rpx;
- background-color: rgba(0, 0, 0, 0.05);
- transition: all 0.2s ease;
- }
-
- .back-btn:active {
- background-color: rgba(0, 0, 0, 0.1);
- }
-
- .back-icon {
- font-size: 32rpx;
- color: #333;
- font-weight: bold;
- margin-right: 5rpx;
- }
-
- .back-text {
- font-size: 28rpx;
- color: #333;
- }
-
- .title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- position: absolute;
- left: 50%;
- transform: translateX(-50%);
- }
-
- /* 地图视图 */
- .map-view {
- flex: 1;
- position: relative;
- overflow: hidden;
- }
-
- .map {
- width: 100%;
- height: 100%;
- }
-
- /* 搜索框 */
- .search-box {
- position: absolute;
- top: 20rpx;
- left: 30rpx;
- right: 30rpx;
- height: 80rpx;
- background-color: #fff;
- border-radius: 40rpx;
- display: flex;
- align-items: center;
- padding: 0 30rpx;
- box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
- z-index: 100;
- }
-
- .search-icon {
- font-size: 36rpx;
- margin-right: 20rpx;
- color: #999;
- }
-
- .search-input {
- flex: 1;
- height: 80rpx;
- font-size: 28rpx;
- }
-
- /* 测试按钮 */
- .debug-panel {
- position: absolute;
- top: 20rpx;
- right: 30rpx;
- display: flex;
- flex-direction: column;
- gap: 10rpx;
- z-index: 100;
- }
-
- .debug-btn {
- padding: 10rpx 15rpx;
- border-radius: 10rpx;
- background-color: rgba(255, 255, 255, 0.8);
- box-shadow: 0 2rpx 6rpx rgba(0,0,0,0.1);
- transition: all 0.2s ease;
- text-align: center;
- }
-
- .debug-btn:active {
- background-color: rgba(0, 0, 0, 0.1);
- }
-
- .debug-btn text {
- font-size: 28rpx;
- color: #333;
- }
-
- /* 底部面板 */
- .bottom-panel {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- background-color: #fff;
- border-radius: 30rpx 30rpx 0 0;
- padding: 30rpx;
- box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
- z-index: 100;
- display: flex;
- flex-direction: column;
- max-height: 60vh;
- }
-
- .panel-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 20rpx;
- }
-
- .panel-title {
- font-size: 32rpx;
- font-weight: bold;
- color: #333;
- }
-
- .panel-subtitle {
- font-size: 24rpx;
- color: #999;
- }
-
- /* 地点列表 */
- .location-list {
- max-height: 40vh;
- margin-bottom: 20rpx;
- }
-
- .location-item {
- display: flex;
- align-items: center;
- padding: 20rpx;
- margin-bottom: 10rpx;
- background-color: #f8f9fa;
- border-radius: 10rpx;
- position: relative;
- }
-
- .location-item.active {
- background-color: #e6f7ff;
- }
-
- .location-index {
- width: 40rpx;
- height: 40rpx;
- border-radius: 50%;
- background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
- color: #fff;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 24rpx;
- font-weight: bold;
- margin-right: 15rpx;
- }
-
- .location-info {
- flex: 1;
- }
-
- .location-name {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 5rpx;
- }
-
- .location-address {
- font-size: 24rpx;
- color: #999;
- }
-
- .location-actions {
- display: flex;
- }
-
- .action-btn {
- width: 60rpx;
- height: 60rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- }
-
- .delete-btn {
- color: #ff4d4f;
- }
-
- .action-icon {
- font-size: 36rpx;
- }
-
- /* 空状态 */
- .empty-state {
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- padding: 40rpx 0;
- }
-
- .empty-icon {
- font-size: 60rpx;
- margin-bottom: 20rpx;
- }
-
- .empty-text {
- font-size: 28rpx;
- color: #999;
- }
-
- /* 底部按钮 */
- .action-buttons {
- display: flex;
- justify-content: space-between;
- margin-top: 20rpx;
- }
-
- .action-btn {
- height: 80rpx;
- border-radius: 40rpx;
- display: flex;
- justify-content: center;
- align-items: center;
- font-size: 28rpx;
- transition: all 0.3s ease;
- }
-
- .secondary {
- width: 30%;
- background-color: #f0f0f0;
- color: #666;
- }
-
- .secondary:active {
- background-color: #e0e0e0;
- }
-
- .primary {
- width: 65%;
- background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
- color: #fff;
- box-shadow: 0 4rpx 15rpx rgba(79, 172, 254, 0.4);
- }
-
- .primary:active {
- transform: translateY(2rpx);
- box-shadow: 0 2rpx 8rpx rgba(79, 172, 254, 0.3);
- }
-
- .disabled {
- opacity: 0.6;
- }
- </style>
|