3 Commity 07a20f23be ... b7d24689c5

Autor SHA1 Wiadomość Data
  lalalashen b7d24689c5 Merge branch 'master' of http://150.158.33.144:3000/lalalashen/MoeNovaClient 2 miesięcy temu
  lalalashen 901482b1a1 Merge branch 'master' of http://150.158.33.144:3000/lalalashen/MoeNovaClient 2 miesięcy temu
  lalalashen bcf6ee4d44 添加引导部分 2 miesięcy temu
4 zmienionych plików z 382 dodań i 31 usunięć
  1. 329 0
      components/guide/GuideManager.vue
  2. 0 5
      pages.json
  3. 17 3
      pages/isLand/homeLand.vue
  4. 36 23
      pages/isLand/mainLand.vue

+ 329 - 0
components/guide/GuideManager.vue

@@ -0,0 +1,329 @@
+<template>
+  <view class="guide-manager">
+    <!-- 遮罩层 -->
+    <view class="guide-mask" v-if="currentStage" @click="handleMaskClick">
+      <!-- 高亮区域 -->
+      <view class="highlight-area" :style="highlightStyle"></view>
+      
+      <!-- 提示框 -->
+      <view class="guide-tips" :style="tipsStyle">
+        <view class="tips-content">
+          <text class="tips-text">{{ currentStep.tips }}</text>
+          <view class="tips-buttons">
+            <text class="skip-btn" @click.stop="skipStage">跳过</text>
+            <text class="next-btn" @click.stop="nextStep">{{ isLastStep ? '完成' : '下一步' }}</text>
+          </view>
+        </view>
+        <!-- 箭头 -->
+        <view class="arrow" :style="arrowStyle"></view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+export default {
+  name: 'GuideManager',
+  data() {
+    return {
+      // 当前引导阶段
+      currentStage: null,
+      // 当前步骤索引
+      currentStepIndex: 0,
+      // 已完成阶段
+      completedStages: [],
+      // 引导配置
+      guideConfig: {
+        // 主岛引导
+        mainLand: {
+          id: 'mainLand',
+          steps: [
+            {
+              target: '.house-image',
+              tips: '这是你的房屋,点击可以进入查看',
+              position: 'bottom'
+            },
+            {
+              target: '.farm-image',
+              tips: '这是农场,可以种植作物',
+              position: 'bottom'
+            },
+            {
+              target: '.shop-image',
+              tips: '这是商店,可以购买物品',
+              position: 'bottom'
+            }
+          ]
+        },
+        // 家园引导
+        homeLand: {
+          id: 'homeLand',
+          steps: [
+            {
+              target: '.house-image',
+              tips: '这是你的家,点击可以进入',
+              position: 'bottom'
+            },
+            {
+              target: '.table-image',
+              tips: '这是工作台,可以制作物品',
+              position: 'bottom'
+            },
+            {
+              target: '.taskBoard-image',
+              tips: '这是任务板,可以查看任务',
+              position: 'bottom'
+            }
+          ]
+        }
+      }
+    }
+  },
+  computed: {
+    // 当前步骤
+    currentStep() {
+      if (!this.currentStage) return null
+      return this.currentStage.steps[this.currentStepIndex]
+    },
+    // 是否是最后一步
+    isLastStep() {
+      if (!this.currentStage) return false
+      return this.currentStepIndex === this.currentStage.steps.length - 1
+    },
+    // 高亮区域样式
+    highlightStyle() {
+      if (!this.currentStep) return {}
+      return this.currentStep.rect ? {
+        top: `${this.currentStep.rect.top}px`,
+        left: `${this.currentStep.rect.left}px`,
+        width: `${this.currentStep.rect.width}px`,
+        height: `${this.currentStep.rect.height}px`
+      } : {}
+    },
+    // 提示框样式
+    tipsStyle() {
+      if (!this.currentStep || !this.currentStep.rect) return {}
+      
+      const rect = this.currentStep.rect
+      const position = this.currentStep.position
+      const systemInfo = uni.getSystemInfoSync()
+      
+      let style = {}
+      switch (position) {
+        case 'top':
+          style = {
+            bottom: `${systemInfo.windowHeight - rect.top + 10}px`,
+            left: `${rect.left + rect.width / 2}px`,
+            transform: 'translateX(-50%)'
+          }
+          break
+        case 'bottom':
+          style = {
+            top: `${rect.bottom + 10}px`,
+            left: `${rect.left + rect.width / 2}px`,
+            transform: 'translateX(-50%)'
+          }
+          break
+        case 'left':
+          style = {
+            top: `${rect.top + rect.height / 2}px`,
+            right: `${systemInfo.windowWidth - rect.left + 10}px`,
+            transform: 'translateY(-50%)'
+          }
+          break
+        case 'right':
+          style = {
+            top: `${rect.top + rect.height / 2}px`,
+            left: `${rect.right + 10}px`,
+            transform: 'translateY(-50%)'
+          }
+          break
+      }
+      
+      return style
+    },
+    // 箭头样式
+    arrowStyle() {
+      if (!this.currentStep) return {}
+      const position = this.currentStep.position
+      
+      let style = {}
+      switch (position) {
+        case 'top':
+          style = {
+            transform: 'rotate(180deg)',
+            bottom: '0'
+          }
+          break
+        case 'bottom':
+          style = {
+            transform: 'rotate(0deg)',
+            top: '0'
+          }
+          break
+        case 'left':
+          style = {
+            transform: 'rotate(90deg)',
+            right: '0'
+          }
+          break
+        case 'right':
+          style = {
+            transform: 'rotate(-90deg)',
+            left: '0'
+          }
+          break
+      }
+      
+      return style
+    }
+  },
+  methods: {
+    // 开始引导
+    startGuide(stageId) {
+      // 检查是否已完成
+      if (this.completedStages.includes(stageId)) {
+        return
+      }
+      
+      // 设置当前阶段
+      this.currentStage = this.guideConfig[stageId]
+      this.currentStepIndex = 0
+      
+      // 等待DOM更新后更新位置
+      this.$nextTick(() => {
+        this.updatePositions()
+      })
+    },
+    // 下一步
+    nextStep() {
+      if (this.isLastStep) {
+        this.completeStage()
+      } else {
+        this.currentStepIndex++
+        this.$nextTick(() => {
+          this.updatePositions()
+        })
+      }
+    },
+    // 跳过当前阶段
+    skipStage() {
+      this.completeStage()
+    },
+    // 完成当前阶段
+    completeStage() {
+      if (this.currentStage) {
+        // 添加到已完成列表
+        this.completedStages.push(this.currentStage.id)
+        // 保存到本地存储
+        this.saveCompletedStages()
+        // 重置状态
+        this.currentStage = null
+        this.currentStepIndex = 0
+      }
+    },
+    // 更新位置
+    updatePositions() {
+      if (!this.currentStep) return
+      
+      const query = uni.createSelectorQuery().in(this)
+      query.select(this.currentStep.target).boundingClientRect(data => {
+        if (data) {
+          // 更新当前步骤的位置信息
+          this.$set(this.currentStage.steps[this.currentStepIndex], 'rect', data)
+        }
+      }).exec()
+    },
+    // 保存已完成阶段
+    saveCompletedStages() {
+      uni.setStorageSync('completedGuideStages', this.completedStages)
+    },
+    // 加载已完成阶段
+    loadCompletedStages() {
+      const stages = uni.getStorageSync('completedGuideStages')
+      if (stages) {
+        this.completedStages = stages
+      }
+    },
+    // 处理遮罩层点击
+    handleMaskClick() {
+      // 可以在这里添加点击遮罩层的处理逻辑
+    }
+  },
+  mounted() {
+    // 加载已完成阶段
+    this.loadCompletedStages()
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.guide-manager {
+  .guide-mask {
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-color: rgba(0, 0, 0, 0.7);
+    z-index: 9999;
+    
+    .highlight-area {
+      position: absolute;
+      box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.7);
+      border-radius: 4px;
+      transition: all 0.3s ease;
+    }
+    
+    .guide-tips {
+      position: absolute;
+      background: #fff;
+      border-radius: 8px;
+      padding: 16px;
+      min-width: 200px;
+      box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
+      transition: all 0.3s ease;
+      
+      .tips-content {
+        .tips-text {
+          font-size: 14px;
+          color: #333;
+          line-height: 1.5;
+          margin-bottom: 12px;
+        }
+        
+        .tips-buttons {
+          display: flex;
+          justify-content: space-between;
+          align-items: center;
+          
+          .skip-btn,
+          .next-btn {
+            font-size: 14px;
+            padding: 4px 12px;
+            border-radius: 4px;
+            cursor: pointer;
+          }
+          
+          .skip-btn {
+            color: #999;
+          }
+          
+          .next-btn {
+            color: #fff;
+            background-color: #1890ff;
+          }
+        }
+      }
+      
+      .arrow {
+        position: absolute;
+        width: 0;
+        height: 0;
+        border: 8px solid transparent;
+        border-bottom-color: #fff;
+      }
+    }
+  }
+}
+</style> 

+ 0 - 5
pages.json

@@ -339,11 +339,6 @@
 				"navigationBarTitleText": "我的星灵",
 				"navigationStyle": "custom"
 			}
-		}, {
-			"path": "pages/isLand/test",
-			"style": {
-				"navigationBarTitleText": "测试"
-			}
 		}, {
 			"path": "pages/isLand/mainLand",
 			"style": {

+ 17 - 3
pages/isLand/homeLand.vue

@@ -66,6 +66,9 @@
 
     <!-- 制造台对话框组件 -->
     <crafting-dialog :visible.sync="craftingVisible" @close="craftingVisible = false"></crafting-dialog>
+
+    <!-- 引导管理器 -->
+    <guide-manager ref="guideManager"></guide-manager>
   </view> 
 </template>
 
@@ -77,6 +80,7 @@ import ShopDialog from '@/components/dialogs/ShopDialog.vue'
 import TaskDialog from './TaskDialog.vue'
 import TalkGuide from './talkGuide.vue'
 import CraftingDialog from '@/components/dialogs/CraftingDialog.vue'
+import GuideManager from '@/components/guide/GuideManager.vue'
 
 export default {
 	components: {
@@ -85,7 +89,8 @@ export default {
 		ShopDialog,
 		TaskDialog,
 		TalkGuide,
-		CraftingDialog
+		CraftingDialog,
+		GuideManager
 	},
 	data() {
 		return {
@@ -144,7 +149,8 @@ export default {
 					isMirror: true
 				}
 			],
-			craftingVisible: false
+			craftingVisible: false,
+			guideManager: null,
 		}
 	},
 	onLoad() {
@@ -158,7 +164,8 @@ export default {
 		});
 	},
 	onShow() {
-		// this.loadData();
+		// 检查是否需要显示引导
+		this.checkAndShowGuide();
 	},
 	onReady() {
 		// 在组件渲染完成后获取图片尺寸
@@ -425,6 +432,13 @@ export default {
 			console.log('引导完成')
 			// 这里可以添加引导完成后的逻辑
 			uni.setStorageSync('isGuideCompleted', true)
+		},
+		// 检查并显示引导
+		checkAndShowGuide() {
+			// 延迟执行以确保DOM已经渲染
+			setTimeout(() => {
+				this.$refs.guideManager && this.$refs.guideManager.startGuide('homeLand');
+			}, 500);
 		}
 	},
 	beforeDestroy() {

+ 36 - 23
pages/isLand/mainLand.vue

@@ -93,32 +93,38 @@
 			</view>
 		</view>
 
-		<!-- 对话框组件 -->
-		<backpack-dialog :visible.sync="inventoryVisible" @close="onInventoryClose"></backpack-dialog>
-		<character-dialog :visible.sync="characterVisible" @close="onCharacterClose"></character-dialog>
-		<shop-dialog :visible.sync="shopVisible" :shopName="currentShopName" @close="onShopClose"
-			@buy="onShopBuy"></shop-dialog>
-		<hua-tian :visible.sync="huaTianVisible" @close="onHuaTianClose" ref="huaTian"></hua-tian>
-		<task-dialog :visible.sync="taskDialogVisible" @close="onTaskDialogClose"></task-dialog>
-	</view>
+
+    <!-- 对话框组件 -->
+    <backpack-dialog :visible.sync="inventoryVisible" @close="onInventoryClose"></backpack-dialog>
+    <character-dialog :visible.sync="characterVisible" @close="onCharacterClose"></character-dialog>
+    <shop-dialog :visible.sync="shopVisible" :shopName="currentShopName" @close="onShopClose" @buy="onShopBuy"></shop-dialog>
+    <hua-tian :visible.sync="huaTianVisible" @close="onHuaTianClose" ref="huaTian"></hua-tian>
+    <task-dialog :visible.sync="taskDialogVisible" @close="onTaskDialogClose"></task-dialog>
+
+    <!-- 引导管理器 -->
+    <guide-manager ref="guideManager"></guide-manager>
+  </view> 
+
 </template>
 
 
 <script>
-	import BackpackDialog from '@/components/dialogs/BackpackDialog.vue'
-	import CharacterDialog from '@/components/dialogs/CharacterDialog.vue'
-	import ShopDialog from '@/components/dialogs/ShopDialog.vue'
-	import HuaTian from './HuaTian.vue'
-	import TaskDialog from './TaskDialog.vue'
-
-	export default {
-		components: {
-			BackpackDialog,
-			CharacterDialog,
-			ShopDialog,
-			HuaTian,
-			TaskDialog
-		},
+import BackpackDialog from '@/components/dialogs/BackpackDialog.vue'
+import CharacterDialog from '@/components/dialogs/CharacterDialog.vue'
+import ShopDialog from '@/components/dialogs/ShopDialog.vue'
+import HuaTian from './HuaTian.vue'
+import TaskDialog from './TaskDialog.vue'
+import GuideManager from '@/components/guide/GuideManager.vue'
+
+export default {
+	components: {
+		BackpackDialog,
+		CharacterDialog,
+		ShopDialog,
+		HuaTian,
+		TaskDialog,
+		GuideManager
+	},
 		data() {
 			return {
 				// // 背景位置控制
@@ -445,7 +451,6 @@
 							duration: 1000
 						});
 						this.homeArrowAnimation = animation.export();
-
 						setTimeout(() => {
 							if (this.homeArrowAnimating) {
 								animate();
@@ -492,6 +497,14 @@
 					}
 				})
 			},
+
+			// 检查并显示引导
+			checkAndShowGuide() {
+				// 延迟执行以确保DOM已经渲染
+				setTimeout(() => {
+					this.$refs.guideManager && this.$refs.guideManager.startGuide('mainLand');
+				}, 500);
+			},
 		}
 	}
 </script>