congming_huose-apk/pages/index/index.vue

524 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="page-container"
@touchstart="handleTouchStart"
@touchmove="handleTouchMove"
@touchend="handleTouchEnd">
<!-- 顶部栏空间切换 -->
<CustomHeader
:title="currentPageInfo.title"
:subtitle="currentPageInfo.subtitle"
:spaces="spaceOptions"
:selectedIndex="selectedSpaceIndex"
@space-change="handleSpaceChange"
@toggle-side-menu="toggleSideMenu"
/>
<!-- 加载遮罩请求空间数据时覆盖页面 -->
<view class="loading-overlay" v-if="isLoadingSpaces">
<view class="spinner"></view>
<text class="loading-text">加载中...</text>
</view>
<!-- 页面内容区域 -->
<view class="page-content">
<!-- 设备模块 -->
<DeviceTab v-if="currentTabIndex === 0" />
<!-- 房间模块 -->
<RoomTab v-if="currentTabIndex === 1" />
<!-- 通知模块 -->
<NotificationTab v-if="currentTabIndex === 2" ref="notificationTab" />
<!-- 控制模块 -->
<ControlTab v-if="currentTabIndex === 3" :statusTitle="currentStatusTitle" @status-changed="handleStatusChanged" />
</view>
<!-- 底部导航 -->
<BottomTab
:currentIndex="currentTabIndex"
@tab-change="handleTabChange"
/>
<!-- 侧边菜单 -->
<SideMenu
:visible="showSideMenu"
:logoflag="logoflag"
@close="closeSideMenu"
@menu-click="handleMenuClick"
@add-room="handleAddRoom"
/>
<!-- 无空间展示 -->
<view class="" v-if="!isLoadingSpaces && spaceOptions.length == 0" style="background-color: #F3F5F6;position: fixed;top: 168rpx;left: 0;width: 100%;height: 100vh;z-index: 999;text-align: center;">
<image src="https://api.ccttiot.com/smartmeter/img/static/uKFO4XdQVUgGYJHt4gwn" style="width: 272rpx;height: 272rpx;margin-top: 80rpx;" mode="aspectFill"></image>
<view class="" style="font-weight: 600;font-size: 36rpx;margin-top: 70rpx;color: #3D3D3D;">
{{ $i18n.t('emptySpaceTitle') }}
</view>
<view class="" style="width: 524rpx;margin-top: 30rpx;font-size: 28rpx;color: #727272;margin: auto;">
{{ $i18n.t('emptySpaceDesc') }}
</view>
<view class="" @click="btnaddkj" style="width: 674rpx;height: 100rpx;background: #0F0F0F;border-radius: 60rpx 60rpx 60rpx 60rpx;border: 2rpx solid #0F0F0F;font-size: 36rpx;color: #fff;font-weight: 600;text-align: center;line-height: 100rpx;margin: auto;margin-top: 70rpx;">
+ {{ $i18n.t('addSpace') || $i18n.t('emptySpaceCta') }}
</view>
</view>
</view>
</template>
<script>
import CustomHeader from '@/common/components/CustomHeader.vue'
import BottomTab from '@/common/components/BottomTab.vue'
import SideMenu from '@/common/components/SideMenu.vue'
import DeviceTab from '@/common/components/DeviceTab.vue'
import RoomTab from '@/common/components/RoomTab.vue'
import NotificationTab from '@/common/components/NotificationTab.vue'
import ControlTab from '@/common/components/ControlTab.vue'
export default {
components: {
CustomHeader,
BottomTab,
SideMenu,
DeviceTab,
RoomTab,
NotificationTab,
ControlTab
},
data() {
return {
currentTabIndex: 0, // 当前选中的标签页索引
showSideMenu: false, // 控制侧边菜单的显示状态
// 加载状态
isLoadingSpaces: true,
// 添加页面配置数据
pageConfigs: [],
// 空间下拉
spaceOptions: [
{ name: 'home', status: '2' }, // 撤防
{ name: 'office', status: '1' }, // 布防
{ name: 'warehouse', status: '3' }, // 夜间
{ name: 'garage', status: '4' } // 紧急
],
selectedSpaceIndex: 0,
// 添加触摸相关数据
touchStartX: 0,
touchStartY: 0,
touchEndX: 0,
touchEndY: 0,
minSwipeDistance: 50, // 最小滑动距离
maxVerticalDistance: 100, // 最大垂直距离(防止误触)
touchStartTime: 0, // 触摸开始时间
maxSwipeTime: 500, // 最大滑动时间(毫秒)
lastSwipeTime: 0, // 上次手势时间
swipeDebounceTime: 300 ,// 手势防抖时间(毫秒)
logoflag:false
}
},
computed: {
// 计算当前语言,用于触发更新
currentLanguage() {
return this.$i18n.getCurrentLanguage()
},
currentPageInfo() {
return this.pageConfigs[0] || { title: '', subtitle: '' }
},
// 当前选中空间的状态标题1-布防 2-撤防 3-夜间 4-紧急)
currentStatusTitle() {
const spaces = Array.isArray(this.spaceOptions) ? this.spaceOptions : []
const index = Math.min(Math.max(0, this.selectedSpaceIndex || 0), spaces.length - 1)
const status = spaces[index] && (spaces[index].status || spaces[index].Status || spaces[index].state)
return this.getStatusTitleByCode(status)
}
},
watch: {
// 监听语言变化,强制更新组件
currentLanguage() {
console.log('主页面语言变化:', this.currentLanguage)
this.updatePageConfigs()
this.updateSpaceOptions()
}
},
mounted() {
// 监听语言变化事件
uni.$on('languageChanged', this.handleLanguageChange)
this.updatePageConfigs()
// this.updateSpaceOptions();
},
beforeDestroy() {
// 移除事件监听
uni.$off('languageChanged', this.handleLanguageChange)
},
onLoad() {
console.log('页面加载完成');
if(!uni.getStorageSync('language')){
uni.setStorageSync('language','zh')
}
},
onShow() {
// 页面显示时强制更新
this.updatePageConfigs()
this.updateSpaceOptions()
},
methods: {
// 点击跳转添加空间
btnaddkj(){
if(this.logoflag == true){
uni.reLaunch({
url:'/pages/login/index'
})
}else{
uni.navigateTo({
url:'/pages/kongjian/index'
})
}
},
// 触摸开始事件
handleTouchStart(e) {
// 在通知页面时只有高亮索引为0时才启用手势
if (this.currentTabIndex === 2) {
// 获取通知页面的高亮索引
const notificationTab = this.$refs.notificationTab
if (notificationTab && notificationTab.swiperCurrent !== 0) {
return; // 高亮索引不是0时禁用手势
}
}
// 记录触摸开始位置,无论侧边菜单是否显示
this.touchStartX = e.touches[0].clientX
this.touchStartY = e.touches[0].clientY
this.touchStartTime = Date.now() // 记录触摸开始时间
},
// 触摸移动事件
handleTouchMove(e) {
// 在通知页面时只有高亮索引为0时才启用手势
if (this.currentTabIndex === 2) {
// 获取通知页面的高亮索引
const notificationTab = this.$refs.notificationTab
if (notificationTab && notificationTab.swiperCurrent !== 0) {
return; // 高亮索引不是0时禁用手势
}
}
// 可以在这里添加实时反馈,比如显示滑动提示
// 暂时保持空实现,避免影响性能
},
// 触摸结束事件
handleTouchEnd(e) {
// 在通知页面时只有高亮索引为0时才启用手势
if (this.currentTabIndex === 2) {
// 获取通知页面的高亮索引
const notificationTab = this.$refs.notificationTab
if (notificationTab && notificationTab.swiperCurrent !== 0) {
return // 高亮索引不是0时禁用手势
}
}
const touchEndTime = Date.now()
const deltaTime = touchEndTime - this.touchStartTime
// 防抖检查:避免快速连续触发
if (touchEndTime - this.lastSwipeTime < this.swipeDebounceTime) {
return
}
this.touchEndX = e.changedTouches[0].clientX
this.touchEndY = e.changedTouches[0].clientY
// 计算滑动距离
const deltaX = this.touchEndX - this.touchStartX
const deltaY = Math.abs(this.touchEndY - this.touchStartY)
// 判断是否为有效的左滑手势(隐藏侧边菜单)
if (this.showSideMenu && deltaX < -this.minSwipeDistance && deltaY < this.maxVerticalDistance && deltaTime < this.maxSwipeTime) {
console.log('检测到左滑手势,隐藏侧边菜单')
this.closeSideMenu()
this.lastSwipeTime = touchEndTime // 更新上次手势时间
// 可选:添加触觉反馈
uni.vibrateShort({
type: 'light'
})
}
// 判断是否为有效的右滑手势(打开侧边菜单)
else if (!this.showSideMenu && deltaX > this.minSwipeDistance && deltaY < this.maxVerticalDistance && deltaTime < this.maxSwipeTime) {
console.log('检测到右滑手势,打开侧边菜单')
this.toggleSideMenu()
this.lastSwipeTime = touchEndTime // 更新上次手势时间
// 可选:添加触觉反馈
uni.vibrateShort({
type: 'light'
})
}
},
handleLanguageChange(lang) {
console.log('主页面语言切换事件触发:', lang)
this.updatePageConfigs()
this.updateSpaceOptions()
},
// 将状态码映射为标题
getStatusTitleByCode(code) {
const n = Number(code)
// 添加容错处理
const t = this.$i18n && this.$i18n.t ? this.$i18n.t.bind(this.$i18n) : (key) => key
if (n === 1) return t('statusArmed') || '布防'
if (n === 2) return t('statusDisarmed') || '撤防'
if (n === 3) return t('statusNight') || '夜间'
if (n === 4) return t('statusEmergency') || '紧急'
return t('work') || '工作'
},
// 更新主页面配置
updatePageConfigs() {
console.log('更新主页面配置');
// 重新构建页面配置,确保所有文本都通过 $i18n.t() 获取
const spaces = Array.isArray(this.spaceOptions) ? this.spaceOptions : []
const index = Math.min(Math.max(0, this.selectedSpaceIndex || 0), spaces.length - 1)
const status = spaces[index] && (spaces[index].status || spaces[index].Status || spaces[index].state)
const title = this.getStatusTitleByCode(status)
// 添加容错处理
const t = this.$i18n && this.$i18n.t ? this.$i18n.t.bind(this.$i18n) : (key) => key
this.pageConfigs = [
{
title,
subtitle: t('alarmCleared') || '--'
}
]
// 强制更新组件
this.$forceUpdate()
},
// 更新空间下拉选项(示例数据,可替换为实际接口)
updateSpaceOptions() {
this.spaceOptions = []
this.selectedSpaceIndex = 0
this.isLoadingSpaces = true
this.$http.get('/bst/space/list').then(res => {
if (res.code == 200) {
this.logoflag = false
this.spaceOptions = res.rows
// 若有本地已选空间,默认选中;否则选中第一个并写入本地
try {
const localKjid = uni.getStorageSync('kjid')
const spaces = Array.isArray(this.spaceOptions) ? this.spaceOptions : []
let matchIndex = 0
if (localKjid !== undefined && localKjid !== null && localKjid !== '') {
const found = spaces.findIndex(s => (s.id || s.spaceId || s.ID || s.Id) == localKjid)
if (found >= 0) {
matchIndex = found
}
}
// 如果空间列表不为空,设置默认选中并写入本地
if (spaces.length > 0) {
this.selectedSpaceIndex = matchIndex
const selected = spaces[matchIndex]
const kjid = selected && (selected.id || selected.spaceId || selected.ID || selected.Id)
if (kjid !== undefined && kjid !== null) {
uni.setStorageSync('kjid', kjid)
uni.setStorageSync('kjobj', selected)
}
}
} catch(e) {
console.warn('处理本地空间ID失败:', e)
}
// 空间列表加载后,立即根据状态刷新标题
this.updatePageConfigs()
}else if(res.code == 401){
this.logoflag = true
}
}).finally(() => {
this.isLoadingSpaces = false
})
},
// 顶部空间选择变更
handleSpaceChange(index, item, name) {
this.selectedSpaceIndex = index
console.log('选择空间:', index, item, name)
// 获取新选中的空间信息
const selected = item || (Array.isArray(this.spaceOptions) ? this.spaceOptions[index] : null)
const kjid = selected && (selected.id || selected.spaceId || selected.ID || selected.Id)
if (kjid !== undefined && kjid !== null) {
// 持久化选中的空间ID到本地
uni.setStorageSync('kjid', kjid)
uni.setStorageSync('kjobj', selected)
console.log('已保存 kjid:', kjid)
// 广播全局事件,通知需要依赖空间的模块刷新
console.log('主页面发送空间变化事件:', { kjid, space: selected })
uni.$emit('spaceChanged', { kjid, space: selected })
// 根据当前tab刷新对应的数据
this.refreshCurrentTabData(kjid)
}
this.updatePageConfigs()
},
// 根据当前tab刷新对应的数据
refreshCurrentTabData(kjid) {
console.log('刷新当前tab数据空间ID:', kjid)
switch (this.currentTabIndex) {
case 0: // 设备模块
this.refreshDeviceTab(kjid)
break;
case 1: // 房间模块
this.refreshRoomTab(kjid)
break;
case 2: // 通知模块
this.refreshNotificationTab(kjid)
break;
case 3: // 控制模块
this.refreshControlTab(kjid)
break;
default:
console.log('未知的tab索引:', this.currentTabIndex)
}
},
// 刷新设备模块数据
refreshDeviceTab(kjid) {
console.log('刷新设备模块数据')
// 如果有设备模块的引用,可以调用其刷新方法
// 这里可以根据实际的DeviceTab组件API进行调整
uni.$emit('refreshDeviceData', { kjid })
},
// 刷新房间模块数据
refreshRoomTab(kjid) {
console.log('刷新房间模块数据')
// 如果有房间模块的引用,可以调用其刷新方法
// 这里可以根据实际的RoomTab组件API进行调整
uni.$emit('refreshRoomData', { kjid })
},
// 刷新通知模块数据
refreshNotificationTab(kjid) {
console.log('刷新通知模块数据')
if (this.$refs && this.$refs.notificationTab) {
try {
this.$refs.notificationTab.pageNum = 1
this.$refs.notificationTab.kjid = kjid
this.$refs.notificationTab.getlist()
} catch(err) {
console.warn('通知页刷新失败:', err)
}
}
},
// 刷新控制模块数据
refreshControlTab(kjid) {
console.log('刷新控制模块数据')
// 控制模块会自动通过kjid获取最新状态无需额外操作
// 如果需要强制刷新,可以发送事件
uni.$emit('refreshControlData', { kjid })
},
// 处理标签页切换
handleTabChange(index) {
console.log('点击了标签页:', index)
this.currentTabIndex = index
console.log('切换到标签页:', index)
},
// 侧边菜单相关方法
toggleSideMenu() {
console.log('点击了菜单按钮')
this.showSideMenu = !this.showSideMenu
console.log('侧边菜单状态:', this.showSideMenu)
},
closeSideMenu() {
this.showSideMenu = false
},
handleMenuClick(type) {
console.log('Clicked menu item:', type)
this.closeSideMenu();
// 根据 type 执行不同的操作
uni.showToast({
title: `${this.$i18n.t('clicked')}${type}`,
icon: 'none',
duration:3000
})
},
handleAddRoom() {
console.log('Add Room clicked')
this.closeSideMenu()
uni.showToast({
title: this.$i18n.t('addRoomClicked'),
icon: 'none',
duration:3000
})
},
// 处理控制模块状态变化
handleStatusChanged(data) {
console.log('控制模块状态改变:', data)
// 刷新空间列表以更新状态
this.refreshSpaceStatus(data.spaceId, data.status)
},
// 刷新空间状态
refreshSpaceStatus(spaceId, newStatus) {
// 更新本地存储的空间状态
try {
const currentSpace = uni.getStorageSync('kjobj')
if (currentSpace && currentSpace.id === spaceId) {
currentSpace.status = newStatus
uni.setStorageSync('kjobj', currentSpace)
}
} catch(e) {
console.warn('更新本地空间状态失败:', e)
}
// 更新spaceOptions中对应空间的状态
const spaces = Array.isArray(this.spaceOptions) ? this.spaceOptions : []
const targetIndex = spaces.findIndex(space =>
(space.id || space.spaceId || space.ID || space.Id) == spaceId
)
if (targetIndex >= 0) {
// 直接更新状态
this.spaceOptions[targetIndex].status = newStatus
// 强制更新页面配置以刷新头部显示
this.updatePageConfigs()
console.log('空间状态已更新:', this.spaceOptions[targetIndex])
}
},
},
}
</script>
<style lang="scss">
page {
background: #fff;
height: 100vh;
overflow: hidden;
pointer-events: auto;
}
.page-container {
background: #fff;
pointer-events: auto;
/* 确保触摸事件能够正常工作 */
touch-action: pan-x pan-y;
/* 防止页面滚动干扰手势识别 */
overflow: hidden;
height: 100vh;
}
/* 加载遮罩层样式 */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
background: rgba(255,255,255,0.96);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.spinner {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
border: 6rpx solid #e0e0e0;
border-top-color: #4caf50;
animation: spin 1s linear infinite;
margin-bottom: 24rpx;
}
.loading-text {
font-size: 28rpx;
color: #4caf50;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.page-content {
padding-bottom: 120rpx; /* 为底部导航留出空间 */
height: 83vh;
overflow: scroll;
position: relative;
z-index: 1;
/* 确保内容区域可以正常滚动 */
touch-action: pan-x pan-y;
}
</style>