Browse Source

提交

dev_xrcc
chenkainan 3 months ago
parent
commit
d2a0019d2d
  1. 93
      App.vue
  2. 84
      components/BackgroundMusic.vue
  3. 39
      components/BuyPeaches.vue
  4. 3
      components/CustomTabBar.vue
  5. 6
      components/MusicControl.vue
  6. 67
      components/ShareGuide.vue
  7. 106
      components/TitleHeader.vue
  8. 6
      components/chapter3/RandomImage.vue
  9. 14
      components/header.vue
  10. 575
      components/messageBoard.vue
  11. 508
      components/messagePop.vue
  12. 10
      mixins/myMixins.js
  13. 630
      pages.json
  14. 49
      pages/index/iSoul.vue
  15. 27
      pages/index/index.vue
  16. 4
      pages/index/intelligentAgent.vue
  17. 94
      pages/index/readingBody.vue
  18. 49
      pages/index/sensoryStore.vue
  19. 45
      pages/stratIndex.vue
  20. BIN
      static/fonts/SourceHanSerifSC-Regular.otf
  21. 37
      static/js/CommonFunction.js
  22. 36
      static/js/common.js
  23. 2
      subPackages/haveFeeling/detailXiang.vue
  24. 912
      subPackages/order/gwcOrder.vue
  25. 173
      subPackages/search/search.vue
  26. 8
      subPackages/techan/detail.vue
  27. 286
      taozi/chapter1/chapter1.vue
  28. 336
      taozi/chapter2/chapter2.vue
  29. 369
      taozi/chapter3/chapter3.vue
  30. 297
      taozi/chapter4/chapter4.vue
  31. 786
      taozi/home/home.vue
  32. 108
      utils/audioManager.js
  33. 163
      utils/request.js
  34. 164
      xxdf/chapter1/cover1.vue
  35. 10
      xxdf/chapter1/detail1.vue
  36. 12
      xxdf/chapter1/detail2.vue
  37. 12
      xxdf/chapter1/detail3.vue
  38. 26
      xxdf/chapter1/detail4.vue
  39. 12
      xxdf/chapter1/detail5.vue
  40. 460
      xxdf/chapter2/cover.vue
  41. 586
      xxdf/chapter3/cover.vue
  42. 18
      xxdf/chapter3/randomImage.vue
  43. 362
      xxdf/chapter4/cover.vue
  44. 269
      xxdf/home/home.vue

93
App.vue

@ -4,13 +4,14 @@
mainSliderIndex: 0, mainSliderIndex: 0,
randomImages: [], randomImages: [],
bgMusic: null, bgMusic: null,
isMusicPlaying: false isMusicPlaying: false,
musicSrc: 'https://static.ticket.sz-trip.com/epicSoul/EpicSouls.mp3'
}, },
onLaunch: function() { onLaunch: function() {
console.warn('当前组件仅支持 uni_modules 目录结构 ,请升级 HBuilderX 到 3.1.0 版本以上!') console.warn('当前组件仅支持 uni_modules 目录结构 ,请升级 HBuilderX 到 3.1.0 版本以上!')
console.log('App Launch') console.log('App Launch')
// //
this.initBackgroundMusic(); // this.initBackgroundMusic();
}, },
onShow: function() { onShow: function() {
console.log('App Show') console.log('App Show')
@ -21,46 +22,58 @@
methods: { methods: {
initBackgroundMusic() { initBackgroundMusic() {
try { try {
console.log('bgMusic',this.globalData.bgMusic)
//
if (this.globalData.bgMusic) {
this.globalData.bgMusic.stop();
this.globalData.bgMusic.destroy()
this.globalData.bgMusic = null;
}
let bgMusic; let bgMusic;
// - 使H5使 // - 使H5使
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
try { // try {
bgMusic = uni.getBackgroundAudioManager(); // bgMusic = uni.getBackgroundAudioManager();
// title // // title
bgMusic.title = '背景音乐'; // bgMusic.title = '';
} catch (e) { // // ID
console.error('获取背景音频管理器失败,改用内部音频上下文', e); // bgMusic.id = 'mp-audio';
bgMusic = uni.createInnerAudioContext(); // } catch (e) {
} // console.error('', e);
// bgMusic = uni.createInnerAudioContext();
// }
bgMusic = uni.createInnerAudioContext();
// #endif // #endif
// #ifndef MP-WEIXIN // #ifndef MP-WEIXIN
bgMusic = uni.createInnerAudioContext(); bgMusic = uni.createInnerAudioContext();
// #endif // #endif
// //
bgMusic.src = 'https://mp-8aaaff75-9c10-4e68-919c-7f4ee2d555b6.cdn.bspapp.com/xxdf.MP3'; bgMusic.src = this.globalData.musicSrc;
console.log(bgMusic.src)
bgMusic.loop = true; // bgMusic.loop = true; //
// 使 // 使
if (bgMusic.onPlay) { if (bgMusic.onPlay) {
// BackgroundAudioManager // BackgroundAudioManager
bgMusic.onPlay(() => { bgMusic.onPlay(() => {
this.globalData.isMusicPlaying = true; this.globalData.isMusicPlaying = true;
}); });
bgMusic.onPause(() => { bgMusic.onPause(() => {
this.globalData.isMusicPlaying = false; this.globalData.isMusicPlaying = false;
}); });
bgMusic.onStop(() => { bgMusic.onStop(() => {
this.globalData.isMusicPlaying = false; this.globalData.isMusicPlaying = false;
}); });
bgMusic.onEnded(() => { bgMusic.onEnded(() => {
// (BackgroundAudioManagersrc) // (BackgroundAudioManagersrc)
bgMusic.src = 'https://static.ticket.sz-trip.com/epicSoul/xxdf.MP3'; bgMusic.src = this.globalData.musicSrc;
bgMusic.play(); bgMusic.play();
}); });
} else { } else {
@ -68,24 +81,24 @@
bgMusic.onPlay(() => { bgMusic.onPlay(() => {
this.globalData.isMusicPlaying = true; this.globalData.isMusicPlaying = true;
}); });
bgMusic.onPause(() => { bgMusic.onPause(() => {
this.globalData.isMusicPlaying = false; this.globalData.isMusicPlaying = false;
}); });
bgMusic.onStop(() => { bgMusic.onStop(() => {
this.globalData.isMusicPlaying = false; this.globalData.isMusicPlaying = false;
}); });
bgMusic.onEnded(() => { bgMusic.onEnded(() => {
// InnerAudioContextloop // InnerAudioContextloop
this.globalData.isMusicPlaying = false; this.globalData.isMusicPlaying = false;
}); });
} }
// //
this.globalData.bgMusic = bgMusic; this.globalData.bgMusic = bgMusic;
// //
uni.$bgMusic = { uni.$bgMusic = {
play: () => { play: () => {
@ -102,7 +115,7 @@
}, },
toggle: () => { toggle: () => {
if (!bgMusic) return false; if (!bgMusic) return false;
if (this.globalData.isMusicPlaying) { if (this.globalData.isMusicPlaying) {
if (bgMusic.pause) bgMusic.pause(); if (bgMusic.pause) bgMusic.pause();
} else { } else {
@ -115,6 +128,12 @@
} catch (err) { } catch (err) {
console.error('初始化背景音乐失败:', err); console.error('初始化背景音乐失败:', err);
} }
},
updateMusicSrc(newSrc) {
this.globalData.musicSrc = newSrc;
if (this.globalData.bgMusic) {
this.globalData.bgMusic.src = newSrc;
}
} }
} }
} }
@ -124,6 +143,7 @@
/*每个页面公共css */ /*每个页面公共css */
@import '@/uni_modules/uni-scss/index.scss'; @import '@/uni_modules/uni-scss/index.scss';
@import "@/static/css/base.css"; @import "@/static/css/base.css";
/* #ifndef APP-NVUE */ /* #ifndef APP-NVUE */
// //
page { page {
@ -136,14 +156,14 @@
color: #333; color: #333;
padding: 10px; padding: 10px;
} }
/* 清除按钮默认样式 */ /* 清除按钮默认样式 */
button::after { button::after {
border: none; border: none;
} }
@keyframes bounce { @keyframes bounce {
0%, 0%,
20%, 20%,
50%, 50%,
@ -151,24 +171,29 @@
100% { 100% {
transform: translateY(0); transform: translateY(0);
} }
40% { 40% {
transform: translateY(-20rpx); transform: translateY(-20rpx);
} }
60% { 60% {
transform: translateY(-10rpx); transform: translateY(-10rpx);
} }
} }
/* 音乐控制按钮动画 */ /* 音乐控制按钮动画 */
@keyframes rotate { @keyframes rotate {
from { from {
transform: rotate(0deg); transform: rotate(0deg);
} }
to { to {
transform: rotate(360deg); transform: rotate(360deg);
} }
} }
</style>
/* 隐藏微信小程序默认音频组件 */
#mp-audio {
display: none;
}
</style>

84
components/BackgroundMusic.vue

@ -0,0 +1,84 @@
<template>
<view class="music-player" :class="{'playing': isPlaying}" @click="togglePlay">
<text :class="['player-icon', isPlaying ? 'rotate' : '']">{{ isPlaying ? '🎵' : '🔇' }}</text>
</view>
</template>
<script>
import audioManager from '@/utils/audioManager';
export default {
data() {
return {
isPlaying: audioManager.getPlayingStatus()
};
},
mounted() {
audioManager.init();
uni.$on('audioStateChanged', this.updateState);
this.isPlaying = audioManager.getPlayingStatus();
uni.$on('playBackgroundMusic', () => {
if (!audioManager.getUserDisabled()) {
audioManager.play();
}
});
},
beforeDestroy() {
uni.$off('audioStateChanged', this.updateState);
},
methods: {
updateState(state) {
this.isPlaying = state.isPlaying;
},
togglePlay() {
audioManager.togglePlay();
this.isPlaying = audioManager.getPlayingStatus();
}
}
};
</script>
<style lang="scss" scoped>
.music-player {
position: fixed;
right: 30rpx;
bottom: 30rpx;
width: 80rpx;
height: 80rpx;
background-color: rgba(255, 255, 255, 0.9);
border-radius: 50%;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.2);
display: flex;
align-items: center;
justify-content: center;
z-index: 9;
&:active {
transform: scale(0.95);
}
&.playing {
background-color: rgba(245, 163, 204, 0.9);
}
}
.player-icon {
font-size: 40rpx;
line-height: 1;
&.rotate {
display: inline-block;
animation: rotate 3s linear infinite;
}
}
@keyframes rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
</style>

39
components/BuyPeaches.vue

@ -0,0 +1,39 @@
<template>
<view>
<image @click="buyTaozi" class="taozi" src="https://static.ticket.sz-trip.com/epicSoul/taozi/taozi.png" mode=""></image>
</view>
</template>
<script>
export default {
methods: {
buyTaozi() {
uni.setClipboardData({
data: 'https://www.xiaohongshu.com/goods-detail/684beba28a6cef0001a9ed2c',
success: function() {
uni.showToast({
title: '链接已复制,请打开小红书APP查看',
icon: 'none',
duration: 2000
});
}
});
}
}
};
</script>
<style lang="scss" scoped>
.taozi {
width: 80rpx;
height: 80rpx;
position: fixed;
right: 0;
top: 25%;
z-index: 9;
&:active {
transform: scale(0.9);
}
}
</style>

3
components/CustomTabBar.vue

@ -89,13 +89,12 @@ export default {
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
flex: 1;
flex-shrink: 0; flex-shrink: 0;
height: 100%; height: 100%;
} }
.tab-item text { .tab-item text {
font-size: 36rpx; font-size: 31rpx;
} }
</style> </style>

6
components/MusicControl.vue

@ -1,5 +1,5 @@
<template> <template>
<view class="music-control" @click="toggleMusic"> <view class="music-control" @click.stop="toggleMusic">
<text class="music-text" :class="{ 'rotating': isPlaying }"> <text class="music-text" :class="{ 'rotating': isPlaying }">
{{ isPlaying ? '🎵' : '🔇' }} {{ isPlaying ? '🎵' : '🔇' }}
</text> </text>
@ -46,6 +46,8 @@ export default {
} }
const bgMusic = app.globalData.bgMusic; const bgMusic = app.globalData.bgMusic;
console.log(bgMusic)
// //
if (this.isPlaying) { if (this.isPlaying) {
@ -62,7 +64,7 @@ export default {
.music-control { .music-control {
position: fixed; position: fixed;
right: 30rpx; right: 30rpx;
bottom: 30rpx; bottom: 150rpx;
width: 80rpx; width: 80rpx;
height: 80rpx; height: 80rpx;
border-radius: 50%; border-radius: 50%;

67
components/ShareGuide.vue

@ -1,10 +1,7 @@
<template> <template>
<view v-if="visible" class="share-guide-mask" @click="closeGuide"> <view v-if="modelValue" class="share-guide-mask" @click="closeGuide">
<view class="guide-content"> <view class="guide-content">
<image class="guide-arrow" :src="arrowImage" mode=""></image> <image class="share-tips" src="https://static.ticket.sz-trip.com/epicSoul/share-tips.png" mode=""></image>
<view v-for="(text, index) in textArray" :key="index" class="guide-text">
{{ text }}
</view>
</view> </view>
</view> </view>
</template> </template>
@ -15,42 +12,28 @@ export default {
value: { value: {
type: Boolean, type: Boolean,
default: false default: false
},
text: {
type: [String, Array],
default: '点击右上角"..."选择"分享到朋友圈"'
},
arrowImage: {
type: String,
default: '/static/share-arrow.png'
} }
}, },
computed: { data() {
visible: { return {
get() { modelValue: this.value
return this.value; };
}, },
set(val) { watch: {
this.$emit('input', val); value(newVal) {
} this.modelValue = newVal;
},
textArray() {
if (Array.isArray(this.text)) {
return this.text;
}
return [this.text];
} }
}, },
methods: { methods: {
closeGuide() { closeGuide() {
this.visible = false; this.$emit('input', false);
this.$emit('close'); this.$emit('close');
} }
} }
} };
</script> </script>
<style scoped> <style>
.share-guide-mask { .share-guide-mask {
position: fixed; position: fixed;
top: 0; top: 0;
@ -71,27 +54,7 @@ export default {
padding-top: 100rpx; padding-top: 100rpx;
padding-right: 60rpx; padding-right: 60rpx;
} }
.share-tips{
.guide-arrow { width: 450rpx;
width: 100rpx;
height: 160rpx;
animation: arrow-up 1s infinite alternate;
}
.guide-text {
font-size: 32rpx;
color: #FFFFFF;
font-weight: bold;
margin-bottom: 10rpx;
text-align: center;
}
@keyframes arrow-up {
from {
transform: translateY(0);
}
to {
transform: translateY(-15rpx);
}
} }
</style> </style>

106
components/TitleHeader.vue

@ -0,0 +1,106 @@
<template>
<view class="title-header-box" :style="{height:`${height}px`}">
<view class="title-header" :style="{paddingTop:`${padHeight}px`,height:`${height}px`}">
<view class="left" @click="goBack"><uni-icons type="left" size="30"></uni-icons></view>
<view class="center">
<view class="title">三个桃子</view>
<view class="subtitle">时间里的约定</view>
</view>
<view class="right"></view>
</view>
</view>
</template>
<script>
export default {
name: "SearchHeader",
props: ['title', 'icon'],
watch: {
'title'(newVal, oldVal) {
this.title = newVal
}
},
data() {
return {
keywords: '',
padHeight: 60,
height: 88
}
},
created() {
const systemInfo = uni.getSystemInfoSync();
const statusBarHeight = systemInfo.statusBarHeight;
const rect = uni.getMenuButtonBoundingClientRect();
this.height = statusBarHeight + 55
uni.setStorageSync('titleHeight', this.height)
this.padHeight = systemInfo.statusBarHeight - 15
this.right = (systemInfo.screenWidth - rect.right) + rect.width
}
}
</script>
<style scoped>
.title-header-box {
background-color: #FFF;
color: #000000;
}
.title-header {
/* background-color: #FFC825; */
background: white;
display: flex;
justify-content: center;
align-items: center;
height: 88rpx;
position: fixed;
left: 0;
right: 0;
top: 0;
z-index: 1000;
padding-top: 60rpx;
}
.title-header .left {
padding-left: 30rpx;
width: 58rpx;
display: flex;
position: absolute;
left: 0;
}
.title-header .search-box {
width: 502rpx;
height: 58rpx;
border-radius: 29rpx;
background: #F0F0F0;
padding: 0 26rpx;
font-size: 26rpx;
display: flex;
align-items: center;
}
.title-header .search-box .iconfont {
flex-shrink: 0;
color: #999999;
font-size: 30rpx;
margin-right: 10;
}
.title-header .search-box .input {
flex: 1;
border: none;
outline: none;
background: none;
color: #666;
}
.title{
font-size: 30rpx;
text-align: center;
}
.subtitle{
font-size: 22rpx;
text-align: center;
}
</style>

6
components/chapter3/RandomImage.vue

@ -37,6 +37,8 @@ export default {
if (this.images && this.images.length > 0) { if (this.images && this.images.length > 0) {
const randomIndex = Math.floor(Math.random() * this.images.length) const randomIndex = Math.floor(Math.random() * this.images.length)
this.selectedItem = this.images[randomIndex] this.selectedItem = this.images[randomIndex]
console.log(this.selectedItem)
} }
} }
}, },
@ -53,8 +55,8 @@ export default {
<style scoped> <style scoped>
.random-image { .random-image {
width: 100%; width: 100vw;
height: 100%; height: 100vh;
} }
.random-image-name { .random-image-name {

14
components/header.vue

@ -1,6 +1,8 @@
<template> <template>
<view class="header" :style="{'height': height+'px','padding-top':statusBarHeight+'px'}"> <view class="header" :style="{'height': height+'px','padding-top':statusBarHeight+'px'}">
<image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/search.png" mode="heightFix"></image> <image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/search.png" mode="heightFix"
@click="gotoPath('/subPackages/search/search?type='+type)" v-if="isSearch"></image>
<view style="width: 50rpx;" v-else></view>
<image src="https://static.ticket.sz-trip.com/uploads/20250625/9bb05097e07570a934235983e1681a9f.png" mode="heightFix"></image> <image src="https://static.ticket.sz-trip.com/uploads/20250625/9bb05097e07570a934235983e1681a9f.png" mode="heightFix"></image>
<view style="width: 50rpx;"></view> <view style="width: 50rpx;"></view>
</view> </view>
@ -8,6 +10,16 @@
<script> <script>
export default { export default {
props: {
isSearch: {
type: Boolean,
default: true
},
type: {
type: String,
default: ''
}
},
name:"header", name:"header",
data() { data() {
return { return {

575
components/messageBoard.vue

@ -0,0 +1,575 @@
<template>
<view>
<view class="message-board">
<view class="header">
<view class="title-container">
<text class="title">留言板</text>
<text class="subtitle">查看所有留言</text>
</view>
<view class="decor decor-1"></view>
<view class="decor decor-2"></view>
</view>
<view class="content">
<view class="stats-card">
<view class="stats-header">
<view class="stats-icon-container">
<view class="stats-icon">
<text class="icon-text">💬</text>
</view>
</view>
<text class="stats-title">全部留言</text>
<view class="stats-count">
<text class="count-text"> {{ total }} </text>
</view>
</view>
</view>
<view class="message-list">
<view v-if="loading && messageList.length === 0" class="empty-state">
<view class="loading-container">
<view class="loading-spinner"></view>
<text class="loading-text">加载中...</text>
</view>
</view>
<view v-else-if="messageList.length === 0" class="empty-state">
<view class="empty-container">
<view class="empty-icon">📭</view>
<text class="empty-title">暂无留言</text>
<text class="empty-desc">还没有人留言呢</text>
</view>
</view>
<view v-else class="message-items">
<view v-for="(item, index) in messageList" :key="item.id" class="message-item"
:style="{ animationDelay: `${index * 100}ms` }">
<view class="user-info">
<view class="avatar">
<text class="avatar-text">{{ getAvatarText(item.nickname) }}</text>
</view>
<view class="user-details">
<view class="user-header">
<text class="username">{{ item.nickname }}</text>
<text class="message-id">#{{ item.id }}</text>
</view>
<text class="message-time">{{ formatTime(item.createtime) }}</text>
</view>
</view>
<view class="message-content">
<text class="message-text">{{ item.content }}</text>
</view>
</view>
</view>
</view>
<view v-if="pages > 1" class="pagination">
<view class="pagination-container">
<button @click="changePage(page - 1)" :disabled="page <= 1" class="page-button prev-button">
<text class="button-icon"></text>
<text>上一页</text>
</button>
<view class="page-info">
<text class="current-page">{{ page }}</text>
<text class="page-divider">/</text>
<text class="total-pages">{{ pages }}</text>
</view>
<button @click="changePage(page + 1)" :disabled="page >= pages" class="page-button next-button">
<text>下一页</text>
<text class="button-icon"></text>
</button>
</view>
</view>
<view class="refresh-container">
<button @click="refresh" :disabled="loading" class="refresh-button">
<text class="refresh-icon" :class="{ 'rotating': loading }">🔄</text>
<text>{{ loading ? '刷新中...' : '刷新' }}</text>
</button>
</view>
</view>
</view>
</view>
</template>
<script>
import {
getMessageList
} from '@/static/js/common';
export default {
props: {
isActive: {
type: Boolean,
default: true
}
},
data() {
return {
loading: false,
messageList: [],
total: 0,
page: 1,
limit: 10,
pages: 0
};
},
created() {
if (this.isActive) {
this.fetchMessages();
}
},
watch: {
isActive(newVal) {
if (newVal) {
this.fetchMessages();
}
}
},
methods: {
getAvatarText(nickname) {
return nickname ? nickname.charAt(0).toUpperCase() : '?';
},
formatTime(timestamp) {
if (!timestamp) return '未知时间';
const date = new Date(timestamp * 1000);
const now = new Date();
const diff = now - date;
if (diff < 60000) {
return '刚刚';
}
if (diff < 3600000) {
return `${Math.floor(diff / 60000)}分钟前`;
}
if (diff < 86400000) {
return `${Math.floor(diff / 3600000)}小时前`;
}
const month = date.getMonth() + 1;
const day = date.getDate();
const hour = date.getHours().toString().padStart(2, '0');
const minute = date.getMinutes().toString().padStart(2, '0');
return `${month}${day}${hour}:${minute}`;
},
async fetchMessages(pageNum = 1) {
try {
if (this.loading) return;
this.loading = true;
const params = {
page: pageNum,
limit: this.limit
};
const res = await getMessageList(params, {
loading: {
title: '加载留言中...'
},
error: true
});
const data = res.data || {};
this.messageList = data.list || [];
this.total = data.total || 0;
this.page = data.page || 1;
this.pages = data.pages || 0;
} catch (error) {
console.error('获取留言异常:', error);
} finally {
this.loading = false;
}
},
changePage(pageNum) {
if (pageNum < 1 || pageNum > this.pages || pageNum === this.page) return;
this.fetchMessages(pageNum);
uni.pageScrollTo({
scrollTop: 0,
duration: 300
});
},
refresh() {
if (this.loading) return;
this.fetchMessages(this.page);
}
}
};
</script>
<style lang="scss" scoped>
.message-board {
min-height: 100vh;
background-color: #d76388;
}
.header {
position: relative;
padding: 180rpx 30rpx 40rpx;
}
.title-container {
text-align: center;
}
.title {
font-size: 48rpx;
font-weight: bold;
color: #ffffff;
margin-bottom: 10rpx;
display: block;
}
.subtitle {
font-size: 26rpx;
color: rgba(255, 255, 255, 0.8);
display: block;
}
.decor {
position: absolute;
border-radius: 50%;
&.decor-1 {
top: 40rpx;
left: 30rpx;
width: 100rpx;
height: 100rpx;
background-color: rgba(255, 255, 255, 0.1);
filter: blur(30rpx);
}
&.decor-2 {
top: 80rpx;
right: 40rpx;
width: 80rpx;
height: 80rpx;
background-color: rgba(255, 192, 203, 0.2);
filter: blur(20rpx);
}
}
.content {
padding: 0 30rpx 40rpx;
}
.stats-card {
background-color: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10rpx);
border-radius: 30rpx;
padding: 30rpx;
margin-bottom: 30rpx;
}
.stats-header {
display: flex;
align-items: center;
}
.stats-icon-container {
margin-right: 16rpx;
}
.stats-icon {
width: 50rpx;
height: 50rpx;
background-color: #4299e1;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
}
.icon-text {
color: #ffffff;
font-size: 24rpx;
}
.stats-title {
color: #4a5568;
font-weight: 500;
font-size: 28rpx;
flex: 1;
}
.stats-count {
background-color: #f7fafc;
border-radius: 50rpx;
padding: 8rpx 20rpx;
}
.count-text {
color: #718096;
font-size: 24rpx;
}
.message-list {
margin-bottom: 30rpx;
}
.empty-state {
background-color: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10rpx);
border-radius: 30rpx;
padding: 60rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.loading-container {
display: flex;
flex-direction: column;
align-items: center;
}
.loading-spinner {
width: 60rpx;
height: 60rpx;
border: 6rpx solid #e2e8f0;
border-top-color: #9f7aea;
border-radius: 50%;
animation: spin 1s linear infinite;
margin-bottom: 20rpx;
}
.loading-text {
color: #718096;
font-size: 28rpx;
}
.empty-container {
text-align: center;
}
.empty-icon {
width: 100rpx;
height: 100rpx;
background-color: #f7fafc;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 30rpx;
font-size: 50rpx;
}
.empty-title {
color: #2d3748;
font-size: 34rpx;
font-weight: 500;
margin-bottom: 10rpx;
display: block;
}
.empty-desc {
color: #718096;
font-size: 26rpx;
display: block;
}
.message-items {
display: flex;
flex-direction: column;
gap: 20rpx;
}
.message-item {
background-color: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10rpx);
border-radius: 30rpx;
padding: 30rpx;
box-shadow: 0 4rpx 10rpx rgba(0, 0, 0, 0.05);
transition: box-shadow 0.2s;
animation: fadeIn 0.6s ease-out forwards;
&:active {
box-shadow: 0 8rpx 20rpx rgba(0, 0, 0, 0.1);
}
}
.user-info {
display: flex;
align-items: flex-start;
margin-bottom: 20rpx;
}
.avatar {
width: 80rpx;
height: 80rpx;
background: linear-gradient(135deg, #a78bfa, #ec4899);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 20rpx;
flex-shrink: 0;
}
.avatar-text {
color: #ffffff;
font-size: 32rpx;
font-weight: 500;
}
.user-details {
flex: 1;
min-width: 0;
}
.user-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 6rpx;
}
.username {
font-weight: 500;
color: #2d3748;
font-size: 28rpx;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.message-id {
font-size: 22rpx;
color: #a0aec0;
background-color: #f7fafc;
padding: 4rpx 16rpx;
border-radius: 50rpx;
}
.message-time {
font-size: 22rpx;
color: #a0aec0;
}
.message-content {
margin-left: 100rpx;
}
.message-text {
color: #4a5568;
font-size: 28rpx;
line-height: 1.6;
word-break: break-word;
}
.pagination {
background-color: rgba(255, 255, 255, 0.9);
backdrop-filter: blur(10rpx);
border-radius: 30rpx;
padding: 20rpx;
margin-bottom: 30rpx;
}
.pagination-container {
display: flex;
align-items: center;
justify-content: center;
gap: 20rpx;
}
.page-button {
display: flex;
align-items: center;
gap: 10rpx;
padding: 0 30rpx;
height: 70rpx;
font-size: 26rpx;
font-weight: 500;
color: #4a5568;
background-color: #ffffff;
border: 2rpx solid #e2e8f0;
border-radius: 12rpx;
&:active {
background-color: #f7fafc;
}
&[disabled] {
opacity: 0.5;
}
}
.page-info {
display: flex;
align-items: center;
gap: 10rpx;
padding: 0 20rpx;
}
.current-page,
.total-pages {
font-size: 26rpx;
color: #4a5568;
}
.page-divider {
color: #cbd5e0;
font-size: 26rpx;
}
.refresh-container {
text-align: center;
}
.refresh-button {
display: inline-flex;
align-items: center;
gap: 10rpx;
padding: 0 40rpx;
height: 80rpx;
background-color: rgba(255, 255, 255, 0.2);
color: #ffffff;
border: none;
border-radius: 16rpx;
font-size: 28rpx;
font-weight: 500;
&:active {
background-color: rgba(255, 255, 255, 0.3);
}
&[disabled] {
opacity: 0.5;
}
}
.refresh-icon {
font-size: 28rpx;
&.rotating {
animation: spin 1s linear infinite;
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(40rpx);
}
to {
opacity: 1;
transform: translateY(0);
}
}
</style>

508
components/messagePop.vue

@ -0,0 +1,508 @@
<template>
<view>
<image @click="togglePopup" class="suspension-img" :class="{'rotated': isOpen}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/suspension-icon.png" mode=""></image>
<view v-if="isOpen" class="mask" @click="closeMessage"></view>
<view v-if="isOpen" class="message-popup" :style="popupStyle">
<view class="popup-content">
<view class="popup-header">
<text class="popup-title">我要留言</text>
<view class="header-line"></view>
</view>
<input v-model="nickname" class="input-field" placeholder="我的昵称" maxlength="20" :disabled="loading" />
<input v-model="email" type="text" class="input-field" placeholder="我的邮箱" :disabled="loading" />
<textarea v-model="messageText" class="textarea-field" placeholder="我想对TA说:" maxlength="500"
:disabled="loading"></textarea>
<view class="char-count">
<text>{{ messageText.length }}/500</text>
</view>
<view class="button-group">
<button @click="closeMessage" :disabled="loading" class="btn-cancel">
返回
</button>
<button @click="handleSubmit" :disabled="loading" class="btn-submit"
:class="{'btn-disabled': !canSubmit}">
<view v-if="loading" class="loading-icon"></view>
<text>{{ loading ? '发布中...' : '发布' }}</text>
</button>
</view>
</view>
</view>
<view v-if="toast.show" class="toast" :class="toast.type">
<view class="toast-icon" :class="toast.type">
<view v-if="toast.type === 'success'" class="success-icon"></view>
<view v-if="toast.type === 'error'" class="error-icon"></view>
</view>
<text class="toast-message">{{ toast.message }}</text>
<view class="toast-progress">
<view class="progress-bar" :style="{animationDuration: '3s'}"></view>
</view>
</view>
</view>
</template>
<script>
import {
sendMessage
} from '@/static/js/common';
export default {
data() {
return {
isOpen: false,
popupStyle: {
opacity: 0,
transform: 'translate(-50%, -50%) scale(0.9)'
},
nickname: "",
email: "",
messageText: "",
loading: false,
toast: {
show: false,
type: 'success',
message: ''
}
};
},
computed: {
canSubmit() {
const hasNickname = this.nickname.trim().length > 0;
const hasMessage = this.messageText.trim().length > 0;
const validEmail = this.isValidEmail(this.email);
return hasNickname && hasMessage && validEmail;
}
},
watch: {
nickname() {
//
},
email() {
//
},
messageText() {
//
}
},
methods: {
togglePopup() {
if (this.isOpen) {
this.closeMessage();
} else {
this.openPop();
}
},
openPop() {
this.isOpen = true;
setTimeout(() => {
this.popupStyle = {
opacity: 1,
transform: 'translate(-50%, -50%) scale(1)'
};
}, 50);
},
closeMessage() {
this.popupStyle = {
opacity: 0,
transform: 'translate(-50%, -50%) scale(0.9)'
};
setTimeout(() => {
this.isOpen = false;
}, 400);
},
isValidEmail(email) {
if (!email.trim()) return false;
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
},
showToast(type, message) {
this.toast.show = true;
this.toast.type = type;
this.toast.message = message;
setTimeout(() => {
this.toast.show = false;
}, 3000);
},
handleSubmit() {
if (!this.nickname.trim()) {
this.showToast('error', '请填写昵称');
return;
}
if (!this.isValidEmail(this.email)) {
this.showToast('error', '请填写正确的邮箱地址');
return;
}
if (!this.messageText.trim()) {
this.showToast('error', '请填写留言内容');
return;
}
this.submitMessage();
},
async submitMessage() {
try {
this.loading = true;
const res = await sendMessage({
nickname: this.nickname.trim(),
email: this.email.trim(),
content: this.messageText.trim()
});
if (res && res.code === 1) {
this.nickname = "";
this.email = "";
this.messageText = "";
this.showToast('success', '留言发布成功!');
setTimeout(() => {
this.closeMessage();
}, 1500);
} else {
this.showToast('error', res?.msg || '发布失败,请重试');
}
} catch (error) {
console.error('发布留言失败:', error);
this.showToast('error', '网络错误,请重试');
} finally {
this.loading = false;
}
}
}
};
</script>
<style lang="scss" scoped>
.suspension-img {
width: 80rpx;
height: 80rpx;
position: fixed;
right: 0;
top: 18%;
z-index: 9;
transition: transform 0.3s ease;
&.rotated {
transform: rotate(180deg);
}
&:active {
opacity: 0.8;
}
}
.mask {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
z-index: 10;
animation: fadeIn 0.3s ease forwards;
}
.message-popup {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(0.9);
z-index: 11;
width: 75%;
max-width: 650rpx;
transition: opacity 0.4s ease, transform 0.4s ease;
}
.popup-content {
background-color: #fff;
border-radius: 20rpx;
box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.2);
padding: 30rpx;
display: flex;
flex-direction: column;
max-height: 80vh;
}
.popup-header {
margin-bottom: 30rpx;
}
.popup-title {
font-size: 40rpx;
font-weight: bold;
color: #ec4899;
margin-bottom: 10rpx;
}
.header-line {
height: 2rpx;
background-color: #ec4899;
width: 100%;
}
.input-field {
height: 90rpx;
padding: 0 20rpx;
border: 2rpx solid #ccc;
border-radius: 10rpx;
margin-bottom: 20rpx;
font-size: 28rpx;
&:focus {
border-color: #ec4899;
}
}
.textarea-field {
text-indent: 10rpx;
width: 100%;
height: 300rpx;
border: 2rpx solid #ccc;
border-radius: 10rpx;
margin-bottom: 20rpx;
font-size: 28rpx;
&:focus {
border-color: #ec4899;
}
}
.char-count {
text-align: right;
font-size: 24rpx;
color: #888;
margin-bottom: 20rpx;
}
.button-group {
display: flex;
justify-content: space-between;
gap: 20rpx;
}
.btn-cancel {
flex: 1;
background-color: #fff;
color: #ec4899;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
border: 2rpx solid #ccc;
font-size: 28rpx;
text-align: center;
&:active {
background-color: #f5f5f5;
}
}
.btn-submit {
flex: 1;
background-color: #f5a3cc;
color: #fff;
height: 80rpx;
line-height: 80rpx;
border-radius: 40rpx;
border: none;
font-size: 28rpx;
text-align: center;
display: flex;
align-items: center;
justify-content: center;
&:active {
background-color: darken(#ec4899, 10%);
}
}
.loading-icon {
width: 30rpx;
height: 30rpx;
border: 4rpx solid #fff;
border-top-color: transparent;
border-radius: 50%;
margin-right: 10rpx;
animation: spin 1s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.toast {
position: fixed;
top: 160rpx;
left: 50%;
transform: translateX(-50%);
z-index: 100000;
display: flex;
align-items: center;
padding: 20rpx 30rpx;
border-radius: 16rpx;
box-shadow: 0 10rpx 40rpx rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10rpx);
max-width: 80%;
animation: toastIn 0.5s ease forwards;
&.success {
background-color: rgba(34, 197, 94, 0.9);
}
&.error {
background-color: rgba(239, 68, 68, 0.9);
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes toastIn {
from {
opacity: 0;
transform: translateX(-50%) translateY(-20rpx);
}
to {
opacity: 1;
transform: translateX(-50%) translateY(0);
}
}
.toast-icon {
width: 40rpx;
height: 40rpx;
margin-right: 20rpx;
position: relative;
}
.success-icon {
width: 100%;
height: 100%;
border-radius: 50%;
border: 4rpx solid #fff;
position: relative;
&:after {
content: '';
position: absolute;
top: 40%;
left: 28%;
width: 45%;
height: 25%;
border-left: 4rpx solid #fff;
border-bottom: 4rpx solid #fff;
transform: rotate(-45deg);
animation: checkmark 0.8s ease-out forwards;
}
}
.error-icon {
width: 100%;
height: 100%;
border-radius: 50%;
border: 4rpx solid #fff;
position: relative;
&:before,
&:after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 60%;
height: 4rpx;
background-color: #fff;
animation: crossmark 0.8s ease-out forwards;
}
&:before {
transform: translate(-50%, -50%) rotate(45deg);
}
&:after {
transform: translate(-50%, -50%) rotate(-45deg);
}
}
.toast-message {
color: #fff;
font-size: 28rpx;
font-weight: 500;
}
.toast-progress {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 4rpx;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 0 0 16rpx 16rpx;
overflow: hidden;
}
.progress-bar {
height: 100%;
background-color: rgba(255, 255, 255, 0.5);
width: 100%;
animation: progress 3s linear forwards;
}
@keyframes progress {
from {
width: 100%;
}
to {
width: 0%;
}
}
@keyframes checkmark {
0% {
opacity: 0;
transform: scale(0) rotate(-45deg);
}
50% {
opacity: 1;
}
100% {
opacity: 1;
transform: scale(1) rotate(-45deg);
}
}
@keyframes crossmark {
0% {
opacity: 0;
transform: translate(-50%, -50%) scale(0) rotate(var(--rotation, 45deg));
}
50% {
opacity: 1;
}
100% {
opacity: 1;
transform: translate(-50%, -50%) scale(1) rotate(var(--rotation, 45deg));
}
}
</style>

10
mixins/myMixins.js

@ -15,10 +15,10 @@ export const myMixins ={
// 分享到朋友圈 // 分享到朋友圈
onShareTimeline() { onShareTimeline() {
return { return {
title: 'CGC-ICH', title: 'Epic Soul交响',
type: 0, type: 0,
summary: "", summary: "",
imageUrl: "https://cgc.js-dyyj.com/uploads/20250619/172a730c88bd8894dee1e64c703795eb.jpg" // imageUrl: "https://cgc.js-dyyj.com/uploads/20250619/172a730c88bd8894dee1e64c703795eb.jpg"
} }
}, },
onShareAppMessage() { onShareAppMessage() {
@ -33,10 +33,10 @@ export const myMixins ={
console.log(111,url,`${view.route}?url=${url}`) console.log(111,url,`${view.route}?url=${url}`)
return { return {
title: 'CGC-ICH', // 分享的名称 title: 'Epic Soul交响', // 分享的名称
path: `${view.route}?url=${url}`, // 将 url 作为参数传递 path: `${view.route}?url=${url}`, // 将 url 作为参数传递
imageUrl: "https://cgc.js-dyyj.com/uploads/20250619/172a730c88bd8894dee1e64c703795eb.jpg", // imageUrl: "https://cgc.js-dyyj.com/uploads/20250619/172a730c88bd8894dee1e64c703795eb.jpg",
mpId: 'wx9d68934300b1fe90' // 此处配置微信小程序的 AppId mpId: 'wx8954209bb3ad489e' // 此处配置微信小程序的 AppId
}; };
} }
} }

630
pages.json

@ -1,311 +1,351 @@
{ {
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages "pages": [
{ {
"path": "pages/stratIndex", "path": "pages/stratIndex",
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, },
{ {
"path": "pages/index/index", "path": "pages/index/index",
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom"
// "navigationBarTitleText": "CGC-ICH" // "navigationBarTitleText": "CGC-ICH"
} }
}, },
{ {
"path": "pages/index/readingBody", "path": "pages/index/readingBody",
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom"
// "navigationBarTitleText": "阅读体" // "navigationBarTitleText": "阅读体"
} }
}, },
{ {
"path": "pages/index/sensoryStore", "path": "pages/index/sensoryStore",
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom"
// "navigationBarTitleText": "有感商店" // "navigationBarTitleText": "有感商店"
} }
}, },
{ {
"path": "pages/index/intelligentAgent", "path": "pages/index/intelligentAgent",
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom"
// "navigationBarTitleText": "智能体" // "navigationBarTitleText": "智能体"
} }
}, },
{ {
"path": "pages/index/iSoul", "path": "pages/index/iSoul",
"style": { "style": {
"navigationStyle": "custom" "navigationStyle": "custom"
// "navigationBarTitleText": "iSoul" // "navigationBarTitleText": "iSoul"
} }
}, },
{ {
"path": "pages/login/login", "path": "pages/login/login",
"style": { "style": {
"navigationBarTitleText": "登录", "navigationBarTitleText": "登录",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
} }
], ],
"subPackages": [{ "subPackages": [
"root": "subPackages", {
"pages": [{ "root": "subPackages",
"path": "order/trades", "pages": [
"style": { {
"navigationBarTitleText": "全部订单" "path": "order/trades",
} "style": {
}, "navigationBarTitleText": "全部订单"
}
},
{
"path": "order/detail",
"style": {
"navigationBarTitleText": "订单详情",
"navigationStyle": "custom"
}
},
{
"path": "techan/index",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "techan/detail",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "techan/order",
"style": {
"navigationBarTitleText": "确认订单"
}
},
{
"path": "webPage/webPage",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "video/video",
"style": {
"navigationBarTitleText": ""
}
},
{
"path": "readingBody/index",
"style": {
"navigationBarTitleText": "阅读体",
"navigationStyle": "custom"
}
},
{
"path": "haveFeeling/shopDetail",
"style": {
"navigationBarTitleText": "有感商店详情页",
"navigationStyle": "custom"
}
},
{
"path": "haveFeeling/detailXiang",
"style": {
"navigationBarTitleText": "有感商店"
}
},
{
"path": "letter/detail",
"style": {
"navigationBarTitleText": "文章详情"
}
},
{
"path": "user/privacy",
"style": {
"navigationBarTitleText": "详情"
}
},
{
"path": "user/privacyInfo",
"style": {
"navigationBarTitleText": "详情"
}
},
{
"path": "user/travelerList",
"style": {
"navigationBarTitleText": "收货地址"
}
},
{
"path": "user/myAddressAdd",
"style": {
"navigationBarTitleText": "收货地址"
}
},
{
"path": "user/gwc",
"style": {
"navigationBarTitleText": "购物车"
}
},
{ {
"path": "order/detail", "path" : "order/gwcOrder",
"style": { "style" : {
"navigationBarTitleText": "订单详情", "navigationBarTitleText" : "下单"
"navigationStyle": "custom"
} }
}, },
{ {
"path": "techan/index", "path": "user/profile",
"style": { "style": {
"navigationBarTitleText": "", "navigationBarTitleText": "个人信息"
"navigationStyle": "custom" }
} },
}, {
{ "path": "user/changeNickname",
"path": "techan/detail", "style": {
"style": { "navigationBarTitleText": "修改昵称"
"navigationBarTitleText": "" }
} },
}, {
{ "path": "search/search",
"path": "techan/order", "style": {
"style": { "navigationBarTitleText": "搜索"
"navigationBarTitleText": "确认订单" }
} }
}, ]
},
{ {
"path": "webPage/webPage", "root": "xxdf",
"style": { "pages": [
"navigationBarTitleText": "" {
} "path": "home/home",
}, "style": {
{ "navigationBarTitleText": "",
"path": "video/video", "navigationStyle": "custom"
"style": { }
"navigationBarTitleText": "" },
} {
}, "path": "chapter1/cover1",
{ "style": {
"path": "readingBody/index", "navigationBarTitleText": "",
"style": { "navigationStyle": "custom"
"navigationBarTitleText": "阅读体", }
"navigationStyle": "custom" },
} {
}, "path": "chapter1/detail1",
{ "style": {
"path": "haveFeeling/shopDetail", "navigationBarTitleText": "",
"style": { "navigationStyle": "custom"
"navigationBarTitleText": "有感商店详情页", }
"navigationStyle": "custom" },
} {
}, "path": "chapter1/detail2",
{ "style": {
"path": "haveFeeling/detailXiang", "navigationBarTitleText": "",
"style": { "navigationStyle": "custom"
"navigationBarTitleText": "有感商店" }
} },
}, {
{ "path": "chapter1/detail3",
"path": "letter/detail", "style": {
"style": { "navigationBarTitleText": "",
"navigationBarTitleText": "文章详情" "navigationStyle": "custom"
} }
}, },
{ {
"path": "user/privacy", "path": "chapter1/detail4",
"style": { "style": {
"navigationBarTitleText": "详情" "navigationBarTitleText": "",
} "navigationStyle": "custom"
}, }
{ },
"path": "user/privacyInfo", {
"style": { "path": "chapter1/detail5",
"navigationBarTitleText": "详情" "style": {
} "navigationBarTitleText": "",
}, "navigationStyle": "custom"
{ }
"path": "user/travelerList", },
"style": { {
"navigationBarTitleText": "收货地址" "path": "chapter2/cover",
} "style": {
}, "navigationBarTitleText": "",
{ "navigationStyle": "custom"
"path": "user/myAddressAdd", }
"style": { },
"navigationBarTitleText": "收货地址" {
} "path": "chapter3/cover",
}, "style": {
{ "navigationBarTitleText": "",
"path": "user/gwc", "navigationStyle": "custom"
"style": { }
"navigationBarTitleText": "购物车" },
} {
}, "path": "chapter3/randomImage",
{ "style": {
"path": "user/profile", "navigationBarTitleText": "",
"style": { "navigationStyle": "custom"
"navigationBarTitleText": "个人信息" }
} },
}, {
{ "path": "chapter4/cover",
"path": "user/changeNickname", "style": {
"style": { "navigationBarTitleText": "",
"navigationBarTitleText": "修改昵称" "navigationStyle": "custom",
} "enableShareAppMessage": true,
} "enableShareTimeline": true
] }
}, }
{ ]
"root": "xxdf/home", },
"pages": [{
"path": "home",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}]
},
{ {
"root": "xxdf/chapter1", "root": "taozi",
"pages": [{ "pages": [
"path": "cover1", {
"style": { "path": "home/home",
"navigationBarTitleText": "", "style": {
"navigationStyle": "custom" "navigationBarTitleText": "",
} "navigationStyle": "custom"
}, }
{ },
"path": "detail1",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{ {
"path": "detail2", "path": "chapter1/chapter1",
"style": { "style": {
"navigationBarTitleText": "", "navigationBarTitleText": "",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}, },
{ {
"path": "detail3", "path": "chapter2/chapter2",
"style": { "style": {
"navigationBarTitleText": "", "navigationBarTitleText": "",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
},
{
"path": "detail4",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}, },
{ {
"path": "detail5", "path": "chapter3/chapter3",
"style": { "style": {
"navigationBarTitleText": "", "navigationBarTitleText": "",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
}
]
},
{
"root": "xxdf/chapter2",
"pages": [{
"path": "cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}]
},
{
"root": "xxdf/chapter3",
"pages": [{
"path": "cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}, },
{ {
"path": "randomImage", "path": "chapter4/chapter4",
"style": { "style": {
"navigationBarTitleText": "", "navigationBarTitleText": "",
"navigationStyle": "custom" "navigationStyle": "custom"
} }
} }
] ]
},
{
"root": "xxdf/chapter4",
"pages": [{
"path": "cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enableShareAppMessage": true,
"enableShareTimeline": true
}
}]
} }
], ],
"tabBar": { "tabBar": {
"custom": true, "custom": true,
"color": "#333333", "color": "#333333",
"selectedColor": "#6CA5AA", "selectedColor": "#6CA5AA",
"borderStyle": "black", "borderStyle": "black",
"backgroundColor": "#ffffff", "backgroundColor": "#ffffff",
"fontSize": "24rpx", "fontSize": "24rpx",
"height": "123rpx", "height": "123rpx",
"iconWidth": "40rpx", "iconWidth": "40rpx",
"list": [{ "list": [
"pagePath": "pages/index/index", {
"text": "首页", "pagePath": "pages/index/index",
"visible": false "text": "首页",
}, "visible": false
{ },
"pagePath": "pages/index/readingBody", {
"text": "阅读体", "pagePath": "pages/index/readingBody",
"visible": false "text": "阅读体",
}, "visible": false
{ },
"pagePath": "pages/index/sensoryStore", {
"text": "有感商店", "pagePath": "pages/index/sensoryStore",
"visible": false "text": "有感商店",
}, "visible": false
{ },
"pagePath": "pages/index/intelligentAgent", {
"text": "智能体", "pagePath": "pages/index/intelligentAgent",
"visible": false "text": "智能体",
}, "visible": false
{ },
"pagePath": "pages/index/iSoul", {
"text": "iSoul", "pagePath": "pages/index/iSoul",
"visible": false "text": "iSoul",
} "visible": false
}
] ]
}, },
"globalStyle": { "globalStyle": {
"navigationBarTextStyle": "black", "navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app", "navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8", "navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8" "backgroundColor": "#F8F8F8"
}, },
"uniIdRouter": {} "uniIdRouter": {}
} }

49
pages/index/iSoul.vue

@ -24,8 +24,8 @@
<view class="flex-around" style="margin-top: 20rpx;"> <view class="flex-around" style="margin-top: 20rpx;">
<view class="orderItem" v-for="(item,index) in orderList" :key="index" @click="goTrades(item)"> <view class="orderItem" v-for="(item,index) in orderList" :key="index" @click="goTrades(item)">
<img :src="item.src" alt=""> <image :src="item.src" mode="heightFix"></image>
<view>{{item.title}}</view> <view style="margin-top: 10rpx;">{{item.title}}</view>
</view> </view>
</view> </view>
<!-- 待付款轮播 --> <!-- 待付款轮播 -->
@ -57,13 +57,13 @@
</view> </view>
<img src="https://static.ticket.sz-trip.com/yandu/images/user/rightIcon-gray.png" class="rightIcon"> <img src="https://static.ticket.sz-trip.com/yandu/images/user/rightIcon-gray.png" class="rightIcon">
</view> </view>
<!-- <button id="contact" class="cyItem flex-between" open-type="contact" bindcontact="handleContact" session-from="sessionFrom"> <button id="contact" class="cyItem flex-between" open-type="contact" bindcontact="handleContact" session-from="sessionFrom">
<view class="flex-center"> <view class="flex-center">
<img src="https://static.ticket.sz-trip.com/dongtai/images/user/zxkf.png" class="headIcon"> <img src="https://static.ticket.sz-trip.com/cgc/images/user/kfdh.png" class="headIcon">
在线客服 在线客服
</view> </view>
<img src="https://static.ticket.sz-trip.com/dongtai/images/user/rightIcon-gray.png" class="rightIcon"> <img src="https://static.ticket.sz-trip.com/dongtai/images/user/rightIcon-gray.png" class="rightIcon">
</button> --> </button>
</view> </view>
<!-- 旅游咨询弹框 --> <!-- 旅游咨询弹框 -->
@ -82,14 +82,16 @@
</uni-popup> </uni-popup>
<CustomTabBar :currentTab="4" /> <CustomTabBar :currentTab="4" />
<MusicControl />
</view> </view>
</template> </template>
<script> <script>
import moment from "moment"; import moment from "moment";
import CustomTabBar from '@/components/CustomTabBar.vue'; import CustomTabBar from '@/components/CustomTabBar.vue';
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {CustomTabBar}, components: {CustomTabBar,MusicControl},
data() { data() {
return { return {
dfkList: [], dfkList: [],
@ -97,17 +99,17 @@
nowDateTime: '', // nowDateTime: '', //
userInfo: {}, userInfo: {},
orderList: [{ orderList: [{
src: 'https://static.ticket.sz-trip.com/cgc/images/user/dfk.png', src: 'https://static.ticket.sz-trip.com/epicSoul/image/user/dfk.png',
title: '待付款', title: '待付款',
status: 'WAIT_PAYMENT' status: 'WAIT_PAYMENT'
}, },
{ {
src: 'https://static.ticket.sz-trip.com/cgc/images/user/dfh.png', src: 'https://static.ticket.sz-trip.com/epicSoul/image/user/dfh.png',
title: '待使用/发货', title: '待使用/发货',
status: 'PAYMENT_SUCCESSFULLY' status: 'PAYMENT_SUCCESSFULLY'
}, },
{ {
src: 'https://static.ticket.sz-trip.com/cgc/images/user/dsh.png', src: 'https://static.ticket.sz-trip.com/epicSoul/image/user/dsh.png',
title: '待收货', title: '待收货',
status: 'POST' status: 'POST'
}, },
@ -117,24 +119,24 @@
// status: 'WAIT_COMMENT' // status: 'WAIT_COMMENT'
// }, // },
{ {
src: 'https://static.ticket.sz-trip.com/cgc/images/user/tk.png', src: 'https://static.ticket.sz-trip.com/epicSoul/image/user/sh.png',
title: '退款/售后', title: '退款/售后',
status: 'WAIT_REFUND,REFUND_SUCCESS,REFUND_REFUSAL,REFUND_ERROR,REFUND_PART' status: 'WAIT_REFUND,REFUND_SUCCESS,REFUND_REFUSAL,REFUND_ERROR,REFUND_PART'
}, },
], ],
cyList: [ cyList: [
// {
// src: 'https://static.ticket.sz-trip.com/cgc/images/user/gwc.png',
// title: '',
// path: '/subPackages/user/gwc',
// isShow: true
// },
{ {
src: 'https://static.ticket.sz-trip.com/cgc/images/user/kfdh.png', src: 'https://static.ticket.sz-trip.com/cgc/images/user/gwc.png',
title: '客服电话', title: '购物车',
path: '', path: '/subPackages/user/gwc',
isShow: true isShow: true
}, },
// {
// src: 'https://static.ticket.sz-trip.com/cgc/images/user/kfdh.png',
// title: '',
// path: '',
// isShow: true
// },
{ {
src: 'https://static.ticket.sz-trip.com/cgc/images/user/shdz.png', src: 'https://static.ticket.sz-trip.com/cgc/images/user/shdz.png',
title: '收货地址', title: '收货地址',
@ -333,7 +335,7 @@
.bg { .bg {
min-height: 100vh; min-height: 100vh;
overflow-x: hidden; overflow-x: hidden;
background: url('https://static.ticket.sz-trip.com/cgc/images/user/bg.png') no-repeat; background: url('https://static.ticket.sz-trip.com/epicSoul/image/user/bg.png') no-repeat;
background-size: 100% auto; background-size: 100% auto;
background-color: #F7F7F7; background-color: #F7F7F7;
padding-bottom: 100rpx; padding-bottom: 100rpx;
@ -430,9 +432,8 @@
width: 25%; width: 25%;
text-align: center; text-align: center;
img { image {
width: 80rpx; height: 60rpx;
height: 80rpx;
} }
} }
} }
@ -573,7 +574,7 @@
color: transparent; color: transparent;
cursor: pointer; cursor: pointer;
overflow: hidden; overflow: hidden;
padding: 0 27rpx; padding: 0;
position: relative; position: relative;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;

27
pages/index/index.vue

@ -1,22 +1,24 @@
<template> <template>
<view class="bg"> <view class="bg">
<headerVue></headerVue> <headerVue :isSearch="false"></headerVue>
<view class="content"> <view class="content">
<swiper class="top-banner" :indicator-dots="false" :autoplay="false" v-if="topBanner && topBanner.length > 0"> <swiper class="top-banner" :indicator-dots="false" :autoplay="false" v-if="topBanner && topBanner.length > 0">
<swiper-item v-for="(item, index) in topBanner" :key="index" @click.stop="gotoUrlNew(item)"> <swiper-item v-for="(item, index) in topBanner" :key="index" @click.stop="gotoUrlNew(item,index)">
<image class="top-banner" :src="showImg(item.head_img)" mode="aspectFill" lazy-load="true"></image> <image class="top-banner" :src="showImg(item.head_img)" mode="aspectFill" lazy-load="true"></image>
</swiper-item> </swiper-item>
</swiper> </swiper>
</view> </view>
<CustomTabBar :currentTab="0" /> <CustomTabBar :currentTab="0" />
<MusicControl />
</view> </view>
</template> </template>
<script> <script>
import MusicControl from '@/components/MusicControl.vue';
import headerVue from "@/components/header.vue" import headerVue from "@/components/header.vue"
import CustomTabBar from '@/components/CustomTabBar.vue'; import CustomTabBar from '@/components/CustomTabBar.vue';
export default { export default {
components: {CustomTabBar,headerVue}, components: {CustomTabBar,headerVue,MusicControl},
data() { data() {
return { return {
topBanner: [] topBanner: []
@ -27,12 +29,25 @@
}, },
onReady() { onReady() {
this.getList() this.getList()
},
onShow() {
this.browse_record({type: 'page',title: '首页'});
}, },
onReachBottom() { onReachBottom() {
}, },
methods: { methods: {
gotoUrlNew(item,index) {
if(index == 0) {
uni.switchTab({
url:"/pages/index/readingBody"
})
}else if(index == 1) {
uni.switchTab({
url:"/pages/index/intelligentAgent"
})
}
},
viewDetail(item) { viewDetail(item) {
if (item.url) { if (item.url) {
uni.navigateTo({ uni.navigateTo({
@ -44,7 +59,6 @@
url:'/subPackages/letter/detail?id='+item.id url:'/subPackages/letter/detail?id='+item.id
}) })
}, },
getList() { getList() {
// //
this.Post({ this.Post({
@ -60,8 +74,7 @@
uni.navigateTo({ uni.navigateTo({
url: '/subPackages/video/video?item=' + encodeURIComponent(JSON.stringify(item)) url: '/subPackages/video/video?item=' + encodeURIComponent(JSON.stringify(item))
}) })
}, }
} }
} }
</script> </script>

4
pages/index/intelligentAgent.vue

@ -8,14 +8,16 @@
</swiper> </swiper>
</view> </view>
<CustomTabBar :currentTab="3" /> <CustomTabBar :currentTab="3" />
<MusicControl />
</view> </view>
</template> </template>
<script> <script>
import headerVue from "@/components/header.vue" import headerVue from "@/components/header.vue"
import CustomTabBar from '@/components/CustomTabBar.vue'; import CustomTabBar from '@/components/CustomTabBar.vue';
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {CustomTabBar,headerVue}, components: {CustomTabBar,headerVue,MusicControl},
data() { data() {
return { return {
topBanner: [] topBanner: []

94
pages/index/readingBody.vue

@ -1,8 +1,8 @@
<template> <template>
<view class="bg"> <view class="bg">
<headerVue /> <headerVue :type="'article'" />
<view class="start-swiper" v-show="isShow" @click="this.isShow = false"> <view class="start-swiper" v-show="isShow && startSwiper && startSwiper.length > 0" @click="this.isShow = false">
<swiper class="start-swiper" :indicator-dots="false" :autoplay="true" :interval="5000" :duration="500" <swiper class="start-swiper" :indicator-dots="false" :autoplay="true" :interval="5000" :duration="500"
@change="onSwiperChange"> @change="onSwiperChange">
<swiper-item v-for="(item, index) in startSwiper" :key="index"> <swiper-item v-for="(item, index) in startSwiper" :key="index">
@ -28,27 +28,29 @@
<uni-swiper-dot class="uni-swiper-dot-box" :info="swiperList" :current="current" :mode="mode" <uni-swiper-dot class="uni-swiper-dot-box" :info="swiperList" :current="current" :mode="mode"
:dots-styles="dotsStyles" field="content"> :dots-styles="dotsStyles" field="content">
<swiper class="swiper-box" @change="change" :current="swiperDotIndex"> <swiper class="swiper-box" @change="change" :current="swiperDotIndex" :style="{height : swiperHeight + 'px'}">
<swiper-item v-for="(item, index) in swiperList" :key="index" @click="gotoUrlNew(item)"> <swiper-item v-for="(item, index) in swiperList" :key="index" @click="gotoUrlNew(item)">
<image :src="showImg(item.head_img)" mode=""></image> <image :src="showImg(item.head_img)" mode="widthFix" :id="`swiper-item-${index}`"></image>
</swiper-item> </swiper-item>
</swiper> </swiper>
</uni-swiper-dot> </uni-swiper-dot>
<!-- <scroll-view scroll-x="true" show-scrollbar="false"> <!-- <swiper class="category-scroll">
<view class="category-scroll">
<image v-for="(item,index) in categories" :key="index" :src="showImg(item.head_img)"></image>
</view>
</scroll-view> -->
<swiper class="category-scroll">
<swiper-item v-for="(item, index) in categories" :key="index" @click="gotoUrlNew(item)"> <swiper-item v-for="(item, index) in categories" :key="index" @click="gotoUrlNew(item)">
<image :src="showImg(item.head_img)" mode="aspectFill"></image> <image :src="showImg(item.head_img)" mode="aspectFill"></image>
</swiper-item> </swiper-item>
</swiper> </swiper> -->
<!-- <view class="category-scroll" v-if="categories && categories.length > 0">
<video src="https://static.ticket.sz-trip.com/epicSoul/category.mp4" :poster="showImg(categories[0].head_img)" objectFit="cover"></video>
</view> -->
<view class="category-scroll">
<video src="https://static.ticket.sz-trip.com/epicSoul/categorys.mp4" objectFit="cover"></video>
</view>
<view class="title-box"> <view class="title-box">
全部阅读 阅读合集
<image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/titleSpan.png" mode=""></image> <image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/titleSpan.png" mode=""></image>
</view> </view>
@ -57,26 +59,30 @@
<span :style="{left: readingIndex == 0 ? '32rpx' : (readingIndex == 1 ? '245rpx' : '448rpx')}"></span> --> <span :style="{left: readingIndex == 0 ? '32rpx' : (readingIndex == 1 ? '245rpx' : '448rpx')}"></span> -->
</view> </view>
<view class="reading-box"> <view class="reading-box">
<image v-for="(item,index) in readingList" :key="index" :src="showImg(item.image)" @click="gotoUrlNews(item,index)"></image> <image v-for="(item,index) in readingList" :key="index" :src="showImg(item.image)" @click="gotoUrlNew(item)"></image>
</view> </view>
<CustomTabBar :currentTab="1" /> <CustomTabBar :currentTab="1" />
<MusicControl />
</view> </view>
</template> </template>
<script> <script>
import headerVue from "@/components/header.vue"; import headerVue from "@/components/header.vue";
import CustomTabBar from '@/components/CustomTabBar.vue'; import CustomTabBar from '@/components/CustomTabBar.vue';
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: { components: {
headerVue, headerVue,
CustomTabBar CustomTabBar,
MusicControl
}, },
data() { data() {
return { return {
swiperList: [], swiperList: [],
current: 0, current: 0,
swiperDotIndex: 0, swiperDotIndex: 0,
swiperHeight: 524,
mode: 'round', mode: 'round',
dotsStyles: { dotsStyles: {
selectedBackgroundColor: 'rgb(133, 133, 133)', selectedBackgroundColor: 'rgb(133, 133, 133)',
@ -94,27 +100,17 @@
} }
}, },
onReady() { onReady() {
this.Post({
type_id: 3,
position: 4,
}, '/api/adv/getAdv').then(res => {
if(res.data) {
this.startSwiper = res.data;
}
});
this.sendRequest() this.sendRequest()
}, },
onShow() {
const app = getApp();
if(app.globalData.musicSrc != 'https://static.ticket.sz-trip.com/epicSoul/EpicSouls.mp3') {
app.updateMusicSrc('https://static.ticket.sz-trip.com/epicSoul/EpicSouls.mp3');
app.initBackgroundMusic(); //
uni.$bgMusic.play(); //
}
},
methods: { methods: {
gotoUrlNews(item,index) {
if(index == 0) {
uni.navigateTo({
url: '/xxdf/home/home'
})
}else {
this.gotoUrlNew(item)
}
},
sendRequest() { sendRequest() {
this.Post({ this.Post({
type_id: 3, type_id: 3,
@ -122,6 +118,12 @@
}, '/api/adv/getAdv').then(res => { }, '/api/adv/getAdv').then(res => {
if(res.data) { if(res.data) {
this.swiperList = res.data; this.swiperList = res.data;
setTimeout(() => {
this.$nextTick(() => {
this.change({detail: {current: 0}})
})
},500)
} }
}); });
@ -134,6 +136,15 @@
} }
}); });
this.Post({
type_id: 3,
position: 4,
}, '/api/adv/getAdv').then(res => {
if(res.data) {
this.startSwiper = res.data;
}
});
this.getList() this.getList()
}, },
// //
@ -150,6 +161,14 @@
}, },
change(e) { change(e) {
this.current = e.detail.current this.current = e.detail.current
let element = '#swiper-item-' + e.detail.current
let query = uni.createSelectorQuery().in(this)
query.select(element).boundingClientRect()
query.exec((res) => {
if (res && res[0]) {
this.swiperHeight = res[0].height
}
})
}, },
onSwiperChange(e) { onSwiperChange(e) {
this.currentIndex = e.detail.current; this.currentIndex = e.detail.current;
@ -157,7 +176,6 @@
changeType(index) { changeType(index) {
this.readingIndex = index this.readingIndex = index
this.getList() this.getList()
console.log(index,this.readingIndex)
}, },
viewDetail(item) { viewDetail(item) {
if (item.url) { if (item.url) {
@ -247,6 +265,12 @@
// margin-right: 20rpx; // margin-right: 20rpx;
border-radius: 20rpx; border-radius: 20rpx;
} }
video {
width: 100%;
height: 393rpx;
border-radius: 20rpx;
}
} }
.title-box { .title-box {
@ -302,7 +326,7 @@
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1); box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
padding: 35rpx 10rpx 5rpx; padding: 35rpx 10rpx 5rpx;
display: flex; display: flex;
justify-content: space-between; justify-content: space-around;
flex-wrap: wrap; flex-wrap: wrap;
position: relative; position: relative;
// top: -15rpx; // top: -15rpx;

49
pages/index/sensoryStore.vue

@ -1,6 +1,6 @@
<template> <template>
<view class="bg"> <view class="bg">
<headerVue></headerVue> <headerVue :type="'goods'"></headerVue>
<view class="banner-content"> <view class="banner-content">
<swiper class="top-banner" :circular="true" :interval="6000" :duration="800" <swiper class="top-banner" :circular="true" :interval="6000" :duration="800"
@ -40,14 +40,16 @@
</view> </view>
</view> </view>
<CustomTabBar :currentTab="2" /> <CustomTabBar :currentTab="2" />
<MusicControl />
</view> </view>
</template> </template>
<script> <script>
import headerVue from "@/components/header.vue" import headerVue from "@/components/header.vue"
import CustomTabBar from '@/components/CustomTabBar.vue'; import CustomTabBar from '@/components/CustomTabBar.vue';
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {CustomTabBar,headerVue}, components: {CustomTabBar,headerVue,MusicControl},
data() { data() {
return { return {
topBanner: [], topBanner: [],
@ -117,46 +119,6 @@
} }
}); });
}, },
// 234
gotoUrlNew(item) {
console.log(item);
let that = this;
let url = '';
switch (item.jump_type) {
case 0:
break;
case 2:
uni.navigateTo({
url: item.tdata
});
break;
case 3:
uni.navigateTo({
url: '/subPackages/webPage/webPage?url=' + item.tdata
});
break;
case 4:
uni.navigateToMiniProgram({
appId: item.tdata.appid, // appid
path: item.tdata.page, //
envVersion: 'release',
success: res => {
//
console.log('打开成功', res);
},
fail: err => {
console.log(err);
}
});
break;
default:
break;
}
},
} }
} }
</script> </script>
@ -208,9 +170,10 @@
padding: 36rpx 0 0; padding: 36rpx 0 0;
display: flex; display: flex;
flex-wrap: nowrap; flex-wrap: nowrap;
justify-content: space-between; // justify-content: space-between;
.item{ .item{
width: 214.69rpx; width: 214.69rpx;
margin-right: 20rpx;
} }
.item-img{ .item-img{
width: 214.69rpx; width: 214.69rpx;

45
pages/stratIndex.vue

@ -1,11 +1,17 @@
<template> <template>
<view class="bg" @click="goIndex()"> <view class="bg" @click="goIndex()">
<image :src="showImg(screenPng)"></image> <image :src="showImg(screenPng)" class="img"></image>
<image src="https://static.ticket.sz-trip.com/epicSoul/startBtn.png" mode="widthFix" class="btn"></image>
<MusicControl />
</view> </view>
</template> </template>
<script> <script>
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {
MusicControl
},
data() { data() {
return { return {
screenPng: "" screenPng: ""
@ -23,23 +29,49 @@
}, '/api/adv/getAdv').then(res => { }, '/api/adv/getAdv').then(res => {
if(res.data && res.data.length>0) { if(res.data && res.data.length>0) {
this.screenPng = res.data[0].head_img this.screenPng = res.data[0].head_img
// setTimeout(() => {
// this.goIndex()
// },3000)
} }
}); });
}, },
mounted() {
const app = getApp();
app.initBackgroundMusic(); //
uni.$bgMusic.play(); //
},
methods: { methods: {
goIndex () { goIndex () {
uni.switchTab({ uni.switchTab({
url:"/pages/index/index" url:"/pages/index/index"
}) })
}, },
},
// #ifdef MP-WEIXIN
onShareAppMessage() {
return {
title: 'Epic Soul 交响',
mpId: 'wx8954209bb3ad489e',
path: '/pages/stratIndex',
imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/epicShare.png'
};
},
onShareTimeline() {
return {
title: 'Epic Soul 交响',
query: '',
imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/epicShare.png'
};
} }
// #endif
} }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.bg{ .bg{
height: 100vh; height: 100vh;
image{ .img{
width: 100%; width: 100%;
height: 100%; height: 100%;
position: fixed; position: fixed;
@ -47,4 +79,13 @@
left: 0; left: 0;
} }
} }
.btn {
position: fixed;
left: 0;
right: 0;
margin: 0 auto;
width: 300rpx;
bottom: 250rpx;
}
</style> </style>

BIN
static/fonts/SourceHanSerifSC-Regular.otf

Binary file not shown.

37
static/js/CommonFunction.js

@ -305,7 +305,7 @@ Vue.prototype.goDetailByType= function(item){
}) })
} }
// 轮播图跳转 2是各种详情页,3是列表专题页面,4是小程序 // 轮播图跳转 1产品详情 2是各种详情页,3是列表专题页面,4是小程序
Vue.prototype.gotoUrlNew = (item) => { Vue.prototype.gotoUrlNew = (item) => {
console.log(item); console.log(item);
let that = this; let that = this;
@ -313,9 +313,14 @@ Vue.prototype.gotoUrlNew = (item) => {
switch (item.jump_type) { switch (item.jump_type) {
case 0: case 0:
break; break;
case 1:
uni.navigateTo({
url: '/subPackages/techan/detail?id=' + item.product_model.id
});
break;
case 2: case 2:
uni.navigateTo({ uni.navigateTo({
url: item.tdata url: item.front_model.mini
}); });
break; break;
case 3: case 3:
@ -352,4 +357,32 @@ Vue.prototype.gotoUrlNew = (item) => {
default: default:
break; break;
} }
}
// 埋点
Vue.prototype.getUuid = () => {
return new Promise((resolve, reject) => {
if (uni.getStorageSync('uuid')) {
resolve(uni.getStorageSync('uuid'))
} else {
Vue.prototype.Post({}, '/api/browse/get_uuid').then(res => {
uni.setStorageSync('uuid', res.data.uuid)
resolve(res.data.uuid)
})
}
})
},
// 普通埋点
Vue.prototype.browse_record = (info) => {
info.drive = 'mini'
if (!info.type) {
info.type = 'page'
}
var pages = getCurrentPages() //获取加载的页面
var currentPage = pages[pages.length - 1] //获取当前页面的对象
info.url = currentPage.$page.fullPath
Vue.prototype.getUuid().then(uuid => {
info.uuid = uuid
Vue.prototype.Post(info, '/api/browse/browse_record').then(res => {})
})
} }

36
static/js/common.js

@ -0,0 +1,36 @@
import {
get,
post
} from '@/utils/request';
const API = {
MESSAGE: {
LIST: '/api/questionnaire/index?page=1&limit=10', //获取问卷列表
DETAIL: '/api/questionnaire/detail', //获取问卷详情
ANSWER:'/api/questionnaire/answer', //提交答案
STATISTICS:'/api/questionnaire/statistics', //获取统计选项
ADD: '/api/liuyan/add',
LISTS: '/api/liuyan/lists'
}
};
export const getQuestionnaireList = (params, options = {}) => {
return get(API.MESSAGE.LIST, params, options);
};
export const getQuestionnaireDetail = (params, options = {}) => {
return get(API.MESSAGE.DETAIL, params, options);
};
export const getStatistics = (params, options = {}) => {
return get(API.MESSAGE.STATISTICS, params, options);
};
export const sendAnswer = (data) => {
return post(API.MESSAGE.ANSWER, data);
};
export const sendMessage = (data) => {
return post(API.MESSAGE.ADD, data);
};
export const getMessageList = (params, options = {}) => {
return get(API.MESSAGE.LISTS, params, options);
};
export const ApiPath = API;

2
subPackages/haveFeeling/detailXiang.vue

@ -9,7 +9,7 @@
<view class="content"> <view class="content">
<view class="title text-overflow">{{item.title}}</view> <view class="title text-overflow">{{item.title}}</view>
<view class="flex-between"> <view class="flex-between">
<view class="price">{{(item.price / 100).toFixed(2)}}</view> <view class="price">{{(item.money / 100).toFixed(2)}}</view>
<image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/gwc.png" mode="" class="gwc"></image> <image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/gwc.png" mode="" class="gwc"></image>
</view> </view>
</view> </view>

912
subPackages/order/gwcOrder.vue

@ -0,0 +1,912 @@
<template>
<view class="bg" v-if="info">
<view class="address box" @click="changeAddressPopup('open', '', key)" v-if="!contacts && info[0].is_post == 1">
<!-- <image src="https://kunshan.xmainc.com/uploads/20230105/870e4ce1d5a661986d8a54e9f3c2b0b3.png" mode="aspectFill"></image> -->
<view class="text">+ 添加邮寄地址</view>
</view>
<view class="contacts box" v-if="contacts && info[0].is_post == 1">
<view class="contacts-left">
<view class="name-phone">
<view class="name">{{ contacts.name }}</view>
<view class="phone">{{ contacts.tel }}</view>
</view>
<view class="adds text-overflowRows">{{ contacts.province_text + contacts.city_text + contacts.district_text + contacts.detail_addr }}</view>
</view>
<image @click="changeAddressPopup('open', '', key)" src="https://static.ticket.sz-trip.com/taizhou/images/detail/edit.png" mode="aspectFill"></image>
</view>
<view class="commodity box">
<view class="merchant-name">
{{info[0].merchant_name}}
</view>
<view style="margin-top: 20rpx;" class="" v-for="(item,index) in info" :key="item.id">
<view class="goods">
<image class="img" :src="showImg(item.specifications_image)" mode=""></image>
<view class="" style="display: flex;flex-direction: column;justify-content: space-between;">
<view class="">
{{item.good_name}}
</view>
<!-- <view>
<span class="info-tags" v-for="(itemT,indexT) in item.goods_new_tag.split(',').splice(0,2)" :key="indexT">{{itemT}}</span>
</view> -->
</view>
</view>
<view class="sku-info">
<view class="title">
<view class="text-overflowRows" style="font-size: 31rpx;font-weight: 500;color: #000;">{{ item.specifications_name }}</view>
<view class="price-list">
<view class="price-r">{{ item.Specifications_money / 100 }}</view>
<!-- <view class="price-g">¥{{ info.skuInfo.price / 100 }}</view> -->
<view class="price-g" v-if="item.post_money">{{ item.post_money / 100 }}</view>
</view>
</view>
<view class="num-box">
<view class="ctrl" @click="reduce(item)">-</view>
<view class="num">{{item.num}}</view>
<!-- <input class="num" :disabled="true" type="text" v-model="item.num" @input="rge($event)" @blur="setV()" /> -->
<view class="ctrl" @click="plus(item)">+</view>
</view>
</view>
</view>
</view>
<view class="person-info box" v-if="info[0].is_post == 0 && info[0].is_card == 1">
<view class="person-title">购买信息</view>
<view class="p_name line flex">
<view class="left">用户姓名</view>
<input class="input" type="text" placeholder="请输入姓名" v-model="reserve_name" />
</view>
<view class="p_id line flex">
<view class="left">身份证号</view>
<input class="input" type="text" placeholder="请输入身份证号" v-model="reserve_idcard" />
</view>
<view class="p_tel flex">
<view class="left">手机号码</view>
<input class="input" type="text" placeholder="接受预定信息的号码" v-model="reserve_phone" />
</view>
</view>
<!-- 优惠 -->
<view class="youhui">
<view class="" style="font-size: 32rpx;font-weight: bold;color: #000;">优惠</view>
<view class="youhui-price">
<view class="" style="color: #4D526C;font-weight: 500;">
活动促销
</view>
<view class="" style="color: #FC5109;font-weight: bold;">
-{{delPrice}}
</view>
</view>
</view>
<!-- <view class="remark">
<view class="">备注:</view>
<input type="text" placeholder="订单备注" v-model="remark" maxlength="50"/>
</view> -->
<!-- <view class="" style="font-size: 24rpx;font-weight: 500;color: #FC5109;margin-left: 26.7rpx;margin-top: 27.33rpx;">
*温馨提示本商品不支持退换货
</view> -->
<view class="btn-list">
<view class="price-box">
<view class="text">合计:</view>
<view class="price">{{ (allPrice + post)/100}}</view>
<!-- <view class="price">{{ getAllPrice() - disPrice + (post / 100) }}</view> -->
<view class="post" v-if="post">含邮费:¥{{ post / 100 }}</view>
</view>
<view class="btn" @click="order()">立即购买</view>
</view>
<!-- 选择收货地址弹窗 -->
<uni-popup ref="addressPopup" type="bottom" backgroundColor="#F4F4F4">
<view class="people-popup">
<view class="top-box">
<view class="top flex-between">
<text class="text-overflow" @click="changeAddressPopup('close')">取消</text>
<text class="confirm" @click="changeAddressPopup('close', 'confirm')">确定</text>
</view>
</view>
<navigator url="/subPackages/user/myAddressAdd" class="button">添加收货地址</navigator>
<view class="popup-list" v-if="addressList.length > 0">
<view class="popup-item" v-for="(item, index) in addressList" :key="index" @click="seldThisAddress(item)">
<view class="item-top flex-between">
<view>
<view class="name flex-start">
{{ item.name }}
<text>{{ item.tel }}</text>
<text class="tag" v-if="item.is_default == 1">默认</text>
</view>
<view class="subtitle">{{ item.address }}</view>
</view>
<navigator :url="`/subPackages/user/myAddressAdd?id=${item.id}`">
<img src="https://static.ticket.sz-trip.com/taizhou/images/detail/edit.png" alt="" />
</navigator>
</view>
</view>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
export default {
data() {
return {
contacts: null,
info: null,
num: 1,
post: 0,
flag: true,
addressList: [],
reserve_name: '',
reserve_idcard: '',
reserve_phone: '',
remark: '',
allPrice: 0, //
discounts:null,
disPrice: {}, //
delPrice:0
// disPrice: 0
};
},
onLoad() {
this.info = this.$store.state.user.sshoppingCart
console.log('info',this.info);
this.info.forEach(item => {
this.getDiscount(item)
})
if (!this.info) {
uni.navigateBack();
}
console.log('----***info***------',this.info);
},
onShow() {
this.getContacts();
this.getAllAddressList();
// this.getAllPrice()
// this.getTotal()
},
methods: {
//
getAllPrice() {
this.info.forEach(item => {
if ((item.Specifications_money * item.num) - (this.disPrice[item.specifications_id]*100) <= 0) {
item.price1 = this.disPrice[item.specifications_id]
item.price = 0
} else{
item.price1 = this.disPrice[item.specifications_id]
let price = (item.Specifications_money * item.num) - (this.disPrice[item.specifications_id]*100)
item.price = +price.toFixed(2)
}
})
let allPrice = 0
let delPrice = 0
this.info.forEach(item => {
delPrice += item.price1
allPrice += item.price
})
this.delPrice = delPrice
console.log('delPrice',this.delPrice);
this.allPrice = allPrice
},
getContacts() {
if (this.info[0].is_post == 0) {
return;
}
this.Post({}, '/api/user/getDefaultConsignee').then(res => {
if (res) {
this.contacts = res.data;
this.getPost();
}
});
},
getPost() {
if (this.info[0].is_post == 0 || !this.contacts) {
return;
}
console.log(this.info,55555555,this.contacts);
this.flag = false;
let data = this.info.map((item) => {
return { specifications_id:item.specifications_id, num: item.num, consignee_id: this.contacts.id }
})
// let data = [{ specifications_id: this.info.skuInfo.id, num: this.num, consignee_id: this.contacts.id }];
console.log(data);
this.Post({ data:JSON.stringify(data)}, '/api/order/getNewPost').then(res => {
if (res) {
this.post = 0
res.data.forEach((item)=> {
this.post += item.post_money
const postItem = this.info.find(i => i.specifications_id == item.specifications_id)
if(postItem) postItem.post_money = item.post_money
})
this.flag = true;
}
});
},
rge(val) {
this.$nextTick(() => {
this.num = val.detail.value.replace(/^(0+)|[^\d]+/g, '');
});
},
setV() {
if (!this.num) {
this.$nextTick(() => {
this.num = 1;
if (this.flag) {
this.getPost();
}
});
} else {
if (this.flag) {
this.getPost();
}
}
},
plus(item) {
// this.num = Number(this.num);
this.$nextTick(() => {
item.num += 1;
this.getDiscount(item)
// this.disPrice = this.calculateTotalPrice(this.discounts,this.num)
// console.log(this.disPrice);
if (this.flag) {
this.getPost();
}
});
},
reduce(item) {
if (item.num > 1) {
this.$nextTick(() => {
item.num -= 1;
this.getDiscount(item)
// this.disPrice = this.calculateTotalPrice(item.discounts,item.num)
console.log(this.disPrice);
if (this.flag) {
this.getPost();
}
});
}
// this.num = Number(this.num);
// if (this.num > 1) {
// this.$nextTick(() => {
// this.num -= 1;
// this.disPrice = this.calculateTotalPrice(this.discounts,this.num)
// console.log(this.disPrice);
// if (this.flag) {
// this.getPost();
// }
// });
// }
},
//
getDiscount(item) {
this.Post({ specifications_id: item.specifications_id }, '/api/goods/getSpeNumDiscount').then(res => {
this.discounts = res.data.discount_rule;
if (this.discounts) {
let disPrice_item = this.calculateTotalPrice(this.discounts,item.num)
this.disPrice[item.specifications_id] = +disPrice_item
} else {
this.disPrice[item.specifications_id] = 0
}
this.getAllPrice()
});
},
//
calculateTotalPrice(discounts, selectedQuantity) {
if (discounts) {
let totalPrice = 0;
for (const discount of discounts) {
if (selectedQuantity >= discount.num) {
totalPrice = discount.money;
}
}
return totalPrice;
} else {
return 0;
}
},
//
changeAddressPopup(type, confirm, index) {
if (type == 'open') {
this.$refs.addressPopup.open('bottom');
}
else this.$refs.addressPopup.close();
this.$forceUpdate();
},
//
getAllAddressList() {
this.Post({}, '/api/user/consigneeList').then(res => {
if (res.code === 200) this.addressList = res.data;
});
},
//
seldThisAddress(item) {
if (!this.contacts) this.contacts = {};
Object.assign(this.contacts, item);
if (this.flag) {
this.getPost();
}
this.$refs.addressPopup.close();
this.$forceUpdate();
},
//
order() {
if (this.info[0].is_post == 1 && !this.contacts) {
uni.showToast({
title: '请选择收货地址',
icon: 'none'
});
return;
}
if (this.info[0].is_post == 0 && this.info[0].is_card == 1) {
if (!this.reserve_name) {
uni.showToast({
title: '请输入姓名',
icon: 'none'
});
return;
}
if (!this.reserve_phone) {
uni.showToast({
title: '请输入电话',
icon: 'none'
});
return;
}
if (!this.reserve_idcard) {
uni.showToast({
title: '请输入身份证',
icon: 'none'
});
return;
}
}
// let goods = [];
let goods = this.info.map((item) => {
return { specifications_id:item.specifications_id, num: item.num, consignee_id: item.is_post == 1 ? this.contacts.id : null }
})
// let goodsItem = {
// specifications_id: this.info.skuInfo.id,
// num: this.num,
// consignee_id: this.info.skuInfo.is_post == 1 ? this.contacts.id : null
// };
// goods.push(goodsItem);
let data = {
goods: goods,
coupon: null,
remark: this.remark,
is_post: this.info[0].is_post,
reserve_name: this.reserve_name,
reserve_phone: this.reserve_phone,
reserve_idcard: this.reserve_idcard
};
this.Post(
{
method: 'POST',
data: JSON.stringify(data)
},
'/api/order/place'
).then(resT => {
if (resT.code == 200) {
this.Post(
{
order_id: resT.data.order_id,
type: "miniprogram",
// #ifdef MP-WEIXIN
platform: 'miniprogram',
// #endif
// #ifdef H5
platform: 'JSAPI',
// #endif
},
'/api/pay/unify'
).then(res => {
if (res.data) {
// #ifdef MP-WEIXIN
uni.requestPayment({
nonceStr: res.data.nonceStr,
package: res.data.package,
paySign: res.data.paySign,
signType: res.data.signType,
timeStamp: res.data.timeStamp,
complete() {
},
success(){
uni.showLoading({
title:'加载中...'
})
setTimeout(()=>{
uni.hideLoading()
uni.navigateTo({
url: '/subPackages/order/detail?id='+resT.data.order_id
});
},2000)
}
});
// #endif
// #ifdef H5
WeixinJSBridge.invoke('getBrandWCPayRequest', {
appId: res.data.appId,
timeStamp: res.data.timeStamp,
nonceStr: res.data.nonceStr,
package: res.data.package,
signType: res.data.signType,
paySign: res.data.paySign
}, function(Twores) {
if (Twores.err_msg === 'get_brand_wcpay_request:ok') {
uni.showLoading({
title:'加载中...'
})
setTimeout(()=>{
uni.hideLoading()
uni.navigateTo({
url: '/subPackages/order/detail?id='+resT.data.order_id
});
},2000)
} else {
}
});
// #endif
}
});
}
});
}
}
};
</script>
<style lang="scss" scoped>
.bg {
min-height: 100vh;
overflow-x: hidden;
background: #f2f4f7;
padding-bottom: 200rpx;
}
view {
box-sizing: border-box;
}
.box {
width: 710rpx;
min-height: 100rpx;
padding: 30rpx;
background: #ffffff;
border-radius: 16rpx;
margin: 0 auto;
margin-top: 20rpx;
}
.address {
display: flex;
align-items: center;
justify-content: center;
image {
width: 32rpx;
height: 32rpx;
}
.text {
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6c7a94;
margin-left: 18rpx;
}
}
.commodity {
// display: flex;
// align-items: center;
.img {
width: 140rpx;
height: 140rpx;
background: #f2f4f7;
border-radius: 10rpx;
margin-right: 18rpx;
}
.title {
width: 300rpx;
margin-left: 20rpx;
font-size: 30rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #000000;
.price-list {
width: 600rpx;
display: flex;
justify-content: space-between;
margin-top: 18rpx;
align-items: center;
.price-r {
font-size: 32rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 500;
color: #FC5109;
&:before {
content: '小计:';
display: inline-block;
color: #000;
font-size: 24rpx;
}
}
.price-g {
font-size: 32rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 500;
color: #FC5109;
&:before {
content: '运费:';
display: inline-block;
color: #000;
font-size: 24rpx;
}
}
}
}
.num-box {
display: flex;
align-items: center;
margin-left: 20rpx;
width: 200rpx;
justify-content: space-between;
.num {
text-align: center;
width: 50rpx;
}
.ctrl {
width: 70rpx;
height: 60rpx;
line-height: 60rpx;
text-align: center;
font-weight: bold;
font-size: 36rpx;
}
}
}
.btn-list {
width: 750rpx;
height: 166rpx;
background: #ffffff;
box-shadow: 0rpx -3rpx 9rpx 1rpx rgba(227, 229, 232, 0.5);
display: flex;
position: fixed;
bottom: 0;
padding: 20rpx 50rpx;
align-items: center;
justify-content: space-between;
.btn {
width: 250rpx;
height: 80rpx;
background: #60989E;
border-radius: 44rpx;
text-align: center;
line-height: 80rpx;
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #ffffff;
}
.price-box {
display: flex;
align-items: baseline;
.text {
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #393b3e;
}
.price {
margin-left: 15rpx;
font-size: 48rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #FC5109;
&:before {
content: '¥';
display: inline-block;
color: #FC5109;
font-size: 24rpx;
}
}
.post {
margin-left: 15rpx;
color: #FC5109;
font-size: 24rpx;
}
}
}
.contacts {
display: flex;
align-items: center;
justify-content: space-between;
image {
width: 36rpx;
height: 36rpx;
}
.contacts-left {
.name-phone {
display: flex;
align-items: center;
.name {
font-size: 32rpx;
font-family: PingFangSC-Medium, PingFang SC;
font-weight: 500;
color: #222222;
}
.phone {
margin-left: 27rpx;
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #303030;
}
}
.adds {
font-size: 28rpx;
font-family: PingFangSC-Regular, PingFang SC;
font-weight: 400;
color: #6c7a94;
margin-top: 20rpx;
max-width: 500rpx;
}
}
}
.people-popup {
padding: 26rpx;
min-height: 800rpx;
.top-box {
height: 80rpx;
.top {
position: fixed;
left: 0;
right: 0;
color: #000;
height: 80rpx;
font-size: 0;
overflow: hidden;
padding: 0 26rpx;
text {
text-align: left;
font-size: 30rpx;
font-weight: 400;
color: #000000;
}
.confirm {
font-weight: 400;
color: #000000;
}
}
}
.popup-list {
height: 666rpx;
overflow: scroll;
.popup-item {
border-radius: 12rpx;
padding: 0 20rpx;
margin-top: 24rpx;
font-size: 24rpx;
color: #333333;
font-weight: 400;
background-color: #ffffff;
.item-top {
padding: 32rpx;
img {
color: #666666;
width: 40rpx;
height: 40rpx;
}
.name {
font-size: 30rpx;
color: #000000;
overflow: hidden;
text {
color: #999999;
}
.tag {
width: 70rpx;
height: 32rpx;
background: #00d7ed;
border-radius: 7rpx;
line-height: 32rpx;
text-align: center;
font-size: 21rpx;
font-family: PingFang SC;
font-weight: 500;
color: #ffffff;
}
}
.com-flex-start {
margin: 0 0 30rpx;
}
.subtitle {
font-weight: 400;
flex: 1;
text-align: left;
margin-top: 33rpx;
.mobile {
margin-bottom: 36rpx;
}
}
.status {
width: 40rpx;
height: 40rpx;
line-height: 40rpx;
border-radius: 50%;
text-align: center;
box-sizing: border-box;
img {
width: 27rpx;
height: 21rpx;
}
}
.statuss {
background: linear-gradient(90deg, #fa2b66, #ff9834);
border: none;
}
.noSelect {
border: 1rpx solid #999999;
}
}
// .item-site {
// color: #666666;
// display: flex;
// align-items: center;
// padding: 36rpx 0;
// view {
// width: 23rpx;
// height: 23rpx;
// margin-right: 10rpx;
// border: 1rpx solid #999999;
// border-radius: 50%;
// view {
// width: 8rpx;
// height: 8rpx;
// background: #000000;
// border-radius: 50%;
// margin: auto;
// }
// }
// }
}
}
.button {
font-size: 30rpx;
font-weight: 400;
color: #000000;
text-align: center;
width: 100%;
height: 80rpx;
line-height: 80rpx;
background-color: #ffffff;
border-radius: 60rpx;
}
}
.person-info {
padding: 30rpx 30rpx 15rpx 30rpx;
background: #fff;
margin-top: 30rpx;
border-radius: 16rpx;
}
.person-title {
font-size: 32rpx;
font-weight: bold;
color: #000;
}
.line {
border-bottom: 1px solid #e3e5e8;
}
.flex {
display: flex;
align-items: center;
}
.left {
width: 140rpx;
font-size: 28rpx;
font-weight: 500;
color: #4d526c;
height: 104rpx;
line-height: 104rpx;
}
.input {
font-size: 28rpx;
font-weight: 400;
}
.remark {
padding: 30rpx;
display: flex;
align-items: center;
width: 710rpx;
min-height: 150rpx;
background: #ffffff;
border-radius: 16rpx;
margin: 0 auto;
margin-top: 30rpx;
view {
color: #4d526c;
font-size: 28rpx;
}
input {
margin-left: 64rpx;
width: 500rpx;
font-size: 28rpx;
}
}
.info-tags {
padding: 8rpx 7rpx;
text-align: center;
line-height: 35rpx;
font-size: 20rpx;
font-weight: 500;
}
.info-tags:first-child {
background: rgba(252,81,9,.08);
color: #FC5109;
}
.info-tags:last-child {
background: rgba(73,143,239,.1);
color: #498FEF;
}
.merchant-name {
margin-bottom: 24rpx;
}
.goods {
display: flex;
}
.sku-info {
display: flex;
margin-top: 26rpx;
align-items: baseline;
justify-content: space-between;
border-bottom: 1rpx solid #ccc;
padding-bottom: 25.3rpx;
}
.sku-info:last-child {
border:none !important;
}
.youhui {
width: 710rpx;
margin: 0 auto;
margin-top: 22rpx;
padding: 32.67rpx 19.33rpx 32.67rpx 24rpx;
background: #FFFFFF;
border-radius: 13rpx;
}
.youhui-price {
margin-top: 52.67rpx;
display: flex;
justify-content: space-between;
margin-left: .67rpx;
font-size: 27rpx;
}
</style>

173
subPackages/search/search.vue

@ -0,0 +1,173 @@
<template>
<view class="bg">
<view class="search-box">
<view class="search">
<image src="https://static.ticket.sz-trip.com/taizhou/images/search.png" mode="widthFix"></image>
<input type="text" v-model="keywords" @confirm="getList" placeholder="请输入搜索关键词" />
</view>
<view class="text" @click="goBack">取消</view>
</view>
<view class="box flex-between" v-if="list && list.length > 0">
<view v-for="(item,index) in list" :key="index" class="item" v-if="item.search_data" @click="gotoDetail(item)">
<image :src="showImg(item.search_data.image)" mode="aspectFill" class="headimg"></image>
<view class="content flex-column">
<view class="title text-overflowRows">{{item.title}}</view>
<view class="price" v-if="type == 'goods'">{{item.search_data.money / 100}}</view>
<view class="user-info" v-if="type == 'article'">
<image :src="showImg(item.search_data.author_img)" mode="aspectFill" class="userImg"></image>
{{item.search_data.author}}
</view>
</view>
</view>
</view>
<view v-else class="noData">暂无数据</view>
</view>
</template>
<script>
export default {
data() {
return {
keywords: '',
list: [],
type: ''
}
},
onLoad(option) {
if(option.type) this.type = option.type
},
methods: {
getList() {
this.Post({
name: this.keywords.trim(),
offset: 0,
type: this.type,
limit: 100,
}, '/api/search/search').then(res => {
this.list = res.data
})
},
gotoDetail(item) {
if(this.type == 'goods') {
uni.navigateTo({
url: `/subPackages/techan/detail?id=${item.search_data.id}`
})
}else if(this.type == 'article') {
this.gotoUrlNew(item.search_data)
}
}
}
}
</script>
<style lang="scss" scoped>
.bg {
min-height: 100vh;
background-color: #f7f7f7;
}
.search-box {
width: 100%;
padding: 20rpx;
border-bottom: 1rpx solid #ccc;
display: flex;
align-items: center;
background-color: #fff;
.search {
flex: 1;
padding: 0 20rpx;
display: flex;
align-items: center;
height: 65rpx;
border-radius: 33rpx;
background-color: rgb(245, 245, 245);
image {
display: block;
width: 35rpx;
margin-right: 30rpx;
}
input {
flex: 1;
}
}
.text {
font-size: 30rpx;
color: #b9b9b9;
margin-left: 20rpx;
}
}
.box {
flex-wrap: wrap;
padding: 30rpx 20rpx;
.item {
width: 342rpx;
height: 498rpx;
background: #FFFFFF;
border-radius: 11rpx;
margin-bottom: 20rpx;
.headimg {
width: 343rpx;
height: 327rpx;
border-radius: 11rpx 11rpx 0rpx 0rpx;
}
.content {
height: 170rpx;
justify-content: space-between;
padding: 15rpx 15rpx 20rpx 15rpx;
.title {
font-weight: bold;
font-size: 30rpx;
color: #000000;
}
.price {
font-weight: bold;
font-size: 33rpx;
color: #FF2D3B;
margin-left: auto;
}
.price::before {
font-size: 20rpx;
content: '¥';
}
.price::after {
font-size: 20rpx;
content: '起';
color: rgba(153, 153, 153, 1);
}
.user-info {
font-weight: 500;
font-size: 28rpx;
color: #999999;
display: flex;
align-items: center;
.userImg {
width: 40rpx;
height: 40rpx;
border-radius: 50%;
margin-right: 10rpx;
}
}
}
}
}
.noData {
padding: 30rpx 0;
text-align: center;
font-size: 30rpx;
color: #ccc;
}
</style>

8
subPackages/techan/detail.vue

@ -71,9 +71,8 @@
</view> --> </view> -->
</view> </view>
<view class="btn-post"> <view class="btn-post">
<!-- <view class="left-btn-buy" @click="openPop(true)">加入购物车</view> --> <view class="left-btn-buy" @click="openPop(true)">加入购物车</view>
<view class="right-btn-buy" @click="openPop(false)">立即购买</view> <view class="right-btn-buy" @click="openPop(false)">立即购买</view>
</view> </view>
</view> </view>
@ -215,6 +214,8 @@
uni.setNavigationBarTitle({ uni.setNavigationBarTitle({
title: this.info.title title: this.info.title
}) })
this.browse_record({type: 'goods',title: this.info.title});
} }
}); });
@ -328,7 +329,6 @@
uni.setStorageSync('cartDataInfo', JSON.stringify(selectedData)); uni.setStorageSync('cartDataInfo', JSON.stringify(selectedData));
uni.$emit("updateDataByConnect", {msgType:'updateCartDataInfo',data:null}) uni.$emit("updateDataByConnect", {msgType:'updateCartDataInfo',data:null})
this.closePopup() this.closePopup()
// this.$refs.cartDataVueRef.openPop()
} }
}); });
@ -736,7 +736,7 @@
width: 187rpx; width: 187rpx;
height: 77rpx; height: 77rpx;
background: #74A5AA; background: #74A5AA;
border-radius: 39rpx; border-radius: 0 39rpx 39rpx 0;
color: white; color: white;
} }
} }

286
taozi/chapter1/chapter1.vue

@ -0,0 +1,286 @@
<template>
<view>
<TitleHeader />
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange"
:duration="300" :style="{ height: `calc(100vh - ${titleHeight}px)` }">
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg1s.png"
:lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(0)" class="layer-img1"
:class="{'slide-in-from-left': animationStates[0], 'hidden': !animationStates[0]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg1-info.png" :lazy-load="true" mode="aspectFill">
</image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg2.png"
:lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(1)" class="layer-img2"
:class="{'slide-in-from-left': animationStates[1], 'hidden': !animationStates[1]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg2-info.png" :lazy-load="true" mode="aspectFill">
</image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[2]">
<image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg3.jpg"
:lazy-load="true" mode="aspectFill"></image>
<view class="content-layer" v-show="shouldShowContent(2)">
<image class="layer-img3"
:class="{'slide-in-from-right': animationStates[2], 'hidden': !animationStates[2]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg3-info.png" :lazy-load="true" mode="aspectFill"></image>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[3]">
<image v-show="shouldShowContent(3)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg4.jpg"
:lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(3)" class="layer-img4" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg4-info.gif"
:lazy-load="true" mode="aspectFill">
</image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[4]">
<image v-show="shouldShowContent(4)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg5.png"
:lazy-load="true" mode="aspectFill"></image>
<image :class="{'slide-in-from-right': animationStates[4], 'hidden': !animationStates[4]}"
v-show="shouldShowContent(4)" class="layer-img5" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg5-info.png"
:lazy-load="true" mode="aspectFill">
</image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[5]">
<image v-show="shouldShowContent(5)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg6.png"
:lazy-load="true" mode="aspectFill"></image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[6]">
<image v-show="shouldShowContent(6)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter1/bg7.png"
:lazy-load="true" mode="aspectFill"></image>
<view @click="goBack" class="back-btn" type="default">
<image class="back-icon" src="https://static.ticket.sz-trip.com/epicSoul/taozi/back.png" mode="aspectFill"></image>
</view>
</template>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import TitleHeader from '@/components/TitleHeader.vue';
export default {
components: {
TitleHeader
},
data() {
return {
currentIndex: 0,
loadedPages: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false,
6: false
},
animationStates: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false,
6: false
},
preloadBuffer: 1,
titleHeight: 0
};
},
watch: {
currentIndex(newIndex) {
for (let i = Math.max(0, newIndex - this.preloadBuffer); i <= Math.min(9, newIndex + this
.preloadBuffer); i++) {
this.loadedPages[i] = true;
}
}
},
mounted() {
this.titleHeight = uni.getStorageSync('titleHeight')
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 9); i++) {
this.loadedPages[i] = true;
}
setTimeout(() => {
this.animationStates[this.currentIndex] = true;
}, 50);
},
methods: {
handleSwiperChange(e) {
const newIndex = e.detail.current;
this.currentIndex = newIndex;
this.animationStates[newIndex] = false;
setTimeout(() => {
this.animationStates[newIndex] = true;
}, 50);
},
shouldShowContent(index) {
return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
},
goBack() {
uni.navigateTo({
url: '/taozi/home/home?targetIndex=5'
});
}
}
};
</script>
<style lang="scss" scoped>
.main-swiper {
width: 100%;
height: 100vh;
}
.page-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
position: relative;
overflow: hidden;
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.layer-img1 {
width: 500rpx;
z-index: 2;
margin-right: 180rpx;
margin-top: 50rpx;
}
.layer-img2 {
z-index: 2;
position: absolute;
bottom: 18%;
left: 0;
width: 100%;
height: 350rpx;
}
.content-layer {
margin: 130rpx 0;
width: 100%;
height: 100%;
display: flex;
justify-content: flex-end;
}
.layer-img3 {
height: 100%;
width: 280rpx;
z-index: 2;
margin-top: 10rpx;
margin-right: 30rpx;
}
.layer-img4 {
z-index: 2;
width: 400rpx;
height: 400rpx;
margin-top: 400rpx;
margin-left: 80rpx;
}
.layer-img5 {
z-index: 2;
position: absolute;
bottom: 90rpx;
right: 30rpx;
width: 320rpx;
height: 500rpx;
}
.back-btn {
position: absolute;
top: 50rpx;
left: 50rpx;
z-index: 2;
background-color: rgb(0 0 0 / 0.3);
border-radius: 50%;
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
width: 50rpx;
height: 50rpx;
}
.hidden {
opacity: 0;
}
.slide-in-from-left {
animation: slideInLeft 1.2s ease-out forwards;
}
@keyframes slideInLeft {
0% {
opacity: 0;
transform: translateX(-100px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.slide-in-from-right {
animation: slideInRight 1.2s ease-out forwards;
}
@keyframes slideInRight {
0% {
opacity: 0;
transform: translateX(100px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
</style>

336
taozi/chapter2/chapter2.vue

@ -0,0 +1,336 @@
<template>
<view>
<TitleHeader />
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange"
:duration="300" :style="{ height: `calc(100vh - ${titleHeight}px)` }">
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg1.png"
:lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(0)" class="layer-img1"
:class="{'slide-in-from-left': animationStates[0], 'hidden': !animationStates[0]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg1-info.png" :lazy-load="true" mode="aspectFill" />
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<view class="loadedPages-three-title">
<view class="txt">
#Chapter
</view>
<view class="txt">
IP Art Exhibition
</view>
</view>
<template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg2.png"
:lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(1)" class="layer-img2"
:class="{'slide-in-from-left': animationStates[1], 'hidden': !animationStates[1]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg2-info.png" :lazy-load="true" mode="aspectFill" />
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[2]">
<image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg3.png"
:lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(2)" class="layer-img3"
:class="{'slide-in-from-left': animationStates[2], 'hidden': !animationStates[2]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg3-info.png" :lazy-load="true" mode="aspectFill" />
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[3]">
<image v-show="shouldShowContent(3)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg4.png"
:lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(3)" class="layer-img4"
:class="{'slide-in-from-left': animationStates[3], 'hidden': !animationStates[3]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg4-info.png" :lazy-load="true" mode="aspectFill" />
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[4]">
<image v-show="shouldShowContent(4)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg5.png"
:lazy-load="true" mode="aspectFill"></image>
<video v-show="shouldShowContent(4)" ref="videoPlayer" id="videoPlayer"
class="loadedPages-video" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter2/bg5-video.mp4"
:autoplay="currentIndex === 4" :loop="true" :controls="true" :show-play-btn="true"
:enable-progress-gesture="true" @error="handleVideoError"></video>
<view @click="goBack" class="back-btn" type="default">
<image class="back-icon" src="https://static.ticket.sz-trip.com/epicSoul/taozi/back.png" mode="aspectFill"></image>
</view>
</template>
</view>
</swiper-item>
</swiper>
<MusicControl />
</view>
</template>
<script>
import MusicControl from '@/components/MusicControl.vue';
import TitleHeader from '@/components/TitleHeader.vue';
export default {
components: {
MusicControl,
TitleHeader
},
data() {
return {
currentIndex: 0,
videoPlayer: null,
videoContext: null,
loadedPages: {
0: false,
1: false,
2: false,
3: false,
4: false
},
animationStates: {
0: false,
1: false,
2: false,
3: false,
4: false
},
preloadBuffer: 1,
titleHeight: 0
};
},
watch: {
currentIndex(newIndex) {
for (let i = Math.max(0, newIndex - this.preloadBuffer); i <= Math.min(9, newIndex + this
.preloadBuffer); i++) {
this.loadedPages[i] = true;
}
}
},
mounted() {
this.titleHeight = uni.getStorageSync('titleHeight')
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 9); i++) {
this.loadedPages[i] = true;
}
setTimeout(() => {
this.animationStates[this.currentIndex] = true;
}, 50);
this.$nextTick(() => {
try {
this.videoContext = uni.createVideoContext('videoPlayer');
} catch (error) {
console.error('初始化视频上下文失败:', error);
}
});
},
methods: {
handleSwiperChange(e) {
const newIndex = e.detail.current;
const oldIndex = this.currentIndex;
this.currentIndex = newIndex;
this.animationStates[newIndex] = false;
setTimeout(() => {
this.animationStates[newIndex] = true;
}, 50);
this.$nextTick(() => {
this.handleVideoPlayback(oldIndex, newIndex);
});
},
handleVideoPlayback(oldIndex, newIndex) {
if (!this.videoContext) {
try {
this.videoContext = uni.createVideoContext('videoPlayer');
} catch (error) {}
}
if (!this.videoContext) return;
if (newIndex === 4) {
try {
this.videoContext.play();
} catch (error) {}
} else if (oldIndex === 4) {
try {
this.videoContext.pause();
this.videoContext.seek(0);
} catch (error) {
console.error('视频暂停失败:', error);
}
}
},
handleVideoError(e) {
uni.showToast({
title: '视频加载失败',
icon: 'none'
});
},
shouldShowContent(index) {
return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
},
goBack() {
uni.navigateTo({
url: '/taozi/home/home?targetIndex=6'
});
}
},
onShow() {
if (this.currentIndex === 4 && this.videoContext) {
this.$nextTick(() => {
this.videoContext.play();
});
}
},
onHide() {
if (this.videoContext) {
this.videoContext.pause();
}
}
};
</script>
<style lang="scss" scoped>
.main-swiper {
width: 100%;
height: 100vh;
}
.page-container {
height: 100%;
position: relative;
overflow: hidden;
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.layer-img1 {
position: absolute;
width: 500rpx;
height: 800rpx;
z-index: 2;
top: 120rpx;
left: 60rpx;
}
.layer-img2 {
position: absolute;
top: 0;
left: 0;
width: 640rpx;
height: 750rpx;
z-index: 2;
}
.layer-img3 {
position: absolute;
bottom: 0;
left: 30rpx;
width: 550rpx;
height: 1200rpx;
z-index: 2;
}
.layer-img4 {
position: absolute;
bottom: 50rpx;
left: 30rpx;
width: 400rpx;
height: 900rpx;
z-index: 2;
}
.hidden {
opacity: 0;
}
.slide-in-from-left {
animation: slideInLeft 1.2s ease-out forwards;
}
@keyframes slideInLeft {
0% {
opacity: 0;
transform: translateX(-100px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
@font-face {
font-family: 'SourceHanSerif-Regular';
src: url(https://static.ticket.sz-trip.com/epicSoul/taozi/fonts/SourceHanSerifSC-Regular.otf);
}
.loadedPages-three-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin-top: 30rpx;
z-index: 9;
position: absolute;
.txt {
font-size: 24rpx;
color: #333;
font-family: SourceHanSerif-Regular;
display: flex;
flex-direction: column;
align-items: center;
text {
display: block;
}
}
.txt:first-child {
margin-left: 30rpx;
}
.txt:last-child {
margin-right: 30rpx;
}
}
.loadedPages-video {
width: 100%;
height: 350rpx;
z-index: 9;
margin-top: 150rpx;
}
.back-btn {
position: absolute;
top: 50rpx;
left: 50rpx;
z-index: 2;
background-color: rgb(0 0 0 / 0.3);
border-radius: 50%;
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
width: 50rpx;
height: 50rpx;
}
</style>

369
taozi/chapter3/chapter3.vue

@ -0,0 +1,369 @@
<template>
<view>
<TitleHeader />
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange"
:duration="300" :style="{ height: `calc(100vh - ${titleHeight}px)` }">
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/bg1.png"
:lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(0)" class="layer-img1"
:class="{'rotate-bounce-in': animationStates[0], 'hidden': !animationStates[0]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/bg1-info.png" :lazy-load="true" mode="aspectFill">
</image>
<image v-show="shouldShowContent(0)" class="layer-info" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/bg1-info2.png"
mode="aspectFill"></image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/bg2.png"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(1)" class="layer-content">
<view class="item">
<image class="item-gif" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/liu.gif" mode="aspectFill"></image>
<view class="layer-item-txt">
备的草编席垫送你,<br />咱席地而坐边吃边唠<br />便是人间好时节
</view>
<view class="layer-item-tx2">
刘备 / 挚友款 · 同心桃
</view>
</view>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[2]">
<image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/bg3.png"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(2)" class="layer-content">
<view class="item">
<image class="item-gif" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/guan.gif" mode="aspectFill"></image>
<view class="layer-item-txt">
某卖的不是桃<br />是当年与兄长三弟<br />在桃林下对饮的春秋
</view>
<view class="layer-item-tx2">
关羽 / 挚知己款 · 对饮桃
</view>
</view>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[3]">
<image v-show="shouldShowContent(3)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/bg4.png"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(3)" class="layer-content">
<view class="item">
<image class="item-gif" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/zhang.gif" mode="aspectFill"></image>
<view class="layer-item-txt">
瞧这桃跟俺张飞的脾气<br />一样爽利咬下去<br />噗嗤爆汁,<br />比俺大笑还痛快
</view>
<view class="layer-item-tx2">
张飞 / 热辣款款 · 快哉桃
</view>
</view>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[4]">
<image v-show="shouldShowContent(4)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter3/bg5.png"
:lazy-load="true" mode="aspectFill"></image>
<view class="layer2-content"
:class="{'fade-slide-up': animationStates[4], 'hidden': !animationStates[4]}">
<view class="item">
<view class="bottom-tit">
一起回桃园
</view>
<view class="bottom-tit2">
桃园不是起点而是时间里的约定
</view>
<image class="bottom-img" src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/forewordThree_icon.png" mode="aspectFill"></image>
</view>
</view>
<view @click="goBack" class="back-btn" type="default">
<image class="back-icon" src="https://static.ticket.sz-trip.com/epicSoul/taozi/back.png" mode="aspectFill"></image>
</view>
</template>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import TitleHeader from '@/components/TitleHeader.vue';
export default {
components: {
TitleHeader
},
data() {
return {
currentIndex: 0,
loadedPages: {
0: false,
1: false,
2: false,
3: false
},
animationStates: {
0: false,
1: false,
2: false,
3: false
},
preloadBuffer: 1,
titleHeight: 0
};
},
watch: {
currentIndex(newIndex) {
for (let i = Math.max(0, newIndex - this.preloadBuffer); i <= Math.min(9, newIndex + this
.preloadBuffer); i++) {
this.loadedPages[i] = true;
}
}
},
mounted() {
this.titleHeight = uni.getStorageSync('titleHeight')
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 9); i++) {
this.loadedPages[i] = true;
}
setTimeout(() => {
this.animationStates[this.currentIndex] = true;
}, 50);
},
methods: {
handleSwiperChange(e) {
const newIndex = e.detail.current;
this.currentIndex = newIndex;
this.animationStates[newIndex] = false;
setTimeout(() => {
this.animationStates[newIndex] = true;
}, 50);
},
shouldShowContent(index) {
return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
},
goBack() {
uni.navigateTo({
url: '/taozi/home/home?targetIndex=7'
});
}
}
};
</script>
<style lang="scss" scoped>
.main-swiper {
width: 100%;
height: 100vh;
}
.page-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
position: relative;
overflow: hidden;
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.layer-img1 {
z-index: 2;
position: absolute;
bottom: 300rpx;
right: 60rpx;
width: 300rpx;
height: 300rpx;
}
.layer-info {
width: 100%;
height: 280rpx;
z-index: 2;
position: absolute;
bottom: 0;
left: 0;
}
.layer-content {
position: absolute;
top: 36%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 2;
.item {
position: relative;
.item-gif {
width: 600rpx;
height: 650rpx;
}
.layer-item-txt {
position: absolute;
top: -50rpx;
left: 0;
font-size: 46rpx;
color: #e5007f;
font-weight: 600;
}
.layer-item-tx2 {
position: absolute;
right: 0;
top: -40rpx;
font-size: 36rpx;
writing-mode: vertical-rl;
text-orientation: mixed;
color: #e5007f;
font-weight: 600;
}
}
}
.layer2-content {
width: 100%;
height: 100%;
display: flex;
justify-content: flex-end;
flex-direction: column;
align-items: center;
z-index: 2;
.item {
display: flex;
flex-direction: column;
align-items: center;
width: calc(100% - 100rpx);
margin: 80rpx 0;
.bottom-img {
width: 100%;
height: 190rpx;
margin-top: 50rpx;
}
.bottom-tit {
width: 100%;
text-align: justify;
text-align-last: justify;
font-size: 100rpx;
display: inline-block;
}
.bottom-tit2 {
width: 100%;
color: #e40080;
text-align: justify;
text-align-last: justify;
display: inline-block;
}
}
}
.back-btn {
position: absolute;
top: 50rpx;
left: 50rpx;
z-index: 2;
background-color: rgb(0 0 0 / 0.3);
border-radius: 50%;
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
width: 50rpx;
height: 50rpx;
}
.rotate-bounce-in {
animation: rotateBounceIn 1.2s cubic-bezier(0.215, 0.610, 0.355, 1.000) forwards;
}
@keyframes rotateBounceIn {
0% {
opacity: 0;
transform: rotate(-180deg) scale(0.3);
}
40% {
opacity: 0.6;
transform: rotate(25deg) scale(0.9);
}
60% {
opacity: 0.8;
transform: rotate(-15deg) scale(1.1);
}
80% {
opacity: 0.9;
transform: rotate(5deg) scale(0.95);
}
100% {
opacity: 1;
transform: rotate(0deg) scale(1);
}
}
.slide-in-from-right {
animation: slideInRight 1.2s ease-out forwards;
}
@keyframes slideInRight {
0% {
opacity: 0;
transform: translateX(100px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.fade-slide-up {
animation: fadeSlideUp 1s ease-out forwards;
}
@keyframes fadeSlideUp {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
</style>

297
taozi/chapter4/chapter4.vue

@ -0,0 +1,297 @@
<template>
<view>
<TitleHeader />
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange"
:duration="300" :style="{ height: `calc(100vh - ${titleHeight}px)` }">
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg1.png"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(0)" class="content-layer">
<image class="layer-img"
:class="{'blur-to-clear': animationStates[0], 'hidden': !animationStates[0]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg1-infos.png" :lazy-load="true" mode="aspectFill">
</image>
<image class="btn-img" @click="gotoPath('/subPackages/techan/detail?id=32')"
:class="{'blur-to-clear': animationStates[0], 'hidden': !animationStates[0]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/btn1.png" :lazy-load="true" mode="widthFix">
</image>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg2.png"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(1)" class="content-layer">
<image class="layer-img"
:class="{'blur-to-clear': animationStates[1], 'hidden': !animationStates[1]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg2-infos.png" :lazy-load="true" mode="aspectFill">
</image>
<image class="btn-img" style="right: 30rpx;top: 75vh;" @click="gotoPath('/subPackages/techan/detail?id=32')"
:class="{'blur-to-clear': animationStates[1], 'hidden': !animationStates[1]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/btn2.png" :lazy-load="true" mode="widthFix">
</image>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[2]">
<image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg3.png"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(2)" class="content-layer">
<image class="layer-img"
:class="{'blur-to-clear': animationStates[2], 'hidden': !animationStates[2]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg3-infos.png" :lazy-load="true" mode="aspectFill">
</image>
<image class="btn-img" style="right: 40vw;top: 65vh;" @click="gotoPath('/subPackages/techan/detail?id=32')"
:class="{'blur-to-clear': animationStates[1], 'hidden': !animationStates[1]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/btn3.png" :lazy-load="true" mode="widthFix">
</image>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[3]">
<image v-show="shouldShowContent(3)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg4.png"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(3)" class="content-layer2">
<image class="layer-img2"
:class="{'slide-in-from-left': animationStates[3], 'hidden': !animationStates[3]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg4-info.png" :lazy-load="true" mode="aspectFill">
</image>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[4]">
<image v-show="shouldShowContent(4)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg5.png"
:lazy-load="true" mode="aspectFill"></image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[5]">
<image v-show="shouldShowContent(5)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg6.png"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(5)" class="content-layer3">
<image class="layer-img3"
:class="{'slide-in-from-left': animationStates[5], 'hidden': !animationStates[5]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/chapter4/bg6-info.png" :lazy-load="true" mode="aspectFill">
</image>
</view>
<view @click="goBack" class="back-btn" type="default">
<image class="back-icon" src="https://static.ticket.sz-trip.com/epicSoul/taozi/back.png" mode="aspectFill"></image>
</view>
</template>
</view>
</swiper-item>
</swiper>
</view>
</template>
<script>
import TitleHeader from '@/components/TitleHeader.vue';
export default {
components: {
TitleHeader
},
data() {
return {
currentIndex: 0,
loadedPages: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false
},
animationStates: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false
},
preloadBuffer: 1,
titleHeight: 0
};
},
watch: {
currentIndex(newIndex) {
for (let i = Math.max(0, newIndex - this.preloadBuffer); i <= Math.min(9, newIndex + this
.preloadBuffer); i++) {
this.loadedPages[i] = true;
}
}
},
mounted() {
this.titleHeight = uni.getStorageSync('titleHeight')
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 9); i++) {
this.loadedPages[i] = true;
}
setTimeout(() => {
this.animationStates[this.currentIndex] = true;
}, 50);
},
methods: {
handleSwiperChange(e) {
const newIndex = e.detail.current;
this.currentIndex = newIndex;
this.animationStates[newIndex] = false;
setTimeout(() => {
this.animationStates[newIndex] = true;
}, 50);
},
shouldShowContent(index) {
return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
},
goBack() {
uni.navigateTo({
url: '/taozi/home/home?targetIndex=7'
});
}
}
};
</script>
<style lang="scss" scoped>
.main-swiper {
width: 100%;
height: 100vh;
}
.page-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
position: relative;
overflow: hidden;
}
.content-layer {
width: 100%;
height: 100%;
position: relative;
z-index: 2;
}
.content-layer2 {
width: calc(100% - 100rpx);
height: 100%;
position: relative;
z-index: 2;
display: flex;
flex-direction: column;
justify-content: flex-end;
margin: 0 50rpx 400rpx;
}
.content-layer3 {
width: calc(100% - 100rpx);
height: 100%;
z-index: 2;
display: flex;
align-items: center;
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.layer-img {
width: 100%;
height: 100%;
}
.layer-img2 {
width: 100%;
height: 350rpx;
}
.layer-img3 {
width: 500rpx;
height: 300rpx;
}
.back-btn {
position: absolute;
top: 50rpx;
left: 50rpx;
z-index: 2;
background-color: rgb(0 0 0 / 0.3);
border-radius: 50%;
width: 80rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
.back-icon {
width: 50rpx;
height: 50rpx;
}
.blur-to-clear {
animation: blurToClear .8s ease-out forwards;
}
@keyframes blurToClear {
0% {
filter: blur(10px);
opacity: 0.3;
}
100% {
filter: blur(0);
opacity: 1;
}
}
.hidden {
opacity: 0;
}
.slide-in-from-left {
animation: slideInLeft 1.2s ease-out forwards;
}
@keyframes slideInLeft {
0% {
opacity: 0;
transform: translateX(-100px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.btn-img {
position: fixed;
top: 14vh;
right: 30rpx;
width: 20vw;
}
</style>

786
taozi/home/home.vue

@ -0,0 +1,786 @@
<template>
<view>
<TitleHeader />
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange"
:duration="300" :style="{ height: `calc(100vh - ${titleHeight}px)` }">
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/foreword-bg1.gif"
:lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(0)" class="content-layer">
<image class="layer-img"
:class="{'blur-to-clear': animationStates[0], 'hidden': !animationStates[0]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/foreword-bg1-text.png"
:lazy-load="true" mode="aspectFill">
</image>
<view class="arrow-content">
<image class="arrow-down"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/arrow-icon.png"
:lazy-load="true" mode="aspectFill"></image>
</view>
</view>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/prologue1s.png" :lazy-load="true"
mode="aspectFill"></image>
<!-- <view v-show="shouldShowContent(1)" class="content-layer2">
<image class="layer-icon"
:class="{'bounce-in': animationStates[1], 'hidden': !animationStates[1]}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/prologue1-icon.png"
:lazy-load="true" mode="aspectFill">
</image>
</view> -->
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[2]">
<image v-show="shouldShowContent(2)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/foreword-bg2.gif"
:lazy-load="true" mode="aspectFill"></image>
</template>
</view>
</swiper-item>
<swiper-item>
<template v-if="loadedPages[3]">
<view class="loadedPages-three">
<view class="loadedPages-three-content">
<view class="loadedPages-three-title">
<view class="txt">
DAYUN
</view>
<view class="txt">
<text>IP Art</text>
<text>Exhibition</text>
</view>
<view class="txt">
issue/01
</view>
</view>
<view class="loadedPages-three-center">
<view class="desc">
<text>时间里</text>
<text></text>
<text>约定</text>
</view>
<view class="en-desc">
<text>Agreements</text>
<text>Within</text>
<text>Time</text>
</view>
</view>
<view class="loadedPages-three-bottom"
:class="{'fade-slide-up': animationStates[3], 'hidden': !animationStates[3]}">
<image class="bottom-img"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/forewordThree_icon.png"
mode="aspectFill"></image>
<view class="bottom-tit">
三个桃子IP美数展
</view>
<view class="bottom-txt">
Three Peaches IP Art Exhibition
</view>
</view>
</view>
</view>
</template>
</swiper-item>
<swiper-item v-for="index in [4, 5, 6, 7]" :key="index">
<view class="page-container">
<template v-if="loadedPages[index]">
<image v-show="shouldShowContent(index)" class="bg-image"
:src="`https://static.ticket.sz-trip.com/epicSoul/taozi/home/chapterCover${index-3}.png`"
:lazy-load="true" mode="aspectFill"></image>
<image @click="goChapter" class="chapterCover-btn" v-show="shouldShowContent(index)"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/toggle.png" :lazy-load="true"
mode="aspectFill"></image>
</template>
</view>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[8]">
<image v-show="shouldShowContent(8)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/footer.png" :lazy-load="true"
mode="aspectFill"></image>
<!-- <image class="qrcode-txt" v-show="shouldShowContent(8)"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/qrcode-txt.png" :lazy-load="true"
mode="aspectFill" :show-menu-by-longpress="true"></image> -->
<image class="qrcode-txt" v-show="shouldShowContent(8)" @click="gotoPath('/subPackages/techan/detail?id=32')"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/qrcode-btn.png" :lazy-load="true"
mode="widthFix" :show-menu-by-longpress="true"></image>
<!-- <image class="qrcode-txts" v-show="shouldShowContent(8)"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/home/qrcode-txtss.png" :lazy-load="true"
mode="widthFix"></image> -->
</template>
</view>
</swiper-item>
<swiper-item>
<template v-if="loadedPages[9]">
<image v-show="shouldShowContent(9)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/footers.png" :lazy-load="true" mode="aspectFill"></image>
<image v-show="shouldShowContent(9)" class="qrCode-image" src="https://static.ticket.sz-trip.com/epicSoul/qrCode.png"
:lazy-load="true" mode="widthFix" :show-menu-by-longpress="true"></image>
</template>
</swiper-item>
<swiper-item>
<view class="page-container">
<template v-if="loadedPages[10]">
<messageBoard class="message-board" />
</template>
</view>
</swiper-item>
</swiper>
<view class="overlay" v-if="showMenu" @click="closeMenu"></view>
<view class="fixed-nav" :class="{'hidden': showMenu}" @click="showNavMenu">
<image class="nav-icon" :class="{'rotated': iconRotated, 'bounce-back': iconBounceBack}"
src="https://static.ticket.sz-trip.com/epicSoul/taozi/nav-icon.png" mode="aspectFill"></image>
</view>
<view class="nav-menu" :class="{'show': showMenu}">
<view class="nav-item" :class="{'item-active': isItemActive(item)}" v-for="item in menuItems"
:key="item.targetIndex" @click="() => jumpToPage(item.targetIndex)">
<view v-if="item.text.includes('#Chapter')" class="chapter-text">
<text class="chapter-title">#Chapter</text>
<text :class="{'active': isItemActive(item)}" class="chapter-number">
{{ item.text.replace('#Chapter', '') }}
</text>
</view>
<text v-else :class="{'active': isItemActive(item)}">{{ item.text }}</text>
</view>
</view>
<!-- <BuyPeaches /> -->
<messagePop />
<!-- <BackgroundMusic /> -->
<MusicControl />
</view>
</template>
<script>
import BuyPeaches from '@/components/BuyPeaches.vue';
import messagePop from '@/components/messagePop.vue';
// import BackgroundMusic from '@/components/BackgroundMusic.vue';
import messageBoard from '@/components/messageBoard.vue';
import MusicControl from '@/components/MusicControl.vue';
import TitleHeader from '@/components/TitleHeader.vue';
export default {
components: {
BuyPeaches,
messagePop,
// BackgroundMusic,
messageBoard,
MusicControl,
TitleHeader
},
data() {
return {
currentIndex: 0,
loadedPages: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false,
6: false,
7: false,
8: false,
9: false,
10: false
},
animationStates: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false,
6: false,
7: false,
8: false,
9: false
},
preloadBuffer: 1,
isFirstSwipe: true,
showMenu: false,
iconRotated: false,
iconBounceBack: false,
menuItems: [{
text: 'Intro序曲',
targetIndex: 0
},
{
text: '#Chapter 壹',
targetIndex: 4
},
{
text: '#Chapter 贰',
targetIndex: 5
},
{
text: '#Chapter 叁',
targetIndex: 6
},
{
text: '#Chapter 肆',
targetIndex: 7
},
{
text: 'GuestBook',
targetIndex: 10
}
],
chapterPaths: {
4: '/taozi/chapter1/chapter1',
5: '/taozi/chapter2/chapter2',
6: '/taozi/chapter3/chapter3',
7: '/taozi/chapter4/chapter4'
},
titleHeight: 0
};
},
computed: {
shouldShowContent() {
return (index) => {
return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
};
}
},
watch: {
currentIndex(newIndex) {
for (let i = Math.max(0, newIndex - this.preloadBuffer); i <= Math.min(10, newIndex + this
.preloadBuffer); i++) {
this.loadedPages[i] = true;
}
}
},
methods: {
handleSwiperChange(e) {
const newIndex = e.detail.current;
this.currentIndex = newIndex;
this.animationStates[newIndex] = false;
setTimeout(() => {
this.animationStates[newIndex] = true;
}, 50);
return;
if (this.isFirstSwipe && newIndex > 0) {
this.isFirstSwipe = false;
uni.$emit('playBackgroundMusic');
}
},
goChapter() {
const path = this.chapterPaths[this.currentIndex];
uni.navigateTo({
url: path
});
},
showNavMenu() {
this.iconRotated = true;
setTimeout(() => {
this.showMenu = true;
}, 300);
},
closeMenu() {
this.showMenu = false;
setTimeout(() => {
this.iconBounceBack = true;
this.iconRotated = false;
setTimeout(() => {
this.iconBounceBack = false;
}, 500);
}, 300);
},
jumpToPage(idx) {
const targetIndex = idx;
this.currentIndex = targetIndex;
this.closeMenu();
this.animationStates[targetIndex] = false;
setTimeout(() => {
this.animationStates[targetIndex] = true;
}, 50);
},
isItemActive(item) {
return this.currentIndex === item.targetIndex;
}
},
mounted() {
this.titleHeight = uni.getStorageSync('titleHeight')
console.log(this.titleHeight)
const app = getApp();
app.updateMusicSrc('https://static.ticket.sz-trip.com/epicSoul/taozi/bg.m4a');
app.initBackgroundMusic(); //
uni.$bgMusic.play(); //
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 6); i++) {
this.loadedPages[i] = true;
}
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 10); i++) {
this.loadedPages[i] = true;
}
setTimeout(() => {
this.animationStates[this.currentIndex] = true;
}, 50);
},
onUnload() {
uni.$bgMusic.pause(); //
},
onLoad(options) {
if (options && options.targetIndex) {
const targetIndex = parseInt(options.targetIndex);
this.currentIndex = targetIndex;
for (let i = Math.max(0, targetIndex - this.preloadBuffer); i <= Math.min(10, targetIndex + this
.preloadBuffer); i++) {
this.loadedPages[i] = true;
}
this.animationStates[targetIndex] = false;
setTimeout(() => {
this.animationStates[targetIndex] = true;
}, 50);
}
},
// #ifdef MP-WEIXIN
onShareAppMessage() {
return {
title: '三个桃子·时间里的约定|「Epic Soul」阅读体 issue01',
mpId: 'wx8954209bb3ad489e',
path: '/taozi/home/home',
imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/taozi/home/taoziShare.png'
};
},
onShareTimeline() {
return {
title: '三个桃子·时间里的约定|「Epic Soul」阅读体 issue01',
query: '',
imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/taozi/home/taoziShare.png'
};
}
// #endif
};
</script>
<style lang="scss" scoped>
@font-face {
font-family: 'SourceHanSerif-Regular';
src: url(/static/fonts/SourceHanSerifSC-Regular.otf);
}
.main-swiper {
width: 100%;
height: 100vh;
}
.page-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
position: relative;
overflow: hidden;
}
.loadedPages-three {
height: 100%;
position: relative;
background: #fff;
}
.loadedPages-three-content {
display: flex;
align-items: center;
flex-direction: column;
justify-content: space-between;
height: 100%;
.loadedPages-three-title {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
margin-top: 30rpx;
.txt {
font-size: 24rpx;
color: #333;
font-family: SourceHanSerif-Regular;
display: flex;
flex-direction: column;
align-items: center;
text {
display: block;
}
}
.txt:first-child {
margin-left: 30rpx;
}
.txt:last-child {
margin-right: 30rpx;
}
}
.loadedPages-three-center {
position: relative;
.desc {
display: flex;
flex-direction: column;
font-family: SourceHanSerif-Regular;
font-size: 90rpx;
color: #ec4899;
text {
display: block;
}
}
.en-desc {
display: flex;
flex-direction: column;
position: absolute;
top: 50%;
right: 0;
transform: translate(-25%, -50%);
font-size: 24rpx;
font-style: italic;
color: #4b5563;
text {
display: block;
}
}
}
.loadedPages-three-bottom {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 30rpx;
.bottom-img {
width: 400rpx;
height: 120rpx;
}
.bottom-tit {
font-size: 38rpx;
}
.bottom-txt {
font-size: 24rpx;
font-style: italic;
color: #4b5563;
}
}
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.content-layer {
position: relative;
z-index: 2;
width: 100%;
height: 100%;
display: flex;
align-items: center;
flex-direction: column;
}
.content-layer2 {
z-index: 2;
position: absolute;
bottom: 5%;
right: 5%;
}
.layer-img {
width: 100%;
height: 100%;
}
.arrow-content {
width: 100%;
position: absolute;
bottom: 5%;
left: 50%;
transform: translate(-50%, 0);
display: flex;
align-items: center;
justify-content: center;
}
.arrow-down {
width: 100rpx;
height: 40rpx;
animation: bounce 1.5s infinite;
}
.layer-icon {
width: 100rpx;
height: 100rpx;
animation: bounce 1.5s infinite;
}
.overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
z-index: 10;
}
.fixed-nav {
width: 80rpx;
height: 80rpx;
background-color: rgb(0 0 0 / 0.7);
border-radius: 10rpx 0 0 10rpx;
position: fixed;
right: 0;
top: 0;
bottom: 0;
margin: auto 0;
display: flex;
align-items: center;
justify-content: center;
z-index: 9;
transition: transform 0.3s ease, opacity 0.3s ease;
}
.fixed-nav.hidden {
transform: translateX(100%);
opacity: 0;
pointer-events: none;
}
.nav-icon {
width: 35rpx;
height: 35rpx;
transition: transform 0.3s ease;
}
.nav-icon.rotated {
transform: rotate(180deg);
}
.nav-icon.bounce-back {
animation: bounceRotation 0.5s ease;
}
@keyframes bounceRotation {
0% {
transform: rotate(180deg);
}
50% {
transform: rotate(-20deg);
}
75% {
transform: rotate(10deg);
}
100% {
transform: rotate(0deg);
}
}
.nav-menu {
position: fixed;
top: 50%;
right: 0;
transform: translate(100%, -50%);
z-index: 11;
background-color: rgb(0 0 0 / 0.5);
border-radius: 16rpx 0 0 16rpx;
box-shadow: -4px 0 15px rgba(0, 0, 0, 0.1);
transition: transform 0.3s ease;
}
.nav-menu.show {
transform: translate(0, -50%);
}
.nav-item {
padding: 20rpx;
text-align: center;
text {
color: #fff;
opacity: 0.7;
font-size: 28rpx;
}
}
.item-active {
background-color: rgba(0, 0, 0, 0.718);
}
.nav-item .active {
color: #fff;
opacity: 1;
}
.chapter-text {
display: flex;
flex-direction: column;
align-items: center;
line-height: 1.3;
}
.chapter-title {
color: #fff;
opacity: 0.7;
font-size: 24rpx;
}
.chapter-number {
color: #fff;
opacity: 0.7;
font-size: 28rpx;
margin-top: 8rpx;
}
.item-active .chapter-title,
.item-active .chapter-number.active {
opacity: 1;
}
@keyframes bounce {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-20rpx);
}
60% {
transform: translateY(-10rpx);
}
}
.blur-to-clear {
animation: blurToClear 1.5s ease-out forwards;
}
@keyframes blurToClear {
0% {
filter: blur(10px);
opacity: 0.3;
}
100% {
filter: blur(0);
opacity: 1;
}
}
.hidden {
opacity: 0;
}
.bounce-in {
animation: bounceIn 1s ease forwards;
}
@keyframes bounceIn {
0% {
opacity: 0;
transform: scale(0.3) translateY(100px);
}
50% {
opacity: 1;
transform: scale(1.05) translateY(-10px);
}
70% {
transform: scale(0.9) translateY(5px);
}
100% {
opacity: 1;
transform: scale(1) translateY(0);
}
}
.fade-slide-up {
animation: fadeSlideUp 1s ease-out forwards;
}
@keyframes fadeSlideUp {
0% {
opacity: 0;
transform: translateY(30px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.chapterCover-btn {
position: absolute;
left: 50%;
bottom: 10%;
transform: translate(-50%, -50%);
width: 300rpx;
height: 100rpx;
z-index: 2;
}
.qrcode-txt {
width: 30vw;
z-index: 2;
position: fixed;
left: 0;
right: 0;
margin: 100rpx auto 0;
}
.qrcode-txts {
width: 28vw;
z-index: 2;
position: fixed;
left: 0;
right: 0;
margin: 335rpx auto 0;
}
.message-board {
width: 100%;
}
.qrCode-image {
position: absolute;
left: 0;
right: 0;
bottom: 192rpx;
margin: 0 auto;
z-index: 2;
width: 30vw;
}
</style>

108
utils/audioManager.js

@ -0,0 +1,108 @@
let instance = null;
class AudioManager {
constructor() {
if (instance) {
return instance;
}
this.audioContext = null;
this.isPlaying = false;
this.userDisabled = false;
this.initialized = false;
try {
const musicState = uni.getStorageSync('musicState') || {};
this.userDisabled = musicState.userDisabled === true;
} catch (e) {
console.error('读取音乐状态失败:', e);
}
instance = this;
}
init() {
if (this.initialized) return this;
this.audioContext = uni.createInnerAudioContext();
this.audioContext.src = 'https://static.ticket.sz-trip.com/epicSoul/taozi/bg.m4a';
this.audioContext.loop = true;
this.audioContext.onPlay(() => {
this.isPlaying = true;
this._notifyStateChange();
});
this.audioContext.onPause(() => {
this.isPlaying = false;
this._notifyStateChange();
});
this.audioContext.onStop(() => {
this.isPlaying = false;
this._notifyStateChange();
});
this.audioContext.onError((res) => {
this.isPlaying = false;
this._notifyStateChange();
});
this.initialized = true;
return this;
}
play() {
if (this.userDisabled) return;
this.init();
if (!this.isPlaying) {
this.audioContext.play();
}
}
pause() {
if (!this.initialized || !this.isPlaying) return;
this.audioContext.pause();
}
togglePlay() {
this.init();
if (this.isPlaying) {
this.pause();
this.userDisabled = true;
} else {
this.userDisabled = false;
this.play();
}
try {
uni.setStorageSync('musicState', {
userDisabled: this.userDisabled
});
} catch (e) {
console.error('保存音乐状态失败:', e);
}
return this.isPlaying;
}
_notifyStateChange() {
uni.$emit('audioStateChanged', {
isPlaying: this.isPlaying,
userDisabled: this.userDisabled
});
}
getPlayingStatus() {
return this.isPlaying;
}
getUserDisabled() {
return this.userDisabled;
}
}
export default new AudioManager();

163
utils/request.js

@ -9,54 +9,61 @@
* @param {Object} options.header - 请求头 * @param {Object} options.header - 请求头
* @returns {Promise} - 返回Promise对象 * @returns {Promise} - 返回Promise对象
*/ */
const DOMAIN = 'https://m.dayunyuanjian.com';
export const request = (options = {}) => { export const request = (options = {}) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
// 默认配置 options.url = options.url.startsWith('/') ? `${DOMAIN}${options.url}` : options.url;
const defaultOptions = { // 默认配置
url: '', const defaultOptions = {
method: 'GET', url: '',
data: {}, method: 'GET',
header: { data: {},
'content-type': 'application/json' header: {
}, 'content-type': 'application/json'
timeout: 10000 // 10秒超时 },
}; timeout: 10000 // 10秒超时
};
// 合并配置
const mergedOptions = {...defaultOptions, ...options}; // 合并配置
const mergedOptions = {
// 处理URL ...defaultOptions,
if (!mergedOptions.url) { ...options
reject(new Error('URL不能为空')); };
return;
} // 处理URL
if (!mergedOptions.url) {
// 调用uni.request reject(new Error('URL不能为空'));
uni.request({ return;
url: mergedOptions.url, }
method: mergedOptions.method,
data: mergedOptions.data, // 调用uni.request
header: mergedOptions.header, uni.request({
timeout: mergedOptions.timeout, url: mergedOptions.url,
success: (res) => { method: mergedOptions.method,
// 请求成功 data: mergedOptions.data,
if (res.statusCode >= 200 && res.statusCode < 300) { header: mergedOptions.header,
resolve(res.data); timeout: mergedOptions.timeout,
} else { success: (res) => {
// 服务器返回错误 // 请求成功
reject({ if (res.statusCode >= 200 && res.statusCode < 300) {
statusCode: res.statusCode, resolve(res.data);
errMsg: `请求失败,状态码: ${res.statusCode}`, } else {
data: res.data // 服务器返回错误
}); reject({
} statusCode: res.statusCode,
}, errMsg: `请求失败,状态码: ${res.statusCode}`,
fail: (err) => { data: res.data
// 请求失败 });
reject(err); }
} },
}); fail: (err) => {
}); // 请求失败
reject(err);
}
});
});
}; };
/** /**
@ -66,12 +73,12 @@ export const request = (options = {}) => {
* @param {Object} options - 其他选项 * @param {Object} options - 其他选项
*/ */
export const get = (url, data = {}, options = {}) => { export const get = (url, data = {}, options = {}) => {
return request({ return request({
url, url,
method: 'GET', method: 'GET',
data, data,
...options ...options
}); });
}; };
/** /**
@ -81,12 +88,12 @@ export const get = (url, data = {}, options = {}) => {
* @param {Object} options - 其他选项 * @param {Object} options - 其他选项
*/ */
export const post = (url, data = {}, options = {}) => { export const post = (url, data = {}, options = {}) => {
return request({ return request({
url, url,
method: 'POST', method: 'POST',
data, data,
...options ...options
}); });
}; };
/** /**
@ -97,22 +104,22 @@ export const post = (url, data = {}, options = {}) => {
* @param {Object} formData - 附加的表单数据 * @param {Object} formData - 附加的表单数据
*/ */
export const uploadFile = (url, filePath, name = 'file', formData = {}) => { export const uploadFile = (url, filePath, name = 'file', formData = {}) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
uni.uploadFile({ uni.uploadFile({
url, url,
filePath, filePath,
name, name,
formData, formData,
success: (res) => { success: (res) => {
try { try {
// 尝试解析JSON // 尝试解析JSON
const data = JSON.parse(res.data); const data = JSON.parse(res.data);
resolve(data); resolve(data);
} catch (e) { } catch (e) {
resolve(res.data); resolve(res.data);
} }
}, },
fail: reject fail: reject
}); });
}); });
}; };

164
xxdf/chapter1/cover1.vue

@ -1,75 +1,76 @@
<template> <template>
<view> <view>
<view class="chapter-cover"> <view class="chapter-cover">
<image class="cover-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/cover2.png" mode=""></image> <image class="cover-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/cover2.png" mode=""></image>
<view class="five-senses-content" @click="goFeel">
<view class="box1"></view> <!-- 使用循环渲染五个感官按钮 -->
<view class="senses-txt"> <view
触觉 v-for="(sense, index) in senses"
:key="sense.id"
class="five-senses-content"
:class="sense.className"
@click="goToSense(index)"
>
<image
src="https://static.ticket.sz-trip.com/epicSoul/circle.png"
mode=""
:class="{'bubble-active': loadingStates[index]}"
></image>
<view class="senses-txt">
{{ sense.text }}
</view>
</view> </view>
<image @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/abandon-btn.png" mode=""></image>
</view> </view>
<view class="five-senses-content vision" @click="goVision"> <MusicControl />
<view class="box1"></view>
<view class="senses-txt">
视觉
</view>
</view>
<view class="five-senses-content hearing" @click="goHearing">
<view class="box1"></view>
<view class="senses-txt">
听觉
</view>
</view>
<view class="five-senses-content olfactory" @click="goOlfactory">
<view class="box1"></view>
<view class="senses-txt">
嗅觉
</view>
</view>
<view class="five-senses-content gustation" @click="goGustation">
<view class="box1"></view>
<view class="senses-txt">
味觉
</view>
</view>
<image @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/abandon-btn.png" mode=""></image>
</view> </view>
<MusicControl />
</view>
</template> </template>
<script> <script>
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {
MusicControl
},
data() {
return {
//
senses: [
{ id: 'feel', text: '触觉', className: '', path: '/xxdf/chapter1/detail1' },
{ id: 'vision', text: '视觉', className: 'vision', path: '/xxdf/chapter1/detail2' },
{ id: 'hearing', text: '听觉', className: 'hearing', path: '/xxdf/chapter1/detail3' },
{ id: 'olfactory', text: '嗅觉', className: 'olfactory', path: '/xxdf/chapter1/detail4' },
{ id: 'gustation', text: '味觉', className: 'gustation', path: '/xxdf/chapter1/detail5' }
],
// 使
loadingStates: Array(5).fill(false)
}
},
methods: { methods: {
goback() { goback() {
uni.navigateBack({ const app = getApp();
delta: 1 app.globalData.mainSliderIndex = 2;
}); uni.redirectTo({
}, url: '/xxdf/home/home'
goFeel() {
uni.navigateTo({
url: '/xxdf/chapter1/detail1'
});
},
goVision() {
uni.navigateTo({
url: '/xxdf/chapter1/detail2'
});
},
goHearing() {
uni.navigateTo({
url: '/xxdf/chapter1/detail3'
});
},
goOlfactory() {
uni.navigateTo({
url: '/xxdf/chapter1/detail4'
}); });
}, },
goGustation() { //
uni.navigateTo({ goToSense(index) {
url: '/xxdf/chapter1/detail5' //
}); this.loadingStates[index] = true;
this.$forceUpdate()
setTimeout(() => {
//
this.loadingStates[index] = false;
this.$forceUpdate()
//
uni.navigateTo({
url: this.senses[index].path
});
}, 1000);
} }
} }
}; };
@ -93,40 +94,41 @@ export default {
.five-senses-content { .five-senses-content {
position: absolute; position: absolute;
top: 32%;
right: 28%;
z-index: 2; z-index: 2;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
} }
.five-senses-content image {
width: 40rpx;
height: 40rpx;
transition: transform 1s;
}
/* 气泡效果 */
.bubble-active {
transform: scale(1.5);
}
/* 定位样式 */
.five-senses-content {
top: 32%;
right: 28%;
}
.vision { .vision {
top: 54% !important; top: 54%;
right: 47% !important; right: 47%;
} }
.hearing { .hearing {
top: 62% !important; top: 62%;
right: 8% !important; right: 8%;
} }
.olfactory { .olfactory {
top: 64% !important; top: 64%;
right: 76% !important; right: 76%;
} }
.gustation { .gustation {
top: 73% !important; top: 73%;
right: 86% !important; right: 86%;
}
.box1 {
background: #fff;
border-radius: 50%;
opacity: 0.4;
width: 40rpx;
height: 40rpx;
} }
.senses-txt { .senses-txt {

10
xxdf/chapter1/detail1.vue

@ -4,10 +4,10 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[0]"> <template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/feel.png" mode="" <image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/feel.png" mode=""
:lazy-load="true"></image> :lazy-load="true"></image>
<view v-show="shouldShowContent(0)" class="arrow-content"> <view v-show="shouldShowContent(0)" class="arrow-content">
<image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icon-black.png" mode="" :lazy-load="true"></image> <image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/botIcon.png" mode="" :lazy-load="true"></image>
</view> </view>
</template> </template>
</view> </view>
@ -16,10 +16,10 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[1]"> <template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/feel2.png" <image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/feel2.png"
mode="" :lazy-load="true"></image> mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]"> <view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]">
<image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/feel2-img.png" mode="" :lazy-load="true"> <image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/feel2-img.png" mode="" :lazy-load="true">
</image> </image>
</view> </view>
<image v-show="shouldShowContent(1)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/reselect-btn.png" <image v-show="shouldShowContent(1)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/reselect-btn.png"
@ -33,7 +33,7 @@
</template> </template>
<script> <script>
import MusicControl from '@/components/MusicControl.vue'; import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {MusicControl}, components: {MusicControl},
data() { data() {

12
xxdf/chapter1/detail2.vue

@ -4,10 +4,10 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[0]"> <template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/vision.png" <image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/vision.png"
mode="" :lazy-load="true"></image> mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(0)" class="arrow-content"> <view v-show="shouldShowContent(0)" class="arrow-content">
<image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icon-black.png" mode="" :lazy-load="true"></image> <image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/botIcon.png" mode="" :lazy-load="true"></image>
</view> </view>
</template> </template>
</view> </view>
@ -16,10 +16,10 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[1]"> <template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/vision2.png" <image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/vision2.png"
mode="" :lazy-load="true"></image> mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]"> <view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]">
<image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/vision2-img.png" mode="" <image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/vision2-img.png" mode=""
:lazy-load="true"></image> :lazy-load="true"></image>
</view> </view>
<image v-show="shouldShowContent(1)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/reselect-btn.png" <image v-show="shouldShowContent(1)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/reselect-btn.png"
@ -33,7 +33,11 @@
</template> </template>
<script> <script>
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {
MusicControl
},
data() { data() {
return { return {
isVisible: false, isVisible: false,

12
xxdf/chapter1/detail3.vue

@ -6,9 +6,9 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[0]"> <template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/hearing.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/hearing.png" mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(0)" class="arrow-content"> <view v-show="shouldShowContent(0)" class="arrow-content">
<image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icon-black.png" mode="" :lazy-load="true"></image> <image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/botIcon.png" mode="" :lazy-load="true"></image>
</view> </view>
</template> </template>
</view> </view>
@ -17,9 +17,9 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[1]"> <template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/hearing2.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/hearing2.png" mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]"> <view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]">
<image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/hearing2-img.png" mode="" :lazy-load="true"></image> <image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/hearing2-img.png" mode="" :lazy-load="true"></image>
</view> </view>
<image v-show="shouldShowContent(1)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/reselect-btn.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(1)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/reselect-btn.png" mode="" :lazy-load="true"></image>
</template> </template>
@ -31,7 +31,11 @@
</template> </template>
<script> <script>
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {
MusicControl
},
data() { data() {
return { return {
isVisible: false, isVisible: false,

26
xxdf/chapter1/detail4.vue

@ -6,9 +6,9 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[0]"> <template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/olfactory.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/olfactorys.png" mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(0)" class="arrow-content"> <view v-show="shouldShowContent(0)" class="arrow-content">
<image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icon-black.png" mode="" :lazy-load="true"></image> <image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/botIcon.png" mode="" :lazy-load="true"></image>
</view> </view>
</template> </template>
</view> </view>
@ -17,9 +17,9 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[1]"> <template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/olfactory2.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/olfactory2.png" mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]"> <view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]">
<image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/olfactory2-img.png" mode="" :lazy-load="true"></image> <image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/olfactory2-img.png" mode="" :lazy-load="true"></image>
</view> </view>
</template> </template>
</view> </view>
@ -28,9 +28,9 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[2]"> <template v-if="loadedPages[2]">
<image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/olfactory4.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/olfactory4.png" mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(2)" :class="['animate-content2', {'animate-visible': isVisible2}]"> <view v-show="shouldShowContent(2)" :class="['animate-content2', {'animate-visible': isVisible2}]">
<image class="feel4-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/olfactory4-img.png" mode="" :lazy-load="true"></image> <image class="feel4-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/olfactory4-img.png" mode="" :lazy-load="true"></image>
</view> </view>
</template> </template>
</view> </view>
@ -39,8 +39,8 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[3]"> <template v-if="loadedPages[3]">
<image v-show="shouldShowContent(3)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/olfactory3.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(3)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/olfactory3.png" mode="" :lazy-load="true"></image>
<image v-show="shouldShowContent(3)" class="feel3-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/olfactory3-img.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(3)" class="feel3-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/olfactory3-img.png" mode="" :lazy-load="true"></image>
<image v-show="shouldShowContent(3)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/seek-btn.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(3)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/seek-btn.png" mode="" :lazy-load="true"></image>
</template> </template>
</view> </view>
@ -51,7 +51,11 @@
</template> </template>
<script> <script>
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {
MusicControl
},
data() { data() {
return { return {
isVisible: false, isVisible: false,
@ -74,10 +78,10 @@ export default {
this.currentIndex = e.detail.current; this.currentIndex = e.detail.current;
}, },
goback() { goback() {
const app = getApp(); // const app = getApp();
app.globalData.mainSliderIndex = 3; // app.globalData.mainSliderIndex = 3;
uni.navigateTo({ uni.navigateTo({
url: '/xxdf/home/home' url: '/xxdf/chapter1/cover1'
}); });
} }
}, },

12
xxdf/chapter1/detail5.vue

@ -6,9 +6,9 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[0]"> <template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/gustation.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/gustation.png" mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(0)" class="arrow-content"> <view v-show="shouldShowContent(0)" class="arrow-content">
<image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icon-black.png" mode="" :lazy-load="true"></image> <image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/botIcon.png" mode="" :lazy-load="true"></image>
</view> </view>
</template> </template>
</view> </view>
@ -17,9 +17,9 @@
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[1]"> <template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/gustation2.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/gustation2.png" mode="" :lazy-load="true"></image>
<view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]"> <view v-show="shouldShowContent(1)" :class="['animate-content', {'animate-visible': isVisible}]">
<image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/gustation2-img.png" mode="" :lazy-load="true"></image> <image class="feel2-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/gustation2-img.png" mode="" :lazy-load="true"></image>
</view> </view>
<image v-show="shouldShowContent(1)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/reselect-btn.png" mode="" :lazy-load="true"></image> <image v-show="shouldShowContent(1)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/reselect-btn.png" mode="" :lazy-load="true"></image>
</template> </template>
@ -31,7 +31,11 @@
</template> </template>
<script> <script>
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: {
MusicControl
},
data() { data() {
return { return {
isVisible: false, isVisible: false,

460
xxdf/chapter2/cover.vue

@ -1,202 +1,276 @@
<template> <template>
<view> <view>
<swiper class="main-swiper" :current="currentIndex" @change="handleSwiperChange" :duration="300"> <swiper class="main-swiper" :current="currentIndex" @change="handleSwiperChange" :duration="300">
<!-- 主swiper的第一个item --> <!-- 主swiper的第一个item -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[0]"> <view class="arrow-down">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/cover2.png" mode="" :lazy-load="true"></image> <image src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/rightIcon.png"
</template> :lazy-load="true" mode="widthFix">
</view> </image>
</swiper-item> </view>
<template v-if="loadedPages[0]">
<!-- 主swiper的第二个item --> <image v-show="shouldShowContent(0)" class="bg-image"
<swiper-item> src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/cover2s.png" mode=""
<view class="page-container home-page"> :lazy-load="true"></image>
<template v-if="loadedPages[1]"> </template>
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/cover3.png" mode="" :lazy-load="true"></image> </view>
</template> </swiper-item>
</view>
</swiper-item> <!-- 主swiper的第二个item -->
<swiper-item>
<!-- 主swiper的第三个item --> <view class="page-container home-page">
<swiper-item> <view class="arrow-down">
<view class="page-container home-page"> <image src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/rightIcon.png"
<template v-if="loadedPages[2]"> :lazy-load="true" mode="widthFix">
<image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/cover4.png" mode="" :lazy-load="true"></image> </image>
</template> </view>
</view> <template v-if="loadedPages[1]">
</swiper-item> <image v-show="shouldShowContent(1)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/cover3s.png" mode=""
<!-- 主swiper的第四个item包含嵌套swiper --> :lazy-load="true"></image>
<swiper-item> </template>
<!-- 当主swiper的第四个item被加载时才加载嵌套swiper --> </view>
<template v-if="loadedPages[3]"> </swiper-item>
<swiper v-show="shouldShowContent(3)" class="nested-swiper" :vertical="true" :duration="300" @change="handleVerticalChange" :current="verticalIndex">
<!-- 嵌套swiper的第一个item --> <!-- 主swiper的第三个item -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedNestedPages[0]"> <view class="arrow-down">
<image v-show="shouldShowNestedContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/cover5.png" mode="" :lazy-load="true"></image> <image src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/rightIcon.png"
</template> :lazy-load="true" mode="widthFix">
</view> </image>
</swiper-item> </view>
<template v-if="loadedPages[2]">
<!-- 嵌套swiper的第二个item --> <image v-show="shouldShowContent(2)" class="bg-image"
<swiper-item> src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/cover4s.png" mode=""
<view class="page-container home-page"> :lazy-load="true"></image>
<template v-if="loadedNestedPages[1]"> </template>
<image v-show="shouldShowNestedContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/cover6.png" mode="" :lazy-load="true"></image> </view>
</template> </swiper-item>
</view>
</swiper-item> <!-- 主swiper的第四个item包含嵌套swiper -->
<swiper-item>
<!-- 嵌套swiper的第三个item --> <!-- 当主swiper的第四个item被加载时才加载嵌套swiper -->
<swiper-item> <template v-if="loadedPages[3]">
<view class="page-container home-page"> <swiper v-show="shouldShowContent(3)" class="nested-swiper" :vertical="true" :duration="300"
<template v-if="loadedNestedPages[2]"> @change="handleVerticalChange" :current="verticalIndex">
<image v-show="shouldShowNestedContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/cover7.png" mode="" :lazy-load="true"></image> <!-- 嵌套swiper的第一个item -->
<image v-show="shouldShowNestedContent(2)" @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/seek-btn.png" mode="" :lazy-load="true"></image> <swiper-item>
</template> <view class="page-container home-page">
</view> <template v-if="loadedNestedPages[0]">
</swiper-item> <image v-show="shouldShowNestedContent(0)" class="bg-image"
</swiper> src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/cover5s.png"
</template> mode="" :lazy-load="true"></image>
</swiper-item> </template>
</swiper> </view>
<MusicControl /> </swiper-item>
</view>
<!-- 嵌套swiper的第二个item -->
<swiper-item>
<view class="page-container home-page">
<template v-if="loadedNestedPages[1]">
<image v-show="shouldShowNestedContent(1)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/cover6s.png"
mode="" :lazy-load="true"></image>
</template>
</view>
</swiper-item>
<!-- 嵌套swiper的第三个item -->
<swiper-item>
<view class="page-container home-page">
<template v-if="loadedNestedPages[2]">
<image v-show="shouldShowNestedContent(2)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/cover7.png"
mode="" :lazy-load="true"></image>
<image v-show="shouldShowNestedContent(2)" @click="goback" class="btn"
src="https://static.ticket.sz-trip.com/epicSoul/seek-btn.png" mode=""
:lazy-load="true"></image>
</template>
</view>
</swiper-item>
</swiper>
</template>
</swiper-item>
</swiper>
<MusicControl />
</view>
</template> </template>
<script> <script>
export default { import MusicControl from '@/components/MusicControl.vue';
data() { export default {
return { components: {
currentIndex: 0, MusicControl
verticalIndex: 0, },
// swiper data() {
loadedPages: { return {
0: false, currentIndex: 0,
1: false, verticalIndex: 0,
2: false, // swiper
3: false loadedPages: {
}, 0: false,
// swiper 1: false,
loadedNestedPages: { 2: false,
0: false, 3: false
1: false, },
2: false // swiper
}, loadedNestedPages: {
// 0: false,
preloadBuffer: 1, 1: false,
nestedPreloadBuffer: 1 2: false
} },
}, //
computed: { preloadBuffer: 1,
// swiper nestedPreloadBuffer: 1
shouldShowContent() { }
return (index) => { },
return Math.abs(index - this.currentIndex) <= this.preloadBuffer; computed: {
} // swiper
}, shouldShowContent() {
// swiper return (index) => {
shouldShowNestedContent() { return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
return (index) => { }
return Math.abs(index - this.verticalIndex) <= this.nestedPreloadBuffer; },
} // swiper
} shouldShowNestedContent() {
}, return (index) => {
watch: { return Math.abs(index - this.verticalIndex) <= this.nestedPreloadBuffer;
// swiper currentIndex }
currentIndex(newIndex) { }
// buffer },
for (let i = Math.max(0, newIndex - this.preloadBuffer); i <= Math.min(3, newIndex + this.preloadBuffer); i++) { watch: {
this.loadedPages[i] = true; // swiper currentIndex
} currentIndex(newIndex) {
// buffer
// 4itemswiper for (let i = Math.max(0, newIndex - this.preloadBuffer); i <= Math.min(3, newIndex + this
if (newIndex === 3) { .preloadBuffer); i++) {
this.loadedNestedPages[0] = true; this.loadedPages[i] = true;
if (this.nestedPreloadBuffer >= 1) { }
this.loadedNestedPages[1] = true;
} // 4itemswiper
} if (newIndex === 3) {
}, this.loadedNestedPages[0] = true;
// swiper verticalIndex if (this.nestedPreloadBuffer >= 1) {
verticalIndex(newIndex) { this.loadedNestedPages[1] = true;
// swiper4itemswiper }
if (this.currentIndex === 3) { }
// buffer },
for (let i = Math.max(0, newIndex - this.nestedPreloadBuffer); i <= Math.min(2, newIndex + this.nestedPreloadBuffer); i++) { // swiper verticalIndex
this.loadedNestedPages[i] = true; verticalIndex(newIndex) {
} // swiper4itemswiper
} if (this.currentIndex === 3) {
} // buffer
}, for (let i = Math.max(0, newIndex - this.nestedPreloadBuffer); i <= Math.min(2, newIndex + this
methods: { .nestedPreloadBuffer); i++) {
handleSwiperChange(e) { this.loadedNestedPages[i] = true;
this.currentIndex = e.detail.current; }
}, }
handleVerticalChange(e) { }
this.verticalIndex = e.detail.current; },
}, methods: {
goback() { handleSwiperChange(e) {
const app = getApp(); this.currentIndex = e.detail.current;
app.globalData.mainSliderIndex = 4; },
uni.navigateTo({ handleVerticalChange(e) {
url: '/xxdf/home/home' this.verticalIndex = e.detail.current;
}); },
} goback() {
}, const app = getApp();
mounted() { app.globalData.mainSliderIndex = 4;
// swiper uni.navigateTo({
this.currentIndex = 0; url: '/xxdf/home/home'
for (let i = 0; i <= Math.min(this.preloadBuffer, 3); i++) { });
this.loadedPages[i] = true; }
} },
mounted() {
// swiper // swiper
this.verticalIndex = 0; this.currentIndex = 0;
this.loadedNestedPages[0] = true; for (let i = 0; i <= Math.min(this.preloadBuffer, 3); i++) {
} this.loadedPages[i] = true;
} }
// swiper
this.verticalIndex = 0;
this.loadedNestedPages[0] = true;
}
}
</script> </script>
<style scoped> <style scoped>
.main-swiper { .main-swiper {
width: 100%; width: 100%;
height: 100vh; height: 100vh;
} }
.nested-swiper {
width: 100%; .nested-swiper {
height: 100vh; width: 100%;
} height: 100vh;
.page-container { }
height: 100vh;
} .page-container {
height: 100vh;
.home-page { }
position: relative;
overflow: hidden; .home-page {
} position: relative;
overflow: hidden;
.bg-image { }
position: absolute;
top: 0; .bg-image {
left: 0; position: absolute;
width: 100%; top: 0;
height: 100%; left: 0;
z-index: 1; width: 100%;
} height: 100%;
.btn { z-index: 1;
position: absolute; }
left: 50%;
bottom: 12%; .btn {
transform: translate(-50%, -50%); position: absolute;
z-index: 2; left: 50%;
width: 250rpx; bottom: 12%;
height: 60rpx; transform: translate(-50%, -50%);
} z-index: 2;
width: 250rpx;
height: 60rpx;
}
.arrow-down {
width: fit-content;
height: fit-content;
position: absolute;
animation: bounce 1.5s infinite;
top: 35vh;
bottom: 0;
left: 20rpx;
margin: auto;
z-index: 100;
}
.arrow-down image {
display: block;
width: 50rpx;
transform: rotate(180deg);
}
@keyframes bounce {
0%,
100% {
transform: translateX(0);
}
25% {
transform: translateX(-3px);
}
75% {
transform: translateX(3px);
}
}
</style> </style>

586
xxdf/chapter3/cover.vue

@ -1,274 +1,360 @@
<template> <template>
<view> <view style="position: relative;">
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange"
:duration="300">
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange" :duration="300"> <swiper-item v-for="(_, outerIndex) in 7" :key="outerIndex">
<swiper-item v-for="(_, outerIndex) in 7" :key="outerIndex"> <swiper class="nested-swiper" :duration="300" @change="handleVerticalChange($event, outerIndex)"
<swiper class="nested-swiper" :duration="300" @change="handleVerticalChange" :current="nestedIndices[outerIndex]"> :current="nestedIndices[outerIndex]">
<!-- 嵌套swiper的第一个item封面页 --> <!-- 嵌套swiper的第一个item封面页 -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="arrow-down" v-if="nestedIndices[outerIndex] == 0">
<image class="bg-image" :src="'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/cover' + (outerIndex+2) + '.png'" mode="" :lazy-load="true"></image> <image src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/rightIcon.png" :lazy-load="true" mode="widthFix">
<image class="cover-txt" :class="{'cover-txt2': outerIndex > 0}" :src="'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/cover' + (outerIndex+2) + '-txt.png'" mode="" :lazy-load="true"></image> </image>
<image class="btn" src="https://static.ticket.sz-trip.com/epicSoul/seek2-btn.png" mode="" :lazy-load="true"></image> </view>
</view> <view class="page-container home-page">
</swiper-item> <image class="bg-image"
<!-- 嵌套swiper的第二个item--> :src="'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/cover' + (outerIndex+2) + '.png'"
<swiper-item> mode="" :lazy-load="true"></image>
<view class="page-container home-page"> <image class="cover-txt" :class="{'cover-txt2': outerIndex > 0}"
<view class="gif-container"> :src="'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/cover' + (outerIndex+2) + '-txt.png'"
<image v-if="shouldLoadContent(outerIndex)" class="gif-style" :src="'https://static.ticket.sz-trip.com/epicSoul/3-' + (outerIndex+1) + '-2.gif'" mode="aspectFill" :lazy-load="true"></image> mode="" :lazy-load="true"></image>
</view> <image class="btn" src="https://static.ticket.sz-trip.com/epicSoul/seek2-btn.png" mode=""
:lazy-load="true"></image>
</view>
</swiper-item>
<!-- 嵌套swiper的第二个item-->
<swiper-item>
<view class="arrow-downs" v-if="nestedIndices[outerIndex] == 1">
<image src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/botIcon.png" :lazy-load="true" mode="heightFix">
</image>
</view>
<view class="page-container home-page">
<view class="gif-container">
<image v-if="shouldLoadContent(outerIndex)" class="gif-style"
:src="'https://static.ticket.sz-trip.com/epicSoul/3-' + (outerIndex+1) + '-2.gif'"
mode="aspectFill" :lazy-load="true"></image>
</view>
<image class="bg-image" :src="'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/cover' + (outerIndex+2) + '-1.png'" mode="" :lazy-load="true"></image> <image class="bg-image"
<view class="qrcode-content"> :src="'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/cover' + (outerIndex+2) + '-1.png'"
<image class="qrCode" src="https://static.ticket.sz-trip.com/epicSoul/qrcode.png" mode="" :lazy-load="true"></image> mode="" :lazy-load="true"></image>
<view class="code-txt"> <view class="qrcode-content">
扫码下单 <image class="qrCode" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/btn1.png"
</view> mode="widthFix" :lazy-load="true" :show-menu-by-longpress="true" @click="gotoPath('/subPackages/techan/detail?id=34')"></image>
</view> <!-- <view class="code-txt">
</view> 扫码下单
</swiper-item> </view> -->
</swiper> </view>
</swiper-item> </view>
<swiper-item> </swiper-item>
<view class="page-container home-page"> </swiper>
<image class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter3/cover9.png" mode="" :lazy-load="true"></image> </swiper-item>
<image @click="goRandomImage" class="cover-txt9" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter3/cover9-txt.png" mode="" :lazy-load="true"></image> <swiper-item>
</view> <view class="page-container home-page">
</swiper-item> <image class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/cover9s.png"
</swiper> mode="" :lazy-load="true"></image>
<MusicControl /> <image @click="goRandomImage" class="cover-txt9"
src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/cover9s-txt.png" mode=""
:lazy-load="true"></image>
</view>
</swiper-item>
</swiper>
<MusicControl />
</view> </view>
</template> </template>
<script> <script>
export default { import MusicControl from '@/components/MusicControl.vue';
data() { export default {
return { components: {
currentIndex: 0, MusicControl
// swiper },
nestedIndices: { data() {
0: 0, return {
1: 0, currentIndex: 0,
2: 0, // swiper
3: 0, nestedIndices: {
4: 0, 0: 0,
5: 0, 1: 0,
6: 0 2: 0,
}, 3: 0,
// 4: 0,
activePages: { 5: 0,
mainIndex: 0, 6: 0
nestedIndices: { },
0: 0, //
1: 0, activePages: {
2: 0, mainIndex: 0,
3: 0, nestedIndices: {
4: 0, 0: 0,
5: 0, 1: 0,
6: 0 2: 0,
} 3: 0,
}, 4: 0,
// 5: 0,
preloadBuffer: 2 6: 0
} }
}, },
methods: { //
// swiper preloadBuffer: 2
handleSwiperChange(e) { }
this.currentIndex = e.detail.current; },
this.activePages.mainIndex = e.detail.current; methods: {
}, // swiper
handleSwiperChange(e) {
// swiper this.currentIndex = e.detail.current;
handleVerticalChange(e) { this.activePages.mainIndex = e.detail.current;
const outerIndex = parseInt(e.target.dataset.index); },
this.nestedIndices[outerIndex] = e.detail.current;
this.activePages.nestedIndices[outerIndex] = e.detail.current; // swiper
}, handleVerticalChange(e, outerIndex) {
this.nestedIndices[outerIndex] = e.detail.current;
goRandomImage() { this.activePages.nestedIndices[outerIndex] = e.detail.current;
const imageArray = [ },
{
id: 1,
image: 'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image1.png',
name: '雏菊',
desc: '宋 丛菊图页'
},
{
id: 2,
image: 'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image2.png',
name: '杜鹃',
desc: '清 恽寿平 花卉十开 杜鹃'
},
{
id: 3,
image: 'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image3.png',
name: '金桂',
desc: '清 蒋延锡 桂花图 局部 台北故宫博物馆院藏'
},
{
id: 4,
image: 'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image4.png',
name: '绿梅',
desc: '北宋 赵佶 梅花秀眼图页 北京故宫博物院藏'
},
{
id: 5,
image: 'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image5.png',
name: '墨兰',
desc: '宋 秋兰绽蕊图'
},
{
id: 6,
image: 'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image6.png',
name: '茉莉',
desc: '宋 茉莉花图页'
},
{
id: 7,
image: 'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image7.png',
name: '青莲',
desc: '宋 出水芙蓉图页'
},
];
const app = getApp(); goRandomImage() {
app.globalData.randomImages = imageArray; const imageArray = [{
uni.setStorageSync('randomImages', JSON.stringify(imageArray)); id: 1,
uni.navigateTo({ image: 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image1.png',
url: '/xxdf/chapter3/randomImage' name: '雏菊',
}); desc: '宋 丛菊图页'
}, },
{
goback() { id: 2,
const app = getApp(); image: 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image2.png',
app.globalData.mainSliderIndex = 4; name: '杜鹃',
uni.redirectTo({ desc: '清 恽寿平 花卉十开 杜鹃'
url: '/xxdf/home/home' },
}); {
} id: 3,
}, image: 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image3.png',
computed: { name: '金桂',
shouldLoadContent() { desc: '清 蒋延锡 桂花图 局部 台北故宫博物馆院藏'
return (outerIndex) => { },
// (GIF) {
return Math.abs(outerIndex - this.currentIndex) <= this.preloadBuffer && id: 4,
(this.nestedIndices[outerIndex] === 1 || this.activePages.nestedIndices[outerIndex] === 1); image: 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image4.png',
} name: '绿梅',
} desc: '北宋 赵佶 梅花秀眼图页 北京故宫博物院藏'
}, },
mounted() { {
// id: 5,
this.currentIndex = 0; image: 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image5.png',
this.activePages.mainIndex = 0; name: '墨兰',
}, desc: '宋 秋兰绽蕊图'
beforeDestroy() { },
// {
} id: 6,
} image: 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image6.png',
name: '茉莉',
desc: '宋 茉莉花图页'
},
{
id: 7,
image: 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image7.png',
name: '青莲',
desc: '宋 出水芙蓉图页'
},
];
const app = getApp();
app.globalData.randomImages = imageArray;
uni.setStorageSync('randomImages', JSON.stringify(imageArray));
uni.navigateTo({
url: '/xxdf/chapter3/randomImage'
});
},
shouldLoadContent(outerIndex) {
// (GIF)
return Math.abs(outerIndex - this.currentIndex) <= this.preloadBuffer &&
(this.nestedIndices[outerIndex] === 1 || this.activePages.nestedIndices[outerIndex] === 1);
},
goback() {
const app = getApp();
app.globalData.mainSliderIndex = 4;
uni.redirectTo({
url: '/xxdf/home/home'
});
}
},
mounted() {
//
this.currentIndex = 0;
this.activePages.mainIndex = 0;
},
beforeDestroy() {
//
}
}
</script> </script>
<style scoped> <style scoped>
.main-swiper { .main-swiper {
width: 100%; width: 100%;
height: 100vh; height: 100vh;
} }
.nested-swiper {
width: 100%;
height: 100vh;
}
.page-container {
height: 100vh;
}
.home-page {
position: relative;
overflow: hidden;
}
.bg-image {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.nested-swiper { .cover-txt {
width: 100%; position: absolute;
height: 100vh; left: 50%;
} bottom: 22%;
transform: translate(-50%, -50%);
z-index: 2;
width: 74%;
height: 122rpx;
}
.page-container { .cover-txt2 {
height: 100vh; width: 60% !important;
} height: 134rpx !important;
}
.home-page { .cover-txt9 {
position: relative; position: absolute;
overflow: hidden; left: 50%;
} bottom: 0;
transform: translate(-50%, -20%);
z-index: 2;
width: 360rpx;
height: 280rpx;
}
.bg-image { .btn {
position: absolute; position: absolute;
top: 0; left: 50%;
left: 0; bottom: 16%;
width: 100%; transform: translate(-50%, -50%);
height: 100%; z-index: 2;
z-index: 1; width: 244rpx;
} height: 60rpx;
}
.cover-txt { .qrcode-content {
position: absolute; display: flex;
left: 50%; flex-direction: column;
bottom: 22%; align-items: center;
transform: translate(-50%, -50%); position: absolute;
z-index: 2; left: 50%;
width: 74%; bottom: 10vh;
height: 122rpx; transform: translate(-50%, -25%);
} z-index: 2;
}
.cover-txt2 { .qrCode {
width: 60% !important; width: 400rpx;
height: 134rpx !important; }
}
.cover-txt9 { .code-txt {
position: absolute; color: #333;
left: 50%; font-size: 24rpx;
bottom: 0; margin-top: 10rpx;
transform: translate(-50%, -20%); }
z-index: 2;
width: 360rpx;
height: 280rpx;
}
.btn { .gif-container {
position: absolute; background: #333333;
left: 50%; position: absolute;
bottom: 16%; top: 0;
transform: translate(-50%, -50%); left: 0;
z-index: 2; width: 100%;
width: 244rpx; height: 400rpx;
height: 60rpx; z-index: 2;
} }
.qrcode-content { .gif-style {
display: flex; width: 100%;
flex-direction: column; height: 100%;
align-items: center; object-fit: cover;
position: absolute; }
left: 50%;
bottom: 0;
transform: translate(-50%, -25%);
z-index: 2;
}
.qrCode { .arrow-down {
width: 200rpx; width: fit-content;
height: 200rpx; height: fit-content;
} position: absolute;
animation: bounce 1.5s infinite;
top: 0;
bottom: 0;
left: 20rpx;
margin: auto;
z-index: 100;
}
.code-txt { .arrow-down image {
color: #333; display: block;
font-size: 24rpx; width: 50rpx;
margin-top: 10rpx; transform: rotate(180deg);
} }
.arrow-downs {
width: fit-content;
height: fit-content;
position: absolute;
animation: bounces 1.5s infinite;
left: 0;
right: 0;
bottom: 360rpx;
margin: 0 auto;
z-index: 100;
}
.arrow-downs image {
display: block;
height: 50rpx;
}
@keyframes bounce {
0%,
100% {
transform: translateX(0);
}
.gif-container { 25% {
background: #333333; transform: translateX(-3px);
position: absolute; }
top: 0;
left: 0;
width: 100%;
height: 400rpx;
z-index: 2;
}
.gif-style { 75% {
width: 100%; transform: translateX(3px);
height: 100%; }
object-fit: cover; }
}
@keyframes bounces {
0%,
20%,
50%,
80%,
100% {
transform: translateY(0);
}
40% {
transform: translateY(-20rpx);
}
60% {
transform: translateY(-10rpx);
}
}
</style> </style>

18
xxdf/chapter3/randomImage.vue

@ -34,13 +34,13 @@ export default {
} else { } else {
// 使 // 使
this.randomImages = [ this.randomImages = [
'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image1.png', 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image1.png',
'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image2.png', 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image2.png',
'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image3.png', 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image3.png',
'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image4.png', 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image4.png',
'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image5.png', 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image5.png',
'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image6.png', 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image6.png',
'https://static.ticket.sz-trip.com/epicSoul/images/chapter3/random/image7.png' 'https://static.ticket.sz-trip.com/epicSoul/image/chapter3/random/image7.png'
]; ];
} }
@ -50,6 +50,8 @@ export default {
this.$refs.randomImageRef.selectRandomImage(); this.$refs.randomImageRef.selectRandomImage();
} }
}); });
console.log(this.randomImages)
}, },
methods: { methods: {
// //
@ -76,7 +78,7 @@ export default {
height: 48rpx; height: 48rpx;
position: absolute; position: absolute;
left: 40rpx; left: 40rpx;
top: 40rpx; top: 107rpx;
z-index: 10; z-index: 10;
} }

362
xxdf/chapter4/cover.vue

@ -1,26 +1,25 @@
<template> <template>
<view> <view>
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange" :duration="300"> <swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange" :duration="300">
<swiper-item v-for="(_, outerIndex) in 7" :key="outerIndex"> <swiper-item v-for="(_, outerIndex) in (questionsList.length || 7)" :key="outerIndex">
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[outerIndex]"> <template v-if="loadedPages[outerIndex]">
<image v-show="shouldShowContent(outerIndex)" class="bg-image" <image v-show="shouldShowContent(outerIndex)" class="bg-image"
:src="`https://static.ticket.sz-trip.com/epicSoul/images/chapter4/detail${outerIndex+1}/cover-bg.png`" mode="" :lazy-load="true"> :src="`https://static.ticket.sz-trip.com/epicSoul/image/chapter4/detail${outerIndex+1}/cover-bg.png`" mode="" :lazy-load="true">
</image> </image>
<view v-show="shouldShowContent(outerIndex)" class="content-layer"> <view v-show="shouldShowContent(outerIndex)" class="content-layer">
<swiper class="image-swiper" circular :indicator-dots="false" <swiper class="image-swiper" circular :indicator-dots="false"
@change="(e) => handleImageSwiperChange(e, outerIndex)" :autoplay="false" @change="(e) => handleImageSwiperChange(e, outerIndex)" :autoplay="false"
:current="innerSwiperIndices[outerIndex]" :key="`inner-swiper-${outerIndex}`"> :current="innerSwiperIndices[outerIndex]" :key="`inner-swiper-${outerIndex}`">
<swiper-item v-for="index in 7" :key="index"> <swiper-item v-for="(option, index) in getQuestionOptions(outerIndex)" :key="option.id">
<view class="swiper-item-container"> <view class="swiper-item-container">
<view class="image-wrapper" :class="{'selected-image': selectedImages[outerIndex] === index-1 && userSelected[outerIndex], <view class="image-wrapper" :class="{'selected-image': selectedImages[outerIndex] === index && userSelected[outerIndex],
'image-wrapper-full': [0, 3, 5, 6].includes(outerIndex), 'image-wrapper-full': [0, 3, 5, 6].includes(outerIndex),
'image-wrapper-compact': [1, 2, 4].includes(outerIndex) 'image-wrapper-compact': [1, 2, 4].includes(outerIndex)
}" @click="selectImage(outerIndex, index-1)"> }" @click="selectImage(outerIndex, index)">
<image <image :src="option.image" class="swiper-image" mode="aspectFit"
:src="`https://static.ticket.sz-trip.com/epicSoul/images/chapter4/detail${outerIndex+1}/swiper-img${index}.png`" :lazy-load="true" />
class="swiper-image" mode="aspectFit" :lazy-load="true" />
</view> </view>
</view> </view>
</swiper-item> </swiper-item>
@ -28,16 +27,16 @@
<!-- 自定义指示器 --> <!-- 自定义指示器 -->
<view class="indicator-container"> <view class="indicator-container">
<view v-for="index in 7" :key="index" class="indicator-dot" <view v-for="(_, index) in getQuestionOptions(outerIndex)" :key="index"
:class="{ 'active': innerSwiperIndices[outerIndex] === index - 1 }" class="indicator-dot" :class="{ 'active': innerSwiperIndices[outerIndex] === index }"
@click="() => changeSlide(index - 1, outerIndex)"></view> @click="() => changeSlide(index, outerIndex)"></view>
</view> </view>
</view> </view>
<view v-show="shouldShowContent(outerIndex)" class="content-layer2"> <view v-show="shouldShowContent(outerIndex)" class="content-layer2">
<!-- 点击确认找一找相似度 按钮 --> <!-- 点击确认找一找相似度 按钮 -->
<image @click="findSimilarity(outerIndex)" class="find-btn" src="https://static.ticket.sz-trip.com/epicSoul/find-btn.png" <image @click="findSimilarity(outerIndex)" class="find-btn" src="https://static.ticket.sz-trip.com/epicSoul/find-btn.png"
:lazy-load="true" mode=""></image> :lazy-load="true" mode=""></image>
<view class="problem-description"> <view class="problem-description">
<view class="proportion-txt" :class="{ <view class="proportion-txt" :class="{
'proportion-txt-position': outerIndex === 0, 'proportion-txt-position': outerIndex === 0,
@ -47,18 +46,18 @@
'proportion-txt-position5': outerIndex === 4, 'proportion-txt-position5': outerIndex === 4,
'proportion-txt-position6': outerIndex === 5, 'proportion-txt-position6': outerIndex === 5,
'proportion-txt-position7': outerIndex === 6 'proportion-txt-position7': outerIndex === 6
}"> }">
{{ percentages[outerIndex]}} {{ percentages[outerIndex]}}
</view> </view>
<image class="description-txt" <image class="description-txt"
:class="{'description-txt6': outerIndex === 5,'description-txt7': outerIndex === 6}" :class="{'description-txt6': outerIndex === 5,'description-txt7': outerIndex === 6}"
:src="`https://static.ticket.sz-trip.com/epicSoul/images/chapter4/detail${outerIndex+1}/cover-txt.png`" :lazy-load="true" :src="`https://static.ticket.sz-trip.com/epicSoul/image/chapter4/detail${outerIndex+1}/cover-txt.png`" :lazy-load="true"
mode=""></image> mode=""></image>
</view> </view>
</view> </view>
<view v-show="shouldShowContent(outerIndex)" class="arrow-content"> <view v-show="shouldShowContent(outerIndex)" class="arrow-content">
<image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icon-black.png" :lazy-load="true" mode=""></image> <image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/botIcon.png" :lazy-load="true" mode=""></image>
</view> </view>
</template> </template>
</view> </view>
@ -68,23 +67,24 @@
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[7]"> <template v-if="loadedPages[7]">
<image v-show="shouldShowContent(7)" class="bg-image" <image v-show="shouldShowContent(7)" class="bg-image"
src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/harvestReport/cover-bg.png" :lazy-load="true" mode=""></image> src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/harvestReport/cover-bgs.png" :lazy-load="true" mode=""></image>
<view v-show="shouldShowContent(7)" class="harvestReport-layer"> <view v-show="shouldShowContent(7)" class="harvestReport-layer">
<view class="grid-cover img-shadow"> <view class="grid-cover img-shadow">
<image class="grid-cover-bg" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/harvestReport/cover-grid.png" <!-- <image class="grid-cover-bg" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/harvestReport/cover-grid.png"
:lazy-load="true" mode=""></image> :lazy-load="true" mode="widthFix" :show-menu-by-longpress="true"></image> -->
<image class="grid-cover-bg" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/harvestReport/qrcode.png"
:lazy-load="true" mode="widthFix" :show-menu-by-longpress="true"></image>
<view class="report-text-overlay" v-if="canAccessFinalReport"> <view class="report-text-overlay" v-if="canAccessFinalReport">
<view class="report-title">您的气味收获</view>
<view class="report-content"> <view class="report-content">
<view v-for="(item, index) in selectedResults" :key="index" class="result-item"> <view v-for="(item, index) in finalReportTexts" :key="index" class="result-item">
{{ item }} {{ item }}
</view> </view>
</view> </view>
</view> </view>
</view> </view>
<image @click="ShareMoments" class="chapter4-btn" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/share-img.png" <!-- <image @click="ShareMoments" class="chapter4-btn" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/share-img.png"
:lazy-load="true" mode=""></image> :lazy-load="true" mode=""></image> -->
</view> </view>
<image @click="goBack" class="back-icon" src="https://static.ticket.sz-trip.com/epicSoul/back.png" mode=""></image> <image @click="goBack" class="back-icon" src="https://static.ticket.sz-trip.com/epicSoul/back.png" mode=""></image>
</template> </template>
@ -92,21 +92,31 @@
</swiper-item> </swiper-item>
</swiper> </swiper>
<MusicControl /> <MusicControl />
<ShareGuide v-model="showShareGuide" :text="['点击右上角...', '选择分享到朋友圈']" @close="onShareGuideClose" /> <ShareGuide @close="onShareGuideClose" />
</view> </view>
</template> </template>
<script> <script>
import {
getQuestionnaireList,
getQuestionnaireDetail,
getStatistics,
sendAnswer
} from '@/static/js/common';
import ShareGuide from '@/components/ShareGuide.vue'; import ShareGuide from '@/components/ShareGuide.vue';
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: { components: {
ShareGuide ShareGuide,
MusicControl
}, },
data() { data() {
return { return {
showShareGuide: false, showShareGuide: false,
currentIndex: 0, currentIndex: 0,
questionnaireId: null,
questionsList: [],
innerSwiperIndices: { innerSwiperIndices: {
0: 0, 0: 0,
1: 0, 1: 0,
@ -143,15 +153,6 @@ export default {
5: '', 5: '',
6: '' 6: ''
}, },
requestedData: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false,
6: false
},
similarityCompleted: { similarityCompleted: {
0: false, 0: false,
1: false, 1: false,
@ -171,6 +172,15 @@ export default {
6: false, 6: false,
7: false 7: false
}, },
reportTextTemplates: [
"你喜欢的,{percentage}的ta一样也喜欢。",
"原来,有{percentage}的人,选择和你做知已。",
"这个世界上的{percentage},喜欢你的激情果敢。",
"{percentage}的你,温暖、温柔又闪光。",
"好在,有{percentage}的人,能读懂你的理想。",
"{percentage}的一群人,和你很合拍。",
"{percentage}气味相投的你们,总会如期相遇。"
],
preloadBuffer: 1, preloadBuffer: 1,
moduleTips: [ moduleTips: [
'请选择最有味道的歌曲', '请选择最有味道的歌曲',
@ -180,65 +190,28 @@ export default {
'请选择最有味道的风景', '请选择最有味道的风景',
'请选择最有味道的动漫', '请选择最有味道的动漫',
'请选择最有味道的情感' '请选择最有味道的情感'
], ]
flavorTexts: {
//
0: [
"音符在舌尖跳跃,这首歌如同陈年佳酿",
],
//
1: [
"如墨般浓郁的性格,似茶般清冽的灵魂",
],
//
2: [
"舌尖上的东方,是一场穿越时空的对话",
],
//
3: [
"文字如酒,越品越醇,越读越深",
],
//
4: [
"山水间藏着天地的密语,云雾里是岁月的轻叹",
],
//
5: [
"二次元中的东方灵魂,是跨越文化的共鸣",
],
//
6: [
"情感如茶,或浓或淡,皆有韵味",
]
}
}; };
}, },
computed: { computed: {
canAccessFinalReport() { finalReportTexts() {
const texts = [];
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
if (!this.similarityCompleted[i]) { if (this.similarityCompleted[i]) {
return false; const percentValue = this.percentages[i].replace('%', '');
const text = this.reportTextTemplates[i].replace('{percentage}', percentValue + '%');
texts.push(text);
} }
} }
return true; return texts;
}, },
selectedResults() { canAccessFinalReport() {
const results = [];
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
if (this.userSelected[i]) { if (!this.similarityCompleted[i]) {
const textOptions = this.flavorTexts[i]; return false;
const randomIndex = Math.floor(Math.random() * textOptions.length);
const text = textOptions[randomIndex];
results.push(`${text}`);
} }
} }
return results; return true;
}
},
mounted() {
this.currentIndex = 0;
for (let i = 0; i <= Math.min(this.preloadBuffer, 7); i++) {
this.loadedPages[i] = true;
} }
}, },
watch: { watch: {
@ -248,7 +221,35 @@ export default {
} }
} }
}, },
created() {
this.Post({}, "/api/user/userInfo").then((res) => {});
this.currentIndex = 0;
for (let i = 0; i <= Math.min(this.preloadBuffer, 7); i++) {
this.loadedPages[i] = true;
}
this.loadQuestionnaireList();
},
methods: { methods: {
getQuestionOptions(moduleIndex) {
if (!this.questionsList || this.questionsList.length <= moduleIndex) {
return [];
}
return this.questionsList[moduleIndex]?.options || [];
},
getOptionId(moduleIndex, optionIndex) {
const options = this.getQuestionOptions(moduleIndex);
return options[optionIndex]?.id;
},
getUserId() {
const userInfoFromStorage = uni.getStorageSync('userInfo');
if (userInfoFromStorage) {
const userInfo = JSON.parse(userInfoFromStorage);
if (userInfo.id) {
return userInfo.id;
}
}
return this.$store.state.user.userInfo.id;
},
shouldShowContent(index) { shouldShowContent(index) {
return Math.abs(index - this.currentIndex) <= this.preloadBuffer; return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
}, },
@ -256,7 +257,6 @@ export default {
this.selectedImages[moduleIndex] = imageIndex; this.selectedImages[moduleIndex] = imageIndex;
this.userSelected[moduleIndex] = true; this.userSelected[moduleIndex] = true;
this.innerSwiperIndices[moduleIndex] = imageIndex; this.innerSwiperIndices[moduleIndex] = imageIndex;
console.log(`选中模块${moduleIndex + 1}的图片${imageIndex + 1}`);
}, },
findSimilarity(moduleIndex) { findSimilarity(moduleIndex) {
if (this.selectedImages[moduleIndex] === null || !this.userSelected[moduleIndex]) { if (this.selectedImages[moduleIndex] === null || !this.userSelected[moduleIndex]) {
@ -267,49 +267,53 @@ export default {
icon: 'none' icon: 'none'
}); });
} }
const questionId = this.questionsList[moduleIndex]?.id;
const optionId = this.getOptionId(moduleIndex, this.selectedImages[moduleIndex]);
if (questionId && optionId && this.questionnaireId) {
const userId = this.getUserId();
sendAnswer({
questionnaire_id: this.questionnaireId,
question_id: questionId,
option_id: optionId,
openid: userId
}).catch(error => {
console.error('提交答案失败:', error);
});
}
this.fetchSimilarityData(moduleIndex); this.fetchSimilarityData(moduleIndex);
}, },
async fetchSimilarityData(moduleIndex) { fetchSimilarityData(moduleIndex) {
uni.showLoading({ uni.showLoading({
title: '计算相似度中...' title: '计算相似度中...'
}); });
try { const questionId = this.questionsList[moduleIndex]?.id;
const imageIndex = this.selectedImages[moduleIndex]; const optionId = this.getOptionId(moduleIndex, this.selectedImages[moduleIndex]);
const result = await this.fetchPercentage(moduleIndex + 1, imageIndex + 1); if (!questionId || !optionId) {
this.percentages[moduleIndex] = result.percentage; this.percentages[moduleIndex] = `${Math.floor(Math.random() * 41) + 60}%`;
this.similarityCompleted[moduleIndex] = true; this.similarityCompleted[moduleIndex] = true;
this.requestedData[moduleIndex] = true;
uni.hideLoading();
uni.showToast({
title: '计算完成',
icon: 'success'
});
} catch (error) {
console.error('获取相似度失败:', error);
uni.hideLoading(); uni.hideLoading();
uni.showToast({ return;
title: '获取数据失败',
icon: 'none'
});
}
},
async fetchPercentage(moduleId, imageId) {
try {
return new Promise((resolve) => {
setTimeout(() => {
const percentage = Math.floor(Math.random() * 41) + 60 + '%';
resolve({
success: true,
percentage,
moduleId,
imageId
});
}, 800);
});
} catch (error) {
console.error('API请求失败:', error);
throw error;
} }
getStatistics({
question_id: questionId
}).then(result => {
if (result.code === 1 && result.data && result.data.options) {
const selectedOption = result.data.options.find(option => option.id === optionId);
if (selectedOption && selectedOption.percentage !== undefined) {
this.percentages[moduleIndex] = `${selectedOption.percentage}%`;
} else {
this.percentages[moduleIndex] = `${Math.floor(Math.random() * 41) + 60}%`;
}
} else {
this.percentages[moduleIndex] = `${Math.floor(Math.random() * 41) + 60}%`;
}
this.similarityCompleted[moduleIndex] = true;
uni.hideLoading();
}).catch(error => {
this.percentages[moduleIndex] = `${Math.floor(Math.random() * 41) + 60}%`;
this.similarityCompleted[moduleIndex] = true;
uni.hideLoading();
});
}, },
ShareMoments() { ShareMoments() {
uni.showShareMenu({ uni.showShareMenu({
@ -370,28 +374,61 @@ export default {
this.selectedImages[outerIndex] = index; this.selectedImages[outerIndex] = index;
this.userSelected[outerIndex] = true; this.userSelected[outerIndex] = true;
}, },
getCurrentInnerIndex(outerIndex) { loadQuestionnaireList() {
return this.innerSwiperIndices[outerIndex || this.currentIndex]; getQuestionnaireList().then(res => {
if (res.code === 1 && res.data.list.length > 0) {
this.questionnaireId = res.data.list[0].id;
this.loadQuestionnaireDetail();
} else {
uni.showToast({
title: '未获取到问卷',
icon: 'none'
});
}
}).catch(error => {
console.error('加载问卷列表失败:', error);
uni.showToast({
title: '加载问卷失败',
icon: 'none'
});
});
}, },
getFlavorDescription(percentage) { loadQuestionnaireDetail() {
const value = parseInt(percentage); if (!this.questionnaireId) return;
return; getQuestionnaireDetail({
id: this.questionnaireId
}).then(res => {
if (res.code === 1 && res.data) {
this.questionsList = res.data.questions || [];
} else {
uni.showToast({
title: '未获取到问卷详情',
icon: 'none'
});
}
}).catch(error => {
console.error('加载问卷详情失败:', error);
uni.showToast({
title: '加载问卷详情失败',
icon: 'none'
});
});
},
onShareAppMessage() {
return {
title: '细嗅东方|「Epic Soul」阅读体 issue02',
mpId: 'wx8954209bb3ad489e',
path: '/pages/chapter4/cover',
imageUrl: '/static/share-img.jpg'
};
},
onShareTimeline() {
return {
title: '细嗅东方|「Epic Soul」阅读体 issue02',
query: '',
imageUrl: '/static/share-img.jpg'
};
} }
},
onShareAppMessage() {
return {
title: '细嗅东方|「Epic Soul」阅读体 issue02',
mpId: 'wx8954209bb3ad489e',
path: '/xxdf/chapter4/cover',
imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/share-img.jpg'
};
},
onShareTimeline() {
return {
title: '细嗅东方|「Epic Soul」阅读体 issue02',
query: '',
imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/share-img.jpg'
};
} }
}; };
</script> </script>
@ -504,7 +541,7 @@ export default {
} }
.proportion-txt { .proportion-txt {
font-size: 48rpx; font-size: 30rpx;
color: #0f944f; color: #0f944f;
} }
@ -588,7 +625,7 @@ export default {
height: 48rpx; height: 48rpx;
position: absolute; position: absolute;
left: 40rpx; left: 40rpx;
top: 40rpx; top: 95rpx;
z-index: 10; z-index: 10;
} }
@ -617,20 +654,21 @@ export default {
position: relative; position: relative;
z-index: 2; z-index: 2;
display: flex; display: flex;
margin-top: 42%; margin-top: 57%;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
height: 100%;
} }
.grid-cover { .grid-cover {
width: 85%; width: 85%;
height: 60%;
} }
.grid-cover-bg { .grid-cover-bg {
width: 100%; position: fixed;
height: 100%; width: 180rpx;
bottom: 238px;
left: 135rpx;
z-index: 999;
} }
.chapter4-btn { .chapter4-btn {
@ -641,7 +679,7 @@ export default {
.img-shadow { .img-shadow {
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2),
0 6px 20px 0 rgba(0, 0, 0, 0.19); 0 6px 20px 0 rgba(0, 0, 0, 0.19);
transition: box-shadow 0.3s ease; transition: box-shadow 0.3s ease;
} }
@ -664,7 +702,6 @@ export default {
} }
@keyframes bounce { @keyframes bounce {
0%, 0%,
20%, 20%,
50%, 50%,
@ -672,11 +709,9 @@ export default {
100% { 100% {
transform: translateY(0); transform: translateY(0);
} }
40% { 40% {
transform: translateY(-20rpx); transform: translateY(-20rpx);
} }
60% { 60% {
transform: translateY(-10rpx); transform: translateY(-10rpx);
} }
@ -690,21 +725,10 @@ export default {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; padding: 0rpx 40rpx 40rpx 40rpx;
align-items: center; box-sizing: border-box;
padding: 40rpx; z-index: 8;
box-sizing: border-box; text-indent: 40rpx;
z-index: 8;
text-align: center;
}
.report-title {
font-size: 48rpx;
color: #f0ad4e;
font-weight: bold;
margin-bottom: 40rpx;
text-shadow: 0 0 10rpx rgba(0, 0, 0, 0.3);
animation: fade-in 1.5s ease-out;
} }
.report-content { .report-content {
@ -754,7 +778,6 @@ export default {
opacity: 0; opacity: 0;
transform: translateY(-20rpx); transform: translateY(-20rpx);
} }
to { to {
opacity: 1; opacity: 1;
transform: translateY(0); transform: translateY(0);
@ -766,7 +789,6 @@ export default {
opacity: 0; opacity: 0;
transform: translateX(-30rpx); transform: translateX(-30rpx);
} }
to { to {
opacity: 1; opacity: 1;
transform: translateX(0); transform: translateX(0);

269
xxdf/home/home.vue

@ -1,127 +1,131 @@
<!-- pages/home/home.vue --> <!-- pages/home/home.vue -->
<template> <template>
<view> <view>
<swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange" :duration="300"> <swiper class="main-swiper" :vertical="true" :current="currentIndex" @change="handleSwiperChange" :duration="300">
<!-- 首页内容 --> <!-- 首页内容 -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<!-- 使用loadedPages确定是否已加载v-show控制显示/隐藏 --> <!-- 使用loadedPages确定是否已加载v-show控制显示/隐藏 -->
<template v-if="loadedPages[0]"> <template v-if="loadedPages[0]">
<image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/index.gif" :lazy-load="true" mode=""></image> <image v-show="shouldShowContent(0)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/index.gif" :lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(0)" class="content-layer"> <view v-show="shouldShowContent(0)" class="content-layer">
<image class="layer-img" src="https://static.ticket.sz-trip.com/epicSoul/home.png" :lazy-load="true" mode=""></image> <image class="layer-img" src="https://static.ticket.sz-trip.com/epicSoul/home1.png" :lazy-load="true" mode="widthFix"></image>
<view class="arrow-content"> <view class="arrow-content">
<image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icon.png" :lazy-load="true" mode=""></image> <image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icons.png" :lazy-load="true" mode=""></image>
</view> </view>
</view> </view>
</template> </template>
</view> </view>
</swiper-item> </swiper-item>
<!-- 序章 --> <!-- 序章 -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[1]"> <template v-if="loadedPages[1]">
<image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/prologue-bg.png" :lazy-load="true" mode=""></image> <image v-show="shouldShowContent(1)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/prologue-bg.png" :lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(1)" class="content-layer"> <view v-show="shouldShowContent(1)" class="content-layer">
<view class="layer-text"> <view class="layer-text">
<view class=""> <view class="">
在此我们邀请你 在此我们邀请你
</view> </view>
<view class=""> <view class="">
以指尖触发一场直抵情绪与美学的共生实验 以指尖触发一场直抵情绪与美学的共生实验
</view> </view>
</view> </view>
<view class="arrow-content"> <view class="arrow-content">
<image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icon.png" :lazy-load="true" mode=""></image> <image class="arrow-down" src="https://static.ticket.sz-trip.com/epicSoul/arrow-icons.png" :lazy-load="true" mode=""></image>
</view> </view>
</view> </view>
</template> </template>
</view> </view>
</swiper-item> </swiper-item>
<!-- 第一章封面 --> <!-- 第一章封面 -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[2]"> <template v-if="loadedPages[2]">
<image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/cover.png" :lazy-load="true" mode=""></image> <image v-show="shouldShowContent(2)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/covers.png" :lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(2)" class="content-layer"> <view v-show="shouldShowContent(2)" class="content-layer">
<image class="layer-img2" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/bg-txt.png" :lazy-load="true" mode=""> <image class="layer-img2" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/bg-txts.png" :lazy-load="true" mode="widthFix">
</image> </image>
<view class="arrow-content"> <view class="arrow-content">
<image @click="navigateToChapter1" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/button.png" :lazy-load="true" mode=""></image> <image @click="navigateToChapter1" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/buttons.png" :lazy-load="true" mode=""></image>
</view> </view>
</view> </view>
</template> </template>
</view> </view>
</swiper-item> </swiper-item>
<!-- 第二章封面 --> <!-- 第二章封面 -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[3]"> <template v-if="loadedPages[3]">
<image v-show="shouldShowContent(3)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/cover.png" :lazy-load="true" mode=""></image> <image v-show="shouldShowContent(3)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/cover.png" :lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(3)" class="content-layer"> <view v-show="shouldShowContent(3)" class="content-layer">
<image class="chapter2-bg-txt" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/bg-txt.png" :lazy-load="true" mode=""></image> <image class="chapter2-bg-txt" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/bg-txt.png" :lazy-load="true" mode=""></image>
<view class="arrow-content chapter2-btn"> <view class="arrow-content chapter2-btn">
<image @click="navigateToChapter2" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter2/button.png" :lazy-load="true" mode=""></image> <image @click="navigateToChapter2" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter2/button.png" :lazy-load="true" mode=""></image>
</view> </view>
</view> </view>
</template> </template>
</view> </view>
</swiper-item> </swiper-item>
<!-- 第三章封面 --> <!-- 第三章封面 -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[4]"> <template v-if="loadedPages[4]">
<image v-show="shouldShowContent(4)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter3/cover.png" :lazy-load="true" mode=""></image> <image v-show="shouldShowContent(4)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/cover.png" :lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(4)" class="content-layer"> <view v-show="shouldShowContent(4)" class="content-layer">
<image class="chapter3-bg-txt" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter3/bg-txt.png" :lazy-load="true" mode=""></image> <image class="chapter3-bg-txt" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/bg-txt.png" :lazy-load="true" mode=""></image>
<view class="arrow-content chapter3-btn"> <view class="arrow-content chapter3-btn">
<image @click="navigateToChapter3" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter3/button.png" :lazy-load="true" mode=""></image> <image @click="navigateToChapter3" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter3/button.png" :lazy-load="true" mode=""></image>
</view> </view>
</view> </view>
</template> </template>
</view> </view>
</swiper-item> </swiper-item>
<!-- 第四章封面 --> <!-- 第四章封面 -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[5]"> <template v-if="loadedPages[5]">
<image v-show="shouldShowContent(5)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/cover.png" :lazy-load="true" mode=""></image> <image v-show="shouldShowContent(5)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/covers.png" :lazy-load="true" mode="aspectFill"></image>
<view v-show="shouldShowContent(5)" class="content-layer"> <view v-show="shouldShowContent(5)" class="content-layer">
<image class="chapter4-bg-txt" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/bg-txt.png" :lazy-load="true" mode=""></image> <!-- <image class="chapter4-bg-txt" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/bg-txt.png" :lazy-load="true" mode="widthFix"></image> -->
<view class="chapter4-btn-content"> <view class="chapter4-btn-content">
<image @click="ShareMoments" class="chapter4-btn" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/chapter4-btn.png" :lazy-load="true" mode=""></image> <image @click="ShareMoments" class="chapter4-btn" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/chapter4-btn.png" :lazy-load="true" mode=""></image>
<image @click="navigateToChapter4" class="chapter4-btn chapter4-btn2" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/chapter4-btn2.png" :lazy-load="true" mode=""></image> <image @click="navigateToChapter4" class="chapter4-btn chapter4-btn2" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/chapter4-btn2.png" :lazy-load="true" mode=""></image>
</view> </view>
</view> </view>
</template> </template>
</view> </view>
</swiper-item> </swiper-item>
<!-- 页脚1 --> <!-- 页脚1 -->
<swiper-item> <swiper-item>
<view class="page-container home-page"> <view class="page-container home-page">
<template v-if="loadedPages[6]"> <template v-if="loadedPages[6]">
<image v-show="shouldShowContent(6)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/footer.png" :lazy-load="true" mode=""></image> <image v-show="shouldShowContent(6)" class="bg-image" src="https://static.ticket.sz-trip.com/epicSoul/footers.png" :lazy-load="true" mode="aspectFill"></image>
</template> <image v-show="shouldShowContent(6)" class="qrCode-image" src="https://static.ticket.sz-trip.com/epicSoul/qrCode.png"
</view> :lazy-load="true" mode="widthFix" :show-menu-by-longpress="true"></image>
</swiper-item> </template>
</swiper> </view>
<MusicControl /> </swiper-item>
<ShareGuide v-model="showShareGuide" :text="['点击右上角...', '选择分享到朋友圈']" @close="onShareGuideClose" /> </swiper>
</view> <MusicControl />
<ShareGuide v-model="showShareGuide" @close="onShareGuideClose" />
</view>
</template> </template>
<script> <script>
import ShareGuide from '@/components/ShareGuide.vue'; import ShareGuide from '@/components/ShareGuide.vue';
import MusicControl from '@/components/MusicControl.vue';
export default { export default {
components: { components: {
ShareGuide ShareGuide,
MusicControl
}, },
data() { data() {
return { return {
@ -181,10 +185,17 @@ export default {
} }
}, },
mounted() { mounted() {
const app = getApp();
app.updateMusicSrc('https://static.ticket.sz-trip.com/epicSoul/comfort.mp3');
app.initBackgroundMusic(); //
uni.$bgMusic.play(); //
for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 6); i++) { for (let i = 0; i <= Math.min(1 + this.preloadBuffer, 6); i++) {
this.loadedPages[i] = true; this.loadedPages[i] = true;
} }
}, },
onUnload() {
uni.$bgMusic.pause(); //
},
onShow() { onShow() {
try { try {
const app = getApp(); const app = getApp();
@ -203,15 +214,15 @@ export default {
// #ifdef MP-WEIXIN // #ifdef MP-WEIXIN
onShareAppMessage() { onShareAppMessage() {
return { return {
title: '细嗅东方|「Epic Soul」阅读体 issue02', title: '细嗅东方·Out Of Space|「Epic Soul」阅读体 issue02',
mpId: 'wx8954209bb3ad489e', mpId: 'wx8954209bb3ad489e',
path: '/xxdf/chapter4/cover', path: '/xxdf/home/home',
imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/share-img.jpg' imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/share-img.jpg'
}; };
}, },
onShareTimeline() { onShareTimeline() {
return { return {
title: '细嗅东方|「Epic Soul」阅读体 issue02', title: '细嗅东方·Out Of Space|「Epic Soul」阅读体 issue02',
query: '', query: '',
imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/share-img.jpg' imageUrl: 'https://static.ticket.sz-trip.com/epicSoul/share-img.jpg'
}; };
@ -248,6 +259,16 @@ export default {
z-index: 1; z-index: 1;
} }
.qrCode-image {
position: absolute;
left: 0;
right: 0;
bottom: 192rpx;
margin: 0 auto;
z-index: 2;
width: 30vw;
}
/* 内容层样式 */ /* 内容层样式 */
.content-layer { .content-layer {
position: relative; position: relative;
@ -261,13 +282,13 @@ export default {
.layer-img { .layer-img {
width: 100%; width: 100%;
height: 80%; /* height: 80%; */
} }
.layer-img2 { .layer-img2 {
width: 90%; width: 90%;
height: 88%; /* height: 88%; */
margin-top: 10%; margin-top: 18%;
} }
.chapter2-bg-txt { .chapter2-bg-txt {
@ -279,13 +300,13 @@ export default {
.chapter3-bg-txt { .chapter3-bg-txt {
width: 88%; width: 88%;
height: 88%; height: 88%;
margin-top: 10%; margin-top: 16%;
} }
.chapter4-bg-txt { .chapter4-bg-txt {
width: 75%; width: 75%;
height: 25%; /* height: 25%; */
margin-top: 10%; margin-top: 18%;
} }
.layer-text { .layer-text {
@ -297,7 +318,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
font-size: 24rpx; font-size: 30rpx;
color: #FFFFFF; color: #FFFFFF;
} }

Loading…
Cancel
Save