wangsisi 3 týždňov pred
rodič
commit
243716e4b7

+ 0 - 2
components/checkinPopup/checkinPopup.vue

@@ -72,8 +72,6 @@
 				runningDays.value = res.data.runningDays
 				getRules();
 				showPopup.value = true;
-			} else {
-				closeCheckPopup()
 			}
 		});
 	};

+ 170 - 0
components/danmakuManager/README.md

@@ -0,0 +1,170 @@
+# 弹幕组件使用说明
+
+## 功能特性
+
+- 固定高度200px的弹幕容器
+- 支持无限滚动和单次滚动模式
+- 多轨道智能分配,避免弹幕叠加
+- 弹幕宽度根据文字长度自适应
+- 支持用户头像显示(必显示)
+- 自动清理已播放的弹幕
+- 可自定义滚动速度
+- 智能轨道占用管理
+
+## 使用方法
+
+### 基础用法
+
+```vue
+<template>
+  <danmakuManager 
+    :danmakuList="danmakuList" 
+    :height="200" 
+    :infinite="true"
+    :speed="80"
+    @danmakuComplete="onDanmakuComplete"
+  ></danmakuManager>
+</template>
+
+<script setup>
+import danmakuManager from "@/components/danmakuManager/danmakuManager.vue"
+
+const danmakuList = ref([
+  {
+    text: "晨曦微露,阳光洒满大地",
+    avatar: "头像URL"
+  },
+  {
+    text: "守护果树,收获美好",
+    avatar: null
+  }
+])
+
+const onDanmakuComplete = (id) => {
+  console.log('弹幕播放完成:', id)
+}
+</script>
+```
+
+### Props 参数
+
+| 参数 | 类型 | 默认值 | 说明 |
+|------|------|--------|------|
+| danmakuList | Array | [] | 弹幕数据列表 |
+| height | Number | 200 | 容器高度(px) |
+| infinite | Boolean | true | 是否无限循环 |
+| speed | Number | 100 | 弹幕滚动速度(px/s) |
+| trackCount | Number | 8 | 弹幕轨道数量 |
+| spacing | Number | 20 | 弹幕间距 |
+
+### 弹幕数据格式
+
+```javascript
+{
+  text: "弹幕文本内容",
+  avatar: "头像URL" // 必填,如果为null会使用默认头像
+}
+```
+
+### 事件
+
+| 事件名 | 参数 | 说明 |
+|--------|------|------|
+| danmakuComplete | id | 弹幕播放完成时触发 |
+
+### 方法
+
+组件暴露了以下方法供父组件调用:
+
+- `addDanmaku(text, avatar)` - 动态添加弹幕
+- `clearDanmakus()` - 清空所有弹幕
+- `startDanmakuAnimation()` - 开始弹幕动画
+- `stopDanmakuAnimation()` - 停止弹幕动画
+
+### 无限滚动 vs 单次滚动
+
+```vue
+<!-- 无限滚动 -->
+<danmakuManager :infinite="true" :danmakuList="danmakuList"></danmakuManager>
+
+<!-- 单次滚动 -->
+<danmakuManager :infinite="false" :danmakuList="danmakuList"></danmakuManager>
+```
+
+## 样式定制
+
+弹幕组件使用8个不同的轨道,每个轨道有不同的背景色:
+
+- track-0: 红色
+- track-1: 绿色  
+- track-2: 蓝色
+- track-3: 黄色
+- track-4: 紫色
+- track-5: 青色
+- track-6: 橙色
+- track-7: 紫罗兰色
+
+可以通过修改CSS来自定义轨道样式。
+
+## 新增功能说明
+
+### 1. 自适应宽度
+- 弹幕宽度根据文字长度自动调整
+- 使用 `width: fit-content` 实现自适应
+- 设置最小宽度确保视觉效果
+
+### 2. 必显示头像
+- 每个弹幕都会显示用户头像
+- 如果没有提供头像,会使用默认头像
+- 头像大小固定为32rpx,圆形显示
+
+### 3. 智能轨道管理
+- 避免弹幕在同一轨道叠加
+- 避免弹幕在相邻轨道叠加
+- 智能分配可用轨道,确保轨道间距
+- 记录轨道占用时间,自动释放
+- 如果所有轨道都被占用,选择最早释放的轨道
+
+### 4. 弹幕消失优化
+- 确保弹幕完全离开可视范围才消失
+- 增加额外的消失距离,避免弹幕突然消失
+- 优化弹幕播放间隔,避免过于密集
+
+### 5. 高度自适应优化
+- 根据容器高度动态调整轨道间距
+- 防止弹幕超出容器边界显示不完整
+- 动态调整播放间隔,避免低高度容器中弹幕叠加
+- 添加边界保护,确保弹幕完全显示
+
+### 6. 弹幕稳定性优化
+- 修复弹幕在滚动过程中高度掉下来的问题
+- 确保弹幕在容器边界内完全显示
+- 优化轨道分配算法,避免超出容器边界
+- 固定弹幕元素高度,防止滚动时变形
+
+### 7. 弹幕显示完整性优化
+- 增加弹幕消失的缓冲距离,确保完全显示后再消失
+- 优化弹幕宽度计算,更精确地估算文字宽度
+- 增加内边距和文字间距,确保文字显示完整
+- 延长弹幕动画时间,避免过早消失
+
+### 8. 低高度容器优化
+- 针对100px等低高度容器进行特殊优化
+- 增加轨道间距,避免弹幕垂直叠加
+- 减少可用轨道数量,确保弹幕有足够空间
+- 增加播放间隔时间,避免弹幕过于密集
+- 优化时间间隔计算,确保相邻弹幕不会叠加
+
+### 9. 彻底解决叠加问题
+- 采用严格轨道分配策略,只使用完全空闲的轨道
+- 当没有空闲轨道时,暂停添加新弹幕
+- 进一步减少低高度容器的可用轨道数量(最多2个)
+- 大幅增加播放间隔时间,确保弹幕完全分离
+- 避免任何形式的弹幕叠加,保证观看体验
+
+### 10. 修复显示问题
+- 优化轨道分配策略,确保弹幕能正常显示
+- 采用三级轨道选择策略:完全空闲 > 任何空闲 > 最早释放
+- 调整低高度容器的可用轨道数量为3个,平衡显示和防叠加
+- 优化播放间隔时间,确保弹幕流畅显示
+- 修复过于严格的轨道分配导致的弹幕不显示问题

+ 373 - 0
components/danmakuManager/danmakuManager.vue

@@ -0,0 +1,373 @@
+<template>
+	<view class="danmaku-container" :style="{ height: height + 'px' }">
+		<view class="danmaku-stage">
+			<view 
+				v-for="item in visibleDanmakus" 
+				:key="item.id"
+				class="danmaku-item"
+				:class="[`danmaku-track`, { 'danmaku-scrolling': item.isScrolling }]"
+				:style="getDanmakuStyle(item)"
+			>
+				<view class="danmaku-content">
+					<image class="danmaku-avatar" :src="item.avatar || defaultAvatar" mode="aspectFill"></image>
+					<view class="danmaku-text">{{ item.text }}</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script setup>
+import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
+
+const props = defineProps({
+	danmakuList: {
+		type: Array,
+		default: () => []
+	},
+	height: {
+		type: Number,
+		default: 200
+	},
+	infinite: {
+		type: Boolean,
+		default: true
+	},
+	speed: {
+		type: Number,
+		default: 100
+	},
+	trackCount: {
+		type: Number,
+		default: 8
+	},
+	spacing: {
+		type: Number,
+		default: 20
+	}
+})
+
+const emit = defineEmits(['danmakuComplete'])
+
+const visibleDanmakus = ref([])
+const animationTimer = ref(null)
+const danmakuIdCounter = ref(0)
+const trackOccupancy = ref(new Array(props.trackCount).fill(0)) // 记录每个轨道的占用情况
+
+const trackHeight = computed(() => props.height / props.trackCount)
+
+// 默认头像
+const defaultAvatar = 'https://birdseye-img.sysuimars.com/youwei-uniapp/img/default-avatar.png'
+
+const getDanmakuStyle = (danmaku) => {
+	// 获取屏幕宽度,兼容不同平台
+	const screenWidth = uni.getSystemInfoSync().screenWidth || 375
+	// 增加更多的额外距离确保弹幕完全离开可视范围
+	const extraDistance = 200 // 增加缓冲距离
+	const duration = (screenWidth + danmaku.width + extraDistance) / props.speed
+	const trackSpacing = calculateTrackSpacing()
+	const danmakuHeight = calculateDanmakuHeight()
+	
+	// 计算弹幕的垂直位置,确保在轨道中居中且不超出容器边界
+	const trackTop = danmaku.track * trackSpacing
+	const centerOffset = trackSpacing / 2
+	const topPosition = Math.max(
+		danmakuHeight / 2, // 确保不超出顶部
+		Math.min(
+			trackTop + centerOffset, // 轨道中心位置
+			props.height - danmakuHeight / 2 // 确保不超出底部
+		)
+	)
+	
+	return {
+		top: `${topPosition}px`,
+		left: `${danmaku.left}px`,
+		transition: `left ${duration}s linear`
+	}
+}
+
+// 计算弹幕实际宽度
+const calculateDanmakuWidth = (text) => {
+	// 更精确的宽度计算:每个字符约16px,头像32px,内边距40px,额外缓冲20px
+	return text.length * 16 + 32 + 40 + 20
+}
+
+// 计算弹幕实际高度
+const calculateDanmakuHeight = () => {
+	return 48 // 弹幕高度约48rpx
+}
+
+// 计算轨道间距
+const calculateTrackSpacing = () => {
+	const danmakuHeight = calculateDanmakuHeight()
+	const trackHeight = props.height / props.trackCount
+	// 对于低高度容器,增加轨道间距避免叠加
+	const minSpacing = props.height < 150 ? danmakuHeight + 20 : danmakuHeight + 10
+	return Math.max(minSpacing, trackHeight) // 确保轨道间距足够
+}
+
+// 查找可用轨道
+const findAvailableTrack = () => {
+	const screenWidth = uni.getSystemInfoSync().screenWidth || 375
+	const currentTime = Date.now()
+	const danmakuHeight = calculateDanmakuHeight()
+	const trackSpacing = calculateTrackSpacing()
+	
+	// 清理过期的轨道占用记录
+	for (let i = 0; i < trackOccupancy.value.length; i++) {
+		if (trackOccupancy.value[i] < currentTime) {
+			trackOccupancy.value[i] = 0
+		}
+	}
+	
+	// 计算可用的轨道数量,确保弹幕不会超出容器边界
+	const maxTracks = Math.floor((props.height - danmakuHeight) / trackSpacing) + 1
+	const availableTracks = Math.min(props.trackCount, maxTracks)
+	
+	// 对于低高度容器,减少可用轨道数量避免叠加
+	const finalTracks = props.height < 150 ? Math.min(availableTracks, 3) : availableTracks
+	
+	// 首先尝试寻找完全空闲的轨道
+	for (let i = 0; i < finalTracks; i++) {
+		if (trackOccupancy.value[i] === 0) {
+			// 检查相邻轨道是否被占用
+			const prevTrack = i > 0 ? trackOccupancy.value[i - 1] : 0
+			const nextTrack = i < finalTracks - 1 ? trackOccupancy.value[i + 1] : 0
+			
+			// 优先选择完全空闲的轨道
+			if (prevTrack === 0 && nextTrack === 0) {
+				return i
+			}
+		}
+	}
+	
+	// 如果没有完全空闲的轨道,寻找任何空闲轨道
+	for (let i = 0; i < finalTracks; i++) {
+		if (trackOccupancy.value[i] === 0) {
+			return i
+		}
+	}
+	
+	// 如果所有轨道都被占用,选择最早释放的轨道
+	let earliestTrack = 0
+	let earliestTime = trackOccupancy.value[0]
+	for (let i = 1; i < finalTracks; i++) {
+		if (trackOccupancy.value[i] < earliestTime) {
+			earliestTime = trackOccupancy.value[i]
+			earliestTrack = i
+		}
+	}
+	
+	return earliestTrack
+}
+
+const createDanmaku = (text, avatar = null) => {
+	const id = ++danmakuIdCounter.value
+	const track = findAvailableTrack()
+	
+	const width = calculateDanmakuWidth(text)
+	// 获取屏幕宽度,兼容不同平台
+	const screenWidth = uni.getSystemInfoSync().screenWidth || 375
+	const left = screenWidth + props.spacing
+	
+	// 计算弹幕持续时间并记录轨道占用,增加缓冲时间
+	const extraDistance = 200
+	const duration = (screenWidth + width + extraDistance) / props.speed
+	const endTime = Date.now() + duration * 1000
+	trackOccupancy.value[track] = endTime
+	
+	return {
+		id,
+		text,
+		avatar,
+		track,
+		width,
+		left,
+		isScrolling: false,
+		startTime: Date.now()
+	}
+}
+
+const addDanmaku = (text, avatar = null) => {
+	const danmaku = createDanmaku(text, avatar)
+	
+	visibleDanmakus.value.push(danmaku)
+	
+	setTimeout(() => {
+		danmaku.isScrolling = true
+		// 确保弹幕完全离开可视范围才消失,增加更多缓冲距离
+		danmaku.left = -(danmaku.width + 100)
+	}, 50)
+	
+	// 获取屏幕宽度,兼容不同平台
+	const screenWidth = uni.getSystemInfoSync().screenWidth || 375
+	// 增加更多的额外距离确保弹幕完全离开可视范围
+	const extraDistance = 200 // 增加缓冲距离
+	const duration = (screenWidth + danmaku.width + extraDistance) / props.speed
+	setTimeout(() => {
+		removeDanmaku(danmaku.id)
+	}, duration * 1000)
+}
+
+const removeDanmaku = (id) => {
+	const index = visibleDanmakus.value.findIndex(item => item.id === id)
+	if (index > -1) {
+		visibleDanmakus.value.splice(index, 1)
+		emit('danmakuComplete', id)
+	}
+}
+
+const clearDanmakus = () => {
+	visibleDanmakus.value = []
+	// 清空轨道占用记录
+	trackOccupancy.value = new Array(props.trackCount).fill(0)
+}
+
+const startDanmakuAnimation = () => {
+	if (props.danmakuList.length === 0) return
+	
+	let currentIndex = 0
+	
+	const playNext = () => {
+		if (currentIndex >= props.danmakuList.length) {
+			if (props.infinite) {
+				currentIndex = 0
+			} else {
+				return
+			}
+		}
+		
+		const danmaku = props.danmakuList[currentIndex]
+		addDanmaku(danmaku.text, danmaku.avatar)
+		currentIndex++
+		
+		// 根据容器高度动态调整间隔时间,低高度容器需要更大的间隔避免叠加
+		const baseInterval = props.height < 150 ? 
+			Math.max(2000, props.height * 2) : // 低高度容器使用适中的基础间隔
+			Math.max(1500, props.height * 2)   // 正常高度容器
+		const minInterval = baseInterval
+		const maxInterval = baseInterval + (props.height < 150 ? 2000 : 2000)
+		const interval = Math.random() * (maxInterval - minInterval) + minInterval
+		animationTimer.value = setTimeout(playNext, interval)
+	}
+	
+	playNext()
+}
+
+const stopDanmakuAnimation = () => {
+	if (animationTimer.value) {
+		clearTimeout(animationTimer.value)
+		animationTimer.value = null
+	}
+}
+
+watch(() => props.danmakuList, (newList) => {
+	if (newList.length > 0) {
+		stopDanmakuAnimation()
+		clearDanmakus()
+		startDanmakuAnimation()
+	}
+}, { deep: true })
+
+onMounted(() => {
+	if (props.danmakuList.length > 0) {
+		startDanmakuAnimation()
+	}
+})
+
+onUnmounted(() => {
+	stopDanmakuAnimation()
+})
+
+defineExpose({
+	addDanmaku,
+	clearDanmakus,
+	startDanmakuAnimation,
+	stopDanmakuAnimation
+})
+</script>
+
+<style lang="scss" scoped>
+.danmaku-container {
+	width: 100%;
+	position: relative;
+	overflow: hidden;
+	// background: rgba(0, 0, 0, 0.1);
+	border-radius: 8rpx;
+}
+
+.danmaku-stage {
+	width: 100%;
+	height: 100%;
+	position: relative;
+}
+
+.danmaku-item {
+	position: absolute;
+	top: 0;
+	left: 0;
+	z-index: 10;
+	pointer-events: none;
+	
+	&.danmaku-scrolling {
+		transition: left linear;
+	}
+	
+	// 确保弹幕在轨道中居中显示
+	transform: translateY(-50%);
+}
+
+.danmaku-content {
+	display: flex;
+	align-items: center;
+	background: rgba(0, 0, 0, 0.6);
+	border-radius: 20rpx;
+	padding: 8rpx 20rpx;
+	backdrop-filter: blur(10rpx);
+	border: 1rpx solid rgba(255, 255, 255, 0.2);
+	// box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.3);
+	width: fit-content;
+	min-width: 120rpx;
+	// 确保弹幕内容不会超出容器边界
+	max-height: 48rpx;
+	overflow: hidden;
+	// 防止弹幕在滚动过程中高度变化
+	line-height: 1.2;
+	// 增加内边距确保文字有足够空间
+	box-sizing: border-box;
+}
+
+.danmaku-avatar {
+	width: 32rpx;
+	height: 32rpx;
+	border-radius: 50%;
+	margin-right: 12rpx;
+	border: 2rpx solid rgba(255, 255, 255, 0.3);
+	flex-shrink: 0;
+	// 确保头像高度稳定
+	object-fit: cover;
+}
+
+.danmaku-text {
+	color: #000;
+	font-size: 24rpx;
+	font-weight: 500;
+	// text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.5);
+	white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+	max-width: 400rpx;
+	flex: 1;
+	// 确保文字高度稳定
+	line-height: 1.2;
+	height: 32rpx;
+	display: flex;
+	align-items: center;
+	// 增加文字间距确保显示完整
+	letter-spacing: 1rpx;
+}
+
+.danmaku-track .danmaku-content {
+	background: rgba(244, 246, 248, 0.6);
+}
+</style>

+ 2 - 1
components/posterPopup/posterPopup.vue

@@ -180,7 +180,8 @@
 			}
 
 			.qr-code {
-				text-align: right;
+				text-align: right;
+				font-family: "SweiSpringCJKtc";
 
 				.image {
 					width: 112rpx;

+ 129 - 18
pages/tabBar/tree/tree.vue

@@ -5,7 +5,24 @@
 				<view class="toogle" @click="handleShow">切换 {{name}}<up-icon class="icon" name="arrow-down" color="#fff"
 						size="12"></up-icon></view>
 			</member-level>
-			<view class="tree-cont">
+			<view class="tree-cont">
+				<!-- 弹幕组件 -->
+				<view class="danmaku-wrapper">
+					<danmakuManager 
+						:danmakuList="danmakuList" 
+						:height="100" 
+						:infinite="true"
+						:speed="80"
+						@danmakuComplete="onDanmakuComplete"
+					></danmakuManager>
+				</view>
+				<view class="dialogue-tips">
+					<view class="tips-name">
+						<image class="tip-img" :src="`${config.BASIC_IMG}img/treePage/sun-icon.png`"></image>
+						<text>亲爱的主人!</text>
+					</view>
+					<view class="tips-cont">今天是我开花的日子,我很开心!</view>
+				</view>
 				<view class="tree-name">
 					<view>{{treeName}}</view>
 					<image @click="handleEditName" class="edit-icon" :src="`${config.BASIC_IMG}img/edit-icon.png`">
@@ -32,17 +49,20 @@
 				</view>
 			</view>
 			<view class="tree-footer">
-				<view class="footer-item" v-for="(item,index) in footerList" :key="index" @click="handleItem(index)">
-					<view @click="requestSubscribe">
-						<button class="share-btn" open-type="share" v-if="index === 2">
-							<image class="icon" :src="`${config.BASIC_IMG}img/treePage/b-tree-icon-${index+1}.png`">
-							</image>
-						</button>
-						<image v-else class="icon" :src="`${config.BASIC_IMG}img/treePage/b-tree-icon-${index+1}.png`">
-						</image>
-						<view class="name">{{item}}</view>
-					</view>
-				</view>
+				<template v-if="userInfo.tel">
+					<view class="footer-item" v-for="(item,index) in footerList" :key="index" @click="handleItem(index)">
+						<view @click="requestSubscribe">
+							<button class="share-btn" open-type="share" v-if="index === 2">
+								<image class="icon" :src="`${config.BASIC_IMG}img/treePage/b-tree-icon-${index+1}.png`">
+								</image>
+							</button>
+							<image v-else class="icon" :src="`${config.BASIC_IMG}img/treePage/b-tree-icon-${index+1}.png`">
+							</image>
+							<view class="name">{{item}}</view>
+						</view>
+					</view>
+				</template>
+				<view v-else class="button" @click="handlePage">开启我的守护</view>
 			</view>
 		</view>
 		<!-- 引导弹窗 -->
@@ -53,7 +73,7 @@
 		<up-picker :show="showPicker" :columns="columns" :defaultIndex="[0]" @cancel="handleCancel"
 			@confirm="handleConfirm" keyName="name" valueName="speciesId"></up-picker>
 		<!-- 签到打卡 -->
-		<checkinPopup></checkinPopup>
+		<checkinPopup @closedCheckPopup="closedCheckPopup"></checkinPopup>
 		<!-- 编辑树名称 -->
 		<editNamePopup ref="editNameRef" @editEnd="getBySampleId"></editNamePopup>
 		<!-- 海报弹窗 -->
@@ -80,6 +100,7 @@
 	import memberLevel from "./components/memberLevel.vue"
 	import treeAlbumPopup from "./components/treeAlbumPopup.vue"
 	import blessingsPopup from "./components/blessingsPopup.vue"
+	import danmakuManager from "@/components/danmakuManager/danmakuManager.vue"
 	import TREE from '@/api/tree.js'
 	import USER from '@/api/user.js'
 	import {
@@ -156,7 +177,6 @@
 
 	onLoad(() => {
 		featchIsLookedGuide()
-		featchLightTree()
 		featchCategoryList()
 	})
 	
@@ -181,7 +201,8 @@
 			data
 		}) => {
 			if (data == false) {
-				showMask.value = true
+				showMask.value = true
+				
 			}
 		})
 	}
@@ -202,10 +223,15 @@
 				showGuardSuccess.value = !showGuardSuccess.value
 				USER.setSessionStore({
 					key: 'successTree',
-					miniUserId: userInfo.id
+					miniUserId: userInfo.id,
+					val:1
 				})
 			}
 		}))
+	}
+	
+	const closedCheckPopup = () =>{
+		showPoster.value = !showPoster.value
 	}
 	
 	const sampleId = ref('')
@@ -237,6 +263,12 @@
 			farmBuyId.value = data.buyList[0].id
 			featchSessionStore()
 		})
+	}
+	
+	const handlePage = () =>{
+		uni.navigateTo({
+			url: `/pages/login/index`
+		});
 	}
 
 	const showPoster = ref(false)
@@ -260,6 +292,47 @@
 	const showBlessingsPopup = ref(false)
 	const showSuccess = ref(false)
 	const clockinType = ref('1')
+	
+	// 弹幕相关数据
+	const danmakuList = ref([
+		{
+			text: "晨曦微露,阳光洒满大地",
+			avatar: `${userInfo.icon}`
+		},
+		{
+			text: "守护果树,收获美好",
+			avatar: `${userInfo.icon}`
+		},
+		{
+			text: "今天也要给果树浇水哦",
+			avatar: `${userInfo.icon}`
+		},
+		{
+			text: "果树长得好快啊",
+			avatar: `${config.BASIC_IMG}img/treePage/drone-icon.png`
+		},
+		{
+			text: "期待果实成熟的那一天",
+			avatar: `${config.BASIC_IMG}img/treePage/drone-icon.png`
+		},
+		{
+			text: "和好友一起守护果树",
+			avatar: `${config.BASIC_IMG}img/treePage/drone-icon.png`
+		},
+		{
+			text: "每日签到,果树茁壮成长",
+			avatar: `${config.BASIC_IMG}img/treePage/drone-icon.png`
+		},
+		{
+			text: "分享给更多朋友",
+			avatar: `${config.BASIC_IMG}img/treePage/drone-icon.png`
+		}
+	])
+	
+	// 弹幕完成回调
+	const onDanmakuComplete = (id) => {
+		console.log('弹幕播放完成:', id)
+	}
 	const handleItem = (index) => {
 		if (index === 0) {
 			clockinType.value = 1
@@ -364,6 +437,16 @@
 		@include ossBg("tree-bg.png");
 		// background-position: top left;
 		padding: 22rpx 0;
+		position: relative;
+		
+		.danmaku-wrapper {
+			position: absolute;
+			top: 21%;
+			left: 0;
+			right: 0;
+			z-index: 100;
+			pointer-events: none;
+		}
 
 		.toogle {
 			position: absolute;
@@ -383,7 +466,27 @@
 
 		.tree-cont {
 			width: 100%;
-			margin-top: 10rpx;
+			margin-top: 10rpx;
+			.dialogue-tips{
+				position: absolute;
+				top: 31.5%;
+				right: 80rpx;
+				font-size: 24rpx;
+				@include ossBg("treePage/tips-bg.png");
+				padding: 10rpx 10rpx 30rpx 20rpx;
+				.tips-name{
+					font-size: 28rpx;
+					font-weight: 500;
+					margin-bottom: 6rpx;
+					display: flex;
+					align-items: center;
+					.tip-img{
+						width: 40rpx;
+						height: 40rpx;
+						margin-right: 4rpx;
+					}
+				}
+			}
 
 			.tree-name {
 				position: absolute;
@@ -493,7 +596,15 @@
 			bottom: 76rpx;
 			width: 100%;
 			display: flex;
-			justify-content: center;
+			justify-content: center;
+			.button {
+				padding: 26rpx 80rpx;
+				border-radius: 50rpx;
+				border: 2rpx solid #fff;
+				background-image: linear-gradient(120deg, #FFD887, #ED9E1E);
+				margin-top: 20rpx;
+				color: #fff;
+			}
 
 			.footer-item {
 				width: 18%;