Commit 9e3ae0b2 authored by 罗超's avatar 罗超

修改文件

parent 442cdc95
...@@ -25,11 +25,17 @@ ...@@ -25,11 +25,17 @@
margin-top: 32rpx !important; margin-top: 32rpx !important;
} }
.q-mb-md{ .q-mb-md{
margin-bottom: 32rpx; margin-bottom: 32rpx;
} }
.q-mr-sm{ .q-mr-sm{
margin-right: 16rpx; margin-right: 16rpx;
} }
.q-px-md{
padding: 0 32rpx;
}
.q-mx-md{
margin: 0 32rpx;
}
.q-ml-sm{ .q-ml-sm{
margin-left: 16rpx; margin-left: 16rpx;
} }
...@@ -626,4 +632,10 @@ ...@@ -626,4 +632,10 @@
} }
.opacity0{ .opacity0{
opacity: 0; opacity: 0;
}
.window-height{
height: 100vh;
}
.window-width{
width: 100vw;
} }
\ No newline at end of file
@font-face { @font-face {
font-family: "tffont"; /* Project id 4816119 */ font-family: "tffont"; /* Project id 4816119 */
src: url('//at.alicdn.com/t/c/font_4816119_6zzxojucd79.woff2?t=1740378953818') format('woff2'), src: url('//at.alicdn.com/t/c/font_4816119_2wse58hij19.woff2?t=1750606991860') format('woff2'),
url('//at.alicdn.com/t/c/font_4816119_6zzxojucd79.woff?t=1740378953818') format('woff'), url('//at.alicdn.com/t/c/font_4816119_2wse58hij19.woff?t=1750606991860') format('woff'),
url('//at.alicdn.com/t/c/font_4816119_6zzxojucd79.ttf?t=1740378953818') format('truetype'); url('//at.alicdn.com/t/c/font_4816119_2wse58hij19.ttf?t=1750606991860') format('truetype');
} }
.tffont { .tffont {
...@@ -13,6 +13,50 @@ ...@@ -13,6 +13,50 @@
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;
} }
.tffont-dinner:before {
content: "\e686";
}
.tffont-chuang1:before {
content: "\e604";
}
.tffont-lvxing:before {
content: "\e603";
}
.tffont-yuanquan:before {
content: "\e63e";
}
.tffont-niunai:before {
content: "\e61e";
}
.tffont-moonbyueliang:before {
content: "\e6a0";
}
.tffont-jingdian:before {
content: "\e88f";
}
.tffont-roushi-c:before {
content: "\e602";
}
.tffont-175:before {
content: "\e6bb";
}
.tffont-othertraffic:before {
content: "\e62a";
}
.tffont-Sunny:before {
content: "\e8c7";
}
.tffont-checkmark:before { .tffont-checkmark:before {
content: "\e611"; content: "\e611";
} }
...@@ -103,4 +147,4 @@ ...@@ -103,4 +147,4 @@
.tffont-yongjin2:before { .tffont-yongjin2:before {
content: "\e600"; content: "\e600";
} }
\ No newline at end of file
...@@ -682,6 +682,13 @@ ...@@ -682,6 +682,13 @@
}, },
{ {
"path": "videoinfo" "path": "videoinfo"
},
{
"path" : "aiTravelDetail",
"style" :
{
"navigationStyle": "custom"
}
} }
] ]
}, },
......
<template>
<scroll-view class="window-height window-width" @scroll="handleScroll" scroll-y :scroll-top="scrollTop">
<view class="ai-travel-page" v-if="!loading">
<view class="bg-blur-container" id="travel_first">
<view class="bg-blur"></view>
<view class="content">
<view class="title">
行至天光处,
</view>
<view class="title q-mt-md title-indented">
坐看云起时.
</view>
<view class="hero-subtitle">
<view>
尊驾光临,不胜荣幸。我们以匠心丈量世界,
</view>
<view class="hero-subtitle-line2">
为您定制专属旅程,让每一次出发都成为灵魂的礼遇。
</view>
</view>
</view>
</view>
<view
:style="{ 'height': topHeight + 'px', 'opacity': (currentTop >= (screenHeight * 0.6) - topHeight) ? 1 : 0 }"
style="background-color: #25323c;position: fixed;top: 0;left: 0;right: 0;z-index: 9;"></view>
<view class="sticky-nav-bar row items-center" :style="{ 'top': topHeight + 'px' }">
<view v-for="menu in menus" :key="menu.id" :class="{ 'active': activeMenu === menu.id }"
class="col text-center relative" @click="handleMenuClick(menu)">
{{ menu.name }}
</view>
</view>
<view class="main-content-wrapper q-mt-md">
<view class="tag">
请您开启:
</view>
<view class="trip-title q-mt-sm">
{{ travel.title }}
</view>
<view class="travel-demand-quote">
<view class="travel-demand-title">出行需求:</view>
<view v-if="require && require.summaryArray">
<!-- {{ require.summary }} -->
<view v-for="(item, i) in require.summaryArray" :key="i">
{{ item }}
</view>
</view>
</view>
</view>
<view class="travel-ai-title q-mx-md">设计特色</view>
<view class="feature-list q-px-md q-mt-md text-sm">
<template v-if="travel.recommendReason">
<view v-for="(item, i) in travel.recommendReason.split('\n')" :key="i">
{{ item }}
</view>
</template>
</view>
<view class="section-container q-px-md" id="travel_second">
<view class="section-title">
<span>02</span>
<span class="q-ml-md">行程</span>
<span class="text-gold">规划</span>
</view>
<view class="section-subtitle">
Trip Agenda
</view>
<view class="trip-agenda-box">
<view class="sample-day row items-center" v-for="(item, i) in travel.days" :key="i">
<view class="day-num">D{{ item.orderNum }}</view>
<view class="col q-ml-md">
<view class="detail-title">
<text class="q-mr-sm" v-for="(city, j) in item.cities" :key="j">{{ city }}</text>
</view>
<view class="detail-list">
<block v-for="(attraction, j) in item.attractions" :key="j">
<text>{{ attraction.name }}</text>
<u-icon name="arrow" size="20" color="#12121299" class="detail-arrow"
v-if="j < item.attractions.length - 1"></u-icon>
</block>
</view>
</view>
</view>
</view>
</view>
<view class="section-container q-px-md" id="travel_third">
<view class="section-title">
<span>03</span>
<span class="q-ml-md">每日</span>
<span class="text-gold">行程</span>
</view>
<view class="section-subtitle">
Daily Itinerary
</view>
<view class="daily-itinerary-box" style="padding-top: 30px;">
<view class="daily-itinerary-item" v-for="(item, i) in travel.days" :key="i">
<view class="row items-center"
style="background-color: #121212;border-radius: 20rpx;padding:20rpx;">
<view class="title-num q-mr-md">
D{{ item.orderNum }}
</view>
<view class="title-content col">
<view class="">{{ item.title }}</view>
<view style="opacity: .8; font-size:26rpx ;">
<text class="q-mr-sm" v-for="(city, j) in item.cities" :key="j">{{ city }}</text>
</view>
</view>
</view>
<view style="height: 40px;"></view>
<!-- <view class="traff">
<view class="icon-box">
<u-icon name='othertraffic' custom-prefix="tffont" color="#fff" size="40"
style="display: inline-block;"></u-icon>
</view>
<view class="row items-center">
<view style="width: 30px; text-align: center;">
<u-icon name='yuanquan' custom-prefix="tffont" color="#12121266" size="40"
style="display: inline-block;"></u-icon>
</view>
<view class="col q-ml-md">
<view class="text-gold">
成都
</view>
<view style="font-size: 18px;color: #121212;line-height: 1;padding: 10rpx 0;">
成都天府国际机场
</view>
<view style="font-size: 12px;color: #12121266;">
出发时间:08:23
</view>
</view>
</view>
<view class="row items-center">
<view style="height: 86px;">
<view class="relative"
style="height: 100%; width: 30px;text-align: center;line-height: 86px;">
<u-icon name='qianwang' custom-prefix="tffont" color="#12121266" size="16"
style="transform: rotate(90deg) scaleY(-1);margin-left: -8px;"></u-icon>
<view
style="background:#FFF;width: 30px;height: 30px;border:3px solid #12121266;border-radius: 30px;position: absolute;top: 50%;left: 0;transform: translateY(-50%);line-height: 30px;text-align: center;">
<u-icon name='lvxing' custom-prefix="tffont" color="#12121266" size="32"
style="transform: scaleY(-1);display: inline-block;margin-top: -12px;"></u-icon>
</view>
</view>
</view>
<view class="col q-ml-md">
<view style="font-size: 18px;color: #121212;line-height: 1;padding: 10rpx 0;">
CA2351
</view>
<view style="font-size: 12px;color: #12121266;">
用时: 3小时58分
</view>
</view>
</view>
<view class="row items-center">
<view style="width: 30px; text-align: center;">
<u-icon name='dingwei' custom-prefix="tffont" color="#12121266" size="40"
style="display: inline-block;"></u-icon>
</view>
<view class="col q-ml-md">
<view class="text-gold">
成都
</view>
<view style="font-size: 18px;color: #121212;line-height: 1;padding: 10rpx 0;">
成都天府国际机场
</view>
<view style="font-size: 12px;color: #12121266;">
出发时间:08:23
</view>
</view>
</view>
</view> -->
<!-- <view class="split-line"></view> -->
<template v-if="i > 0 && travel.days[i - 1].hotels && travel.days[i - 1].hotels.length > 0">
<view class="hotel">
<view class="icon-box icon-box-sum">
<!-- <u-icon name='moonbyueliang' custom-prefix="tffont" color="#fff" size="40" style="display: inline-block;"></u-icon> -->
<u-icon name='Sunny' custom-prefix="tffont" color="#fff" size="40"
style="display: inline-block;"></u-icon>
</view>
<image :src="travel.days[i - 1].hotels[0].images" class="hotel-image" mode="aspectFill"
v-if="travel.days[i - 1].hotels[0].images"></image>
<view v-else class="hotel-image" style="background-color: #12121266;"></view>
<view class="hotel-info">
<view class="hotel-name">
<u-icon name='chuang1' custom-prefix="tffont" color="#121212CC" size="40"
style="display: inline-block;"></u-icon>
<text class="q-ml-sm">{{ travel.days[i - 1].hotels[0].name }}</text>
</view>
<view class="hotel-desc">
{{ travel.days[i - 1].hotels[0].description }}
</view>
<!-- <view class="text-center" style="margin-top: 20px;">
<view class="expense" @click="handleShowMore(i, travel.days[i - 1].hotels[0].id)">
{{ showObject.day == i && showObject.id == travel.days[i - 1].hotels[0].id ?
'点击收起' : '点击展开详情' }}
</view>
</view> -->
</view>
</view>
<view class="split-line"></view>
</template>
<template v-for="(scenicspot, scenIndex) in item.attractions">
<view class="scenicspot" :key="scenIndex">
<view class="icon-box">{{ scenIndex+1 }}</view>
<image :src="scenicspot.images" class="scenicspot-image" mode="aspectFill"
v-if="scenicspot.images">
</image>
<view v-else class="scenicspot-image" style="background-color: #12121266;"></view>
<view class="scenicspot-info">
<view class="scenicspot-name">
<u-icon name='jingdian' custom-prefix="tffont" color="#C5A33E" size="40"
style="display: inline-block;"></u-icon>
<text class="q-ml-sm">{{ scenicspot.name }}</text>
</view>
<view class="scenicspot-desc" >
{{ scenicspot.description }}
</view>
<!-- <view class="text-center" style="margin-top: 20px;">
<view class="expense" @click="handleShowMore(i,scenIndex)">
{{ showObject.day == i && showObject.id == scenIndex ? '点击收起' : '点击展开详情' }}
</view>
</view> -->
</view>
</view>
<view class="split-line"></view>
</template>
<template v-if="item.hotels && item.hotels.length > 0">
<view class="hotel">
<view class="icon-box">
<u-icon name='moonbyueliang' custom-prefix="tffont" color="#fff" size="40" style="display: inline-block;"></u-icon>
</view>
<image :src="item.hotels[0].images" class="hotel-image" mode="aspectFill"
v-if="item.hotels[0].images"></image>
<view v-else class="hotel-image" style="background-color: #12121266;"></view>
<view class="hotel-info">
<view class="hotel-name">
<u-icon name='chuang1' custom-prefix="tffont" color="#121212CC" size="40"
style="display: inline-block;"></u-icon>
<text class="q-ml-sm">{{ item.hotels[0].name }}</text>
</view>
<view class="hotel-desc" >
{{ item.hotels[0].description }}
</view>
<!-- <view class="text-center" style="margin-top: 20px;">
<view class="expense" @click="handleShowMore(i, item.hotels[0].id)">
{{ showObject.day == i && showObject.id == item.hotels[0].id ?
'点击收起' : '点击展开详情' }}
</view>
</view> -->
</view>
</view>
</template>
<view class="split-line"></view>
<view class="dinner">
<view class="icon-box">
<u-icon name='dinner' custom-prefix="tffont" color="#fff" size="40"
style="display: inline-block;"></u-icon>
</view>
<view class="dinner-info row items-center">
<u-icon name='niunai' custom-prefix="tffont" color="#12121266" size="30"></u-icon>
<text style="margin:0 10rpx;">早餐</text>
<view class="dinner-name">
{{ item.caterings.find(x=>x.type=='早餐')?item.caterings.find(x=>x.type=='早餐').name:'敬请自理' }}
</view>
</view>
<view class="dinner-info row items-center">
<u-icon name='roushi-c' custom-prefix="tffont" color="#12121266" size="30"></u-icon>
<text style="margin:0 10rpx;">午餐</text>
<view class="dinner-name">
{{ item.caterings.find(x=>x.type=='午餐')?item.caterings.find(x=>x.type=='午餐').name:'敬请自理' }}
</view>
</view>
<view class="dinner-info row items-center">
<u-icon name='175' custom-prefix="tffont" color="#12121266" size="30"></u-icon>
<text style="margin:0 10rpx;">晚餐</text>
<view class="dinner-name">
{{ item.caterings.find(x=>x.type=='晚餐')?item.caterings.find(x=>x.type=='晚餐').name:'敬请自理' }}
</view>
</view>
</view>
</view>
</view>
</view>
<view class="section-container q-px-md" id="travel_fourth">
<view class="section-title">
<span>04</span>
<span class="q-ml-md">费用</span>
<span class="text-gold">说明</span>
</view>
<view class="section-subtitle">
Cost Breakdown
</view>
<view class="travel-ai-title">费用包含</view>
<view class="include">
<view class="include-content">
<view v-for="(item,index) in travel.include.split('\n')" :key="index">{{ item }}</view>
</view>
</view>
<view class="travel-ai-title">费用不含</view>
<view class="include">
<view class="include-content">
<view v-for="(item,index) in travel.notInclude.split('\n')" :key="index">{{ item }}</view>
</view>
</view>
</view>
<view class="spacer"></view>
</view>
<view class="bg-blur-container" style="height: 100vh;" v-else>
<view class="bg-blur"></view>
<view class="content">
<view class="title">
行至天光处,
</view>
<view class="title q-mt-md title-indented">
坐看云起时.
</view>
<view class="hero-subtitle">
<view>
尊驾光临,不胜荣幸。我们以匠心丈量世界,
</view>
<view class="hero-subtitle-line2">
为您定制专属旅程,让每一次出发都成为灵魂的礼遇。
</view>
</view>
</view>
</view>
</scroll-view>
</template>
<script>
import http from '@/plugin/rwRequest'
export default {
data() {
return {
topHeight: 0,
screenHeight: 0,
currentTop: 0,
menus: [
{
id: 1,
name: '行程亮点',
scrollId: 'travel_first'
},
{
id: 2,
name: '行程规划',
scrollId: 'travel_second'
},
{
id: 3,
name: '每日行程',
scrollId: 'travel_third'
},
{
id: 4,
name: '费用说明',
scrollId: 'travel_fourth'
}
],
activeMenu: 1,
scrollId: '',
sectionTops: [],
isClickScrolling: false,
scrollTimeout: null,
scrollTop: 0,
travelId: '',
travel: {},
require: null,
cities: [],
showObject: {
day: 0,
id: ''
},
loading: true
}
},
onLoad(options) {
const systemInfo = uni.getSystemInfoSync()
this.topHeight = this.getTopSafeArea(systemInfo)
this.screenHeight = systemInfo.screenHeight
if (options.id) {
this.travelId = options.id
this.getTravelDetail()
}
},
onReady() {
},
methods: {
handleShowMore(day, id) {
if (day == this.showObject.day && id == this.showObject.id) {
this.showObject.day = -1
this.showObject.id = ''
} else {
this.showObject.day = day
this.showObject.id = id
}
},
getTravelDetail() {
http.get('/travel/' + this.travelId, {}, {
loading: true
}).then(res => {
this.travel = res
this.resolveCitiesHandler()
this.getTravelRequire()
this.loading = false
console.log(this.cities)
this.$nextTick(() => {
this.calculateSectionTops();
})
})
},
getTravelRequire() {
http.get('/requirement/' + this.travel.requireId, {}, {
loading: true
}).then(res => {
console.log(res)
this.require = res
this.require.summaryArray = this.require.summary.split('\n')
//console.log(this.require.summary.split('\n'))
})
},
getTopSafeArea(systemInfo) {
const isIOS = systemInfo.platform === 'ios'
let menuButtonInfo = {}
try {
menuButtonInfo = uni.getMenuButtonBoundingClientRect()
} catch (e) {
console.warn('非微信小程序环境,使用默认状态栏高度')
}
let navBarHeight = 0
if (menuButtonInfo.top) {
navBarHeight = menuButtonInfo.top + menuButtonInfo.height + (menuButtonInfo.top - systemInfo
.statusBarHeight)
} else {
navBarHeight = isIOS ? 44 : 48
}
return systemInfo.statusBarHeight + (isIOS ? 40 : 44)// + navBarHeight
},
handleScroll(e) {
this.currentTop = e.detail.scrollTop
if (this.isClickScrolling) {
return;
}
const buffer = this.topHeight + 20;
let currentActiveMenu = this.activeMenu;
for (let i = this.sectionTops.length - 1; i >= 0; i--) {
const section = this.sectionTops[i];
if (this.currentTop >= section.top - buffer) {
currentActiveMenu = section.id;
break;
}
}
if (this.activeMenu !== currentActiveMenu) {
this.activeMenu = currentActiveMenu;
}
},
handleMenuClick(menu) {
this.activeMenu = menu.id
this.isClickScrolling = true;
this.scrollTop = this.sectionTops.find(s => s.id === menu.id).top
clearTimeout(this.scrollTimeout);
this.scrollTimeout = setTimeout(() => {
this.isClickScrolling = false;
}, 400);
},
calculateSectionTops() {
const that = this
const query = uni.createSelectorQuery().in(this);
this.menus.forEach(menu => {
query.select('#' + menu.scrollId).boundingClientRect();
});
query.exec(res => {
if (Array.isArray(res) && res.every(item => item)) {
this.sectionTops = res.map((rect, index) => ({
id: this.menus[index].id,
top: rect.top - 50 - that.topHeight
}));
}
});
},
resolveCitiesHandler() {
this.travel.days = this.travel.days.sort((a, b) => a.orderNum - b.orderNum)
this.cities = [];
this.travel.days.forEach(x => {
x.cities = [];
const departures = x.traffics.map(y => y.departure)
const destinations = x.traffics.map(y => y.destination)
const attractionsCities = x.attractions.map(y => y.city)
const cateringsCities = x.caterings.map(y => y.city)
const hotelsCities = x.hotels.map(y => y.city)
let temp = [...new Set([...departures, ...destinations, ...attractionsCities, ...cateringsCities, ...hotelsCities])]
temp = temp.filter(y => y !== null && y !== undefined && y !== '' && !y.includes('实际') && !y.includes('周边') && !y.includes('或'))
temp = temp.map(y => {
y = y.replace('省', '').replace('市', '').replace('区', '').replace('县', '')
return y
})
x.cities = [...new Set(temp)]
this.cities = [...new Set([...this.cities, ...x.cities])]
});
},
}
}
</script>
<style lang="scss">
@import url("@/asset/css/flex.css");
@font-face {
font-family: 'SJhuazhaozhong';
src: url('https://im.oytour.com/tripfont/687060f51259482db1ca519ef285541d.woff') format('woff');
}
.ai-travel-page {
background-color: #f5f5f5;
}
.bg-blur-container {
position: relative;
height: 60vh;
width: 100vw;
overflow: hidden;
margin: 0;
padding: 0;
box-sizing: border-box;
}
.bg-blur {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
background-image: url('https://viitto-1301420277.cos.ap-chengdu.myqcloud.com/Upload/Goods/638861400391621664.jpeg');
background-size: cover;
background-position: center;
z-index: 1;
margin: 0;
padding: 0;
box-sizing: border-box;
}
.content {
position: relative;
z-index: 2;
margin-top: 70%;
padding: 0 40rpx;
opacity: 0.8;
height: 30%;
}
.content .title {
font-size: 60rpx;
font-weight: bold;
background: linear-gradient(0deg, rgb(255, 243, 183) 0%, 14%, rgb(253, 223, 153) 28%, 45%, rgb(247, 205, 131) 62%, 81%, rgb(253, 251, 213)) center center no-repeat fixed rgb(255, 255, 255);
opacity: 1;
line-height: 1;
letter-spacing: 0px;
color: rgb(247, 205, 131);
writing-mode: horizontal-tb;
background-clip: text !important;
font-family: SJhuazhaozhong;
text-shadow: 0 0 10rpx #000;
}
.title-indented {
text-indent: 110rpx;
}
.hero-subtitle {
font-size: 28rpx;
color: #fff;
text-shadow: 0 0 10rpx #000;
margin-top: 40rpx;
}
.hero-subtitle-line2 {
margin-top: 20rpx;
line-height: 52rpx;
}
.sticky-nav-bar {
background-color: #25323c;
color: #b8c1c8;
padding: 30rpx 0;
position: sticky;
left: 0;
right: 0;
z-index: 9;
}
.main-content-wrapper {
padding: 0 32rpx;
}
.tag {
display: inline-block;
border-radius: 10rpx;
padding: 6rpx 12rpx;
font-size: 24rpx;
background-color: #121212;
color: #C5A33E;
}
.trip-title {
font-size: 36rpx;
font-weight: 800;
color: #232323;
}
.travel-demand-quote {
position: relative;
font-size: 28rpx;
color: #333;
line-height: 1.7;
padding: 20rpx;
padding-left: 60rpx;
margin: 40rpx 0;
background: #eee;
border-radius: 20rpx;
box-shadow: none;
}
.travel-ai-title {
padding-left: 40rpx;
font-size: 32rpx;
font-weight: bold;
position: relative;
margin-top: 40px;
}
.text-gold {
color: #C5A33E !important;
}
.travel-ai-title::before {
display: block;
content: " ";
width: 8rpx;
top: 0;
left: 0;
bottom: 0;
background-color: #C5A33E;
border-radius: 4rpx;
position: absolute;
}
.travel-demand-quote::before {
content: "“";
position: absolute;
left: 0;
top: -10rpx;
font-size: 80rpx;
color: #d0d0d0;
font-family: serif;
line-height: 1;
z-index: 1;
}
.travel-demand-title {
font-weight: bold;
margin-bottom: 10rpx;
font-size: 30rpx;
color: #222;
}
.feature-list {
line-height: 1.8;
}
.section-container {
margin-top: 160rpx;
}
.section-title {
font-size: 48rpx;
color: #121212;
font-weight: bold;
}
.section-subtitle {
padding-left: 48px;
font-size: 12px;
color: #12121266;
}
.trip-agenda-box {
margin-top: 80rpx;
background-color: #FFF;
box-shadow: 0 0 10px #00000011;
border-radius: 20rpx;
}
.sample-day {
padding: 45rpx 30rpx;
border-bottom: 1px solid #12121211;
}
.sample-day:last-child {
border-bottom: none;
}
.sample-day .day-num {
width: 60rpx;
height: 60rpx;
border-radius: 60rpx;
line-height: 60rpx;
background-color: #C5A33E66;
color: #C5A33E;
font-size: 30rpx;
font-weight: bold;
text-align: center !important;
}
.sample-day .detail-title {
font-size: 28rpx;
line-height: 1;
color: #121212;
margin-bottom: 10rpx;
}
.sample-day .detail-list {
font-size: 24rpx;
color: #12121299;
flex-wrap: wrap;
}
.detail-arrow {
margin: 0 10rpx;
display: inline-block;
}
.spacer {
height: 40px;
}
.sticky-nav-bar .active {
color: #C5A33E !important;
}
.relative {
position: relative;
}
.sticky-nav-bar .active::after {
content: " ";
display: block;
width: 8px;
height: 8px;
background-color: #C5A33E;
position: absolute;
bottom: -15px;
left: 50%;
transform: translateX(-50%);
border-radius: 8px;
}
.sticky-nav-bar .active::before {
content: " ";
display: block;
height: 4px;
background-color: #C5A33E;
position: absolute;
bottom: -15px;
left: 30%;
right: 30%;
}
.daily-itinerary-item {
margin-top: 40rpx;
padding-bottom: 40px;
.title-num {
font-size: 40rpx;
color: #C5A33E;
}
.title-content {
margin-left: 15px;
color: #fff !important;
font-size: 28rpx;
}
.traff {
padding: 30rpx;
border-radius: 20rpx;
border: 1px solid #12121211;
position: relative;
padding-top: 50rpx;
.icon-box {
width: 80rpx;
height: 80rpx;
border-radius: 80rpx;
position: absolute;
top: -20px;
left: 10px;
background-color: #121212;
color: #fff;
text-align: center;
line-height: 80rpx;
}
}
.hotel {
border-radius: 20rpx;
position: relative;
.icon-box {
width: 80rpx;
height: 80rpx;
border-radius: 80rpx;
position: absolute;
top: -20px;
left: 10px;
background-color: #121212;
color: #fff;
text-align: center;
line-height: 80rpx;
z-index: 3;
}
.icon-box-sum {
background-color: #C5A33E !important;
}
.hotel-image {
width: 100%;
height: 150px;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
}
.hotel-info {
padding: 20rpx;
background-color: #FFF;
border-bottom-left-radius: 20rpx;
border-bottom-right-radius: 20rpx;
border: 1px solid #12121211;
border-top: none;
.hotel-name {
color: #121212CC;
font-weight: bold;
font-size: 22px;
}
.hotel-desc {
font-size: 12px;
color: #12121266;
margin-top: 5px;
}
.hotel-desc-overflow {
text-overflow: ellipsis;
overflow: hidden;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
display: -webkit-box;
}
}
}
.scenicspot {
border-radius: 20rpx;
position: relative;
.icon-box {
width: 80rpx;
height: 80rpx;
border-radius: 80rpx;
position: absolute;
top: -20px;
left: 10px;
background-color: #C5A33E;
color: #fff;
text-align: center;
line-height: 80rpx;
z-index: 3;
font-size: 40rpx;
}
.scenicspot-image {
width: 100%;
height: 150px;
border-top-left-radius: 20rpx;
border-top-right-radius: 20rpx;
}
.scenicspot-info {
padding: 20rpx;
background-color: #FFF;
border-bottom-left-radius: 20rpx;
border-bottom-right-radius: 20rpx;
border: 1px solid #12121211;
border-top: none;
.scenicspot-name {
color: #121212CC;
font-weight: bold;
font-size: 22px;
color: #C5A33E;
}
.scenicspot-desc {
font-size: 12px;
color: #12121266;
margin-top: 5px;
}
.scenicspot-desc-overflow {
text-overflow: ellipsis;
overflow: hidden;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
display: -webkit-box;
}
}
}
.dinner {
border-radius: 20rpx;
position: relative;
background-color: #12121212;
padding: 20px;
.icon-box {
width: 80rpx;
height: 80rpx;
border-radius: 80rpx;
position: absolute;
top: -20px;
left: 10px;
background-color: #121212;
color: #fff;
text-align: center;
line-height: 80rpx;
}
.dinner-info {
font-size: 24rpx;
color: #12121266;
margin-top: 15px;
.dinner-name {
font-size: 24rpx;
color: #121212;
}
}
}
.expense {
padding: 10rpx 20rpx;
border-radius: 10rpx;
border: 1px solid #C5A33E;
color: #C5A33E;
font-size: 24rpx;
display: inline-block;
}
.split-line {
height: 40px;
border-left: 3px dashed #12121222;
margin: 10rpx 29px;
}
}
.include {
background-color: #12121205;
border-radius: 20rpx;
padding: 20rpx;
margin-top: 20rpx;
font-size: 28rpx;
color: #121212;
line-height: 1.5;
.include-title {
// font-weight: bold;
font-size: 18px;
margin-bottom: 10rpx;
color: #C5A33E;
}
}
</style>
\ No newline at end of file
...@@ -23,8 +23,8 @@ export default { ...@@ -23,8 +23,8 @@ export default {
install(Vue, options) { install(Vue, options) {
Vue.prototype.host = "https://wx.weibaoge.cn/web/index.php?_mall_id=1285" Vue.prototype.host = "https://wx.weibaoge.cn/web/index.php?_mall_id=1285"
// "http://192.168.5.204:8030" // "http://192.168.5.204:8030"
Vue.prototype.host2 = process.env.NODE_ENV=="development"?"http://192.168.5.214:8033":"https://erpmallapi.oytour.com" Vue.prototype.host2 = process.env.NODE_ENV=="development"?"https://erpmallapi.oytour.com":"https://erpmallapi.oytour.com"
Vue.prototype.host3 = process.env.NODE_ENV=="development"?"http://192.168.5.214":"https://reborn.oytour.com" Vue.prototype.host3 = process.env.NODE_ENV=="development"?"https://reborn.oytour.com":"https://reborn.oytour.com"
// Vue.prototype.host2 = "https://erpmallapi.oytour.com" // Vue.prototype.host2 = "https://erpmallapi.oytour.com"
// Vue.prototype.host3 = "https://reborn.oytour.com" // Vue.prototype.host3 = "https://reborn.oytour.com"
// "http://192.168.5.204:8030": // "http://192.168.5.204:8030":
......
// utils/request.js
const BASE_URL = process.env.NODE_ENV === 'production'
? 'https://rw.oytour.com/api/app'
: 'https://rw.oytour.com/api/app';
const request = (method, url, data = {}, config = {}) => {
// 获取用户信息
let header = {
'Accept': 'application/json',
...config.header
};
try {
const userInfoStr = uni.getStorageSync('userInfo');
if (userInfoStr) {
const userInfo = JSON.parse(userInfoStr);
header['Authorization'] = `Bearer ${userInfo.token}`;
}
} catch (e) {
console.error('获取用户信息失败', e);
}
return new Promise((resolve, reject) => {
uni.request({
url: BASE_URL + url,
method: method.toUpperCase(),
data,
header,
timeout: config.timeout || 10000,
success: (res) => {
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data);
} else {
// 处理错误状态码
let errorMessage = '请求失败';
switch (res.statusCode) {
case 401:
errorMessage = '未授权,请登录';
break;
case 403:
errorMessage = '拒绝访问';
break;
case 404:
errorMessage = '请求地址不存在';
break;
case 500:
errorMessage = '服务器内部错误';
break;
default:
errorMessage = `请求错误: ${res.statusCode}`;
}
uni.showToast({
title: errorMessage,
icon: 'none',
duration: 2000
});
reject(res.data);
}
},
fail: (err) => {
let errorMessage = '网络错误';
if (err.errMsg.includes('timeout')) {
errorMessage = '请求超时';
}
uni.showToast({
title: errorMessage,
icon: 'none',
duration: 2000
});
reject(err);
}
});
});
};
// 封装常用方法
const http = {
get(url, params = {}, config = {}) {
return request('GET', url, params, config);
},
post(url, data = {}, config = {}) {
return request('POST', url, data, config);
},
put(url, data = {}, config = {}) {
return request('PUT', url, data, config);
},
delete(url, data = {}, config = {}) {
return request('DELETE', url, data, config);
},
// 文件上传
upload(url, filePath, name = 'file', formData = {}, config = {}) {
return new Promise((resolve, reject) => {
// 获取token
let header = {};
try {
const userInfoStr = uni.getStorageSync('userInfo');
if (userInfoStr) {
const userInfo = JSON.parse(userInfoStr);
header['Authorization'] = `Bearer ${userInfo.token}`;
}
} catch (e) {
console.error('获取用户信息失败', e);
}
uni.uploadFile({
url: BASE_URL + url,
filePath,
name,
formData,
header,
success: (res) => {
if (res.statusCode === 200) {
try {
const data = JSON.parse(res.data);
resolve(data);
} catch (e) {
resolve(res.data);
}
} else {
reject(res);
}
},
fail: (err) => {
reject(err);
}
});
});
}
};
export default http;
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment