buddhism/pages/nearbystores/index.vue

751 lines
17 KiB
Vue
Raw Normal View History

2025-07-28 10:53:56 +08:00
<template>
<view class="page">
2025-08-01 17:53:56 +08:00
<!-- 加载状态指示器 -->
<view v-if="loading" class="loading-overlay">
<view class="loading-content">
<text>正在加载配置...</text>
</view>
</view>
2025-07-28 10:53:56 +08:00
<!-- 背景图 -->
<image class="bj" :src="templeData.imgUrl" mode="aspectFill"></image>
2025-07-28 10:53:56 +08:00
<!-- 公告 -->
<view class="announcement">
<image class="ggimg" :src="pageConfig.announcement.icon" mode="" />
2025-07-28 10:53:56 +08:00
<view class="marquee-wrap">
<view class="marquee" :style="{ transform: `translateX(${marqueeX}rpx)` }">
{{ templeData.bulletinContent }}
2025-07-28 10:53:56 +08:00
</view>
</view>
</view>
2025-08-06 14:47:08 +08:00
<!-- 音频与VR图标 -->
2025-07-28 10:53:56 +08:00
<view class="tubiao">
<view class="audio-controls">
2025-08-06 14:47:08 +08:00
<image
v-if="pageConfig.topIcons.leftIcon.hidden"
:src="pageConfig.topIcons.leftIcon.img"
mode=""
@click="playAudio"
:class="{ 'playing': isAudioPlaying }"
></image>
<image
:src="pageConfig.topIcons.rightIcon.img"
mode=""
@click="stopAudio"
:class="{ 'stopped': !isAudioPlaying }"
></image>
2025-07-28 10:53:56 +08:00
</view>
2025-07-30 13:38:33 +08:00
<view class="tubiao-item">
<image :src="pageConfig.topIcons.bottomIcon.img" mode=""></image>
2025-07-28 10:53:56 +08:00
</view>
</view>
<!-- 底部 -->
<view class="bot">
<view class="name">
<image :src="bottomSection.openingTime.decorationImg" mode=""></image> <text>{{ bottomSection.openingTime.title }}</text> <image :src="bottomSection.openingTime.decorationImg" mode=""></image>
2025-07-28 10:53:56 +08:00
</view>
<view class="time">
{{ templeData.startTime }} - {{ templeData.endTime }}
2025-07-28 10:53:56 +08:00
</view>
<view class="hua">
<image src="https://api.ccttiot.com/smartmeter/img/static/uyz1LDPTjPqeOzBMjLZ7" mode=""></image>
</view>
2025-08-04 16:17:43 +08:00
<view class="list-scroll">
<view class="list">
2025-08-06 12:04:17 +08:00
<!-- 导航项目列表 -->
<view
class="li"
2025-08-05 17:40:15 +08:00
v-for="(item, index) in navigationItems"
2025-08-06 11:46:08 +08:00
:key="index"
2025-08-05 17:40:15 +08:00
@click="navigateToPage(item, index)"
>
<image :src="item.img" mode=""></image>
2025-08-04 16:17:43 +08:00
<view class="da">
{{ item.title }}
2025-08-04 16:17:43 +08:00
</view>
<view class="xiao">
{{ item.subtitle }}
2025-08-04 16:17:43 +08:00
</view>
</view>
2025-08-06 12:04:17 +08:00
<!-- 空状态提示 -->
<view v-if="!loading && navigationItems.length === 0" class="empty-state">
<text>暂无功能项目</text>
</view>
</view>
2025-07-28 10:53:56 +08:00
</view>
2025-08-06 15:24:45 +08:00
<view class="bottom" v-if="bottomSection.prayerSection && bottomSection.prayerSection.backgroundImg">
<image :src="bottomSection.prayerSection.backgroundImg" mode=""></image>
<view class="rixing">
{{ bottomSection.prayerSection.title }}
</view>
<view class="qifu" @click="goToPray">
<image :src="bottomSection.prayerSection.prayerButton.icon" mode=""></image>
<view class="zaixian">
<view class="da">
{{ bottomSection.prayerSection.prayerButton.title }}
</view>
<view class="xiao">
{{ bottomSection.prayerSection.prayerButton.subtitle }}
</view>
</view>
</view>
2025-07-28 10:53:56 +08:00
</view>
</view>
</view>
</template>
<script>
2025-07-30 10:10:31 +08:00
import { navigateToPage } from "../../utils/router.js";
import { getHomeConfig,getTempleIndex } from "../../api/index/index.js";
2025-08-05 17:40:15 +08:00
import { getArticleById } from "../../api/article/article.js";
2025-07-30 10:10:31 +08:00
2025-07-28 10:53:56 +08:00
export default {
data() {
return {
marqueeX: '', // 初始位置和marquee-wrap宽度一致
timer: null,
2025-08-06 12:04:17 +08:00
loading: true, // 默认为true等待API数据加载
// 页面配置数据完全依赖API
pageConfig: {
background: { img: '' },
announcement: { icon: '', text: '' },
topIcons: {
leftIcon: { hidden: false, img: '' },
rightIcon: { img: '' },
bottomIcon: { img: '' }
}
},
navigationItems: [],
bottomSection: {
openingTime: {
title: '',
time: '',
decorationImg: ''
}
},
templeData: {
imgUrl: '',
bulletinContent: '',
startTime: '',
endTime: '',
audioUrl: ''
},
isAudioPlaying: false,
audioContext: null
2025-07-28 10:53:56 +08:00
}
},
onLoad() {
// 页面加载时获取配置
this.loadHomeConfig();
// 获取寺庙数据
this.loadTempleData();
},
2025-08-06 12:04:17 +08:00
// 添加下拉刷新支持
onPullDownRefresh() {
console.log('用户触发下拉刷新');
Promise.all([
this.loadHomeConfig(),
this.loadTempleData()
]).finally(() => {
2025-08-06 12:04:17 +08:00
uni.stopPullDownRefresh();
});
},
onShow() {
// 启动跑马灯(方法内部会检查是否有文本)
this.startMarquee();
2025-07-28 10:53:56 +08:00
},
onUnload() {
this.stopMarquee();
// 停止音频播放
this.stopAudio();
2025-07-28 10:53:56 +08:00
},
2025-07-28 17:28:52 +08:00
methods: {
/**
* 获取首页配置
*/
async loadHomeConfig() {
2025-08-01 17:53:56 +08:00
console.log('开始获取首页配置...');
this.loading = true;
2025-08-01 17:53:56 +08:00
// 重试机制
const maxRetries = 3;
let retryCount = 0;
while (retryCount < maxRetries) {
2025-08-01 17:53:56 +08:00
try {
console.log(`${retryCount + 1} 次尝试获取配置...`);
const response = await getHomeConfig();
console.log('API响应:', response);
// 简化验证:只检查关键字段
if (response?.code === 200 && response?.data?.[0]?.body) {
const parsedConfig = JSON.parse(response.data[0].body);
// 更新页面配置
this.updatePageConfig(parsedConfig);
// 重新启动跑马灯
this.stopMarquee();
this.startMarquee();
console.log('配置加载成功');
break;
} else {
throw new Error('API响应数据无效');
}
2025-08-01 17:53:56 +08:00
} catch (error) {
retryCount++;
console.error(`${retryCount} 次尝试失败:`, error.message);
2025-08-01 17:53:56 +08:00
if (retryCount >= maxRetries) {
console.error('所有重试都失败了');
2025-08-01 17:53:56 +08:00
this.useDefaultConfig();
break;
} else {
await new Promise(resolve => setTimeout(resolve, retryCount * 1000));
}
}
}
this.loading = false;
console.log('配置加载完成');
2025-08-01 17:53:56 +08:00
},
/**
2025-08-06 12:04:17 +08:00
* 处理配置加载失败
2025-08-01 17:53:56 +08:00
*/
useDefaultConfig() {
2025-08-06 12:04:17 +08:00
console.log('API获取失败无法加载配置');
// 不设置任何默认配置,保持初始化的空状态
// 数据保持为初始化时的空结构
2025-08-01 17:53:56 +08:00
// 显示提示信息
2025-08-06 12:04:17 +08:00
uni.showModal({
title: '加载失败',
content: '无法获取页面配置,请检查网络连接后重试',
showCancel: true,
cancelText: '取消',
confirmText: '重试',
success: (res) => {
if (res.confirm) {
this.loadHomeConfig();
}
}
2025-08-01 17:53:56 +08:00
});
},
2025-08-01 17:53:56 +08:00
/**
* 更新页面配置
*/
updatePageConfig(parsedConfig) {
// 直接更新配置使用默认值防止undefined
this.pageConfig = parsedConfig.pageConfig || this.pageConfig;
this.navigationItems = parsedConfig.navigationItems || [];
this.bottomSection = parsedConfig.bottomSection || this.bottomSection;
console.log('配置更新完成');
2025-08-01 17:53:56 +08:00
},
/**
* 获取寺庙数据
2025-08-01 17:53:56 +08:00
*/
async loadTempleData() {
try {
console.log('开始获取寺庙数据...');
const response = await getTempleIndex();
console.log('寺庙数据API响应:', response);
if (response?.code === 200 && response?.data) {
this.templeData = {
imgUrl: response.data.imgUrl || '',
bulletinContent: response.data.bulletinContent || '',
startTime: response.data.startTime || '',
endTime: response.data.endTime || '',
audioUrl: response.data.audioUrl || ''
};
2025-08-07 13:47:13 +08:00
uni.setStorageSync('abbotId', response.data.abbotId);
// 重新启动跑马灯
this.stopMarquee();
this.startMarquee();
console.log('寺庙数据加载成功');
} else {
throw new Error('寺庙数据API响应无效');
}
} catch (error) {
console.error('获取寺庙数据失败:', error);
uni.showToast({
title: '获取寺庙数据失败',
icon: 'none'
2025-08-01 17:53:56 +08:00
});
}
},
2025-07-28 10:53:56 +08:00
startMarquee() {
// 简单检查公告文本是否存在
const announcementText = this.templeData?.bulletinContent || this.pageConfig?.announcement?.text;
if (!announcementText) {
return;
}
// 停止之前的定时器
this.stopMarquee();
// 估算文字宽度每个字24rpx
const textWidth = announcementText.length * 24;
2025-07-28 10:53:56 +08:00
this.timer = setInterval(() => {
this.marqueeX--;
if (this.marqueeX < -textWidth) {
this.marqueeX = 600;
}
}, 16);
},
stopMarquee() {
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
},
// 兼容两种跳转方式page路由跳转 或 aid文章详情跳转
async navigateToPage(item, index) {
try {
console.log('导航项信息:', item);
console.log('导航项索引:', index);
// 优先使用page字段进行路由跳转
if (item.page) {
console.log('使用page字段进行路由跳转:', item.page);
// 导入路由工具
const { navigateToPage: routerNavigate } = await import("../../utils/router.js");
routerNavigate(item.page);
return;
}
// 如果没有page字段则使用aid进行文章详情跳转
if (item.aid) {
console.log('使用aid字段获取文章详情:', item.aid);
// 显示加载提示
uni.showLoading({
title: '加载中...',
mask: true
});
// 调用API获取文章详情
const response = await getArticleById(item.aid);
// 隐藏加载提示
uni.hideLoading();
if (response.code === 200 && response.data) {
console.log('获取文章详情成功:', response.data);
// 将文章数据存储到本地,供目标页面使用
uni.setStorageSync('currentArticle', response.data);
// 直接跳转到文章详情页面
uni.navigateTo({
url: '/pages/article/article-detail',
fail: (err) => {
console.error('跳转到文章详情页面失败:', err);
uni.showToast({
title: '页面跳转失败',
icon: 'none'
});
}
});
} else {
console.error('获取文章详情失败:', response);
uni.showToast({
title: '获取内容失败',
icon: 'none'
});
}
} else {
console.error('导航项既没有page字段也没有aid字段:', item);
uni.showToast({
title: '配置错误',
icon: 'none'
});
}
} catch (error) {
// 隐藏加载提示
uni.hideLoading();
console.error('导航跳转出错:', error);
uni.showToast({
title: '网络错误',
icon: 'none'
2025-08-06 15:24:45 +08:00
});
}
},
/**
* 跳转到祈福页面
*/
goToPray() {
try {
console.log('跳转到祈福页面');
// 使用navigateToPage方法传入参数pray
navigateToPage('pray');
} catch (error) {
console.error('跳转到祈福页面失败:', error);
uni.showToast({
title: '页面跳转失败',
icon: 'none'
});
}
2025-08-06 14:47:08 +08:00
},
/**
* 播放音频
*/
playAudio() {
if (!this.templeData.audioUrl) {
uni.showToast({
title: '暂无音频资源',
icon: 'none'
});
return;
}
try {
// 如果已经在播放,先停止
if (this.audioContext) {
this.stopAudio();
}
// 创建音频上下文
this.audioContext = uni.createInnerAudioContext();
this.audioContext.src = this.templeData.audioUrl;
this.audioContext.loop = true; // 循环播放
// 监听播放状态
this.audioContext.onPlay(() => {
console.log('音频开始播放');
this.isAudioPlaying = true;
uni.showToast({
title: '音频已开启',
icon: 'none'
});
});
this.audioContext.onError((err) => {
console.error('音频播放错误:', err);
this.isAudioPlaying = false;
uni.showToast({
title: '音频播放失败',
icon: 'none'
});
});
this.audioContext.onEnded(() => {
console.log('音频播放结束');
this.isAudioPlaying = false;
});
// 开始播放
this.audioContext.play();
} catch (error) {
console.error('音频播放失败:', error);
this.isAudioPlaying = false;
uni.showToast({
title: '音频播放失败',
icon: 'none'
});
}
},
/**
* 停止音频
*/
stopAudio() {
if (this.audioContext) {
this.audioContext.stop();
this.audioContext.destroy();
this.audioContext = null;
}
this.isAudioPlaying = false;
uni.showToast({
title: '音频已关闭',
icon: 'none'
});
2025-07-28 10:53:56 +08:00
}
}
}
</script>
<style lang="scss">
page {
background-color: #fff;
}
.bot{
position: fixed;
left: 50%;
transform: translateX(-50%);
bottom: 56rpx;
width: 100%;
max-width: 750rpx;
/* 确保不会限制子元素的滚动 */
overflow: visible;
2025-07-28 10:53:56 +08:00
.bottom{
margin-top: 64rpx;
display: flex;
padding: 0 118rpx;
box-sizing: border-box;
image{
width: 64rpx;
height: 64rpx;
}
.rixing{
width: 206rpx;
height: 64rpx;
background: #522510;
border-radius: 45rpx 45rpx 45rpx 45rpx;
text-align: center;
line-height: 64rpx;
font-weight: 600;
font-size: 24rpx;
color: #FFFFFF;
border-radius: 50rpx;
margin-left: 26rpx;
margin-right: 26rpx;
}
.qifu{
width: 194rpx;
height: 64rpx;
border-radius: 41rpx 41rpx 41rpx 41rpx;
border: 1rpx solid #522510;
display: flex;
align-items: center;
justify-content: center;
image{
width: 32rpx;
height: 32rpx;
}
.zaixian{
margin-left: 12rpx;
.da{
font-size: 24rpx;
color: #522510;
font-weight: 600;
}
.xiao{
font-size: 12rpx;
color: #522510;
}
}
}
}
.list-scroll {
width: 100%;
margin-top: 20rpx;
height: 120rpx;
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
/* 确保滚动容器不被父元素限制 */
position: relative;
z-index: 1;
/* 隐藏滚动条 */
scrollbar-width: none;
-ms-overflow-style: none;
&::-webkit-scrollbar {
display: none;
}
}
2025-07-28 10:53:56 +08:00
.list{
display: flex;
width: 1600rpx; /* 更大的宽度确保滚动 */
padding: 0 20rpx;
2025-07-28 10:53:56 +08:00
box-sizing: border-box;
/* 确保内容不被压缩 */
flex-shrink: 0;
2025-07-28 10:53:56 +08:00
.li{
width: 150rpx;
flex: 0 0 150rpx;
2025-07-28 10:53:56 +08:00
text-align: center;
margin-right: 20rpx;
2025-07-28 10:53:56 +08:00
image{
width: 56rpx;
height: 56rpx;
}
.da{
font-size: 24rpx;
color: #522510;
margin-top: 8rpx;
}
.xiao{
font-size: 12rpx;
color: #522510;
}
}
2025-08-06 12:04:17 +08:00
.empty-state {
width: 100%;
text-align: center;
padding: 40rpx;
color: #999;
font-size: 28rpx;
}
2025-07-28 10:53:56 +08:00
}
.hua{
width: 100%;
text-align: center;
margin-top: 30rpx;
image{
width: 656rpx;
height: 108rpx;
}
}
.time{
font-weight: 600;
font-size: 32rpx;
color: #522510;
margin-top: 8rpx;
width: 100%;
text-align: center;
}
.name{
display: flex;
align-items: center;
width: 100%;
justify-content: center;
text{
font-weight: 600;
font-size: 32rpx;
color: #522510;
margin-left: 24rpx;
margin-right: 24rpx;
}
image{
width: 12rpx;
height: 12rpx;
}
}
}
.tubiao{
width: 100%;
display: flex;
padding: 0 40rpx;
2025-07-28 10:53:56 +08:00
box-sizing: border-box;
justify-content: space-between;
.audio-controls {
display: flex;
align-items: center;
gap: 26rpx;
}
image{
width: 82rpx;
height: 82rpx;
display: block;
margin-top: 50rpx;
transition: all 0.3s ease;
&:active {
transform: scale(0.9);
opacity: 0.8;
}
&.playing {
animation: pulse 2s infinite;
}
&.stopped {
opacity: 0.6;
2025-08-06 14:47:08 +08:00
}
}
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.1);
}
100% {
transform: scale(1);
2025-07-28 10:53:56 +08:00
}
}
.announcement {
width: 100%;
margin-top: 184rpx;
padding: 0 48rpx;
box-sizing: border-box;
display: flex;
align-items: center;
white-space: nowrap;
.ggimg {
width: 32rpx;
height: 32rpx;
margin-right: 14rpx;
}
.marquee-wrap {
width: 600rpx;
overflow: hidden;
position: relative;
height: 32rpx;
display: flex;
align-items: center;
}
.marquee {
white-space: nowrap;
position: absolute;
left: 0;
top: 0;
font-size: 24rpx;
color: #522510;
}
}
2025-08-01 17:53:56 +08:00
.bj{
width: 100%;
height: 100vh;
position: fixed;
top: 0;
left: 0;
z-index: -1;
}
2025-08-01 17:53:56 +08:00
/* 加载状态指示器样式 */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.loading-content {
background-color: rgba(255, 255, 255, 0.9);
padding: 40rpx 60rpx;
border-radius: 20rpx;
text-align: center;
}
.loading-content text {
font-size: 28rpx;
color: #333;
}
2025-07-28 10:53:56 +08:00
</style>