parent
b2ccf76fd0
commit
1f42e5d713
|
|
@ -1,405 +0,0 @@
|
|||
<template>
|
||||
<div class="spring-couple-container">
|
||||
<!-- 背景图 -->
|
||||
<div class="background">
|
||||
<img
|
||||
v-lazy="backgroundImage"
|
||||
alt="四合院背景"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 春联展示区 -->
|
||||
<div class="couplet-display" v-if="couplet">
|
||||
<div class="couplet-item top-couplet">{{ couplet.top }}</div>
|
||||
<div class="couplet-item bottom-couplet">{{ couplet.bottom }}</div>
|
||||
<div class="couplet-item横批">{{ couplet.横批 }}</div>
|
||||
</div>
|
||||
|
||||
<!-- 输入区域 -->
|
||||
<div class="input-section">
|
||||
<h2 class="title">AI春联生成</h2>
|
||||
<p class="subtitle">输入两个字的关键词,生成个性化春联</p>
|
||||
|
||||
<div class="input-container">
|
||||
<input
|
||||
v-model="keyword"
|
||||
type="text"
|
||||
placeholder="请输入关键词(如:吉祥、如意)"
|
||||
maxlength="2"
|
||||
@input="handleKeywordInput"
|
||||
class="keyword-input"
|
||||
/>
|
||||
<button
|
||||
@click="generateCouple"
|
||||
:disabled="loading || keyword.length < 2"
|
||||
class="generate-btn"
|
||||
>
|
||||
<span v-if="loading">生成中...</span>
|
||||
<span v-else>生成春联</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 推荐关键词 -->
|
||||
<div class="recommended-keywords">
|
||||
<span
|
||||
v-for="word in recommendedWords"
|
||||
:key="word"
|
||||
@click="selectKeyword(word)"
|
||||
class="keyword-tag"
|
||||
>
|
||||
{{ word }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分享按钮 -->
|
||||
<div class="share-section" v-if="couplet">
|
||||
<button @click="shareCouple" class="share-btn">
|
||||
📤 分享春联
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 加载动画 -->
|
||||
<div v-if="loading" class="loading-overlay">
|
||||
<uni-spinner type="circle" size="48" color="#fff"></uni-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from 'vue';
|
||||
import { generateSpringCouple } from '../api/ai';
|
||||
import { share } from '../utils/share';
|
||||
|
||||
// 响应式数据
|
||||
const keyword = ref('');
|
||||
const couplet = ref(null);
|
||||
const loading = ref(false);
|
||||
const backgroundImage = ref('https://placeholder.pics/svg/640x1136/E8F5E9/4CAF50/四合院背景');
|
||||
|
||||
// 推荐关键词
|
||||
const recommendedWords = [
|
||||
'吉祥', '如意', '幸福', '安康', '财源', '富贵', '团圆', '快乐',
|
||||
'平安', '健康', '顺利', '成功', '美满', '和谐', '兴旺', '发达'
|
||||
];
|
||||
|
||||
// 处理关键词输入
|
||||
const handleKeywordInput = () => {
|
||||
// 限制关键词长度为2个字符
|
||||
if (keyword.value.length > 2) {
|
||||
keyword.value = keyword.value.slice(0, 2);
|
||||
}
|
||||
};
|
||||
|
||||
// 选择推荐关键词
|
||||
const selectKeyword = (word) => {
|
||||
keyword.value = word;
|
||||
generateCouple();
|
||||
};
|
||||
|
||||
// 生成春联
|
||||
const generateCouple = async () => {
|
||||
if (!keyword.value || keyword.value.length < 2) {
|
||||
uni.uni.showToast({title: '请输入两个字的关键词', duration: 2000});
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const result = await generateSpringCouple(keyword.value);
|
||||
|
||||
if (result.code === 200) {
|
||||
couplet.value = result.data;
|
||||
uni.uni.showToast({title: '春联生成成功', duration: 2000});
|
||||
// 添加生成动画效果
|
||||
setTimeout(() => {
|
||||
const coupletElements = document.querySelectorAll('.couplet-item');
|
||||
coupletElements.forEach((el, index) => {
|
||||
el.style.opacity = '0';
|
||||
el.style.transform = 'translateY(20px)';
|
||||
|
||||
setTimeout(() => {
|
||||
el.style.transition = 'opacity 0.5s ease, transform 0.5s ease';
|
||||
el.style.opacity = '1';
|
||||
el.style.transform = 'translateY(0)';
|
||||
}, index * 200);
|
||||
});
|
||||
}, 100);
|
||||
} else {
|
||||
uni.uni.showToast({title: '生成失败,请重试', duration: 2000});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('生成春联失败:', error);
|
||||
uni.uni.showToast({title: '网络异常,请稍后重试', duration: 2000});
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 分享春联
|
||||
const shareCouple = () => {
|
||||
if (!couplet.value) {
|
||||
uni.uni.showToast({title: '请先生成春联', duration: 2000});
|
||||
return;
|
||||
}
|
||||
|
||||
const shareText = `
|
||||
我用AI生成了一副春联:
|
||||
${couplet.value.top}
|
||||
${couplet.value.bottom}
|
||||
${couplet.value.横批}
|
||||
#2026新春东城商圈#
|
||||
`;
|
||||
|
||||
// 调用分享工具函数
|
||||
share({
|
||||
title: 'AI春联生成',
|
||||
text: shareText,
|
||||
image: backgroundImage.value
|
||||
});
|
||||
};
|
||||
|
||||
// 处理图片加载错误
|
||||
const handleImageError = (event) => {
|
||||
event.target.src = 'https://placeholder.pics/svg/640x1136/E8F5E9/4CAF50/四合院背景';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.spring-couple-container {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.background img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.couplet-display {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 40px 0;
|
||||
padding: 60px 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.couplet-item {
|
||||
font-family: 'STKaiti', 'Kaiti SC', serif;
|
||||
font-size: 24px;
|
||||
font-weight: bold;
|
||||
color: #e67e22;
|
||||
text-align: center;
|
||||
line-height: 1.8;
|
||||
writing-mode: vertical-rl;
|
||||
text-orientation: upright;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.top-couplet,
|
||||
.bottom-couplet {
|
||||
width: 60px;
|
||||
height: 240px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.横批 {
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
writing-mode: horizontal-tb;
|
||||
font-size: 32px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.input-section {
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border-radius: 20px;
|
||||
padding: 30px;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
z-index: 2;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
color: #e67e22;
|
||||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
margin-bottom: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.keyword-input {
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
border: 2px solid #ddd;
|
||||
border-radius: 10px;
|
||||
font-size: 18px;
|
||||
text-align: center;
|
||||
transition: border-color 0.3s ease;
|
||||
}
|
||||
|
||||
.keyword-input:focus {
|
||||
outline: none;
|
||||
border-color: #e67e22;
|
||||
}
|
||||
|
||||
.generate-btn {
|
||||
padding: 15px 25px;
|
||||
background: linear-gradient(135deg, #e67e22, #d35400);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.generate-btn:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(230, 126, 34, 0.4);
|
||||
}
|
||||
|
||||
.generate-btn:disabled {
|
||||
background: #ddd;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.recommended-keywords {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.keyword-tag {
|
||||
padding: 8px 16px;
|
||||
background: #f39c12;
|
||||
color: white;
|
||||
border-radius: 20px;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.keyword-tag:hover {
|
||||
background: #e67e22;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.share-section {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.share-btn {
|
||||
padding: 15px 30px;
|
||||
background: linear-gradient(135deg, #3498db, #2980b9);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.share-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.4);
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 480px) {
|
||||
.spring-couple-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.couplet-item {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.top-couplet,
|
||||
.bottom-couplet {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.input-section {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.keyword-input,
|
||||
.generate-btn {
|
||||
font-size: 16px;
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.input-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useSceneStore } from '../../src/store/scene'
|
||||
import { useCollectionStore } from '../../src/store/collection'
|
||||
import LongImageViewer from '../components/LongImageViewer.vue'
|
||||
import MediaPlayer from '../components/MediaPlayer.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const sceneStore = useSceneStore()
|
||||
const collectionStore = useCollectionStore()
|
||||
|
||||
// 场景数据
|
||||
const sceneData = ref({
|
||||
id: 'chongwen',
|
||||
name: '崇文商圈',
|
||||
description: '融合传统文化与现代商业的活力区域',
|
||||
image: 'https://picsum.photos/id/1016/750/1600', // 长图占位图
|
||||
thumbnail: 'https://picsum.photos/id/1016/200/100',
|
||||
location: '北京市东城区崇文门外大街',
|
||||
history: '崇文商圈历史悠久,曾是明清时期的文化中心,如今成为现代化的商业区域。',
|
||||
attractions: [
|
||||
{ name: '北京新世界百货', description: '大型综合性购物中心' },
|
||||
{ name: '红桥市场', description: '著名的珍珠和工艺品市场' },
|
||||
{ name: '天坛公园', description: '世界文化遗产,明清皇帝祭天的场所' }
|
||||
],
|
||||
audio: 'https://example.com/audio/chongwen.mp3', // 音频占位符
|
||||
video: 'https://example.com/video/chongwen.mp4' // 视频占位符
|
||||
})
|
||||
|
||||
// 交互状态
|
||||
const isInteractive = ref(false)
|
||||
const sealCollected = ref(false)
|
||||
const showInfoPanel = ref(false)
|
||||
|
||||
// 福印收集状态
|
||||
const sealStatus = computed(() => {
|
||||
return collectionStore.isSceneSealCollected(sceneData.value.id)
|
||||
})
|
||||
|
||||
// 组件挂载后初始化
|
||||
onMounted(() => {
|
||||
// 激活当前场景
|
||||
sceneStore.activateScene(sceneData.value.id)
|
||||
|
||||
// 设置当前场景索引
|
||||
const sceneIndex = sceneStore.scenes.findIndex(scene => scene.id === sceneData.value.id)
|
||||
if (sceneIndex !== -1) {
|
||||
sceneStore.setCurrentScene(sceneIndex)
|
||||
}
|
||||
|
||||
// 检查福印是否已收集
|
||||
sealCollected.value = sealStatus.value
|
||||
})
|
||||
|
||||
// 点击场景交互区域
|
||||
const handleSceneInteraction = () => {
|
||||
if (!isInteractive.value) {
|
||||
isInteractive.value = true
|
||||
|
||||
// 模拟交互过程
|
||||
setTimeout(() => {
|
||||
collectSeal()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
// 收集福印
|
||||
const collectSeal = () => {
|
||||
if (!sealCollected.value) {
|
||||
const success = collectionStore.collectSealBySceneId(sceneData.value.id)
|
||||
if (success) {
|
||||
sealCollected.value = true
|
||||
showToast({
|
||||
message: '恭喜获得崇文门福印!',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} else {
|
||||
showFailToast({
|
||||
message: '福印收集失败',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
} else {
|
||||
showToast({
|
||||
message: '福印已收集',
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 查看场景信息
|
||||
const showSceneInfo = () => {
|
||||
showInfoPanel.value = true
|
||||
}
|
||||
|
||||
// 关闭信息面板
|
||||
const closeInfoPanel = () => {
|
||||
showInfoPanel.value = false
|
||||
}
|
||||
|
||||
// 跳转到下一个场景
|
||||
const goToNextScene = () => {
|
||||
router.push('/wangfujing')
|
||||
}
|
||||
|
||||
// 跳转到上一个场景
|
||||
const goToPreviousScene = () => {
|
||||
router.push('/qianmen')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="scene-page">
|
||||
<!-- 场景标题 -->
|
||||
<div class="scene-header">
|
||||
<h1 class="scene-title">{{ sceneData.name }}</h1>
|
||||
<p class="scene-description">{{ sceneData.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 长图查看器 -->
|
||||
<div class="long-image-container">
|
||||
<LongImageViewer
|
||||
:image-url="sceneData.image"
|
||||
:description="sceneData.name"
|
||||
@click="handleSceneInteraction"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 交互提示 -->
|
||||
<div class="interaction-tip" v-if="!isInteractive">
|
||||
<div class="tip-icon">👆</div>
|
||||
<p>点击图片查看详情</p>
|
||||
</div>
|
||||
|
||||
<!-- 福印收集提示 -->
|
||||
<div class="seal-collect-tip" v-if="sealCollected">
|
||||
<div class="seal-icon">🏮</div>
|
||||
<p>已收集崇文福印</p>
|
||||
</div>
|
||||
|
||||
<!-- 场景信息面板 -->
|
||||
<div class="info-panel" v-if="showInfoPanel">
|
||||
<div class="info-panel-content">
|
||||
<div class="info-panel-header">
|
||||
<h2>场景信息</h2>
|
||||
<button class="close-btn" @click="closeInfoPanel">×</button>
|
||||
</div>
|
||||
|
||||
<div class="info-panel-body">
|
||||
<div class="info-item">
|
||||
<label>名称:</label>
|
||||
<span>{{ sceneData.name }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>位置:</label>
|
||||
<span>{{ sceneData.location }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>历史:</label>
|
||||
<span>{{ sceneData.history }}</span>
|
||||
</div>
|
||||
|
||||
<div class="attractions-section">
|
||||
<h3>主要景点:</h3>
|
||||
<ul class="attractions-list">
|
||||
<li v-for="(attraction, index) in sceneData.attractions" :key="index">
|
||||
<div class="attraction-name">{{ attraction.name }}</div>
|
||||
<div class="attraction-description">{{ attraction.description }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 媒体播放器 -->
|
||||
<div class="media-player-container">
|
||||
<MediaPlayer
|
||||
:audio-url="sceneData.audio"
|
||||
:video-url="sceneData.video"
|
||||
:scene-name="sceneData.name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 场景导航 -->
|
||||
<div class="scene-navigation">
|
||||
<button class="nav-btn prev-btn" @click="goToPreviousScene">
|
||||
上一个
|
||||
</button>
|
||||
<button class="nav-btn info-btn" @click="showSceneInfo">
|
||||
场景信息
|
||||
</button>
|
||||
<button class="nav-btn next-btn" @click="goToNextScene">
|
||||
下一个
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.scene-page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-top: 0.88rem;
|
||||
padding-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
.scene-header {
|
||||
padding: 0.2rem;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-title {
|
||||
font-size: 0.4rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-description {
|
||||
font-size: 0.28rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.long-image-container {
|
||||
width: 100%;
|
||||
height: 5rem;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.interaction-tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 0.3rem 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
z-index: 10;
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-50%, -50%) scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
font-size: 0.6rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.seal-collect-tip {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 0.2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 107, 53, 0.9);
|
||||
color: #fff;
|
||||
padding: 0.15rem 0.3rem;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.seal-icon {
|
||||
font-size: 0.4rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.info-panel-content {
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
background-color: #fff;
|
||||
border-radius: 0.2rem;
|
||||
overflow: hidden;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.info-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.3rem;
|
||||
background-color: #ff6b35;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-panel-header h2 {
|
||||
font-size: 0.36rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 0.4rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-panel-body {
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
}
|
||||
|
||||
.info-item label {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.attractions-section {
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.attractions-section h3 {
|
||||
font-size: 0.32rem;
|
||||
margin-bottom: 0.2rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.attractions-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attractions-list li {
|
||||
margin-bottom: 0.2rem;
|
||||
padding: 0.2rem;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 0.1rem;
|
||||
}
|
||||
|
||||
.attraction-name {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
|
||||
.attraction-description {
|
||||
color: #666;
|
||||
font-size: 0.26rem;
|
||||
}
|
||||
|
||||
.media-player-container {
|
||||
margin: 0.2rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.2rem;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.scene-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
flex: 1;
|
||||
padding: 0.2rem;
|
||||
margin: 0 0.1rem;
|
||||
font-size: 0.3rem;
|
||||
border: none;
|
||||
border-radius: 0.15rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.prev-btn {
|
||||
background-color: #2196f3;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.prev-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info-btn {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.next-btn {
|
||||
background-color: #ff9800;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-btn:hover:not(:disabled) {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useSceneStore } from '../../src/store/scene'
|
||||
import { useCollectionStore } from '../../src/store/collection'
|
||||
import LongImageViewer from '../components/LongImageViewer.vue'
|
||||
import MediaPlayer from '../components/MediaPlayer.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const sceneStore = useSceneStore()
|
||||
const collectionStore = useCollectionStore()
|
||||
|
||||
// 场景数据
|
||||
const sceneData = ref({
|
||||
id: 'dongzhimen',
|
||||
name: '东直门商圈',
|
||||
description: '国际化的交通枢纽与商业中心',
|
||||
image: 'https://picsum.photos/id/1019/750/1600', // 长图占位图
|
||||
thumbnail: 'https://picsum.photos/id/1019/200/100',
|
||||
location: '北京市东城区东直门内大街',
|
||||
history: '东直门商圈是北京重要的交通枢纽,连接着多条地铁线路和长途汽车站,如今成为国际化的商业中心。',
|
||||
attractions: [
|
||||
{ name: '东直门交通枢纽', description: '大型综合交通枢纽' },
|
||||
{ name: '东方银座', description: '高端商务中心' },
|
||||
{ name: '簋街', description: '著名的美食街' }
|
||||
],
|
||||
audio: 'https://example.com/audio/dongzhimen.mp3', // 音频占位符
|
||||
video: 'https://example.com/video/dongzhimen.mp4' // 视频占位符
|
||||
})
|
||||
|
||||
// 交互状态
|
||||
const isInteractive = ref(false)
|
||||
const sealCollected = ref(false)
|
||||
const showInfoPanel = ref(false)
|
||||
|
||||
// 福印收集状态
|
||||
const sealStatus = computed(() => {
|
||||
return collectionStore.isSceneSealCollected(sceneData.value.id)
|
||||
})
|
||||
|
||||
// 组件挂载后初始化
|
||||
onMounted(() => {
|
||||
// 激活当前场景
|
||||
sceneStore.activateScene(sceneData.value.id)
|
||||
|
||||
// 设置当前场景索引
|
||||
const sceneIndex = sceneStore.scenes.findIndex(scene => scene.id === sceneData.value.id)
|
||||
if (sceneIndex !== -1) {
|
||||
sceneStore.setCurrentScene(sceneIndex)
|
||||
}
|
||||
|
||||
// 检查福印是否已收集
|
||||
sealCollected.value = sealStatus.value
|
||||
})
|
||||
|
||||
// 点击场景交互区域
|
||||
const handleSceneInteraction = () => {
|
||||
if (!isInteractive.value) {
|
||||
isInteractive.value = true
|
||||
|
||||
// 模拟交互过程
|
||||
setTimeout(() => {
|
||||
collectSeal()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
// 收集福印
|
||||
const collectSeal = () => {
|
||||
if (!sealCollected.value) {
|
||||
const success = collectionStore.collectSealBySceneId(sceneData.value.id)
|
||||
if (success) {
|
||||
sealCollected.value = true
|
||||
showToast({
|
||||
message: '恭喜获得东直门福印!',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} else {
|
||||
showFailToast({
|
||||
message: '福印收集失败',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
} else {
|
||||
showToast({
|
||||
message: '福印已收集',
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 查看场景信息
|
||||
const showSceneInfo = () => {
|
||||
showInfoPanel.value = true
|
||||
}
|
||||
|
||||
// 关闭信息面板
|
||||
const closeInfoPanel = () => {
|
||||
showInfoPanel.value = false
|
||||
}
|
||||
|
||||
// 跳转到下一个场景
|
||||
const goToNextScene = () => {
|
||||
router.push('/ai-spring')
|
||||
}
|
||||
|
||||
// 跳转到上一个场景
|
||||
const goToPreviousScene = () => {
|
||||
router.push('/longfusi')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="scene-page">
|
||||
<!-- 场景标题 -->
|
||||
<div class="scene-header">
|
||||
<h1 class="scene-title">{{ sceneData.name }}</h1>
|
||||
<p class="scene-description">{{ sceneData.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 长图查看器 -->
|
||||
<div class="long-image-container">
|
||||
<LongImageViewer
|
||||
:image-url="sceneData.image"
|
||||
:description="sceneData.name"
|
||||
@click="handleSceneInteraction"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 交互提示 -->
|
||||
<div class="interaction-tip" v-if="!isInteractive">
|
||||
<div class="tip-icon">👆</div>
|
||||
<p>点击图片查看详情</p>
|
||||
</div>
|
||||
|
||||
<!-- 福印收集提示 -->
|
||||
<div class="seal-collect-tip" v-if="sealCollected">
|
||||
<div class="seal-icon">🏮</div>
|
||||
<p>已收集东直门福印</p>
|
||||
</div>
|
||||
|
||||
<!-- 场景信息面板 -->
|
||||
<div class="info-panel" v-if="showInfoPanel">
|
||||
<div class="info-panel-content">
|
||||
<div class="info-panel-header">
|
||||
<h2>场景信息</h2>
|
||||
<button class="close-btn" @click="closeInfoPanel">×</button>
|
||||
</div>
|
||||
|
||||
<div class="info-panel-body">
|
||||
<div class="info-item">
|
||||
<label>名称:</label>
|
||||
<span>{{ sceneData.name }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>位置:</label>
|
||||
<span>{{ sceneData.location }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>历史:</label>
|
||||
<span>{{ sceneData.history }}</span>
|
||||
</div>
|
||||
|
||||
<div class="attractions-section">
|
||||
<h3>主要景点:</h3>
|
||||
<ul class="attractions-list">
|
||||
<li v-for="(attraction, index) in sceneData.attractions" :key="index">
|
||||
<div class="attraction-name">{{ attraction.name }}</div>
|
||||
<div class="attraction-description">{{ attraction.description }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 媒体播放器 -->
|
||||
<div class="media-player-container">
|
||||
<MediaPlayer
|
||||
:audio-url="sceneData.audio"
|
||||
:video-url="sceneData.video"
|
||||
:scene-name="sceneData.name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 场景导航 -->
|
||||
<div class="scene-navigation">
|
||||
<button class="nav-btn prev-btn" @click="goToPreviousScene">
|
||||
上一个
|
||||
</button>
|
||||
<button class="nav-btn info-btn" @click="showSceneInfo">
|
||||
场景信息
|
||||
</button>
|
||||
<button class="nav-btn next-btn" @click="goToNextScene">
|
||||
下一个
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.scene-page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-top: 0.88rem;
|
||||
padding-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
.scene-header {
|
||||
padding: 0.2rem;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-title {
|
||||
font-size: 0.4rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-description {
|
||||
font-size: 0.28rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.long-image-container {
|
||||
width: 100%;
|
||||
height: 5rem;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.interaction-tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 0.3rem 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
z-index: 10;
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-50%, -50%) scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
font-size: 0.6rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.seal-collect-tip {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 0.2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 107, 53, 0.9);
|
||||
color: #fff;
|
||||
padding: 0.15rem 0.3rem;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.seal-icon {
|
||||
font-size: 0.4rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.info-panel-content {
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
background-color: #fff;
|
||||
border-radius: 0.2rem;
|
||||
overflow: hidden;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.info-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.3rem;
|
||||
background-color: #ff6b35;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-panel-header h2 {
|
||||
font-size: 0.36rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 0.4rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-panel-body {
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
}
|
||||
|
||||
.info-item label {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.attractions-section {
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.attractions-section h3 {
|
||||
font-size: 0.32rem;
|
||||
margin-bottom: 0.2rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.attractions-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attractions-list li {
|
||||
margin-bottom: 0.2rem;
|
||||
padding: 0.2rem;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 0.1rem;
|
||||
}
|
||||
|
||||
.attraction-name {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
|
||||
.attraction-description {
|
||||
color: #666;
|
||||
font-size: 0.26rem;
|
||||
}
|
||||
|
||||
.media-player-container {
|
||||
margin: 0.2rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.2rem;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.scene-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
flex: 1;
|
||||
padding: 0.2rem;
|
||||
margin: 0 0.1rem;
|
||||
font-size: 0.3rem;
|
||||
border: none;
|
||||
border-radius: 0.15rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.prev-btn {
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.prev-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info-btn {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.next-btn {
|
||||
background-color: #2196f3;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-btn:hover:not(:disabled) {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,489 +0,0 @@
|
|||
<template>
|
||||
<div class="end-page-container">
|
||||
<!-- 背景图 -->
|
||||
<div class="background">
|
||||
<img
|
||||
v-lazy="backgroundImage"
|
||||
alt="结束页背景"
|
||||
@error="handleImageError"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 标题 -->
|
||||
<h1 class="title">🎉 恭喜完成全部场景游览 🎉</h1>
|
||||
|
||||
<!-- 福印收集展示 -->
|
||||
<div class="seal-collection-section">
|
||||
<h2 class="section-title">福印收集成果</h2>
|
||||
|
||||
<!-- 收集进度 -->
|
||||
<div class="collection-progress">
|
||||
<div class="progress-bar">
|
||||
<div
|
||||
class="progress-fill"
|
||||
:style="{ width: `${progressPercentage}%` }"
|
||||
></div>
|
||||
</div>
|
||||
<p class="progress-text">
|
||||
已收集 {{ collectedSeals.length }} / {{ totalSeals }} 个福印
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- 福印列表 -->
|
||||
<div class="seal-grid">
|
||||
<div
|
||||
v-for="seal in allSeals"
|
||||
:key="seal.id"
|
||||
class="seal-item"
|
||||
:class="{ 'collected': seal.collected }"
|
||||
>
|
||||
<div class="seal-image">
|
||||
<img
|
||||
v-lazy="seal.collected ? seal.image : uncollectedImage"
|
||||
:alt="seal.name"
|
||||
/>
|
||||
</div>
|
||||
<div class="seal-name">{{ seal.name }}</div>
|
||||
<div class="seal-status" :class="{ 'collected-status': seal.collected }">
|
||||
{{ seal.collected ? '已收集' : '未收集' }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 全部收集奖励 -->
|
||||
<div class="full-collection-reward" v-if="allCollected">
|
||||
<div class="reward-content">
|
||||
<div class="reward-icon">🏆</div>
|
||||
<h3>恭喜集齐全部福印!</h3>
|
||||
<p>您已完成所有商圈的探索,获得了完整的福印收集成就!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="action-buttons">
|
||||
<button @click="restartTour" class="btn restart-btn">
|
||||
重新游览
|
||||
</button>
|
||||
<button @click="generateCouple" class="btn couple-btn">
|
||||
生成AI春联
|
||||
</button>
|
||||
<button @click="participateLottery" class="btn lottery-btn">
|
||||
参与抽奖
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 分享按钮 -->
|
||||
<div class="share-section">
|
||||
<button @click="shareResult" class="share-btn">
|
||||
📤 分享我的成果
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- 加载动画 -->
|
||||
<div v-if="loading" class="loading-overlay">
|
||||
<uni-spinner type="circle" size="48" color="#fff"></uni-spinner>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, computed, onMounted } from 'vue';
|
||||
import { useRouter } from 'vue-router';
|
||||
import { useCollectionStore } from '../../src/store/collection';
|
||||
import { share } from '../utils/share';
|
||||
|
||||
const router = useRouter();
|
||||
const collectionStore = useCollectionStore();
|
||||
|
||||
// 响应式数据
|
||||
const loading = ref(false);
|
||||
const backgroundImage = ref('/static/bg/bg_finish.jpg');
|
||||
const uncollectedImage = ref('https://placeholder.pics/svg/100x100/CCCCCC/999999/未收集');
|
||||
|
||||
// 计算属性
|
||||
const allSeals = computed(() => {
|
||||
return collectionStore.seals;
|
||||
});
|
||||
|
||||
const collectedSeals = computed(() => {
|
||||
return collectionStore.collectedSeals;
|
||||
});
|
||||
|
||||
const totalSeals = computed(() => {
|
||||
return allSeals.value.length;
|
||||
});
|
||||
|
||||
const progressPercentage = computed(() => {
|
||||
return collectionStore.getCollectionProgress;
|
||||
});
|
||||
|
||||
const allCollected = computed(() => {
|
||||
return collectionStore.isAllCollected;
|
||||
});
|
||||
|
||||
// 组件挂载后初始化
|
||||
onMounted(() => {
|
||||
// 如果是全部收集,显示特殊效果
|
||||
if (allCollected.value) {
|
||||
uni.showToast({
|
||||
title: '恭喜集齐全部福印!',
|
||||
icon: 'success',
|
||||
duration: 3000
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 重新游览
|
||||
const restartTour = () => {
|
||||
// 重置收集状态
|
||||
collectionStore.resetCollection();
|
||||
// 跳转到首页
|
||||
router.push('/');
|
||||
};
|
||||
|
||||
// 生成AI春联
|
||||
const generateCouple = () => {
|
||||
router.push('/ai-spring');
|
||||
};
|
||||
|
||||
// 参与抽奖
|
||||
const participateLottery = () => {
|
||||
router.push('/');
|
||||
uni.showToast({
|
||||
title: '抽奖功能请在首页参与',
|
||||
icon: 'none',
|
||||
duration: 2000
|
||||
});
|
||||
};
|
||||
|
||||
// 分享成果
|
||||
const shareResult = () => {
|
||||
const shareText = `
|
||||
我在2026新春东城商圈H5中完成了全部场景游览!
|
||||
已收集 ${collectedSeals.value.length} / ${totalSeals.value} 个福印
|
||||
#2026新春东城商圈#
|
||||
`;
|
||||
|
||||
// 调用分享工具函数
|
||||
share(
|
||||
'新春商圈游览成果',
|
||||
shareText,
|
||||
backgroundImage.value
|
||||
);
|
||||
};
|
||||
|
||||
// 处理图片加载错误
|
||||
const handleImageError = (event) => {
|
||||
event.target.src = 'https://placeholder.pics/svg/640x1136/FDF2E9/F39C12/结束页背景';
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.end-page-container {
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.background {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.background img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 28px;
|
||||
color: #f39c12;
|
||||
text-align: center;
|
||||
margin: 40px 0 30px;
|
||||
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.seal-collection-section {
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 20px;
|
||||
padding: 25px;
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 24px;
|
||||
color: #e67e22;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.collection-progress {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 15px;
|
||||
background: #e0e0e0;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(135deg, #f39c12, #e67e22);
|
||||
border-radius: 10px;
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
color: #666;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.seal-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.seal-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 15px;
|
||||
background: #f9f9f9;
|
||||
border-radius: 15px;
|
||||
transition: all 0.3s ease;
|
||||
border: 2px solid #ddd;
|
||||
}
|
||||
|
||||
.seal-item.collected {
|
||||
background: linear-gradient(135deg, #fff9c4, #fff59d);
|
||||
border-color: #ffd740;
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.seal-image {
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
margin-bottom: 10px;
|
||||
background: #fff;
|
||||
border: 3px solid #e67e22;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.seal-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.seal-name {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.seal-status {
|
||||
font-size: 14px;
|
||||
color: #999;
|
||||
padding: 3px 8px;
|
||||
border-radius: 10px;
|
||||
background: #eee;
|
||||
}
|
||||
|
||||
.seal-status.collected-status {
|
||||
color: #4caf50;
|
||||
background: #e8f5e9;
|
||||
}
|
||||
|
||||
.full-collection-reward {
|
||||
background: linear-gradient(135deg, #ffeb3b, #ffc107);
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
box-shadow: 0 4px 12px rgba(255, 193, 7, 0.3);
|
||||
animation: glow 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
0%, 100% {
|
||||
box-shadow: 0 4px 12px rgba(255, 193, 7, 0.3);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0 6px 18px rgba(255, 193, 7, 0.6);
|
||||
}
|
||||
}
|
||||
|
||||
.reward-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.reward-icon {
|
||||
font-size: 64px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.reward-content h3 {
|
||||
font-size: 22px;
|
||||
color: #e65100;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.reward-content p {
|
||||
font-size: 16px;
|
||||
color: #8d6e63;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 15px 25px;
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.restart-btn {
|
||||
background: linear-gradient(135deg, #95a5a6, #7f8c8d);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.restart-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(149, 165, 166, 0.4);
|
||||
}
|
||||
|
||||
.couple-btn {
|
||||
background: linear-gradient(135deg, #e67e22, #d35400);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.couple-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(230, 126, 34, 0.4);
|
||||
}
|
||||
|
||||
.lottery-btn {
|
||||
background: linear-gradient(135deg, #e74c3c, #c0392b);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.lottery-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(231, 76, 60, 0.4);
|
||||
}
|
||||
|
||||
.share-section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.share-btn {
|
||||
padding: 15px 30px;
|
||||
background: linear-gradient(135deg, #3498db, #2980b9);
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 25px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.share-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.4);
|
||||
}
|
||||
|
||||
.loading-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 480px) {
|
||||
.title {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
.seal-collection-section {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.seal-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.seal-image {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
}
|
||||
|
||||
.seal-name {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-size: 16px;
|
||||
padding: 12px 20px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useSceneStore } from '../../src/store/scene'
|
||||
import { useCollectionStore } from '../../src/store/collection'
|
||||
import LongImageViewer from '../components/LongImageViewer.vue'
|
||||
import MediaPlayer from '../components/MediaPlayer.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const sceneStore = useSceneStore()
|
||||
const collectionStore = useCollectionStore()
|
||||
|
||||
// 场景数据
|
||||
const sceneData = ref({
|
||||
id: 'longfusi',
|
||||
name: '隆福寺商圈',
|
||||
description: '融合传统文化与现代艺术的新兴商圈',
|
||||
image: 'https://picsum.photos/id/1018/750/1600', // 长图占位图
|
||||
thumbnail: 'https://picsum.photos/id/1018/200/100',
|
||||
location: '北京市东城区隆福寺街',
|
||||
history: '隆福寺商圈历史悠久,曾是明清时期的重要庙会场所,如今成为融合传统文化与现代艺术的新兴商业区域。',
|
||||
attractions: [
|
||||
{ name: '隆福寺', description: '历史悠久的佛教寺院' },
|
||||
{ name: '隆福文化中心', description: '现代化的文化艺术中心' },
|
||||
{ name: '隆福广场', description: '时尚潮流的购物中心' }
|
||||
],
|
||||
audio: 'https://example.com/audio/longfusi.mp3', // 音频占位符
|
||||
video: 'https://example.com/video/longfusi.mp4' // 视频占位符
|
||||
})
|
||||
|
||||
// 交互状态
|
||||
const isInteractive = ref(false)
|
||||
const sealCollected = ref(false)
|
||||
const showInfoPanel = ref(false)
|
||||
|
||||
// 福印收集状态
|
||||
const sealStatus = computed(() => {
|
||||
return collectionStore.isSceneSealCollected(sceneData.value.id)
|
||||
})
|
||||
|
||||
// 组件挂载后初始化
|
||||
onMounted(() => {
|
||||
// 激活当前场景
|
||||
sceneStore.activateScene(sceneData.value.id)
|
||||
|
||||
// 设置当前场景索引
|
||||
const sceneIndex = sceneStore.scenes.findIndex(scene => scene.id === sceneData.value.id)
|
||||
if (sceneIndex !== -1) {
|
||||
sceneStore.setCurrentScene(sceneIndex)
|
||||
}
|
||||
|
||||
// 检查福印是否已收集
|
||||
sealCollected.value = sealStatus.value
|
||||
})
|
||||
|
||||
// 点击场景交互区域
|
||||
const handleSceneInteraction = () => {
|
||||
if (!isInteractive.value) {
|
||||
isInteractive.value = true
|
||||
|
||||
// 模拟交互过程
|
||||
setTimeout(() => {
|
||||
collectSeal()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
// 收集福印
|
||||
const collectSeal = () => {
|
||||
if (!sealCollected.value) {
|
||||
const success = collectionStore.collectSealBySceneId(sceneData.value.id)
|
||||
if (success) {
|
||||
sealCollected.value = true
|
||||
showToast({
|
||||
message: '恭喜获得隆福寺福印!',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} else {
|
||||
showFailToast({
|
||||
message: '福印收集失败',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
} else {
|
||||
showToast({
|
||||
message: '福印已收集',
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 查看场景信息
|
||||
const showSceneInfo = () => {
|
||||
showInfoPanel.value = true
|
||||
}
|
||||
|
||||
// 关闭信息面板
|
||||
const closeInfoPanel = () => {
|
||||
showInfoPanel.value = false
|
||||
}
|
||||
|
||||
// 跳转到下一个场景
|
||||
const goToNextScene = () => {
|
||||
router.push('/dongzhimen')
|
||||
}
|
||||
|
||||
// 跳转到上一个场景
|
||||
const goToPreviousScene = () => {
|
||||
router.push('/wangfujing')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="scene-page">
|
||||
<!-- 场景标题 -->
|
||||
<div class="scene-header">
|
||||
<h1 class="scene-title">{{ sceneData.name }}</h1>
|
||||
<p class="scene-description">{{ sceneData.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 长图查看器 -->
|
||||
<div class="long-image-container">
|
||||
<LongImageViewer
|
||||
:image-url="sceneData.image"
|
||||
:description="sceneData.name"
|
||||
@click="handleSceneInteraction"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 交互提示 -->
|
||||
<div class="interaction-tip" v-if="!isInteractive">
|
||||
<div class="tip-icon"><EFBFBD><EFBFBD></div>
|
||||
<p>点击图片查看详情</p>
|
||||
</div>
|
||||
|
||||
<!-- 福印收集提示 -->
|
||||
<div class="seal-collect-tip" v-if="sealCollected">
|
||||
<div class="seal-icon"><EFBFBD><EFBFBD></div>
|
||||
<p>已收集隆福寺福印</p>
|
||||
</div>
|
||||
|
||||
<!-- 场景信息面板 -->
|
||||
<div class="info-panel" v-if="showInfoPanel">
|
||||
<div class="info-panel-content">
|
||||
<div class="info-panel-header">
|
||||
<h2>场景信息</h2>
|
||||
<button class="close-btn" @click="closeInfoPanel">×</button>
|
||||
</div>
|
||||
|
||||
<div class="info-panel-body">
|
||||
<div class="info-item">
|
||||
<label>名称:</label>
|
||||
<span>{{ sceneData.name }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>位置:</label>
|
||||
<span>{{ sceneData.location }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>历史:</label>
|
||||
<span>{{ sceneData.history }}</span>
|
||||
</div>
|
||||
|
||||
<div class="attractions-section">
|
||||
<h3>主要景点:</h3>
|
||||
<ul class="attractions-list">
|
||||
<li v-for="(attraction, index) in sceneData.attractions" :key="index">
|
||||
<div class="attraction-name">{{ attraction.name }}</div>
|
||||
<div class="attraction-description">{{ attraction.description }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 媒体播放器 -->
|
||||
<div class="media-player-container">
|
||||
<MediaPlayer
|
||||
:audio-url="sceneData.audio"
|
||||
:video-url="sceneData.video"
|
||||
:scene-name="sceneData.name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 场景导航 -->
|
||||
<div class="scene-navigation">
|
||||
<button class="nav-btn prev-btn" @click="goToPreviousScene">
|
||||
上一个
|
||||
</button>
|
||||
<button class="nav-btn info-btn" @click="showSceneInfo">
|
||||
场景信息
|
||||
</button>
|
||||
<button class="nav-btn next-btn" @click="goToNextScene">
|
||||
下一个
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.scene-page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-top: 0.88rem;
|
||||
padding-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
.scene-header {
|
||||
padding: 0.2rem;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-title {
|
||||
font-size: 0.4rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-description {
|
||||
font-size: 0.28rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.long-image-container {
|
||||
width: 100%;
|
||||
height: 5rem;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.interaction-tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 0.3rem 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
z-index: 10;
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-50%, -50%) scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
font-size: 0.6rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.seal-collect-tip {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 0.2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 107, 53, 0.9);
|
||||
color: #fff;
|
||||
padding: 0.15rem 0.3rem;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.seal-icon {
|
||||
font-size: 0.4rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.info-panel-content {
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
background-color: #fff;
|
||||
border-radius: 0.2rem;
|
||||
overflow: hidden;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.info-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.3rem;
|
||||
background-color: #ff6b35;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-panel-header h2 {
|
||||
font-size: 0.36rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 0.4rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-panel-body {
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
}
|
||||
|
||||
.info-item label {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.attractions-section {
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.attractions-section h3 {
|
||||
font-size: 0.32rem;
|
||||
margin-bottom: 0.2rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.attractions-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attractions-list li {
|
||||
margin-bottom: 0.2rem;
|
||||
padding: 0.2rem;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 0.1rem;
|
||||
}
|
||||
|
||||
.attraction-name {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
|
||||
.attraction-description {
|
||||
color: #666;
|
||||
font-size: 0.26rem;
|
||||
}
|
||||
|
||||
.media-player-container {
|
||||
margin: 0.2rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.2rem;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.scene-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
flex: 1;
|
||||
padding: 0.2rem;
|
||||
margin: 0 0.1rem;
|
||||
font-size: 0.3rem;
|
||||
border: none;
|
||||
border-radius: 0.15rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.prev-btn {
|
||||
background-color: #9c27b0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.prev-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info-btn {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.next-btn {
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-btn:hover:not(:disabled) {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useSceneStore } from '../../src/store/scene'
|
||||
import { useCollectionStore } from '../../src/store/collection'
|
||||
import LongImageViewer from '../components/LongImageViewer.vue'
|
||||
import MediaPlayer from '../components/MediaPlayer.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const sceneStore = useSceneStore()
|
||||
const collectionStore = useCollectionStore()
|
||||
|
||||
// 场景数据
|
||||
const sceneData = ref({
|
||||
id: 'qianmen',
|
||||
name: '前门商圈',
|
||||
description: '北京最具历史文化底蕴的商圈之一',
|
||||
image: 'https://picsum.photos/id/1015/750/1600', // 长图占位图
|
||||
thumbnail: 'https://picsum.photos/id/1015/200/100',
|
||||
location: '北京市东城区前门大街',
|
||||
history: '前门大街形成于明代,已有600多年历史,是北京最古老的商业街之一。',
|
||||
attractions: [
|
||||
{ name: '前门大街', description: '北京著名的商业街,汇集众多老字号' },
|
||||
{ name: '大栅栏', description: '明清时期的商业中心,保留大量传统建筑' },
|
||||
{ name: '天安门广场', description: '世界最大的城市广场,中国的象征' }
|
||||
],
|
||||
audio: 'https://example.com/audio/qianmen.mp3', // 音频占位符
|
||||
video: 'https://example.com/video/qianmen.mp4' // 视频占位符
|
||||
})
|
||||
|
||||
// 交互状态
|
||||
const isInteractive = ref(false)
|
||||
const sealCollected = ref(false)
|
||||
const showInfoPanel = ref(false)
|
||||
|
||||
// 福印收集状态
|
||||
const sealStatus = computed(() => {
|
||||
return collectionStore.isSceneSealCollected(sceneData.value.id)
|
||||
})
|
||||
|
||||
// 组件挂载后初始化
|
||||
onMounted(() => {
|
||||
// 激活当前场景
|
||||
sceneStore.activateScene(sceneData.value.id)
|
||||
|
||||
// 设置当前场景索引
|
||||
const sceneIndex = sceneStore.scenes.findIndex(scene => scene.id === sceneData.value.id)
|
||||
if (sceneIndex !== -1) {
|
||||
sceneStore.setCurrentScene(sceneIndex)
|
||||
}
|
||||
|
||||
// 检查福印是否已收集
|
||||
sealCollected.value = sealStatus.value
|
||||
})
|
||||
|
||||
// 点击场景交互区域
|
||||
const handleSceneInteraction = () => {
|
||||
if (!isInteractive.value) {
|
||||
isInteractive.value = true
|
||||
|
||||
// 模拟交互过程
|
||||
setTimeout(() => {
|
||||
collectSeal()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
// 收集福印
|
||||
const collectSeal = () => {
|
||||
if (!sealCollected.value) {
|
||||
const success = collectionStore.collectSealBySceneId(sceneData.value.id)
|
||||
if (success) {
|
||||
sealCollected.value = true
|
||||
showToast({
|
||||
message: '恭喜获得前门福印!',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} else {
|
||||
showFailToast({
|
||||
message: '福印收集失败',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
} else {
|
||||
showToast({
|
||||
message: '福印已收集',
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 查看场景信息
|
||||
const showSceneInfo = () => {
|
||||
showInfoPanel.value = true
|
||||
}
|
||||
|
||||
// 关闭信息面板
|
||||
const closeInfoPanel = () => {
|
||||
showInfoPanel.value = false
|
||||
}
|
||||
|
||||
// 跳转到下一个场景
|
||||
const goToNextScene = () => {
|
||||
router.push('/chongwen')
|
||||
}
|
||||
|
||||
// 跳转到上一个场景
|
||||
const goToPreviousScene = () => {
|
||||
Toast('已经是第一个场景了')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="scene-page">
|
||||
<!-- 场景标题 -->
|
||||
<div class="scene-header">
|
||||
<h1 class="scene-title">{{ sceneData.name }}</h1>
|
||||
<p class="scene-description">{{ sceneData.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 长图查看器 -->
|
||||
<div class="long-image-container">
|
||||
<LongImageViewer
|
||||
:image-url="sceneData.image"
|
||||
:description="sceneData.name"
|
||||
@click="handleSceneInteraction"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 交互提示 -->
|
||||
<div class="interaction-tip" v-if="!isInteractive">
|
||||
<div class="tip-icon">👆</div>
|
||||
<p>点击图片查看详情</p>
|
||||
</div>
|
||||
|
||||
<!-- 福印收集提示 -->
|
||||
<div class="seal-collect-tip" v-if="sealCollected">
|
||||
<div class="seal-icon">🏮</div>
|
||||
<p>已收集前门福印</p>
|
||||
</div>
|
||||
|
||||
<!-- 场景信息面板 -->
|
||||
<div class="info-panel" v-if="showInfoPanel">
|
||||
<div class="info-panel-content">
|
||||
<div class="info-panel-header">
|
||||
<h2>场景信息</h2>
|
||||
<button class="close-btn" @click="closeInfoPanel">×</button>
|
||||
</div>
|
||||
|
||||
<div class="info-panel-body">
|
||||
<div class="info-item">
|
||||
<label>名称:</label>
|
||||
<span>{{ sceneData.name }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>位置:</label>
|
||||
<span>{{ sceneData.location }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>历史:</label>
|
||||
<span>{{ sceneData.history }}</span>
|
||||
</div>
|
||||
|
||||
<div class="attractions-section">
|
||||
<h3>主要景点:</h3>
|
||||
<ul class="attractions-list">
|
||||
<li v-for="(attraction, index) in sceneData.attractions" :key="index">
|
||||
<div class="attraction-name">{{ attraction.name }}</div>
|
||||
<div class="attraction-description">{{ attraction.description }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 媒体播放器 -->
|
||||
<div class="media-player-container">
|
||||
<MediaPlayer
|
||||
:audio-url="sceneData.audio"
|
||||
:video-url="sceneData.video"
|
||||
:scene-name="sceneData.name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 场景导航 -->
|
||||
<div class="scene-navigation">
|
||||
<button class="nav-btn prev-btn" @click="goToPreviousScene">
|
||||
上一个
|
||||
</button>
|
||||
<button class="nav-btn info-btn" @click="showSceneInfo">
|
||||
场景信息
|
||||
</button>
|
||||
<button class="nav-btn next-btn" @click="goToNextScene">
|
||||
下一个
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.scene-page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-top: 0.88rem;
|
||||
padding-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
.scene-header {
|
||||
padding: 0.2rem;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-title {
|
||||
font-size: 0.4rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-description {
|
||||
font-size: 0.28rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.long-image-container {
|
||||
width: 100%;
|
||||
height: 5rem;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.interaction-tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 0.3rem 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
z-index: 10;
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-50%, -50%) scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
font-size: 0.6rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.seal-collect-tip {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 0.2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 107, 53, 0.9);
|
||||
color: #fff;
|
||||
padding: 0.15rem 0.3rem;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.seal-icon {
|
||||
font-size: 0.4rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.info-panel-content {
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
background-color: #fff;
|
||||
border-radius: 0.2rem;
|
||||
overflow: hidden;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.info-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.3rem;
|
||||
background-color: #ff6b35;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-panel-header h2 {
|
||||
font-size: 0.36rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 0.4rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-panel-body {
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
}
|
||||
|
||||
.info-item label {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.attractions-section {
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.attractions-section h3 {
|
||||
font-size: 0.32rem;
|
||||
margin-bottom: 0.2rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.attractions-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attractions-list li {
|
||||
margin-bottom: 0.2rem;
|
||||
padding: 0.2rem;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 0.1rem;
|
||||
}
|
||||
|
||||
.attraction-name {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
|
||||
.attraction-description {
|
||||
color: #666;
|
||||
font-size: 0.26rem;
|
||||
}
|
||||
|
||||
.media-player-container {
|
||||
margin: 0.2rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.2rem;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.scene-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
flex: 1;
|
||||
padding: 0.2rem;
|
||||
margin: 0 0.1rem;
|
||||
font-size: 0.3rem;
|
||||
border: none;
|
||||
border-radius: 0.15rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.prev-btn {
|
||||
background-color: #e0e0e0;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.prev-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info-btn {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.next-btn {
|
||||
background-color: #2196f3;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-btn:hover:not(:disabled) {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
<script setup>
|
||||
import { ref, onMounted, computed } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useSceneStore } from '../../src/store/scene'
|
||||
import { useCollectionStore } from '../../src/store/collection'
|
||||
import LongImageViewer from '../components/LongImageViewer.vue'
|
||||
import MediaPlayer from '../components/MediaPlayer.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const sceneStore = useSceneStore()
|
||||
const collectionStore = useCollectionStore()
|
||||
|
||||
// 场景数据
|
||||
const sceneData = ref({
|
||||
id: 'wangfujing',
|
||||
name: '王府井商圈',
|
||||
description: '北京最繁华的商业中心之一',
|
||||
image: 'https://picsum.photos/id/1018/750/1600', // 长图占位图
|
||||
thumbnail: 'https://picsum.photos/id/1018/200/100',
|
||||
location: '北京市东城区王府井大街',
|
||||
history: '王府井商圈已有百年历史,是北京著名的商业步行街,汇聚了众多国内外知名品牌。',
|
||||
attractions: [
|
||||
{ name: '王府井步行街', description: '北京最著名的商业步行街' },
|
||||
{ name: '东方新天地', description: '高端购物中心' },
|
||||
{ name: '北京apm', description: '时尚潮流购物中心' }
|
||||
],
|
||||
audio: 'https://example.com/audio/wangfujing.mp3', // 音频占位符
|
||||
video: 'https://example.com/video/wangfujing.mp4' // 视频占位符
|
||||
})
|
||||
|
||||
// 交互状态
|
||||
const isInteractive = ref(false)
|
||||
const sealCollected = ref(false)
|
||||
const showInfoPanel = ref(false)
|
||||
|
||||
// 福印收集状态
|
||||
const sealStatus = computed(() => {
|
||||
return collectionStore.isSceneSealCollected(sceneData.value.id)
|
||||
})
|
||||
|
||||
// 组件挂载后初始化
|
||||
onMounted(() => {
|
||||
// 激活当前场景
|
||||
sceneStore.activateScene(sceneData.value.id)
|
||||
|
||||
// 设置当前场景索引
|
||||
const sceneIndex = sceneStore.scenes.findIndex(scene => scene.id === sceneData.value.id)
|
||||
if (sceneIndex !== -1) {
|
||||
sceneStore.setCurrentScene(sceneIndex)
|
||||
}
|
||||
|
||||
// 检查福印是否已收集
|
||||
sealCollected.value = sealStatus.value
|
||||
})
|
||||
|
||||
// 点击场景交互区域
|
||||
const handleSceneInteraction = () => {
|
||||
if (!isInteractive.value) {
|
||||
isInteractive.value = true
|
||||
|
||||
// 模拟交互过程
|
||||
setTimeout(() => {
|
||||
collectSeal()
|
||||
}, 1000)
|
||||
}
|
||||
}
|
||||
|
||||
// 收集福印
|
||||
const collectSeal = () => {
|
||||
if (!sealCollected.value) {
|
||||
const success = collectionStore.collectSealBySceneId(sceneData.value.id)
|
||||
if (success) {
|
||||
sealCollected.value = true
|
||||
showToast({
|
||||
message: '恭喜获得王府井福印!',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
} else {
|
||||
showFailToast({
|
||||
message: '福印收集失败',
|
||||
duration: 2000
|
||||
})
|
||||
}
|
||||
} else {
|
||||
showToast({
|
||||
message: '福印已收集',
|
||||
duration: 1500
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 查看场景信息
|
||||
const showSceneInfo = () => {
|
||||
showInfoPanel.value = true
|
||||
}
|
||||
|
||||
// 关闭信息面板
|
||||
const closeInfoPanel = () => {
|
||||
showInfoPanel.value = false
|
||||
}
|
||||
|
||||
// 跳转到下一个场景
|
||||
const goToNextScene = () => {
|
||||
router.push('/longfusi')
|
||||
}
|
||||
|
||||
// 跳转到上一个场景
|
||||
const goToPreviousScene = () => {
|
||||
router.push('/chongwen')
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="scene-page">
|
||||
<!-- 场景标题 -->
|
||||
<div class="scene-header">
|
||||
<h1 class="scene-title">{{ sceneData.name }}</h1>
|
||||
<p class="scene-description">{{ sceneData.description }}</p>
|
||||
</div>
|
||||
|
||||
<!-- 长图查看器 -->
|
||||
<div class="long-image-container">
|
||||
<LongImageViewer
|
||||
:image-url="sceneData.image"
|
||||
:description="sceneData.name"
|
||||
@click="handleSceneInteraction"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 交互提示 -->
|
||||
<div class="interaction-tip" v-if="!isInteractive">
|
||||
<div class="tip-icon"><EFBFBD><EFBFBD></div>
|
||||
<p>点击图片查看详情</p>
|
||||
</div>
|
||||
|
||||
<!-- 福印收集提示 -->
|
||||
<div class="seal-collect-tip" v-if="sealCollected">
|
||||
<div class="seal-icon"><EFBFBD><EFBFBD></div>
|
||||
<p>已收集王府井福印</p>
|
||||
</div>
|
||||
|
||||
<!-- 场景信息面板 -->
|
||||
<div class="info-panel" v-if="showInfoPanel">
|
||||
<div class="info-panel-content">
|
||||
<div class="info-panel-header">
|
||||
<h2>场景信息</h2>
|
||||
<button class="close-btn" @click="closeInfoPanel">×</button>
|
||||
</div>
|
||||
|
||||
<div class="info-panel-body">
|
||||
<div class="info-item">
|
||||
<label>名称:</label>
|
||||
<span>{{ sceneData.name }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>位置:</label>
|
||||
<span>{{ sceneData.location }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<label>历史:</label>
|
||||
<span>{{ sceneData.history }}</span>
|
||||
</div>
|
||||
|
||||
<div class="attractions-section">
|
||||
<h3>主要景点:</h3>
|
||||
<ul class="attractions-list">
|
||||
<li v-for="(attraction, index) in sceneData.attractions" :key="index">
|
||||
<div class="attraction-name">{{ attraction.name }}</div>
|
||||
<div class="attraction-description">{{ attraction.description }}</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 媒体播放器 -->
|
||||
<div class="media-player-container">
|
||||
<MediaPlayer
|
||||
:audio-url="sceneData.audio"
|
||||
:video-url="sceneData.video"
|
||||
:scene-name="sceneData.name"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 场景导航 -->
|
||||
<div class="scene-navigation">
|
||||
<button class="nav-btn prev-btn" @click="goToPreviousScene">
|
||||
上一个
|
||||
</button>
|
||||
<button class="nav-btn info-btn" @click="showSceneInfo">
|
||||
场景信息
|
||||
</button>
|
||||
<button class="nav-btn next-btn" @click="goToNextScene">
|
||||
下一个
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.scene-page {
|
||||
width: 100%;
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-top: 0.88rem;
|
||||
padding-bottom: 1.2rem;
|
||||
}
|
||||
|
||||
.scene-header {
|
||||
padding: 0.2rem;
|
||||
text-align: center;
|
||||
background-color: #fff;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-title {
|
||||
font-size: 0.4rem;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.scene-description {
|
||||
font-size: 0.28rem;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.long-image-container {
|
||||
width: 100%;
|
||||
height: 5rem;
|
||||
overflow: hidden;
|
||||
background-color: #000;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.interaction-tip {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
color: #fff;
|
||||
padding: 0.3rem 0.5rem;
|
||||
border-radius: 0.2rem;
|
||||
z-index: 10;
|
||||
animation: pulse 1.5s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
50% {
|
||||
transform: translate(-50%, -50%) scale(1.1);
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.tip-icon {
|
||||
font-size: 0.6rem;
|
||||
margin-bottom: 0.1rem;
|
||||
}
|
||||
|
||||
.seal-collect-tip {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 0.2rem;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: rgba(255, 107, 53, 0.9);
|
||||
color: #fff;
|
||||
padding: 0.15rem 0.3rem;
|
||||
border-radius: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.seal-icon {
|
||||
font-size: 0.4rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.info-panel {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.info-panel-content {
|
||||
width: 90%;
|
||||
max-width: 500px;
|
||||
background-color: #fff;
|
||||
border-radius: 0.2rem;
|
||||
overflow: hidden;
|
||||
max-height: 80vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.info-panel-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0.3rem;
|
||||
background-color: #ff6b35;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.info-panel-header h2 {
|
||||
font-size: 0.36rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #fff;
|
||||
font-size: 0.4rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.info-panel-body {
|
||||
padding: 0.3rem;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 0.2rem;
|
||||
font-size: 0.28rem;
|
||||
}
|
||||
|
||||
.info-item label {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.info-item span {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.attractions-section {
|
||||
margin-top: 0.3rem;
|
||||
}
|
||||
|
||||
.attractions-section h3 {
|
||||
font-size: 0.32rem;
|
||||
margin-bottom: 0.2rem;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.attractions-list {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.attractions-list li {
|
||||
margin-bottom: 0.2rem;
|
||||
padding: 0.2rem;
|
||||
background-color: #f9f9f9;
|
||||
border-radius: 0.1rem;
|
||||
}
|
||||
|
||||
.attraction-name {
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 0.05rem;
|
||||
}
|
||||
|
||||
.attraction-description {
|
||||
color: #666;
|
||||
font-size: 0.26rem;
|
||||
}
|
||||
|
||||
.media-player-container {
|
||||
margin: 0.2rem;
|
||||
background-color: #fff;
|
||||
border-radius: 0.1rem;
|
||||
padding: 0.2rem;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.scene-navigation {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 0.2rem;
|
||||
margin-top: 0.2rem;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
flex: 1;
|
||||
padding: 0.2rem;
|
||||
margin: 0 0.1rem;
|
||||
font-size: 0.3rem;
|
||||
border: none;
|
||||
border-radius: 0.15rem;
|
||||
cursor: pointer;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.prev-btn {
|
||||
background-color: #ff9800;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.prev-btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.info-btn {
|
||||
background-color: #4caf50;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.next-btn {
|
||||
background-color: #9c27b0;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.nav-btn:hover:not(:disabled) {
|
||||
opacity: 0.8;
|
||||
}
|
||||
</style>
|
||||
|
|
@ -17,7 +17,7 @@ onLoad((options) => {
|
|||
console.log('Webview loading URL:', url.value)
|
||||
} else {
|
||||
// 默认URL
|
||||
url.value = 'https://www.720yun.com/t/1dvktq8b0fl?scene_id=74010726'
|
||||
url.value = 'https://www.720yun.com/vr/cd4jtOyusw4'
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue