12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184 |
- <template>
- <view class="content">
- <!-- 顶部背景装饰 -->
- <view class="bg-decoration">
- <view class="bg-circle bg-circle-1"></view>
- <view class="bg-circle bg-circle-2"></view>
- </view>
- <!-- 顶部标题 -->
- <view class="header">
- <text class="header-title">旅游规划</text>
- <text class="header-subtitle">创造您的完美旅行体验</text>
- </view>
- <!-- 行程规划选项 -->
- <view class="planning-options">
- <view class="option-card custom-plan" hover-class="card-hover" @tap="createCustomPlan">
- <view class="option-icon-wrap">
- <image class="option-icon" src="/static/custom_plan_icon.png"></image>
- </view>
- <text class="option-title">自定义行程</text>
- <text class="option-desc">根据自己的想法安排行程</text>
- <view class="option-arrow">
- <text class="arrow-text">开始规划</text>
- <text class="arrow-icon">→</text>
- </view>
- </view>
- <view class="option-card ai-plan" hover-class="card-hover" @tap="createAiPlan">
- <view class="option-icon-wrap ai-icon-wrap">
- <image class="option-icon" src="/static/ai_plan_icon.png"></image>
- </view>
- <text class="option-title">AI规划行程</text>
- <text class="option-desc">智能推荐最佳行程路线</text>
- <view class="option-arrow">
- <text class="arrow-text">智能生成</text>
- <text class="arrow-icon">→</text>
- </view>
- </view>
- </view>
- <!-- 待出发行程 -->
- <view class="upcoming-trips">
- <view class="section-header">
- <view class="section-title-wrap">
- <text class="section-title">待出发</text>
- <view class="title-underline"></view>
- </view>
- <view class="section-more" @tap="showMoreTrips">
- <text class="more-text">查看全部</text>
- <text class="more-icon">></text>
- </view>
- </view>
- <!-- 行程卡片列表 -->
- <view class="trip-list">
- <!-- 显示已保存的行程(限制为2条) -->
- <view
- v-for="(trip, index) in displayTrips"
- :key="trip.id"
- class="trip-card"
- hover-class="card-hover"
- @tap="viewTripDetail(trip.id)"
- >
- <!-- 添加景区图片背景 -->
- <image
- class="trip-background-image"
- :src="getTripCoverImage(trip)"
- mode="aspectFill"
- ></image>
- <view class="trip-overlay"></view>
-
- <view class="trip-info">
- <view class="trip-location">
- <image class="location-icon" src="/static/location_icon.png"></image>
- <view class="trip-main-info">
- <text class="trip-name">{{trip.name}}</text>
- <text v-if="trip.startDate" class="trip-date">{{formatDate(trip.startDate)}}</text>
- <view v-else class="trip-date-wrap">
- <text class="trip-date-label">出发时间</text>
- <text class="trip-date-value">待定</text>
- </view>
- </view>
- </view>
- <view class="trip-members">
- <image class="member-icon" src="/static/member_icon.png"></image>
- <text class="member-count">共{{trip.peopleCount || 1}}名成员</text>
- </view>
- </view>
- <view class="trip-stats">
- <view class="trip-tag">
- <text class="tag-title">THE TRIP</text>
- <text class="tag-subtitle">MUST GO ON</text>
- <image class="globe-icon" src="/static/globe_icon.png"></image>
- </view>
- <view class="trip-divider"></view>
- <view class="trip-duration">
- <text class="stat-label">时长:</text>
- <text class="stat-value">{{trip.days}}天{{trip.days - 1}}晚</text>
- </view>
- <view v-if="trip.budget" class="trip-distance">
- <text class="stat-label">预算:</text>
- <text class="stat-value">¥{{trip.budget}}</text>
- </view>
- </view>
- <view class="card-shadow"></view>
- </view>
-
- <!-- 没有行程时显示的提示 -->
- <view class="empty-trip" v-if="savedTrips.length === 0">
- <view class="empty-icon">🗺️</view>
- <view class="empty-text">您还没有创建任何行程</view>
- <view class="empty-subtext">点击上方选项开始规划您的旅行</view>
- </view>
- </view>
- </view>
- <!-- 底部推荐 -->
- <view class="recommendations">
- <view class="recommendation-title">
- <text>热门目的地</text>
- </view>
- <view class="recommendation-list">
- <!-- 直接显示两条模拟数据 -->
- <view class="spots-grid">
- <!-- 北京故宫 -->
- <view class="spot-card" @tap="selectDestination('故宫博物院', {name: '故宫博物院', city: '北京', district: '东城区'})">
- <view class="spot-tag">5A</view>
- <image class="spot-image" src="/static/beijing.jpg" mode="aspectFill"></image>
- <view class="spot-name">故宫博物院</view>
- <view class="spot-location">
- <text class="location-dot">●</text>
- <text>北京东城区</text>
- </view>
- </view>
-
- <!-- 上海外滩 -->
- <view class="spot-card" @tap="selectDestination('上海外滩', {name: '上海外滩', city: '上海', district: '黄浦区'})">
- <view class="spot-tag">5A</view>
- <image class="spot-image" src="/static/shanghai.jpg" mode="aspectFill"></image>
- <view class="spot-name">上海外滩</view>
- <view class="spot-location">
- <text class="location-dot">●</text>
- <text>上海黄浦区</text>
- </view>
- </view>
- </view>
- </view>
- </view>
- </view>
- </template>
- <script>
- // 导入景点API
- import { findalls, findById } from '@/pages/api/luyou.js';
-
- export default {
- data() {
- return {
- title: '旅游规划',
- isLoadingSpots: true,
- hotSpots: [],
- savedTrips: [],
- defaultImages: [
- '/static/beijing.jpg',
- '/static/shanghai.jpg',
- '/static/chengdu.jpg',
- '/static/hangzhou.jpg',
- '/static/guangzhou.jpg'
- ]
- }
- },
- onLoad() {
- // 加载热门景点数据
- this.loadHotSpots();
-
- // 注册刷新行程事件监听
- uni.$on('refreshTrips', () => {
- console.log('接收到刷新行程列表事件');
- this.loadSavedTrips();
- });
- },
-
- onShow() {
- // 页面显示时加载保存的行程数据
- this.loadSavedTrips();
-
- // 页面显示时也尝试加载数据(如果还没有数据)
- if (this.hotSpots.length === 0 && !this.isLoadingSpots) {
- this.loadHotSpots();
- }
- },
-
- onUnload() {
- // 注销事件监听
- uni.$off('refreshTrips');
- },
-
- computed: {
- // 限制只显示前3个热门景点
- displaySpots() {
- return this.hotSpots.slice(0, 3);
- },
-
- // 限制只显示前2个行程
- displayTrips() {
- return this.savedTrips.slice(0, 2);
- }
- },
- methods: {
- // 加载热门景点数据
- loadHotSpots() {
- this.isLoadingSpots = true;
-
- // 调用API获取景点数据
- findalls().then(res => {
- console.log('景点API返回数据:', res);
-
- if (res && res.code === 200) {
- // 获取API返回的数据数组
- let spotsData = res.obj;
-
- // 如果数据在不同的位置,尝试找到正确的位置
- if (!Array.isArray(spotsData)) {
- if (Array.isArray(res.data)) {
- spotsData = res.data;
- } else if (res.data && Array.isArray(res.data.obj)) {
- spotsData = res.data.obj;
- }
- }
-
- // 确保获取到的是数组数据
- if (Array.isArray(spotsData) && spotsData.length > 0) {
- // 过滤有效的景点数据(必须有名称、经纬度和封面图片)
- const validSpots = spotsData.filter(spot =>
- spot.name &&
- (spot.latitude || spot.latitude === 0) &&
- (spot.longitude || spot.longitude === 0)
- );
-
- // 按景点等级排序,保留最高级别的热门景点
- this.hotSpots = validSpots
- .sort((a, b) => {
- // 先按等级排序
- const levelA = a.level ? a.level.replace('A', '') : '0';
- const levelB = b.level ? b.level.replace('A', '') : '0';
- const levelDiff = parseInt(levelB) - parseInt(levelA);
-
- // 如果等级相同,按城市排序(优先显示保定的景点)
- if (levelDiff === 0) {
- if (a.city === '保定市' && b.city !== '保定市') return -1;
- if (a.city !== '保定市' && b.city === '保定市') return 1;
- }
-
- return levelDiff;
- });
-
- // 处理封面图片
- this.hotSpots = this.hotSpots.map((spot, index) => {
- // 如果没有封面图,使用默认图片
- if (!spot.coverImage) {
- spot.coverImage = this.defaultImages[index % this.defaultImages.length];
- } else if (spot.coverImage.startsWith('http')) {
- // 如果是完整URL,直接使用
- // 不做处理
- } else if (!spot.coverImage.startsWith('/')) {
- // 如果不是以/开头,添加/
- spot.coverImage = '/' + spot.coverImage;
- }
- return spot;
- });
-
- console.log('已加载热门景点:', this.hotSpots.length);
- } else {
- console.error('API返回的数据不是数组格式:', spotsData);
- this.hotSpots = [];
- }
- } else {
- console.error('API返回错误:', res);
- this.hotSpots = [];
- }
- }).catch(err => {
- console.error('加载景点数据失败:', err);
- this.hotSpots = [];
- }).finally(() => {
- this.isLoadingSpots = false;
- });
- },
-
- // 获取景点的简短描述
- getShortDesc(spot) {
- if (spot.description) {
- // 截取描述的前15个字符,如果超过则添加省略号
- return spot.description.length > 15 ?
- spot.description.substring(0, 15) + '...' :
- spot.description;
- } else if (spot.city) {
- return spot.city + (spot.category ? ' · ' + spot.category : '');
- } else if (spot.category) {
- return spot.category;
- } else {
- return '热门景点';
- }
- },
-
- // 选择目的地
- selectDestination(name, spot = null) {
- if (spot) {
- // 显示加载提示
- uni.showLoading({
- title: '加载景点详情...'
- });
-
- // 调用API获取景点详情
- findById(spot.id).then(res => {
- uni.hideLoading();
-
- console.log('景点详情API返回:', res);
-
- let detailSpot = null;
-
- // 解析API返回的数据
- if (res && res.code === 200) {
- // 尝试从不同位置获取数据
- if (res.obj) {
- detailSpot = res.obj;
- } else if (res.data && res.data.obj) {
- detailSpot = res.data.obj;
- } else if (res.data) {
- detailSpot = res.data;
- }
- }
-
- // 合并API返回的详情和已有的基本数据
- const finalSpot = detailSpot ? {...spot, ...detailSpot} : spot;
-
- // 跳转到景点详情页面
- uni.navigateTo({
- url: `/pages/spot-detail/index?spotId=${finalSpot.id}&spotName=${encodeURIComponent(finalSpot.name)}`,
- fail: (err) => {
- console.error('跳转到景点详情页失败:', err);
- // 如果景点详情页面不存在,则直接跳转到地图页面
- this.navigateToSpotMap(finalSpot);
- }
- });
- }).catch(err => {
- uni.hideLoading();
- console.error('获取景点详情失败:', err);
-
- // 获取详情失败,使用已有的基本信息跳转到地图页面
- this.navigateToSpotMap(spot);
- });
- } else {
- uni.showToast({
- title: '已选择目的地: ' + name,
- icon: 'none'
- });
- }
- },
-
- // 导航到景点地图页面
- navigateToSpotMap(spot) {
- uni.navigateTo({
- url: `/pages/custom-trip/map?lat=${spot.latitude}&lng=${spot.longitude}&name=${encodeURIComponent(spot.name)}`,
- fail: (err) => {
- console.error('跳转到地图页面失败:', err);
- uni.showToast({
- title: '跳转失败',
- icon: 'none'
- });
- }
- });
- },
-
- createCustomPlan() {
- uni.showToast({
- title: '跳转到保定自定义行程',
- icon: 'none',
- duration: 2000
- });
- // 使用navigateTo方式打开地图页面
- uni.navigateTo({
- url: '/pages/custom-trip/map',
- success: () => {
- console.log('成功打开保定自定义行程!');
- },
- fail: (err) => {
- console.error('打开保定自定义行程失败:', err);
- uni.showModal({
- title: '跳转失败',
- content: JSON.stringify(err),
- showCancel: false
- });
- }
- });
- },
- createAiPlan() {
- // 直接跳转到AI助手页面,默认使用OpenAI
- uni.navigateTo({
- url: '/pages/ai-assistant/index',
- success: (navRes) => {
- // 默认使用OpenAI (aiType = 1)
- navRes.eventChannel.emit('setAIType', {
- aiType: 1
- });
- console.log('成功打开AI行程助手!');
- },
- fail: (err) => {
- console.error('打开AI行程助手失败:', err);
- uni.showModal({
- title: '跳转失败',
- content: JSON.stringify(err),
- showCancel: false
- });
- }
- });
- },
- viewTripDetail(id) {
- uni.showToast({
- title: '查看行程详情: ' + id,
- icon: 'none'
- });
-
- // 跳转到行程详情页
- uni.navigateTo({
- url: `/pages/travel-detail/index?planId=${id}`,
- fail: (err) => {
- console.error('跳转到行程详情页失败:', err);
- }
- });
- },
- showMoreTrips() {
- // 跳转到全部行程页面
- uni.navigateTo({
- url: '/pages/planning/all-trips',
- success: () => {
- console.log('成功跳转到全部行程页面');
- },
- fail: (err) => {
- console.error('跳转到全部行程页面失败:', err);
- uni.showToast({
- title: '跳转失败',
- icon: 'none'
- });
- }
- });
- },
- // 加载保存的行程数据
- loadSavedTrips() {
- // 首先尝试从API获取行程数据
- const useApi = true; // 是否使用API(可以根据环境设置)
-
- if (useApi && this.$api) {
- // 显示加载中提示
- uni.showLoading({
- title: '加载行程数据...',
- mask: false
- });
-
- // 调用API获取行程列表
- this.$api.trip.list()
- .then(res => {
- if (res && res.data) {
- console.log('从API加载行程数据成功:', res.data.length);
- this.savedTrips = res.data;
-
- // 同时更新本地存储,保持同步
- uni.setStorageSync('savedTrips', res.data);
- } else {
- console.log('API没有返回行程数据,尝试从本地存储加载');
- this.loadLocalTrips();
- }
- })
- .catch(err => {
- console.error('从API加载行程数据失败:', err);
- // 加载失败时从本地存储获取
- this.loadLocalTrips();
- })
- .finally(() => {
- uni.hideLoading();
- });
- } else {
- // 直接从本地存储加载
- this.loadLocalTrips();
- }
- },
-
- // 从本地存储加载行程数据
- loadLocalTrips() {
- try {
- const trips = uni.getStorageSync('savedTrips') || [];
- console.log('从本地存储加载的行程:', trips.length);
- this.savedTrips = trips;
-
- // 如果有行程数据且API可用,考虑同步到服务器
- if (trips.length > 0 && this.$api) {
- console.log('有本地行程数据,可以考虑同步到服务器');
- // 这里可以调用API.trip.sync(trips)同步数据到服务器
- }
- } catch (e) {
- console.error('加载本地行程失败:', e);
- this.savedTrips = [];
- }
- },
-
- // 格式化日期显示
- formatDate(dateString) {
- if (!dateString) return '';
- const date = new Date(dateString);
- return `${date.getFullYear()}.${date.getMonth() + 1}.${date.getDate()}`;
- },
- // 获取行程封面图片
- getTripCoverImage(trip) {
- // 如果行程有spots并且第一个spot有图片,则使用该图片
- if (trip.spots && trip.spots.length > 0 && trip.spots[0].coverImage) {
- return trip.spots[0].coverImage;
- }
-
- // 根据行程名称选择默认图片
- if (trip.name.includes('保定')) {
- return '/static/baoding.jpg';
- } else if (trip.name.includes('西安')) {
- return '/static/xian.jpg';
- } else if (trip.name.includes('北京')) {
- return '/static/beijing.jpg';
- } else if (trip.name.includes('上海')) {
- return '/static/shanghai.jpg';
- }
-
- // 默认使用景点图片数组中的一张
- const defaultImages = [
- '/static/baoding.jpg',
- '/static/custom_plan_icon.png',
- '/static/beijing.jpg',
- '/static/chengdu.jpg'
- ];
-
- // 根据行程ID生成一个固定的索引,确保每次显示相同的图片
- const hash = trip.id.split('_')[1] || Date.now();
- const index = hash % defaultImages.length;
-
- return defaultImages[index];
- }
- }
- }
- </script>
- <style>
- .content {
- display: flex;
- flex-direction: column;
- background: linear-gradient(to bottom, #dbf0ff 0%, #e3f4ff 40%, #f0f9ff 100%);
- min-height: 100vh;
- padding: 30rpx;
- position: relative;
- overflow: hidden;
- }
- /* 背景装饰 */
- .bg-decoration {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- z-index: 0;
- overflow: hidden;
- }
- .bg-circle {
- position: absolute;
- border-radius: 50%;
- opacity: 0.1;
- }
- .bg-circle-1 {
- top: -300rpx;
- right: -200rpx;
- width: 800rpx;
- height: 800rpx;
- background: linear-gradient(120deg, #a1c4fd 0%, #c2e9fb 100%);
- }
- .bg-circle-2 {
- bottom: -400rpx;
- left: -300rpx;
- width: 1000rpx;
- height: 1000rpx;
- background: linear-gradient(120deg, #89f7fe 0%, #66a6ff 100%);
- }
- .header {
- margin-bottom: 40rpx;
- position: relative;
- z-index: 1;
- }
- .header-title {
- font-size: 48rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 10rpx;
- text-shadow: 2rpx 2rpx 4rpx rgba(0, 0, 0, 0.1);
- }
- .header-subtitle {
- font-size: 28rpx;
- color: #666;
- font-style: italic;
- }
- /* 行程规划选项样式 */
- .planning-options {
- display: flex;
- justify-content: space-between;
- margin-bottom: 60rpx;
- position: relative;
- z-index: 1;
- }
- .option-card {
- width: 48%;
- background-color: #fff;
- border-radius: 20rpx;
- padding: 30rpx;
- display: flex;
- flex-direction: column;
- box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
- transition: all 0.3s ease;
- position: relative;
- overflow: hidden;
- }
- .card-hover {
- transform: translateY(-10rpx);
- box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.15);
- }
- .custom-plan {
- background: linear-gradient(to bottom right, #ffffff, #f8f8f8);
- border: 1rpx solid #eaeaea;
- }
- .ai-plan {
- background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
- }
- .ai-plan .option-title,
- .ai-plan .option-desc,
- .ai-plan .arrow-text,
- .ai-plan .arrow-icon {
- color: #fff;
- }
- .option-icon-wrap {
- width: 100rpx;
- height: 100rpx;
- border-radius: 50%;
- background-color: #f0f8ff;
- display: flex;
- justify-content: center;
- align-items: center;
- margin-bottom: 20rpx;
- box-shadow: 0 6rpx 15rpx rgba(0, 0, 0, 0.05);
- }
- .ai-icon-wrap {
- background-color: rgba(255, 255, 255, 0.2);
- }
- .option-icon {
- width: 60rpx;
- height: 60rpx;
- }
- .option-title {
- font-size: 32rpx;
- font-weight: bold;
- margin-bottom: 10rpx;
- color: #333;
- }
- .option-desc {
- font-size: 24rpx;
- color: #666;
- margin-bottom: 20rpx;
- }
- .option-arrow {
- display: flex;
- align-items: center;
- justify-content: space-between;
- margin-top: 20rpx;
- }
- .arrow-text {
- font-size: 26rpx;
- color: #3a9eeb;
- }
- .arrow-icon {
- font-size: 30rpx;
- color: #3a9eeb;
- }
- /* 待出发行程样式 */
- .upcoming-trips {
- margin-top: 20rpx;
- position: relative;
- z-index: 1;
- }
- .section-header {
- display: flex;
- justify-content: space-between;
- align-items: center;
- margin-bottom: 30rpx;
- }
- .section-title-wrap {
- position: relative;
- }
- .section-title {
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- position: relative;
- z-index: 1;
- }
- .title-underline {
- position: absolute;
- bottom: 0;
- left: 0;
- width: 80rpx;
- height: 10rpx;
- background: linear-gradient(to right, #4facfe, #00f2fe);
- border-radius: 10rpx;
- }
- .section-more {
- display: flex;
- align-items: center;
- }
- .more-text {
- font-size: 26rpx;
- color: #3a9eeb;
- }
- .more-icon {
- margin-left: 5rpx;
- font-size: 26rpx;
- color: #3a9eeb;
- }
- .trip-list {
- display: flex;
- flex-direction: column;
- gap: 30rpx;
- }
- .trip-card {
- background-color: #fff;
- border-radius: 20rpx;
- display: flex;
- overflow: hidden;
- position: relative;
- box-shadow: 0 10rpx 30rpx rgba(0, 0, 0, 0.1);
- transition: all 0.3s ease;
- }
- /* 行程卡片背景图片 */
- .trip-background-image {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- object-fit: cover;
- z-index: 1;
- }
-
- .trip-overlay {
- position: absolute;
- top: 0;
- left: 0;
- width: 100%;
- height: 100%;
- background: linear-gradient(to right, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.3) 100%);
- z-index: 2;
- }
- .card-shadow {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- height: 8rpx;
- background: linear-gradient(to right, #4facfe, #00f2fe);
- border-radius: 0 0 20rpx 20rpx;
- z-index: 5;
- }
- .trip-info {
- flex: 1;
- padding: 30rpx;
- display: flex;
- flex-direction: column;
- justify-content: space-between;
- position: relative;
- z-index: 3;
- }
-
- .trip-location {
- display: flex;
- align-items: flex-start;
- margin-bottom: 30rpx;
- }
-
- .location-icon {
- width: 40rpx;
- height: 40rpx;
- margin-right: 15rpx;
- margin-top: 6rpx;
- }
-
- .trip-main-info {
- flex: 1;
- }
-
- /* 修改文本颜色以适应图片背景 */
- .trip-name {
- font-size: 32rpx;
- font-weight: bold;
- color: #ffffff;
- margin-bottom: 15rpx;
- line-height: 1.4;
- text-shadow: 1rpx 1rpx 3rpx rgba(0, 0, 0, 0.5);
- }
-
- .trip-date {
- font-size: 28rpx;
- color: #f0f0f0;
- text-shadow: 1rpx 1rpx 2rpx rgba(0, 0, 0, 0.5);
- }
-
- .trip-date-wrap {
- display: flex;
- align-items: center;
- }
-
- .trip-date-label {
- font-size: 26rpx;
- color: #e0e0e0;
- margin-right: 10rpx;
- text-shadow: 1rpx 1rpx 2rpx rgba(0, 0, 0, 0.5);
- }
-
- .trip-date-value {
- font-size: 26rpx;
- color: #ffffff;
- background-color: rgba(0, 0, 0, 0.3);
- padding: 4rpx 16rpx;
- border-radius: 100rpx;
- }
-
- .trip-members {
- display: flex;
- align-items: center;
- }
-
- .member-icon {
- width: 40rpx;
- height: 40rpx;
- margin-right: 15rpx;
- }
-
- .member-count {
- font-size: 26rpx;
- color: #f0f0f0;
- text-shadow: 1rpx 1rpx 2rpx rgba(0, 0, 0, 0.5);
- }
- .trip-stats {
- width: 200rpx;
- background: linear-gradient(to bottom, rgba(182, 230, 255, 0.9), rgba(132, 212, 255, 0.9));
- padding: 30rpx 20rpx;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: center;
- position: relative;
- z-index: 3;
- }
- .trip-tag {
- display: flex;
- flex-direction: column;
- align-items: center;
- margin-bottom: 20rpx;
- }
- .tag-title {
- font-size: 24rpx;
- font-weight: bold;
- color: #333;
- }
- .tag-subtitle {
- font-size: 24rpx;
- font-weight: bold;
- color: #333;
- }
- .globe-icon {
- width: 40rpx;
- height: 40rpx;
- margin-top: 10rpx;
- }
- .trip-divider {
- width: 80%;
- height: 2rpx;
- background-color: rgba(51, 51, 51, 0.2);
- margin: 15rpx 0;
- }
- .trip-duration,
- .trip-distance {
- width: 100%;
- display: flex;
- flex-direction: column;
- align-items: flex-end;
- margin-top: 10rpx;
- }
- .stat-label {
- font-size: 24rpx;
- color: #333;
- text-align: right;
- }
- .stat-value {
- font-size: 28rpx;
- font-weight: bold;
- color: #333;
- text-align: right;
- }
- /* 热门目的地推荐 */
- .recommendations {
- margin-top: 60rpx;
- position: relative;
- z-index: 1;
- padding: 0 10rpx;
- }
- .recommendation-title {
- font-size: 36rpx;
- font-weight: bold;
- color: #333;
- margin-bottom: 20rpx;
- display: flex;
- align-items: center;
- }
-
- .recommendation-title::before {
- content: "";
- display: inline-block;
- width: 8rpx;
- height: 36rpx;
- background: linear-gradient(to bottom, #4facfe, #00f2fe);
- margin-right: 16rpx;
- border-radius: 4rpx;
- }
- .recommendation-scroll {
- width: 100%;
- }
- .recommendation-list {
- display: flex;
- flex-direction: column;
- gap: 20rpx;
- padding: 10rpx 0;
- }
- .recommendation-item {
- width: 100%;
- height: 220rpx;
- border-radius: 16rpx;
- overflow: hidden;
- box-shadow: 0 6rpx 20rpx rgba(0, 0, 0, 0.1);
- position: relative;
- transition: all 0.3s ease;
- }
-
- .recommendation-item:active {
- transform: scale(0.98);
- box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.15);
- }
- .recommendation-image {
- width: 100%;
- height: 100%;
- object-fit: cover;
- }
-
- .recommendation-overlay {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: linear-gradient(to top, rgba(0,0,0,0.7) 0%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0) 100%);
- }
- .recommendation-info {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- padding: 20rpx;
- z-index: 2;
- }
- .recommendation-name {
- font-size: 32rpx;
- font-weight: bold;
- color: #ffffff;
- margin-bottom: 6rpx;
- text-shadow: 0 1px 3px rgba(0,0,0,0.5);
- }
- .recommendation-desc {
- font-size: 24rpx;
- color: rgba(255,255,255,0.9);
- text-shadow: 0 1px 2px rgba(0,0,0,0.4);
- }
-
- /* 加载中样式 */
- .loading-container {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100%;
- height: 200rpx;
- background-color: #f2f2f2;
- border-radius: 16rpx;
- margin-bottom: 20rpx;
- }
-
- .loading-text {
- font-size: 30rpx;
- color: #999;
- }
-
- /* 空数据样式 */
- .empty-trip {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- background-color: #f9f9f9;
- border-radius: 20rpx;
- padding: 60rpx 0;
- box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.05);
- }
-
- .empty-icon {
- font-size: 80rpx;
- margin-bottom: 20rpx;
- }
-
- .empty-text {
- font-size: 32rpx;
- color: #666;
- margin-bottom: 10rpx;
- }
-
- .empty-subtext {
- font-size: 26rpx;
- color: #999;
- }
-
- .empty-container {
- display: flex;
- justify-content: center;
- align-items: center;
- width: 100%;
- height: 200rpx;
- background-color: #f2f2f2;
- border-radius: 16rpx;
- margin-bottom: 20rpx;
- }
-
- .empty-text {
- font-size: 30rpx;
- color: #999;
- }
- /* 测试按钮样式 */
- .test-btn {
- background-color: #ff9500;
- color: #fff;
- padding: 15rpx 30rpx;
- border-radius: 10rpx;
- font-size: 28rpx;
- font-weight: bold;
- text-align: center;
- margin-bottom: 20rpx;
- align-self: center;
- box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.1);
- }
- /* 热门目的地样式 */
- .spots-grid {
- display: flex;
- justify-content: space-between;
- padding: 0 10rpx;
- gap: 30rpx;
- }
-
- .spot-card {
- width: 320rpx;
- height: 280rpx;
- background-color: #fff;
- border-radius: 20rpx;
- overflow: hidden;
- position: relative;
- box-shadow: 0 4rpx 12rpx rgba(0,0,0,0.1);
- margin-bottom: 20rpx;
- }
-
- .spot-image {
- width: 100%;
- height: 180rpx;
- border-radius: 20rpx 20rpx 0 0;
- }
-
- .spot-tag {
- position: absolute;
- top: 16rpx;
- left: 16rpx;
- background-color: #ff6b35;
- color: white;
- font-size: 24rpx;
- padding: 4rpx 12rpx;
- border-radius: 8rpx;
- font-weight: bold;
- z-index: 1;
- }
-
- .spot-name {
- font-size: 30rpx;
- font-weight: bold;
- color: #333;
- padding: 16rpx 16rpx 8rpx;
- }
-
- .spot-location {
- display: flex;
- align-items: center;
- font-size: 24rpx;
- color: #999;
- padding: 0 16rpx;
- }
-
- .location-dot {
- color: #ff4f81;
- font-size: 24rpx;
- margin-right: 6rpx;
- }
- </style>
|