123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- <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>
- import {mapState} from 'vuex'
- export default {
- name: 'GuideManager',
- data() {
- return {
- // 当前引导阶段
- currentStage: null,
- // 当前步骤索引
- currentStepIndex: 0,
- // 已完成阶段
- completedStages: [],
- // 已完成的主线
- // completedMainLines: [],
- // 引导配置
- guideConfig: {
- },
- // 当前主线ID
- currentMainLineId: 0,
- // 当前主线
- currentMainLine: null,
- // 对话数据
- currentTalkData: [],
- // 当前对话索引
- currentTalkIndex: 0
- }
- },
- computed: {
- ...mapState('switchingModule', ['picture', 'name']),
- // 当前步骤
- 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(stage) {
- // 获取当前主线
- const mainLine = this.guideConfig.mainLines[this.currentMainLineId];
-
- // 检查主线是否存在且场景是否匹配
- if (!mainLine || mainLine.stage !== stage) {
- return false;
- }
- // 检查主线是否已完成
- // if (this.completedMainLines.includes(this.currentMainLineId)) {
- // return false;
- // }
- // 设置当前主线
- this.currentMainLine = mainLine;
- this.currentStepIndex = 0;
- this.currentTalkIndex = 0;
-
- // 初始化对话数据
- this.initTalkData();
-
- return true;
- },
- // 设置当前主线ID
- setMainLineId(id) {
- if (id >= 0 && id < this.guideConfig.mainLines.length) {
- this.currentMainLineId = id;
- // 保存到本地存储
- this.saveCurrentMainLineId();
- }
- },
- // 保存当前主线ID
- saveCurrentMainLineId() {
- uni.setStorageSync('currentGuideMainLineId', this.currentMainLineId);
- },
- // 加载当前主线ID
- loadCurrentMainLineId() {
- const id = uni.getStorageSync('currentGuideMainLineId');
- if (id !== '') {
- this.currentMainLineId = id;
- }
- },
- // 初始化对话数据
- initTalkData() {
- if (this.currentMainLine && this.currentMainLine.steps[this.currentStepIndex]) {
- this.currentTalkData = this.currentMainLine.steps[this.currentStepIndex].talkData;
- }
- },
- // 下一步
- nextStep() {
- console.log("-------- next step", {
- currentMainLine: this.currentMainLine,
- currentStepIndex: this.currentStepIndex,
- currentTalkIndex: this.currentTalkIndex,
- currentTalkData: this.currentTalkData
- });
-
- if (!this.currentMainLine) return;
- // 如果当前步骤是最后一步
- if (this.currentStepIndex === this.currentMainLine.steps.length - 1) {
- this.completeMainLine();
- } else {
- // 进入下一步
- this.currentStepIndex++;
- this.currentTalkIndex = 0;
- this.initTalkData();
- }
- console.log("-------- next step2", {
- currentMainLine: this.currentMainLine,
- currentStepIndex: this.currentStepIndex,
- currentTalkIndex: this.currentTalkIndex,
- currentTalkData: this.currentTalkData
- });
-
- },
- // 完成主线
- completeMainLine() {
- if (this.currentMainLine) {
- // 添加到已完成列表
- // this.completedMainLines.push(this.currentMainLineId);
-
- // 保存到本地存储
- // this.saveCompletedMainLines();
-
- // 重置状态
- this.currentMainLine = null;
- this.currentStepIndex = 0;
- this.currentTalkIndex = 0;
- this.currentTalkData = [];
-
- // 增加主线ID
- this.currentMainLineId++;
- this.saveCurrentMainLineId();
- }
- },
- // 保存已完成主线
- // saveCompletedMainLines() {
- // uni.setStorageSync('completedGuideMainLines', this.completedMainLines);
- // },
- // 加载已完成主线
- // loadCompletedMainLines() {
- // const mainLines = uni.getStorageSync('completedGuideMainLines');
- // if (mainLines) {
- // this.completedMainLines = mainLines;
- // }
- // },
- // 获取当前箭头位置
- getCurrentArrowPosition() {
- if (!this.currentMainLine || !this.currentMainLine.steps[this.currentStepIndex]) {
- return null;
- }
- return this.currentMainLine.steps[this.currentStepIndex].arrow;
- },
- // 获取当前对话数据
- getCurrentTalkData() {
- if (!this.currentTalkData.length) return null;
- return this.currentTalkData;
- },
- // 跳过当前阶段
- skipStage() {
- this.completeStage()
- },
- // 完成当前阶段
- completeStage() {
- if (this.currentStage) {
- // 添加到已完成列表
- this.completedStages.push(this.currentStage.id)
-
- // 如果当前阶段有主线ID,检查该主线的所有阶段是否都已完成
- if (this.currentStage.mainLineId) {
- const mainLineId = this.currentStage.mainLineId
- const mainLineStages = Object.values(this.guideConfig).filter(
- stage => stage.mainLineId === mainLineId
- )
-
- // 检查该主线的所有阶段是否都已完成
- const isMainLineCompleted = mainLineStages.every(
- stage => this.completedStages.includes(stage.id)
- )
-
- // 如果主线完成,添加到已完成主线列表
- // if (isMainLineCompleted && !this.completedMainLines.includes(mainLineId)) {
- // this.completedMainLines.push(mainLineId)
- // }
- }
-
- // 保存到本地存储
- this.saveCompletedStages()
- // this.saveCompletedMainLines()
-
- // 重置状态
- 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() {
- // 加载已完成主线和当前主线ID
- // this.loadCompletedMainLines();
- var _this = this
- _this.guideConfig = { mainLines: [
- {
- name: "new immigrant",
- stage: "homeLand",
- steps: [
- {
- arrow: null,
- talkData: [
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '你好!欢迎来到萌创星球,你的移民计划正式完成。',
- position: 'left',
- isMirror: true
- }
- ]
- },
- {
- arrow: {x: 350, y: 460, r: 0},
- talkData: [
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '这里是工具台 ,它可以制作各实用和非常棒的工具和装饰物,千万不要错过哟。',
- position: 'left',
- isMirror: true
- },
- ]
- }
- ]
- },
- {
- name: "new craftsman",
- stage: "homeLand_table",
- steps: [
- {
- arrow: null,
- talkData: [
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '果然很顺利的打开了工作台呢!',
- position: 'left',
- isMirror: true
- },
- {
- characterImage: _this.picture,
- characterName: _this.name,
- text: '好像可以有好多工具,但是好像没有材料呢~',
- position: 'right',
- isMirror: false
- },
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '材料确实不太容易获取呢,可以去看看公告栏。',
- position: 'left',
- isMirror: true
- }
- ]
- },
- {
- arrow: {x: 885, y: 535, r: 270},
- talkData: [
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '看到小箭头指示的地方了么...那是任务看板,可以获取一些稀有道具和铃钱哦。',
- position: 'left',
- isMirror: true
- }
- ]
- }
- ]
- },
- {
- name: "oh, taskBoard",
- stage: "homeLand_TaskBoard",
- steps: [
- {
- arrow: null,
- talkData: [
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '这里就是任务面板呦....',
- position: 'left',
- isMirror: true
- },
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '顺便说一下,你的移民计划正式开启目前您需要缴纳移民费用为388888元。也在任务面板发布了呦~',
- position: 'left',
- isMirror: true
- },
- {
- characterImage: '/static/island/building/1.png',
- characterName: '我',
- text: '什么!移民费用388888铃钱,这也太贵了吧...',
- position: 'right',
- isMirror: false
- },
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '移民本就是一件不容易的事呢...',
- position: 'left',
- isMirror: true
- },
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '对了,听说近期市政厅那边的花田正在招募园丁,报酬丰厚,',
- position: 'left',
- isMirror: true
- },
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '相信以你的能力完全是没问题的,右侧过桥后就到了。',
- position: 'left',
- isMirror: true
- }
- ]
- }
- ]
- },
- {
- name: "welcome to mainLand~",
- stage: "mainLand",
- steps: [
- {
- arrow: null,
- talkData: [
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '正式欢迎您来到我们的市政厅所在的主岛....',
- position: 'left',
- isMirror: true
- },
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '因为前几天发生了台风,所以还有两条路被倒下的树给拦住了。',
- position: 'left',
- isMirror: true
- },
- {
- characterImage: '/static/island/building/1.png',
- characterName: '我',
- text: 'ah...原来如此,你刚才说的花田有没有被拦住?',
- position: 'right',
- isMirror: false
- }
- ]
- },
- {
- arrow: {x: 785, y: 535, r: 270},
- talkData: [
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '哦~瞧我这记性,花田在市政厅的旁边,就在那儿。走,我会告诉你怎么种花。',
- position: 'left',
- isMirror: true
- }
- ]
- }
- ]
- },
- {
- name: "flowerFarm",
- stage: "mainLand_farm",
- steps: [
- {
- arrow: null,
- talkData: [
- {
- characterImage: '/static/island/npc.png',
- characterName: '罗宾',
- text: '快来吧,这里就是花田了。',
- position: 'left',
- isMirror: true
- }
- ]
- }
- ]
- }
- ]}
-
- this.loadCurrentMainLineId();
- //测试重置主线
- // this.currentMainLineId=0;
- console.log(this.guideConfig,'------------------------');
-
- }
- }
- </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>
|