congming_huose-apk/common/components/NotificationTab.vue

850 lines
22 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">
<view class="tabs-wrap">
<view :class="swiperCurrent == index ? 'active tab' : 'tab'" v-for="(item,index) in tabsDisplay"
:key="item.key" @click="onTabClick(index)">
{{item.name}}
</view>
<view class="settings-btn" @click="showNotificationSettings">
</view>
</view>
<!-- 原来的筛选按钮和时间选择弹窗已移除时间筛选功能已集成到tab中 -->
<swiper class="swiper" :current="swiperCurrent" @change="onSwiperChange" :duration="200" :circular="false">
<swiper-item v-for="(tab) in tabsDisplay" :key="tab.key">
<scroll-view class="list" scroll-y @scrolltolower="handqixing" refresher-enabled
@refresherrefresh="onRefresh" :refresher-triggered="isRefreshing" refresher-default-style="black">
<view class="cell" v-for="(n,idx) in listByKey(tab.key)" :key="tab.key + idx">
<view class="content">
<view class="row1">
<image class="small-icon" v-if="n.type == 'delete'"
src="https://api.ccttiot.com/smartmeter/img/static/uzIKbrzVRDbX1TdbALJx"
mode="aspectFill"></image>
<image class="small-icon" v-if="n.type == 'unbind'"
src="https://api.ccttiot.com/smartmeter/img/static/uJ4PSY8O4kde1AdCdf91"
mode="aspectFill"></image>
<image class="small-icon" v-if="n.type == 'bind'"
src="https://api.ccttiot.com/smartmeter/img/static/un9RVkNVxeENkCrtYVug"
mode="aspectFill"></image>
<image class="small-icon" v-if="n.type == 'add'"
src="https://api.ccttiot.com/smartmeter/img/static/uzSrhuScUj743gsVwEqd"
mode="aspectFill"></image>
<image class="small-icon" v-if="n.type == 'edit'"
src="https://api.ccttiot.com/smartmeter/img/static/u42kBohuBIohCoNWYazi"
mode="aspectFill"></image>
<text class="time" :style="{color: n.timeColor}">{{ n.time }}</text>
</view>
<view class="row2">{{ n.titleKey }}</view>
</view>
<image class="thumb thumb-placeholder" :src="n.picture" mode="aspectFill"></image>
</view>
<view class="no-more">{{ $i18n.t('noMore') }}</view>
</scroll-view>
</swiper-item>
</swiper>
<!-- 通知设置弹窗 -->
<view class="settings-modal" v-if="showSettings" @click="hideNotificationSettings">
<view class="settings-content" @click.stop>
<view class="settings-header">
<text class="settings-title">{{ $i18n.t('notificationSettingsTitle') }}</text>
<text class="close-btn" @click="hideNotificationSettings">×</text>
</view>
<scroll-view class="settings-list" scroll-y>
<view class="setting-item" v-for="(category, index) in notificationSettings" :key="index">
<view class="setting-main" @click="toggleCategory(index)">
<view class="setting-info">
<text class="setting-title">{{ $i18n.t(category.titleKey) }}</text>
<view class="setting-desc-row">
<text class="setting-desc">{{ getEnabledSubItemsDesc(category) }}</text>
<text class="arrow" v-if="category.hasSubSettings">〉</text>
</view>
</view>
<view class="setting-controls">
<switch
:checked="category.enabled"
@change="onMainSwitchChange(index, $event)"
@click.stop
color="#000000"
/>
</view>
</view>
</view>
</scroll-view>
</view>
</view>
<!-- 子设置弹窗 -->
<view class="sub-settings-modal" v-if="showSubSettings" @click="hideSubSettings">
<view class="sub-settings-content" @click.stop>
<view class="sub-settings-header">
<text class="sub-settings-title">{{ getSubSettingsTitle() }}</text>
<text class="close-btn" @click="hideSubSettings">×</text>
</view>
<scroll-view class="sub-settings-list" scroll-y>
<view class="sub-setting-item" v-for="(subItem, index) in currentCategory.subSettings" :key="index">
<view class="sub-setting-main">
<view class="sub-setting-info">
<text class="sub-setting-title">{{ $i18n.t(subItem.titleKey) }}</text>
</view>
<switch
:checked="subItem.enabled"
@change="onSubSwitchChange(index, $event)"
color="#000000"
/>
</view>
</view>
</scroll-view>
<view class="save-btn" @click="saveSubSettings">
<text class="save-btn-text">{{ $i18n.t('saveSettings') }}</text>
</view>
</view>
</view>
</view>
</template>
<script>
export default {
name: 'NotificationTab',
data() {
return {
timeindex:0,
createTimeRange:'',
swiperCurrent: 0,
timelist: [
{ key: 'allTime', name: 'allTime' },
{ key: 'oneHour', name: 'oneHour' },
{ key: 'twentyFourHours', name: 'twentyFourHours' },
{ key: 'oneMonth', name: 'oneMonth' }
],
icons: {
security: 'https://api.ccttiot.com/FleUeHa_R3Rr2RsjlZ30f1xqvjR7',
picture: 'https://api.ccttiot.com/smartmeter/img/static/usZCKDHBGZ2XQ5FUy0Al',
malfunctions: 'https://api.ccttiot.com/smartmeter/img/static/usZCKDHBGZ2XQ5FUy0Al',
control: 'https://api.ccttiot.com/smartmeter/img/static/ui8Gz7gVZYFjS8XSDS45',
system: 'https://api.ccttiot.com/smartmeter/img/static/uiRElxpcH7NbtJWIRtf1',
env: 'https://api.ccttiot.com/smartmeter/img/static/uiRElxpcH7NbtJWIRtf1'
},
notifications: [],
isRefreshing: false,
pageNum: 1,
pageSize: 10,
kjid: '',
total: 0,
hasMore: true,
requestInProgress: false,
// 通知设置相关
showSettings: false,
showSubSettings: false,
currentCategoryIndex: -1,
notificationSettings: [
{
titleKey: 'alertTitle',
descKey: 'alertDesc',
enabled: true,
hasSubSettings: true,
subSettings: [
{ titleKey: 'intrusion', enabled: true },
{ titleKey: 'fire', enabled: false },
{ titleKey: 'waterLeak', enabled: false },
{ titleKey: 'serverDisconnected', enabled: false }
]
},
{
titleKey: 'videoWarningTitle',
descKey: 'videoWarningDesc',
enabled: false,
hasSubSettings: false,
subSettings: []
},
{
titleKey: 'faultTitle',
descKey: 'faultDesc',
enabled: true,
hasSubSettings: true,
subSettings: [
{ titleKey: 'connectionLost', enabled: true },
{ titleKey: 'lowBattery', enabled: true },
{ titleKey: 'coverOpen', enabled: false }
]
},
{
titleKey: 'securityStatusChangeTitle',
descKey: 'securityStatusChangeDesc',
enabled: true,
hasSubSettings: true,
subSettings: [
{ titleKey: 'arm', enabled: true },
{ titleKey: 'disarm', enabled: true },
{ titleKey: 'nightMode', enabled: false }
]
},
{
titleKey: 'systemNotificationTitle',
descKey: 'systemNotificationDesc',
enabled: true,
hasSubSettings: true,
subSettings: [
{ titleKey: 'hubUpdate', enabled: true },
{ titleKey: 'maintenance', enabled: true }
]
},
{
titleKey: 'environmentalNotificationTitle',
descKey: 'environmentalNotificationDesc',
enabled: false,
hasSubSettings: true,
subSettings: [
{ titleKey: 'temperature', enabled: false },
{ titleKey: 'humidity', enabled: false },
{ titleKey: 'carbonDioxide', enabled: false }
]
}
]
};
},
computed: {
// 计算当前语言,用于触发更新
currentLanguage() {
return this.$i18n.getCurrentLanguage();
},
// 生成展示用的标签文案(使用时间列表)
tabsDisplay() {
return this.timelist.map((timeItem, index) => ({
key: `time_${index}`,
name: this.$i18n.t(timeItem.name)
}));
},
filteredList() {
// 现在所有tab都显示相同的数据因为时间筛选在API层面处理
return this.notifications;
},
// 当前选中的分类
currentCategory() {
return this.currentCategoryIndex >= 0 ? this.notificationSettings[this.currentCategoryIndex] : null;
}
},
watch: {
// 监听语言变化
currentLanguage() {
console.log('通知页面语言变化:', this.currentLanguage);
// 语言切换时重新加载设置
this.loadNotificationSettings();
}
},
mounted() {
// 监听语言变化事件
uni.$on('languageChanged', this.handleLanguageChange);
// 初始化空间ID并首次拉取列表
this.kjid = uni.getStorageSync('kjid')
// 初始化时设置默认时间筛选(全部)
this.timeindex = 0
this.btntimeindex(0)
this.getlist()
// 监听空间切换事件
uni.$on('spaceChanged', this.handleSpaceChanged)
// 加载通知设置
this.loadNotificationSettings()
},
beforeDestroy() {
// 移除事件监听
uni.$off('languageChanged', this.handleLanguageChange);
uni.$off('spaceChanged', this.handleSpaceChanged)
},
methods: {
// 点击选择时间
btntimeindex(index){
this.timeindex = index
// 计算并打印时间范围
const now = new Date()
if(index === 0){
// 全部 -> 清空
this.createTimeRange = ''
console.log('时间筛选:全部(清空)')
return
}
let start = new Date(now)
switch(index){
case 1: // 1小时
start = new Date(now.getTime() - 1 * 60 * 60 * 1000)
break
case 2: // 24小时
start = new Date(now.getTime() - 24 * 60 * 60 * 1000)
break
case 3: // 1个月
start.setMonth(start.getMonth() - 1)
break
default:
break
}
const startStr = this.formatDate(start)
const endStr = this.formatDate(now)
this.createTimeRange = startStr + ',' + endStr
console.log('时间范围:', { startTime: startStr, endTime: endStr })
},
// 格式化时间为 YYYY-MM-DD HH:mm:ss
formatDate(date){
const pad = (n) => n < 10 ? ('0' + n) : n
const y = date.getFullYear()
const m = pad(date.getMonth() + 1)
const d = pad(date.getDate())
const hh = pad(date.getHours())
const mm = pad(date.getMinutes())
const ss = pad(date.getSeconds())
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
},
// 请求通知列表
getlist() {
if (this.requestInProgress) return
this.requestInProgress = true
// 添加调试日志
console.log('请求通知列表:', {
pageNum: this.pageNum,
pageSize: this.pageSize,
spaceId: this.kjid,
createTimeRange: this.createTimeRange
})
this.$http.get(`/bst/notice/list?pageNum=${this.pageNum}&pageSize=${this.pageSize}&spaceId=${this.kjid}&classify=&orderByColumn=createTime&isAsc=desc&createTimeRange=${this.createTimeRange}`).then((res) => {
if (res.code == 200) {
this.total = Number(res.total || 0)
const rows = Array.isArray(res.rows) ? res.rows : []
console.log('原始数据行:', rows)
const mapped = rows.map(r => ({
type: r.classify || r.type || 'system', // 优先使用classify字段兼容type字段
time: r.createTime,
timeColor: this.getTimeColor(r.classify || r.type),
titleKey: r.content || '',
picture: r.picture || ''
}))
console.log('映射后的数据:', mapped)
if (this.pageNum == 1) {
this.notifications = mapped
} else {
this.notifications = this.notifications.concat(mapped)
}
this.hasMore = this.notifications.length < this.total
console.log('当前通知数据:', this.notifications)
} else {
console.error('API请求失败:', res)
}
}).catch(error => {
console.error('请求通知列表失败:', error)
}).finally(() => {
this.requestInProgress = false
if (this.isRefreshing) {
this.isRefreshing = false
}
})
},
// 上拉加载更多
handqixing() {
if (!this.hasMore) return
this.pageNum += 1
this.getlist()
},
// 下拉刷新
onRefresh() {
if (this.isRefreshing || this.requestInProgress) return
this.isRefreshing = true
this.pageNum = 1
this.getlist()
},
onTabChange(index) {
this.current = index
},
// 滑动切换时间标签
onSwiperChange(e) {
console.log(':', e.detail.current)
this.swiperCurrent = e.detail.current
// 设置时间筛选
this.timeindex = e.detail.current
this.btntimeindex(e.detail.current)
// 分栏切换后重新拉取
this.pageNum = 1
// 清空当前数据,避免显示错误的数据
this.notifications = []
this.getlist()
},
// 监听语言变化事件
handleLanguageChange(lang) {
console.log('通知页面语言切换事件:', lang)
},
handleSpaceChanged(payload) {
try {
this.kjid = (payload && payload.kjid) || uni.getStorageSync('kjid')
this.pageNum = 1
this.getlist()
} catch (e) {
console.warn('处理空间切换失败:', e)
}
},
// 点击切换时间标签
onTabClick(index) {
console.log(':', index, '标签信息:', this.tabsDisplay[index])
this.swiperCurrent = index
// 设置时间筛选
this.timeindex = index
this.btntimeindex(index)
// 点击切换分栏时主动刷新当前分类数据
this.pageNum = 1
// 清空当前数据,避免显示错误的数据
this.notifications = []
this.getlist()
},
getTimeColor(classify) {
switch (classify) {
case 'security':
return '#1EC28B'
case 'picture':
return '#007AFF'
case 'malfunctions':
return '#FF3B30'
case 'control':
return '#FF8A00'
case 'system':
return '#8B8E94'
case 'env':
return '#34C759'
default:
return '#8B8E94'
}
},
listByKey(key) {
console.log('listByKey调用:', key, '当前数据:', this.notifications)
// 现在所有tab都显示相同的数据因为时间筛选在API层面处理
console.log('返回所有数据:', this.notifications)
return this.notifications
},
// 通知设置相关方法
showNotificationSettings() {
this.showSettings = true
},
hideNotificationSettings() {
this.showSettings = false
},
hideSubSettings() {
this.showSubSettings = false
this.currentCategoryIndex = -1
},
// 切换主分类开关
onMainSwitchChange(index, event) {
const enabled = event.detail.value
this.notificationSettings[index].enabled = enabled
// 如果关闭主开关,则关闭所有子开关
if (!enabled) {
this.notificationSettings[index].subSettings.forEach(subItem => {
subItem.enabled = false
})
}
// 如果开启主开关,则开启所有子开关
else {
this.notificationSettings[index].subSettings.forEach(subItem => {
subItem.enabled = true
})
}
// 保存设置
this.saveNotificationSettings()
},
// 切换子分类开关
onSubSwitchChange(index, event) {
const enabled = event.detail.value;
this.notificationSettings[this.currentCategoryIndex].subSettings[index].enabled = enabled
// 检查是否所有子开关都关闭了,如果是则关闭主开关
const allSubDisabled = this.notificationSettings[this.currentCategoryIndex].subSettings.every(subItem => !subItem.enabled)
if (allSubDisabled) {
this.notificationSettings[this.currentCategoryIndex].enabled = false
}
// 如果至少有一个子开关开启,则开启主开关
else {
this.notificationSettings[this.currentCategoryIndex].enabled = true
}
},
// 点击分类项
toggleCategory(index) {
if (this.notificationSettings[index].hasSubSettings) {
this.currentCategoryIndex = index
this.showSubSettings = true
}
},
// 保存子设置
saveSubSettings() {
this.saveNotificationSettings();
this.hideSubSettings();
uni.showToast({
title: this.$i18n.t('settingsSaved'),
icon: 'success'
});
},
// 保存通知设置到本地存储
saveNotificationSettings() {
try {
uni.setStorageSync('notificationSettings', this.notificationSettings);
console.log('通知设置已保存:', this.notificationSettings);
} catch (error) {
console.error('保存通知设置失败:', error);
}
},
// 从本地存储加载通知设置
loadNotificationSettings() {
try {
const savedSettings = uni.getStorageSync('notificationSettings');
if (savedSettings && Array.isArray(savedSettings)) {
// 检查是否是新的数据结构包含titleKey
if (savedSettings[0] && savedSettings[0].titleKey) {
this.notificationSettings = savedSettings;
} else {
// 旧数据结构,需要转换
this.convertOldSettingsToNew(savedSettings);
}
console.log('通知设置已加载:', this.notificationSettings);
}
} catch (error) {
console.error('加载通知设置失败:', error);
}
},
// 转换旧数据结构到新结构
convertOldSettingsToNew(oldSettings) {
// 如果旧数据存在,尝试转换
// 这里可以根据实际情况进行转换,或者直接使用默认设置
console.log('检测到旧数据结构,使用默认设置');
// 清除旧的本地存储数据
uni.removeStorageSync('notificationSettings');
// 保存新的默认设置
this.saveNotificationSettings();
},
// 获取已开启的子项描述
getEnabledSubItemsDesc(category) {
if (!category.hasSubSettings || !category.subSettings || category.subSettings.length === 0) {
return this.$i18n.t(category.descKey);
}
const enabledItems = category.subSettings.filter(item => item.enabled);
if (enabledItems.length === 0) {
return this.$i18n.t('noEnabledItems');
}
if (enabledItems.length === category.subSettings.length) {
return this.$i18n.t(category.descKey);
}
return enabledItems.map(item => this.$i18n.t(item.titleKey)).join('、');
},
// 获取子设置标题
getSubSettingsTitle() {
if (!this.currentCategory) return '';
return this.$i18n.t(this.currentCategory.titleKey) + this.$i18n.t('saveSettings').replace('保存', '').replace('Save', '').replace('設定', '').replace('Настройки', '');
}
}
}
</script>
<style lang="scss" scoped>
page {
padding-top: 20rpx;
}
.tabs-wrap {
padding: 0 50rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 0;
// justify-content: flex-start;
box-shadow: 1rpx -8rpx 14rpx 4rpx #ccc;
overflow-x: auto;
overflow-y: hidden;
white-space: nowrap;
view {
text-align: center;
flex-shrink: 0;
}
}
.tab {
color: #8B8E94;
font-size: 28rpx;
padding: 24rpx 12rpx;
position: relative;
margin: 0 5rpx;
max-width: 920rpx;
white-space: nowrap;
}
.tab.active {
color: #222;
font-weight: 600;
}
.tab.active:after {
content: '';
position: absolute;
left: 0;
right: 0;
bottom: 8rpx;
height: 6rpx;
background: #0F0F0F;
border-radius: 6rpx;
}
.swiper {
height: 74vh;
}
.list {
box-sizing: border-box;
height: 74vh;
overflow: scroll;
padding-bottom: 30rpx;
}
.cell {
width: 700rpx;
margin: 16rpx auto;
box-sizing: border-box;
display: flex;
align-items: center;
padding: 20rpx;
border-bottom: 0;
background: #fff;
border-radius: 16rpx;
position: relative;
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.08);
}
.cell-badge {
position: absolute;
right: 140rpx;
top: 20rpx;
background: #F5F6F7;
border-radius: 30rpx;
padding: 6rpx 12rpx 6rpx 36rpx;
display: flex;
align-items: center;
color: #5F6368;
font-size: 22rpx;
}
.badge-icon {
position: absolute;
left: 8rpx;
width: 24rpx;
height: 24rpx;
}
.thumb {
width: 112rpx;
height: 112rpx;
border-radius: 12rpx;
margin-left: auto;
background: #E6E6E6;
}
.content {
flex: 1;
min-width: 0;
padding-right: 24rpx;
}
.row1 {
display: flex;
align-items: center;
}
.small-icon {
width: 28rpx;
height: 28rpx;
margin-right: 10rpx;
}
.time {
color: #8B8E94;
font-size: 24rpx;
}
.row2 {
margin-top: 14rpx;
color: #222;
font-size: 28rpx;
}
.no-more {
width: 100%;
text-align: center;
margin-top: 24rpx;
color: #ccc;
}
// 设置按钮样式
.settings-btn {
font-size: 36rpx;
color: #333;
font-weight: bold;
padding: 24rpx 12rpx;
cursor: pointer;
}
// 通知设置弹窗样式
.settings-modal {
position: fixed;
top: 140px;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
}
.settings-content {
background: #fff;
border-radius:0 0 20rpx 20rpx;
width: 90%;
width: 750rpx;
max-height: 80vh;
overflow: hidden;
}
.settings-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 40rpx 30rpx 20rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.settings-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.close-btn {
font-size: 40rpx;
color: #999;
line-height: 1;
}
.settings-list {
max-height: 60vh;
}
.setting-item {
border-bottom: 1rpx solid #f0f0f0;
}
.setting-main {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
}
.setting-info {
flex: 1;
margin-right: 20rpx;
}
.setting-title {
font-size: 28rpx;
color: #333;
font-weight: 500;
display: block;
margin-bottom: 8rpx;
}
.setting-desc-row {
display: flex;
align-items: center;
margin-top: 8rpx;
}
.setting-desc {
font-size: 24rpx;
color: #666;
line-height: 1.4;
// flex: 1;
}
.setting-controls {
display: flex;
align-items: center;
}
.arrow {
font-size: 20rpx;
color: #999;
margin-left: 10rpx;
}
// 子设置弹窗样式
.sub-settings-modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
}
.sub-settings-content {
background: #fff;
border-radius: 20rpx;
width: 90%;
max-width: 600rpx;
max-height: 80vh;
overflow: hidden;
}
.sub-settings-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 40rpx 30rpx 20rpx;
border-bottom: 1rpx solid #f0f0f0;
}
.sub-settings-title {
font-size: 32rpx;
font-weight: bold;
color: #333;
}
.sub-settings-list {
max-height: 50vh;
}
.sub-setting-item {
border-bottom: 1rpx solid #f0f0f0;
}
.sub-setting-main {
display: flex;
justify-content: space-between;
align-items: center;
padding: 30rpx;
}
.sub-setting-info {
flex: 1;
}
.sub-setting-title {
font-size: 28rpx;
color: #333;
font-weight: 500;
}
.save-btn {
background: #333;
margin: 30rpx;
border-radius: 12rpx;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
}
.save-btn-text {
color: #fff;
font-size: 28rpx;
font-weight: 500;
}
</style>