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

6
components/MusicControl.vue

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

67
components/ShareGuide.vue

@ -1,10 +1,7 @@
<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">
<image class="guide-arrow" :src="arrowImage" mode=""></image>
<view v-for="(text, index) in textArray" :key="index" class="guide-text">
{{ text }}
</view>
<image class="share-tips" src="https://static.ticket.sz-trip.com/epicSoul/share-tips.png" mode=""></image>
</view>
</view>
</template>
@ -15,42 +12,28 @@ export default {
value: {
type: Boolean,
default: false
},
text: {
type: [String, Array],
default: '点击右上角"..."选择"分享到朋友圈"'
},
arrowImage: {
type: String,
default: '/static/share-arrow.png'
}
},
computed: {
visible: {
get() {
return this.value;
},
set(val) {
this.$emit('input', val);
}
},
textArray() {
if (Array.isArray(this.text)) {
return this.text;
}
return [this.text];
data() {
return {
modelValue: this.value
};
},
watch: {
value(newVal) {
this.modelValue = newVal;
}
},
methods: {
closeGuide() {
this.visible = false;
this.$emit('input', false);
this.$emit('close');
}
}
}
};
</script>
<style scoped>
<style>
.share-guide-mask {
position: fixed;
top: 0;
@ -71,27 +54,7 @@ export default {
padding-top: 100rpx;
padding-right: 60rpx;
}
.guide-arrow {
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);
}
.share-tips{
width: 450rpx;
}
</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) {
const randomIndex = Math.floor(Math.random() * this.images.length)
this.selectedItem = this.images[randomIndex]
console.log(this.selectedItem)
}
}
},
@ -53,8 +55,8 @@ export default {
<style scoped>
.random-image {
width: 100%;
height: 100%;
width: 100vw;
height: 100vh;
}
.random-image-name {

14
components/header.vue

@ -1,6 +1,8 @@
<template>
<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>
<view style="width: 50rpx;"></view>
</view>
@ -8,6 +10,16 @@
<script>
export default {
props: {
isSearch: {
type: Boolean,
default: true
},
type: {
type: String,
default: ''
}
},
name:"header",
data() {
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() {
return {
title: 'CGC-ICH',
title: 'Epic Soul交响',
type: 0,
summary: "",
imageUrl: "https://cgc.js-dyyj.com/uploads/20250619/172a730c88bd8894dee1e64c703795eb.jpg"
// imageUrl: "https://cgc.js-dyyj.com/uploads/20250619/172a730c88bd8894dee1e64c703795eb.jpg"
}
},
onShareAppMessage() {
@ -33,10 +33,10 @@ export const myMixins ={
console.log(111,url,`${view.route}?url=${url}`)
return {
title: 'CGC-ICH', // 分享的名称
title: 'Epic Soul交响', // 分享的名称
path: `${view.route}?url=${url}`, // 将 url 作为参数传递
imageUrl: "https://cgc.js-dyyj.com/uploads/20250619/172a730c88bd8894dee1e64c703795eb.jpg",
mpId: 'wx9d68934300b1fe90' // 此处配置微信小程序的 AppId
// imageUrl: "https://cgc.js-dyyj.com/uploads/20250619/172a730c88bd8894dee1e64c703795eb.jpg",
mpId: 'wx8954209bb3ad489e' // 此处配置微信小程序的 AppId
};
}
}

630
pages.json

@ -1,311 +1,351 @@
{
"pages": [ //pageshttps://uniapp.dcloud.io/collocation/pages
{
"path": "pages/stratIndex",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "CGC-ICH"
}
},
{
"path": "pages/index/readingBody",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "阅读体"
}
},
{
"path": "pages/index/sensoryStore",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "有感商店"
}
},
{
"path": "pages/index/intelligentAgent",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "智能体"
}
},
{
"path": "pages/index/iSoul",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "iSoul"
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
}
],
"subPackages": [{
"root": "subPackages",
"pages": [{
"path": "order/trades",
"style": {
"navigationBarTitleText": "全部订单"
}
},
"pages": [
{
"path": "pages/stratIndex",
"style": {
"navigationStyle": "custom"
}
},
{
"path": "pages/index/index",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "CGC-ICH"
}
},
{
"path": "pages/index/readingBody",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "阅读体"
}
},
{
"path": "pages/index/sensoryStore",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "有感商店"
}
},
{
"path": "pages/index/intelligentAgent",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "智能体"
}
},
{
"path": "pages/index/iSoul",
"style": {
"navigationStyle": "custom"
// "navigationBarTitleText": "iSoul"
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
}
],
"subPackages": [
{
"root": "subPackages",
"pages": [
{
"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",
"style": {
"navigationBarTitleText": "订单详情",
"navigationStyle": "custom"
"path" : "order/gwcOrder",
"style" : {
"navigationBarTitleText" : "下单"
}
},
{
"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": "user/profile",
"style": {
"navigationBarTitleText": "个人信息"
}
},
{
"path": "user/changeNickname",
"style": {
"navigationBarTitleText": "修改昵称"
}
}
]
},
{
"root": "xxdf/home",
"pages": [{
"path": "home",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}]
},
{
"path": "user/profile",
"style": {
"navigationBarTitleText": "个人信息"
}
},
{
"path": "user/changeNickname",
"style": {
"navigationBarTitleText": "修改昵称"
}
},
{
"path": "search/search",
"style": {
"navigationBarTitleText": "搜索"
}
}
]
},
{
"root": "xxdf",
"pages": [
{
"path": "home/home",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter1/cover1",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter1/detail1",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter1/detail2",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter1/detail3",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter1/detail4",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter1/detail5",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter2/cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter3/cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter3/randomImage",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "chapter4/cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enableShareAppMessage": true,
"enableShareTimeline": true
}
}
]
},
{
"root": "xxdf/chapter1",
"pages": [{
"path": "cover1",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "detail1",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
"root": "taozi",
"pages": [
{
"path": "home/home",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "detail2",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
"path": "chapter1/chapter1",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "detail3",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "detail4",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
"path": "chapter2/chapter2",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "detail5",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
]
},
{
"root": "xxdf/chapter2",
"pages": [{
"path": "cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}]
},
{
"root": "xxdf/chapter3",
"pages": [{
"path": "cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
"path": "chapter3/chapter3",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
},
{
"path": "randomImage",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
"path": "chapter4/chapter4",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom"
}
}
]
},
{
"root": "xxdf/chapter4",
"pages": [{
"path": "cover",
"style": {
"navigationBarTitleText": "",
"navigationStyle": "custom",
"enableShareAppMessage": true,
"enableShareTimeline": true
}
}]
}
],
"tabBar": {
"custom": true,
"color": "#333333",
"selectedColor": "#6CA5AA",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"fontSize": "24rpx",
"height": "123rpx",
"iconWidth": "40rpx",
"list": [{
"pagePath": "pages/index/index",
"text": "首页",
"visible": false
},
{
"pagePath": "pages/index/readingBody",
"text": "阅读体",
"visible": false
},
{
"pagePath": "pages/index/sensoryStore",
"text": "有感商店",
"visible": false
},
{
"pagePath": "pages/index/intelligentAgent",
"text": "智能体",
"visible": false
},
{
"pagePath": "pages/index/iSoul",
"text": "iSoul",
"visible": false
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
],
"tabBar": {
"custom": true,
"color": "#333333",
"selectedColor": "#6CA5AA",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"fontSize": "24rpx",
"height": "123rpx",
"iconWidth": "40rpx",
"list": [
{
"pagePath": "pages/index/index",
"text": "首页",
"visible": false
},
{
"pagePath": "pages/index/readingBody",
"text": "阅读体",
"visible": false
},
{
"pagePath": "pages/index/sensoryStore",
"text": "有感商店",
"visible": false
},
{
"pagePath": "pages/index/intelligentAgent",
"text": "智能体",
"visible": false
},
{
"pagePath": "pages/index/iSoul",
"text": "iSoul",
"visible": false
}
]
},
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "uni-app",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"uniIdRouter": {}
}

49
pages/index/iSoul.vue

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

27
pages/index/index.vue

@ -1,22 +1,24 @@
<template>
<view class="bg">
<headerVue></headerVue>
<headerVue :isSearch="false"></headerVue>
<view class="content">
<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>
</swiper-item>
</swiper>
</view>
<CustomTabBar :currentTab="0" />
<MusicControl />
</view>
</template>
<script>
import MusicControl from '@/components/MusicControl.vue';
import headerVue from "@/components/header.vue"
import CustomTabBar from '@/components/CustomTabBar.vue';
export default {
components: {CustomTabBar,headerVue},
components: {CustomTabBar,headerVue,MusicControl},
data() {
return {
topBanner: []
@ -27,12 +29,25 @@
},
onReady() {
this.getList()
},
onShow() {
this.browse_record({type: 'page',title: '首页'});
},
onReachBottom() {
},
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) {
if (item.url) {
uni.navigateTo({
@ -44,7 +59,6 @@
url:'/subPackages/letter/detail?id='+item.id
})
},
getList() {
//
this.Post({
@ -60,8 +74,7 @@
uni.navigateTo({
url: '/subPackages/video/video?item=' + encodeURIComponent(JSON.stringify(item))
})
},
}
}
}
</script>

4
pages/index/intelligentAgent.vue

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

94
pages/index/readingBody.vue

@ -1,8 +1,8 @@
<template>
<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"
@change="onSwiperChange">
<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"
: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)">
<image :src="showImg(item.head_img)" mode=""></image>
<image :src="showImg(item.head_img)" mode="widthFix" :id="`swiper-item-${index}`"></image>
</swiper-item>
</swiper>
</uni-swiper-dot>
<!-- <scroll-view scroll-x="true" show-scrollbar="false">
<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 class="category-scroll">
<swiper-item v-for="(item, index) in categories" :key="index" @click="gotoUrlNew(item)">
<image :src="showImg(item.head_img)" mode="aspectFill"></image>
</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">
全部阅读
阅读合集
<image src="https://static.ticket.sz-trip.com/epicSoul/readingBody/titleSpan.png" mode=""></image>
</view>
@ -57,26 +59,30 @@
<span :style="{left: readingIndex == 0 ? '32rpx' : (readingIndex == 1 ? '245rpx' : '448rpx')}"></span> -->
</view>
<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>
<CustomTabBar :currentTab="1" />
<MusicControl />
</view>
</template>
<script>
import headerVue from "@/components/header.vue";
import CustomTabBar from '@/components/CustomTabBar.vue';
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {
headerVue,
CustomTabBar
CustomTabBar,
MusicControl
},
data() {
return {
swiperList: [],
current: 0,
swiperDotIndex: 0,
swiperHeight: 524,
mode: 'round',
dotsStyles: {
selectedBackgroundColor: 'rgb(133, 133, 133)',
@ -94,27 +100,17 @@
}
},
onReady() {
this.Post({
type_id: 3,
position: 4,
}, '/api/adv/getAdv').then(res => {
if(res.data) {
this.startSwiper = res.data;
}
});
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: {
gotoUrlNews(item,index) {
if(index == 0) {
uni.navigateTo({
url: '/xxdf/home/home'
})
}else {
this.gotoUrlNew(item)
}
},
sendRequest() {
this.Post({
type_id: 3,
@ -122,6 +118,12 @@
}, '/api/adv/getAdv').then(res => {
if(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()
},
//
@ -150,6 +161,14 @@
},
change(e) {
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) {
this.currentIndex = e.detail.current;
@ -157,7 +176,6 @@
changeType(index) {
this.readingIndex = index
this.getList()
console.log(index,this.readingIndex)
},
viewDetail(item) {
if (item.url) {
@ -247,6 +265,12 @@
// margin-right: 20rpx;
border-radius: 20rpx;
}
video {
width: 100%;
height: 393rpx;
border-radius: 20rpx;
}
}
.title-box {
@ -302,7 +326,7 @@
box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.1);
padding: 35rpx 10rpx 5rpx;
display: flex;
justify-content: space-between;
justify-content: space-around;
flex-wrap: wrap;
position: relative;
// top: -15rpx;

49
pages/index/sensoryStore.vue

@ -1,6 +1,6 @@
<template>
<view class="bg">
<headerVue></headerVue>
<headerVue :type="'goods'"></headerVue>
<view class="banner-content">
<swiper class="top-banner" :circular="true" :interval="6000" :duration="800"
@ -40,14 +40,16 @@
</view>
</view>
<CustomTabBar :currentTab="2" />
<MusicControl />
</view>
</template>
<script>
import headerVue from "@/components/header.vue"
import CustomTabBar from '@/components/CustomTabBar.vue';
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {CustomTabBar,headerVue},
components: {CustomTabBar,headerVue,MusicControl},
data() {
return {
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>
@ -208,9 +170,10 @@
padding: 36rpx 0 0;
display: flex;
flex-wrap: nowrap;
justify-content: space-between;
// justify-content: space-between;
.item{
width: 214.69rpx;
margin-right: 20rpx;
}
.item-img{
width: 214.69rpx;

45
pages/stratIndex.vue

@ -1,11 +1,17 @@
<template>
<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>
</template>
<script>
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {
MusicControl
},
data() {
return {
screenPng: ""
@ -23,23 +29,49 @@
}, '/api/adv/getAdv').then(res => {
if(res.data && res.data.length>0) {
this.screenPng = res.data[0].head_img
// setTimeout(() => {
// this.goIndex()
// },3000)
}
});
},
mounted() {
const app = getApp();
app.initBackgroundMusic(); //
uni.$bgMusic.play(); //
},
methods: {
goIndex () {
uni.switchTab({
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>
<style lang="scss" scoped>
.bg{
height: 100vh;
image{
.img{
width: 100%;
height: 100%;
position: fixed;
@ -47,4 +79,13 @@
left: 0;
}
}
.btn {
position: fixed;
left: 0;
right: 0;
margin: 0 auto;
width: 300rpx;
bottom: 250rpx;
}
</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) => {
console.log(item);
let that = this;
@ -313,9 +313,14 @@ Vue.prototype.gotoUrlNew = (item) => {
switch (item.jump_type) {
case 0:
break;
case 1:
uni.navigateTo({
url: '/subPackages/techan/detail?id=' + item.product_model.id
});
break;
case 2:
uni.navigateTo({
url: item.tdata
url: item.front_model.mini
});
break;
case 3:
@ -352,4 +357,32 @@ Vue.prototype.gotoUrlNew = (item) => {
default:
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="title text-overflow">{{item.title}}</view>
<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>
</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 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>
</view>
@ -215,6 +214,8 @@
uni.setNavigationBarTitle({
title: this.info.title
})
this.browse_record({type: 'goods',title: this.info.title});
}
});
@ -328,7 +329,6 @@
uni.setStorageSync('cartDataInfo', JSON.stringify(selectedData));
uni.$emit("updateDataByConnect", {msgType:'updateCartDataInfo',data:null})
this.closePopup()
// this.$refs.cartDataVueRef.openPop()
}
});
@ -736,7 +736,7 @@
width: 187rpx;
height: 77rpx;
background: #74A5AA;
border-radius: 39rpx;
border-radius: 0 39rpx 39rpx 0;
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 - 请求头
* @returns {Promise} - 返回Promise对象
*/
const DOMAIN = 'https://m.dayunyuanjian.com';
export const request = (options = {}) => {
return new Promise((resolve, reject) => {
// 默认配置
const defaultOptions = {
url: '',
method: 'GET',
data: {},
header: {
'content-type': 'application/json'
},
timeout: 10000 // 10秒超时
};
// 合并配置
const mergedOptions = {...defaultOptions, ...options};
// 处理URL
if (!mergedOptions.url) {
reject(new Error('URL不能为空'));
return;
}
// 调用uni.request
uni.request({
url: mergedOptions.url,
method: mergedOptions.method,
data: mergedOptions.data,
header: mergedOptions.header,
timeout: mergedOptions.timeout,
success: (res) => {
// 请求成功
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data);
} else {
// 服务器返回错误
reject({
statusCode: res.statusCode,
errMsg: `请求失败,状态码: ${res.statusCode}`,
data: res.data
});
}
},
fail: (err) => {
// 请求失败
reject(err);
}
});
});
return new Promise((resolve, reject) => {
options.url = options.url.startsWith('/') ? `${DOMAIN}${options.url}` : options.url;
// 默认配置
const defaultOptions = {
url: '',
method: 'GET',
data: {},
header: {
'content-type': 'application/json'
},
timeout: 10000 // 10秒超时
};
// 合并配置
const mergedOptions = {
...defaultOptions,
...options
};
// 处理URL
if (!mergedOptions.url) {
reject(new Error('URL不能为空'));
return;
}
// 调用uni.request
uni.request({
url: mergedOptions.url,
method: mergedOptions.method,
data: mergedOptions.data,
header: mergedOptions.header,
timeout: mergedOptions.timeout,
success: (res) => {
// 请求成功
if (res.statusCode >= 200 && res.statusCode < 300) {
resolve(res.data);
} else {
// 服务器返回错误
reject({
statusCode: res.statusCode,
errMsg: `请求失败,状态码: ${res.statusCode}`,
data: res.data
});
}
},
fail: (err) => {
// 请求失败
reject(err);
}
});
});
};
/**
@ -66,12 +73,12 @@ export const request = (options = {}) => {
* @param {Object} options - 其他选项
*/
export const get = (url, data = {}, options = {}) => {
return request({
url,
method: 'GET',
data,
...options
});
return request({
url,
method: 'GET',
data,
...options
});
};
/**
@ -81,12 +88,12 @@ export const get = (url, data = {}, options = {}) => {
* @param {Object} options - 其他选项
*/
export const post = (url, data = {}, options = {}) => {
return request({
url,
method: 'POST',
data,
...options
});
return request({
url,
method: 'POST',
data,
...options
});
};
/**
@ -97,22 +104,22 @@ export const post = (url, data = {}, options = {}) => {
* @param {Object} formData - 附加的表单数据
*/
export const uploadFile = (url, filePath, name = 'file', formData = {}) => {
return new Promise((resolve, reject) => {
uni.uploadFile({
url,
filePath,
name,
formData,
success: (res) => {
try {
// 尝试解析JSON
const data = JSON.parse(res.data);
resolve(data);
} catch (e) {
resolve(res.data);
}
},
fail: reject
});
});
};
return new Promise((resolve, reject) => {
uni.uploadFile({
url,
filePath,
name,
formData,
success: (res) => {
try {
// 尝试解析JSON
const data = JSON.parse(res.data);
resolve(data);
} catch (e) {
resolve(res.data);
}
},
fail: reject
});
});
};

164
xxdf/chapter1/cover1.vue

@ -1,75 +1,76 @@
<template>
<view>
<view class="chapter-cover">
<image class="cover-img" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter1/cover2.png" mode=""></image>
<view class="five-senses-content" @click="goFeel">
<view class="box1"></view>
<view class="senses-txt">
触觉
<view>
<view class="chapter-cover">
<image class="cover-img" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/cover2.png" mode=""></image>
<!-- 使用循环渲染五个感官按钮 -->
<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>
<image @click="goback" class="btn" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter1/abandon-btn.png" mode=""></image>
</view>
<view class="five-senses-content vision" @click="goVision">
<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>
<MusicControl />
</view>
<MusicControl />
</view>
</template>
<script>
import MusicControl from '@/components/MusicControl.vue';
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: {
goback() {
uni.navigateBack({
delta: 1
});
},
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'
const app = getApp();
app.globalData.mainSliderIndex = 2;
uni.redirectTo({
url: '/xxdf/home/home'
});
},
goGustation() {
uni.navigateTo({
url: '/xxdf/chapter1/detail5'
});
//
goToSense(index) {
//
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 {
position: absolute;
top: 32%;
right: 28%;
z-index: 2;
display: flex;
flex-direction: column;
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 {
top: 54% !important;
right: 47% !important;
top: 54%;
right: 47%;
}
.hearing {
top: 62% !important;
right: 8% !important;
top: 62%;
right: 8%;
}
.olfactory {
top: 64% !important;
right: 76% !important;
top: 64%;
right: 76%;
}
.gustation {
top: 73% !important;
right: 86% !important;
}
.box1 {
background: #fff;
border-radius: 50%;
opacity: 0.4;
width: 40rpx;
height: 40rpx;
top: 73%;
right: 86%;
}
.senses-txt {

10
xxdf/chapter1/detail1.vue

@ -4,10 +4,10 @@
<swiper-item>
<view class="page-container home-page">
<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>
<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>
</template>
</view>
@ -16,10 +16,10 @@
<swiper-item>
<view class="page-container home-page">
<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>
<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>
</view>
<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>
<script>
import MusicControl from '@/components/MusicControl.vue';
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {MusicControl},
data() {

12
xxdf/chapter1/detail2.vue

@ -4,10 +4,10 @@
<swiper-item>
<view class="page-container home-page">
<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>
<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>
</template>
</view>
@ -16,10 +16,10 @@
<swiper-item>
<view class="page-container home-page">
<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>
<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>
</view>
<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>
<script>
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {
MusicControl
},
data() {
return {
isVisible: false,

12
xxdf/chapter1/detail3.vue

@ -6,9 +6,9 @@
<swiper-item>
<view class="page-container home-page">
<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">
<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>
</template>
</view>
@ -17,9 +17,9 @@
<swiper-item>
<view class="page-container home-page">
<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}]">
<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>
<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>
@ -31,7 +31,11 @@
</template>
<script>
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {
MusicControl
},
data() {
return {
isVisible: false,

26
xxdf/chapter1/detail4.vue

@ -6,9 +6,9 @@
<swiper-item>
<view class="page-container home-page">
<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">
<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>
</template>
</view>
@ -17,9 +17,9 @@
<swiper-item>
<view class="page-container home-page">
<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}]">
<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>
</template>
</view>
@ -28,9 +28,9 @@
<swiper-item>
<view class="page-container home-page">
<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}]">
<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>
</template>
</view>
@ -39,8 +39,8 @@
<swiper-item>
<view class="page-container home-page">
<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="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="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/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>
</template>
</view>
@ -51,7 +51,11 @@
</template>
<script>
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {
MusicControl
},
data() {
return {
isVisible: false,
@ -74,10 +78,10 @@ export default {
this.currentIndex = e.detail.current;
},
goback() {
const app = getApp();
app.globalData.mainSliderIndex = 3;
// const app = getApp();
// app.globalData.mainSliderIndex = 3;
uni.navigateTo({
url: '/xxdf/home/home'
url: '/xxdf/chapter1/cover1'
});
}
},

12
xxdf/chapter1/detail5.vue

@ -6,9 +6,9 @@
<swiper-item>
<view class="page-container home-page">
<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">
<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>
</template>
</view>
@ -17,9 +17,9 @@
<swiper-item>
<view class="page-container home-page">
<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}]">
<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>
<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>
@ -31,7 +31,11 @@
</template>
<script>
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {
MusicControl
},
data() {
return {
isVisible: false,

460
xxdf/chapter2/cover.vue

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

586
xxdf/chapter3/cover.vue

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

18
xxdf/chapter3/randomImage.vue

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

362
xxdf/chapter4/cover.vue

@ -1,26 +1,25 @@
<template>
<view>
<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">
<template v-if="loadedPages[outerIndex]">
<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>
<view v-show="shouldShowContent(outerIndex)" class="content-layer">
<swiper class="image-swiper" circular :indicator-dots="false"
@change="(e) => handleImageSwiperChange(e, outerIndex)" :autoplay="false"
:current="innerSwiperIndices[outerIndex]" :key="`inner-swiper-${outerIndex}`">
<swiper-item v-for="index in 7" :key="index">
@change="(e) => handleImageSwiperChange(e, outerIndex)" :autoplay="false"
:current="innerSwiperIndices[outerIndex]" :key="`inner-swiper-${outerIndex}`">
<swiper-item v-for="(option, index) in getQuestionOptions(outerIndex)" :key="option.id">
<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-compact': [1, 2, 4].includes(outerIndex)
}" @click="selectImage(outerIndex, index-1)">
<image
:src="`https://static.ticket.sz-trip.com/epicSoul/images/chapter4/detail${outerIndex+1}/swiper-img${index}.png`"
class="swiper-image" mode="aspectFit" :lazy-load="true" />
}" @click="selectImage(outerIndex, index)">
<image :src="option.image" class="swiper-image" mode="aspectFit"
:lazy-load="true" />
</view>
</view>
</swiper-item>
@ -28,16 +27,16 @@
<!-- 自定义指示器 -->
<view class="indicator-container">
<view v-for="index in 7" :key="index" class="indicator-dot"
:class="{ 'active': innerSwiperIndices[outerIndex] === index - 1 }"
@click="() => changeSlide(index - 1, outerIndex)"></view>
<view v-for="(_, index) in getQuestionOptions(outerIndex)" :key="index"
class="indicator-dot" :class="{ 'active': innerSwiperIndices[outerIndex] === index }"
@click="() => changeSlide(index, outerIndex)"></view>
</view>
</view>
<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"
:lazy-load="true" mode=""></image>
:lazy-load="true" mode=""></image>
<view class="problem-description">
<view class="proportion-txt" :class="{
'proportion-txt-position': outerIndex === 0,
@ -47,18 +46,18 @@
'proportion-txt-position5': outerIndex === 4,
'proportion-txt-position6': outerIndex === 5,
'proportion-txt-position7': outerIndex === 6
}">
}">
{{ percentages[outerIndex]}}
</view>
<image class="description-txt"
: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"
mode=""></image>
:class="{'description-txt6': outerIndex === 5,'description-txt7': outerIndex === 6}"
:src="`https://static.ticket.sz-trip.com/epicSoul/image/chapter4/detail${outerIndex+1}/cover-txt.png`" :lazy-load="true"
mode=""></image>
</view>
</view>
<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>
</template>
</view>
@ -68,23 +67,24 @@
<view class="page-container home-page">
<template v-if="loadedPages[7]">
<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 class="grid-cover img-shadow">
<image class="grid-cover-bg" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/harvestReport/cover-grid.png"
:lazy-load="true" mode=""></image>
<!-- <image class="grid-cover-bg" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/harvestReport/cover-grid.png"
: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-title">您的气味收获</view>
<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 }}
</view>
</view>
</view>
</view>
<image @click="ShareMoments" class="chapter4-btn" src="https://static.ticket.sz-trip.com/epicSoul/images/chapter4/share-img.png"
:lazy-load="true" mode=""></image>
<!-- <image @click="ShareMoments" class="chapter4-btn" src="https://static.ticket.sz-trip.com/epicSoul/image/chapter4/share-img.png"
:lazy-load="true" mode=""></image> -->
</view>
<image @click="goBack" class="back-icon" src="https://static.ticket.sz-trip.com/epicSoul/back.png" mode=""></image>
</template>
@ -92,21 +92,31 @@
</swiper-item>
</swiper>
<MusicControl />
<ShareGuide v-model="showShareGuide" :text="['点击右上角...', '选择分享到朋友圈']" @close="onShareGuideClose" />
<ShareGuide @close="onShareGuideClose" />
</view>
</template>
<script>
import {
getQuestionnaireList,
getQuestionnaireDetail,
getStatistics,
sendAnswer
} from '@/static/js/common';
import ShareGuide from '@/components/ShareGuide.vue';
import MusicControl from '@/components/MusicControl.vue';
export default {
components: {
ShareGuide
ShareGuide,
MusicControl
},
data() {
return {
showShareGuide: false,
currentIndex: 0,
questionnaireId: null,
questionsList: [],
innerSwiperIndices: {
0: 0,
1: 0,
@ -143,15 +153,6 @@ export default {
5: '',
6: ''
},
requestedData: {
0: false,
1: false,
2: false,
3: false,
4: false,
5: false,
6: false
},
similarityCompleted: {
0: false,
1: false,
@ -171,6 +172,15 @@ export default {
6: false,
7: false
},
reportTextTemplates: [
"你喜欢的,{percentage}的ta一样也喜欢。",
"原来,有{percentage}的人,选择和你做知已。",
"这个世界上的{percentage},喜欢你的激情果敢。",
"{percentage}的你,温暖、温柔又闪光。",
"好在,有{percentage}的人,能读懂你的理想。",
"{percentage}的一群人,和你很合拍。",
"{percentage}气味相投的你们,总会如期相遇。"
],
preloadBuffer: 1,
moduleTips: [
'请选择最有味道的歌曲',
@ -180,65 +190,28 @@ export default {
'请选择最有味道的风景',
'请选择最有味道的动漫',
'请选择最有味道的情感'
],
flavorTexts: {
//
0: [
"音符在舌尖跳跃,这首歌如同陈年佳酿",
],
//
1: [
"如墨般浓郁的性格,似茶般清冽的灵魂",
],
//
2: [
"舌尖上的东方,是一场穿越时空的对话",
],
//
3: [
"文字如酒,越品越醇,越读越深",
],
//
4: [
"山水间藏着天地的密语,云雾里是岁月的轻叹",
],
//
5: [
"二次元中的东方灵魂,是跨越文化的共鸣",
],
//
6: [
"情感如茶,或浓或淡,皆有韵味",
]
}
]
};
},
computed: {
canAccessFinalReport() {
finalReportTexts() {
const texts = [];
for (let i = 0; i < 7; i++) {
if (!this.similarityCompleted[i]) {
return false;
if (this.similarityCompleted[i]) {
const percentValue = this.percentages[i].replace('%', '');
const text = this.reportTextTemplates[i].replace('{percentage}', percentValue + '%');
texts.push(text);
}
}
return true;
return texts;
},
selectedResults() {
const results = [];
canAccessFinalReport() {
for (let i = 0; i < 7; i++) {
if (this.userSelected[i]) {
const textOptions = this.flavorTexts[i];
const randomIndex = Math.floor(Math.random() * textOptions.length);
const text = textOptions[randomIndex];
results.push(`${text}`);
if (!this.similarityCompleted[i]) {
return false;
}
}
return results;
}
},
mounted() {
this.currentIndex = 0;
for (let i = 0; i <= Math.min(this.preloadBuffer, 7); i++) {
this.loadedPages[i] = true;
return true;
}
},
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: {
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) {
return Math.abs(index - this.currentIndex) <= this.preloadBuffer;
},
@ -256,7 +257,6 @@ export default {
this.selectedImages[moduleIndex] = imageIndex;
this.userSelected[moduleIndex] = true;
this.innerSwiperIndices[moduleIndex] = imageIndex;
console.log(`选中模块${moduleIndex + 1}的图片${imageIndex + 1}`);
},
findSimilarity(moduleIndex) {
if (this.selectedImages[moduleIndex] === null || !this.userSelected[moduleIndex]) {
@ -267,49 +267,53 @@ export default {
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);
},
async fetchSimilarityData(moduleIndex) {
fetchSimilarityData(moduleIndex) {
uni.showLoading({
title: '计算相似度中...'
});
try {
const imageIndex = this.selectedImages[moduleIndex];
const result = await this.fetchPercentage(moduleIndex + 1, imageIndex + 1);
this.percentages[moduleIndex] = result.percentage;
const questionId = this.questionsList[moduleIndex]?.id;
const optionId = this.getOptionId(moduleIndex, this.selectedImages[moduleIndex]);
if (!questionId || !optionId) {
this.percentages[moduleIndex] = `${Math.floor(Math.random() * 41) + 60}%`;
this.similarityCompleted[moduleIndex] = true;
this.requestedData[moduleIndex] = true;
uni.hideLoading();
uni.showToast({
title: '计算完成',
icon: 'success'
});
} catch (error) {
console.error('获取相似度失败:', error);
uni.hideLoading();
uni.showToast({
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;
return;
}
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() {
uni.showShareMenu({
@ -370,28 +374,61 @@ export default {
this.selectedImages[outerIndex] = index;
this.userSelected[outerIndex] = true;
},
getCurrentInnerIndex(outerIndex) {
return this.innerSwiperIndices[outerIndex || this.currentIndex];
loadQuestionnaireList() {
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) {
const value = parseInt(percentage);
return;
loadQuestionnaireDetail() {
if (!this.questionnaireId) 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>
@ -504,7 +541,7 @@ export default {
}
.proportion-txt {
font-size: 48rpx;
font-size: 30rpx;
color: #0f944f;
}
@ -588,7 +625,7 @@ export default {
height: 48rpx;
position: absolute;
left: 40rpx;
top: 40rpx;
top: 95rpx;
z-index: 10;
}
@ -617,20 +654,21 @@ export default {
position: relative;
z-index: 2;
display: flex;
margin-top: 42%;
margin-top: 57%;
flex-direction: column;
align-items: center;
height: 100%;
}
.grid-cover {
width: 85%;
height: 60%;
}
.grid-cover-bg {
width: 100%;
height: 100%;
position: fixed;
width: 180rpx;
bottom: 238px;
left: 135rpx;
z-index: 999;
}
.chapter4-btn {
@ -641,7 +679,7 @@ export default {
.img-shadow {
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;
}
@ -664,7 +702,6 @@ export default {
}
@keyframes bounce {
0%,
20%,
50%,
@ -672,11 +709,9 @@ export default {
100% {
transform: translateY(0);
}
40% {
transform: translateY(-20rpx);
}
60% {
transform: translateY(-10rpx);
}
@ -690,21 +725,10 @@ export default {
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 40rpx;
box-sizing: border-box;
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;
padding: 0rpx 40rpx 40rpx 40rpx;
box-sizing: border-box;
z-index: 8;
text-indent: 40rpx;
}
.report-content {
@ -754,7 +778,6 @@ export default {
opacity: 0;
transform: translateY(-20rpx);
}
to {
opacity: 1;
transform: translateY(0);
@ -766,7 +789,6 @@ export default {
opacity: 0;
transform: translateX(-30rpx);
}
to {
opacity: 1;
transform: translateX(0);

269
xxdf/home/home.vue

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

Loading…
Cancel
Save