修改小程序
This commit is contained in:
326
government-mini-program/pages/notification/detail/detail.js
Normal file
326
government-mini-program/pages/notification/detail/detail.js
Normal file
@@ -0,0 +1,326 @@
|
||||
// pages/notification/detail/detail.js
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
loading: true,
|
||||
notificationId: '',
|
||||
notificationInfo: {}
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 检查登录状态
|
||||
this.checkLoginStatus();
|
||||
|
||||
// 获取状态栏高度
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
this.setData({
|
||||
statusBarHeight: systemInfo.statusBarHeight
|
||||
});
|
||||
|
||||
// 获取通知ID
|
||||
if (options.id) {
|
||||
this.setData({
|
||||
notificationId: options.id
|
||||
});
|
||||
this.loadNotificationDetail();
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '参数错误',
|
||||
icon: 'error'
|
||||
});
|
||||
setTimeout(() => {
|
||||
wx.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 检查登录状态
|
||||
this.checkLoginStatus();
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
wx.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// 加载通知详情
|
||||
async loadNotificationDetail() {
|
||||
try {
|
||||
this.setData({ loading: true });
|
||||
|
||||
// 模拟API调用
|
||||
const notificationData = await this.fetchNotificationDetail(this.data.notificationId);
|
||||
|
||||
this.setData({
|
||||
notificationInfo: notificationData,
|
||||
loading: false
|
||||
});
|
||||
|
||||
// 标记为已读
|
||||
this.markAsRead();
|
||||
} catch (error) {
|
||||
console.error('加载通知详情失败:', error);
|
||||
wx.showToast({
|
||||
title: '加载失败',
|
||||
icon: 'error'
|
||||
});
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 模拟获取通知详情API
|
||||
fetchNotificationDetail(notificationId) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
// 根据ID生成不同类型的模拟数据
|
||||
const mockData = this.generateMockNotification(notificationId);
|
||||
resolve(mockData);
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
|
||||
// 生成模拟通知数据
|
||||
generateMockNotification(id) {
|
||||
const types = ['system', 'alert', 'task'];
|
||||
const type = types[parseInt(id) % 3];
|
||||
|
||||
const baseData = {
|
||||
id: id,
|
||||
type: type,
|
||||
time: this.formatTime(new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000)),
|
||||
isRead: false
|
||||
};
|
||||
|
||||
switch (type) {
|
||||
case 'system':
|
||||
return {
|
||||
...baseData,
|
||||
title: '系统维护通知',
|
||||
content: '系统将于今晚22:00-24:00进行例行维护,期间可能影响部分功能使用,请提前做好相关准备工作。维护期间如有紧急情况,请联系技术支持热线。',
|
||||
attachments: [
|
||||
{
|
||||
id: '1',
|
||||
name: '维护说明文档.pdf',
|
||||
size: '2.3MB'
|
||||
}
|
||||
],
|
||||
processRecords: [
|
||||
{
|
||||
id: '1',
|
||||
time: '10:30',
|
||||
action: '发布通知',
|
||||
operator: '系统管理员',
|
||||
remark: '定期系统维护通知'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
case 'alert':
|
||||
return {
|
||||
...baseData,
|
||||
title: '牲畜异常告警',
|
||||
content: '检测到张三养殖场出现牲畜异常情况,请及时处理。系统监测显示该养殖场的牲畜活动异常,可能存在健康风险,建议立即派遣检查人员前往现场核实情况。',
|
||||
alertDetails: {
|
||||
level: 'high',
|
||||
farmerName: '张三',
|
||||
location: '西夏区兴泾镇张三养殖场',
|
||||
reason: '牲畜活动异常,疑似健康问题'
|
||||
},
|
||||
processRecords: [
|
||||
{
|
||||
id: '1',
|
||||
time: '14:25',
|
||||
action: '系统自动告警',
|
||||
operator: '监控系统',
|
||||
remark: '检测到异常数据'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
case 'task':
|
||||
return {
|
||||
...baseData,
|
||||
title: '月度检查任务',
|
||||
content: '请在本月底前完成辖区内所有养殖户的月度例行检查工作。检查内容包括:牲畜健康状况、饲料质量、环境卫生、防疫措施等。请及时提交检查报告。',
|
||||
taskDetails: {
|
||||
taskType: '月度例行检查',
|
||||
deadline: '2024-01-31 18:00',
|
||||
status: 'pending',
|
||||
priority: 'medium'
|
||||
},
|
||||
attachments: [
|
||||
{
|
||||
id: '1',
|
||||
name: '检查清单.xlsx',
|
||||
size: '156KB'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
name: '报告模板.docx',
|
||||
size: '89KB'
|
||||
}
|
||||
],
|
||||
processRecords: [
|
||||
{
|
||||
id: '1',
|
||||
time: '09:00',
|
||||
action: '任务分配',
|
||||
operator: '管理员',
|
||||
remark: '月度例行检查任务'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
default:
|
||||
return baseData;
|
||||
}
|
||||
},
|
||||
|
||||
// 格式化时间
|
||||
formatTime(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(date.getDate()).padStart(2, '0');
|
||||
const hour = String(date.getHours()).padStart(2, '0');
|
||||
const minute = String(date.getMinutes()).padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day} ${hour}:${minute}`;
|
||||
},
|
||||
|
||||
// 标记为已读
|
||||
async markAsRead() {
|
||||
try {
|
||||
// 模拟API调用
|
||||
await this.markNotificationAsRead(this.data.notificationId);
|
||||
console.log('通知已标记为已读');
|
||||
} catch (error) {
|
||||
console.error('标记已读失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 模拟标记已读API
|
||||
markNotificationAsRead(notificationId) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve({ success: true });
|
||||
}, 500);
|
||||
});
|
||||
},
|
||||
|
||||
// 处理告警
|
||||
onHandleAlert() {
|
||||
const alertDetails = this.data.notificationInfo.alertDetails;
|
||||
wx.showModal({
|
||||
title: '处理告警',
|
||||
content: `确定要处理来自${alertDetails.farmerName}的告警吗?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 这里可以跳转到具体的处理页面
|
||||
wx.showToast({
|
||||
title: '正在处理...',
|
||||
icon: 'loading'
|
||||
});
|
||||
|
||||
setTimeout(() => {
|
||||
wx.showToast({
|
||||
title: '处理成功',
|
||||
icon: 'success'
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 处理任务
|
||||
onHandleTask() {
|
||||
const taskDetails = this.data.notificationInfo.taskDetails;
|
||||
wx.showModal({
|
||||
title: '处理任务',
|
||||
content: `确定要开始处理"${taskDetails.taskType}"任务吗?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 这里可以跳转到具体的任务处理页面
|
||||
wx.showToast({
|
||||
title: '任务已接受',
|
||||
icon: 'success'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 分享通知
|
||||
onShare() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['复制链接', '发送给同事', '保存到本地'],
|
||||
success: (res) => {
|
||||
switch (res.tapIndex) {
|
||||
case 0:
|
||||
wx.setClipboardData({
|
||||
data: `通知详情:${this.data.notificationInfo.title}`,
|
||||
success: () => {
|
||||
wx.showToast({
|
||||
title: '已复制到剪贴板',
|
||||
icon: 'success'
|
||||
});
|
||||
}
|
||||
});
|
||||
break;
|
||||
case 1:
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
break;
|
||||
case 2:
|
||||
wx.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 查看附件
|
||||
onAttachmentTap(e) {
|
||||
const attachment = e.currentTarget.dataset.attachment;
|
||||
wx.showModal({
|
||||
title: '查看附件',
|
||||
content: `确定要查看附件"${attachment.name}"吗?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.showToast({
|
||||
title: '正在打开...',
|
||||
icon: 'loading'
|
||||
});
|
||||
|
||||
// 这里可以实现附件预览或下载功能
|
||||
setTimeout(() => {
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
this.loadNotificationDetail().finally(() => {
|
||||
wx.stopPullDownRefresh();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"navigationBarTitleText": "通知详情",
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColor": "#f5f5f5",
|
||||
"backgroundTextStyle": "dark",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
144
government-mini-program/pages/notification/detail/detail.wxml
Normal file
144
government-mini-program/pages/notification/detail/detail.wxml
Normal file
@@ -0,0 +1,144 @@
|
||||
<!--pages/notification/detail/detail.wxml-->
|
||||
<view class="container">
|
||||
<!-- 状态栏 -->
|
||||
<view class="status-bar" style="height: {{statusBarHeight}}px;"></view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view wx:if="{{loading}}" class="loading-container">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 通知详情内容 -->
|
||||
<view wx:else class="detail-content">
|
||||
<!-- 通知头部 -->
|
||||
<view class="notification-header">
|
||||
<view class="notification-title">{{notificationInfo.title}}</view>
|
||||
<view class="notification-meta">
|
||||
<view class="notification-time">{{notificationInfo.time}}</view>
|
||||
<view class="notification-type type-{{notificationInfo.type}}">
|
||||
{{notificationInfo.type === 'system' ? '系统通知' : notificationInfo.type === 'alert' ? '告警通知' : '任务通知'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 通知内容 -->
|
||||
<view class="notification-content">
|
||||
<view class="content-section">
|
||||
<view class="section-title">通知内容</view>
|
||||
<view class="content-text">{{notificationInfo.content}}</view>
|
||||
</view>
|
||||
|
||||
<!-- 告警详情 (仅告警通知显示) -->
|
||||
<view wx:if="{{notificationInfo.type === 'alert' && notificationInfo.alertDetails}}" class="content-section">
|
||||
<view class="section-title">告警详情</view>
|
||||
<view class="alert-details">
|
||||
<view class="detail-item">
|
||||
<view class="detail-label">告警级别</view>
|
||||
<view class="detail-value level-{{notificationInfo.alertDetails.level}}">
|
||||
{{notificationInfo.alertDetails.level === 'high' ? '高级' : notificationInfo.alertDetails.level === 'medium' ? '中级' : '低级'}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<view class="detail-label">涉及养殖户</view>
|
||||
<view class="detail-value">{{notificationInfo.alertDetails.farmerName}}</view>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<view class="detail-label">告警位置</view>
|
||||
<view class="detail-value">{{notificationInfo.alertDetails.location}}</view>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<view class="detail-label">告警原因</view>
|
||||
<view class="detail-value">{{notificationInfo.alertDetails.reason}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 任务详情 (仅任务通知显示) -->
|
||||
<view wx:if="{{notificationInfo.type === 'task' && notificationInfo.taskDetails}}" class="content-section">
|
||||
<view class="section-title">任务详情</view>
|
||||
<view class="task-details">
|
||||
<view class="detail-item">
|
||||
<view class="detail-label">任务类型</view>
|
||||
<view class="detail-value">{{notificationInfo.taskDetails.taskType}}</view>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<view class="detail-label">截止时间</view>
|
||||
<view class="detail-value">{{notificationInfo.taskDetails.deadline}}</view>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<view class="detail-label">任务状态</view>
|
||||
<view class="detail-value status-{{notificationInfo.taskDetails.status}}">
|
||||
{{notificationInfo.taskDetails.status === 'pending' ? '待处理' : notificationInfo.taskDetails.status === 'processing' ? '处理中' : '已完成'}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<view class="detail-label">优先级</view>
|
||||
<view class="detail-value priority-{{notificationInfo.taskDetails.priority}}">
|
||||
{{notificationInfo.taskDetails.priority === 'high' ? '高' : notificationInfo.taskDetails.priority === 'medium' ? '中' : '低'}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 附件信息 -->
|
||||
<view wx:if="{{notificationInfo.attachments && notificationInfo.attachments.length > 0}}" class="content-section">
|
||||
<view class="section-title">相关附件</view>
|
||||
<view class="attachments-list">
|
||||
<view
|
||||
wx:for="{{notificationInfo.attachments}}"
|
||||
wx:key="id"
|
||||
class="attachment-item"
|
||||
bindtap="onAttachmentTap"
|
||||
data-attachment="{{item}}"
|
||||
>
|
||||
<view class="attachment-icon">📎</view>
|
||||
<view class="attachment-info">
|
||||
<view class="attachment-name">{{item.name}}</view>
|
||||
<view class="attachment-size">{{item.size}}</view>
|
||||
</view>
|
||||
<view class="attachment-action">查看</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 处理记录 -->
|
||||
<view wx:if="{{notificationInfo.processRecords && notificationInfo.processRecords.length > 0}}" class="content-section">
|
||||
<view class="section-title">处理记录</view>
|
||||
<view class="process-records">
|
||||
<view
|
||||
wx:for="{{notificationInfo.processRecords}}"
|
||||
wx:key="id"
|
||||
class="record-item"
|
||||
>
|
||||
<view class="record-time">{{item.time}}</view>
|
||||
<view class="record-content">
|
||||
<view class="record-action">{{item.action}}</view>
|
||||
<view class="record-operator">操作人:{{item.operator}}</view>
|
||||
<view wx:if="{{item.remark}}" class="record-remark">{{item.remark}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view wx:if="{{!loading}}" class="bottom-bar">
|
||||
<button
|
||||
wx:if="{{notificationInfo.type === 'alert'}}"
|
||||
class="action-btn handle-btn"
|
||||
bindtap="onHandleAlert"
|
||||
>
|
||||
处理告警
|
||||
</button>
|
||||
<button
|
||||
wx:if="{{notificationInfo.type === 'task'}}"
|
||||
class="action-btn task-btn"
|
||||
bindtap="onHandleTask"
|
||||
>
|
||||
处理任务
|
||||
</button>
|
||||
<button class="action-btn share-btn" bindtap="onShare">分享</button>
|
||||
</view>
|
||||
</view>
|
||||
336
government-mini-program/pages/notification/detail/detail.wxss
Normal file
336
government-mini-program/pages/notification/detail/detail.wxss
Normal file
@@ -0,0 +1,336 @@
|
||||
/* pages/notification/detail/detail.wxss */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-bottom: 120rpx;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background-color: #2c5aa0;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 60vh;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #f3f3f3;
|
||||
border-top: 4rpx solid #2c5aa0;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
margin-top: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
/* 详情内容 */
|
||||
.detail-content {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 通知头部 */
|
||||
.notification-header {
|
||||
background-color: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.notification-meta {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.notification-time {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.notification-type {
|
||||
padding: 6rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 22rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.type-system {
|
||||
background-color: #e6f7ff;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.type-alert {
|
||||
background-color: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.type-task {
|
||||
background-color: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
/* 通知内容 */
|
||||
.notification-content {
|
||||
background-color: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.content-section {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.content-section:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
padding-bottom: 10rpx;
|
||||
border-bottom: 2rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* 详情项 */
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 16rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.detail-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
flex-shrink: 0;
|
||||
width: 160rpx;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* 告警级别 */
|
||||
.level-high {
|
||||
color: #ff4d4f;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.level-medium {
|
||||
color: #fa8c16;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.level-low {
|
||||
color: #52c41a;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 任务状态 */
|
||||
.status-pending {
|
||||
color: #fa8c16;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-processing {
|
||||
color: #1890ff;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-completed {
|
||||
color: #52c41a;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 优先级 */
|
||||
.priority-high {
|
||||
color: #ff4d4f;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.priority-medium {
|
||||
color: #fa8c16;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.priority-low {
|
||||
color: #52c41a;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 附件列表 */
|
||||
.attachments-list {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.attachment-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
margin-bottom: 12rpx;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.attachment-item:active {
|
||||
background-color: #e9ecef;
|
||||
}
|
||||
|
||||
.attachment-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.attachment-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.attachment-name {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.attachment-size {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.attachment-action {
|
||||
font-size: 26rpx;
|
||||
color: #2c5aa0;
|
||||
}
|
||||
|
||||
/* 处理记录 */
|
||||
.process-records {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.record-item {
|
||||
display: flex;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.record-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.record-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
width: 120rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.record-content {
|
||||
flex: 1;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.record-action {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.record-operator {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.record-remark {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: white;
|
||||
padding: 20rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
box-shadow: 0 -2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.action-btn:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.handle-btn {
|
||||
background-color: #ff4d4f;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.task-btn {
|
||||
background-color: #fa8c16;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.share-btn {
|
||||
background-color: #2c5aa0;
|
||||
color: white;
|
||||
}
|
||||
397
government-mini-program/pages/notification/notification.js
Normal file
397
government-mini-program/pages/notification/notification.js
Normal file
@@ -0,0 +1,397 @@
|
||||
const app = getApp();
|
||||
const apiService = require('../../utils/api.js');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
loading: true,
|
||||
|
||||
// 筛选状态
|
||||
selectedType: 'all',
|
||||
selectedStatus: 'all',
|
||||
|
||||
// 筛选选项
|
||||
typeOptions: [
|
||||
{ value: 'all', label: '全部类型' },
|
||||
{ value: 'system', label: '系统通知' },
|
||||
{ value: 'alert', label: '预警通知' },
|
||||
{ value: 'task', label: '任务通知' }
|
||||
],
|
||||
|
||||
statusOptions: [
|
||||
{ value: 'all', label: '全部状态' },
|
||||
{ value: 'unread', label: '未读' },
|
||||
{ value: 'read', label: '已读' }
|
||||
],
|
||||
|
||||
// 通知列表
|
||||
notificationList: [],
|
||||
|
||||
// 分页
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
hasMore: true,
|
||||
|
||||
// 统计信息
|
||||
statistics: {
|
||||
total: 0,
|
||||
unread: 0,
|
||||
system: 0,
|
||||
alert: 0,
|
||||
task: 0
|
||||
}
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
// 获取状态栏高度
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
this.setData({
|
||||
statusBarHeight: systemInfo.statusBarHeight
|
||||
});
|
||||
|
||||
// 检查登录状态
|
||||
this.checkLoginStatus();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 每次显示页面时刷新数据
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
wx.reLaunch({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// 加载数据
|
||||
async loadData(isRefresh = true) {
|
||||
if (!this.checkLoginStatus()) return;
|
||||
|
||||
if (isRefresh) {
|
||||
this.setData({
|
||||
loading: true,
|
||||
currentPage: 1,
|
||||
notificationList: [],
|
||||
hasMore: true
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await this.loadNotifications();
|
||||
} catch (error) {
|
||||
console.error('数据加载失败:', error);
|
||||
// 加载模拟数据作为备用
|
||||
this.loadMockData();
|
||||
} finally {
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 加载通知列表
|
||||
async loadNotifications() {
|
||||
try {
|
||||
const params = {
|
||||
page: this.data.currentPage,
|
||||
pageSize: this.data.pageSize,
|
||||
type: this.data.selectedType === 'all' ? '' : this.data.selectedType,
|
||||
status: this.data.selectedStatus === 'all' ? '' : this.data.selectedStatus
|
||||
};
|
||||
|
||||
// 这里可以调用实际的通知API
|
||||
// const result = await apiService.getNotifications(params);
|
||||
|
||||
// 暂时使用模拟数据
|
||||
this.loadMockData();
|
||||
} catch (error) {
|
||||
console.error('获取通知列表失败:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载模拟数据
|
||||
loadMockData() {
|
||||
const mockNotifications = [
|
||||
{
|
||||
id: 1,
|
||||
type: 'alert',
|
||||
title: '养殖户异常预警',
|
||||
content: '张三养殖场检测到异常情况,请及时处理',
|
||||
status: 'unread',
|
||||
priority: 'high',
|
||||
createTime: '2024-01-15 10:30:00',
|
||||
farmerId: 1,
|
||||
farmerName: '张三',
|
||||
farmName: '张家养殖场'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'system',
|
||||
title: '系统维护通知',
|
||||
content: '系统将于今晚22:00-24:00进行维护,期间可能影响正常使用',
|
||||
status: 'read',
|
||||
priority: 'medium',
|
||||
createTime: '2024-01-15 09:15:00'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'task',
|
||||
title: '检查任务提醒',
|
||||
content: '您有一个待处理的检查任务:李氏牧场定期检查',
|
||||
status: 'unread',
|
||||
priority: 'medium',
|
||||
createTime: '2024-01-15 08:45:00',
|
||||
farmerId: 2,
|
||||
farmerName: '李四',
|
||||
farmName: '李氏牧场'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
type: 'alert',
|
||||
title: '设备离线预警',
|
||||
content: '王家农场的监控设备已离线超过2小时',
|
||||
status: 'unread',
|
||||
priority: 'high',
|
||||
createTime: '2024-01-14 16:20:00',
|
||||
farmerId: 3,
|
||||
farmerName: '王五',
|
||||
farmName: '王家农场'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
type: 'system',
|
||||
title: '数据同步完成',
|
||||
content: '今日数据同步已完成,共同步1250条记录',
|
||||
status: 'read',
|
||||
priority: 'low',
|
||||
createTime: '2024-01-14 15:30:00'
|
||||
}
|
||||
];
|
||||
|
||||
// 根据筛选条件过滤数据
|
||||
let filteredNotifications = mockNotifications;
|
||||
|
||||
if (this.data.selectedType !== 'all') {
|
||||
filteredNotifications = filteredNotifications.filter(n => n.type === this.data.selectedType);
|
||||
}
|
||||
|
||||
if (this.data.selectedStatus !== 'all') {
|
||||
filteredNotifications = filteredNotifications.filter(n => n.status === this.data.selectedStatus);
|
||||
}
|
||||
|
||||
this.setData({
|
||||
notificationList: filteredNotifications,
|
||||
totalCount: filteredNotifications.length,
|
||||
hasMore: false,
|
||||
statistics: {
|
||||
total: mockNotifications.length,
|
||||
unread: mockNotifications.filter(n => n.status === 'unread').length,
|
||||
system: mockNotifications.filter(n => n.type === 'system').length,
|
||||
alert: mockNotifications.filter(n => n.type === 'alert').length,
|
||||
task: mockNotifications.filter(n => n.type === 'task').length
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 类型筛选
|
||||
onTypeChange(e) {
|
||||
const type = e.currentTarget.dataset.type;
|
||||
this.setData({
|
||||
selectedType: type
|
||||
});
|
||||
this.loadData(true);
|
||||
},
|
||||
|
||||
// 状态筛选
|
||||
onStatusChange(e) {
|
||||
const status = e.currentTarget.dataset.status;
|
||||
this.setData({
|
||||
selectedStatus: status
|
||||
});
|
||||
this.loadData(true);
|
||||
},
|
||||
|
||||
// 生成模拟通知数据
|
||||
generateMockNotifications() {
|
||||
const types = ['system', 'alert', 'task']
|
||||
const typeNames = { system: '系统通知', alert: '告警通知', task: '任务通知' }
|
||||
const icons = { system: '🔔', alert: '⚠️', task: '📋' }
|
||||
|
||||
const notifications = []
|
||||
const pageSize = this.data.pageSize
|
||||
|
||||
for (let i = 0; i < pageSize; i++) {
|
||||
const type = types[Math.floor(Math.random() * types.length)]
|
||||
const isRead = Math.random() > 0.3
|
||||
const id = Date.now() + i
|
||||
|
||||
notifications.push({
|
||||
id,
|
||||
type,
|
||||
typeName: typeNames[type],
|
||||
icon: icons[type],
|
||||
title: this.getNotificationTitle(type),
|
||||
content: this.getNotificationContent(type),
|
||||
time: this.formatTime(new Date(Date.now() - Math.random() * 7 * 24 * 60 * 60 * 1000)),
|
||||
isRead
|
||||
})
|
||||
}
|
||||
|
||||
return notifications.filter(item => {
|
||||
if (this.data.selectedTab === 'all') return true
|
||||
return item.type === this.data.selectedTab
|
||||
})
|
||||
},
|
||||
|
||||
// 获取通知标题
|
||||
getNotificationTitle(type) {
|
||||
const titles = {
|
||||
system: ['系统维护通知', '版本更新提醒', '账户安全提醒', '数据备份完成'],
|
||||
alert: ['设备离线告警', '异常数据告警', '温度超标告警', '网络连接异常'],
|
||||
task: ['检疫任务提醒', '报告提交截止', '数据统计任务', '设备巡检任务']
|
||||
}
|
||||
const typeList = titles[type] || titles.system
|
||||
return typeList[Math.floor(Math.random() * typeList.length)]
|
||||
},
|
||||
|
||||
// 获取通知内容
|
||||
getNotificationContent(type) {
|
||||
const contents = {
|
||||
system: ['系统将于今晚进行维护,预计持续2小时', '新版本已发布,请及时更新', '检测到异常登录,请注意账户安全', '数据备份已完成,请查看备份报告'],
|
||||
alert: ['监控摄像头#001已离线超过30分钟', '养殖场温度传感器检测到异常数据', '养殖区域温度超过安全范围', '网络连接不稳定,请检查网络设备'],
|
||||
task: ['您有新的检疫任务需要处理', '月度报告提交截止日期临近', '请完成本周数据统计工作', '设备巡检任务已分配给您']
|
||||
}
|
||||
const typeList = contents[type] || contents.system
|
||||
return typeList[Math.floor(Math.random() * typeList.length)]
|
||||
},
|
||||
|
||||
// 格式化时间
|
||||
formatTime(date) {
|
||||
const now = new Date()
|
||||
const diff = now - date
|
||||
const minutes = Math.floor(diff / (1000 * 60))
|
||||
const hours = Math.floor(diff / (1000 * 60 * 60))
|
||||
const days = Math.floor(diff / (1000 * 60 * 60 * 24))
|
||||
|
||||
if (minutes < 1) return '刚刚'
|
||||
if (minutes < 60) return `${minutes}分钟前`
|
||||
if (hours < 24) return `${hours}小时前`
|
||||
if (days < 7) return `${days}天前`
|
||||
|
||||
return `${date.getMonth() + 1}-${date.getDate()}`
|
||||
},
|
||||
|
||||
// 更新标签计数
|
||||
updateTabCounts() {
|
||||
const tabs = this.data.tabs.map(tab => {
|
||||
if (tab.key === 'all') {
|
||||
tab.count = this.data.notificationList.filter(item => !item.isRead).length
|
||||
} else {
|
||||
tab.count = this.data.notificationList.filter(item => item.type === tab.key && !item.isRead).length
|
||||
}
|
||||
return tab
|
||||
})
|
||||
|
||||
this.setData({ tabs })
|
||||
},
|
||||
|
||||
// 标签切换
|
||||
onTabChange(e) {
|
||||
const { key } = e.currentTarget.dataset
|
||||
this.setData({
|
||||
selectedTab: key,
|
||||
currentPage: 1,
|
||||
notificationList: [],
|
||||
hasMore: true
|
||||
})
|
||||
this.loadNotifications()
|
||||
},
|
||||
|
||||
// 通知点击事件
|
||||
onNotificationTap(e) {
|
||||
const { item } = e.currentTarget.dataset
|
||||
console.log('点击通知:', item)
|
||||
|
||||
// 标记为已读
|
||||
if (!item.isRead) {
|
||||
const notificationList = this.data.notificationList.map(notification => {
|
||||
if (notification.id === item.id) {
|
||||
notification.isRead = true
|
||||
}
|
||||
return notification
|
||||
})
|
||||
|
||||
this.setData({ notificationList })
|
||||
this.updateTabCounts()
|
||||
}
|
||||
|
||||
// 根据通知类型跳转到相应页面
|
||||
switch (item.type) {
|
||||
case 'alert':
|
||||
wx.navigateTo({
|
||||
url: '/pages/alert/detail/detail?id=' + item.id
|
||||
})
|
||||
break
|
||||
case 'task':
|
||||
wx.navigateTo({
|
||||
url: '/pages/task/detail/detail?id=' + item.id
|
||||
})
|
||||
break
|
||||
default:
|
||||
wx.showToast({
|
||||
title: '查看详情功能开发中',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
// 删除通知
|
||||
onDeleteNotification(e) {
|
||||
const { item } = e.currentTarget.dataset
|
||||
|
||||
wx.showModal({
|
||||
title: '确认删除',
|
||||
content: '确定要删除这条通知吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
const notificationList = this.data.notificationList.filter(notification => notification.id !== item.id)
|
||||
this.setData({ notificationList })
|
||||
this.updateTabCounts()
|
||||
|
||||
wx.showToast({
|
||||
title: '删除成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 全部已读
|
||||
onMarkAllRead() {
|
||||
const notificationList = this.data.notificationList.map(item => {
|
||||
item.isRead = true
|
||||
return item
|
||||
})
|
||||
|
||||
this.setData({ notificationList })
|
||||
this.updateTabCounts()
|
||||
|
||||
wx.showToast({
|
||||
title: '已全部标记为已读',
|
||||
icon: 'success'
|
||||
})
|
||||
},
|
||||
|
||||
// 加载更多
|
||||
onLoadMore() {
|
||||
this.loadNotifications()
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "消息通知",
|
||||
"enablePullDownRefresh": true,
|
||||
"backgroundColor": "#f5f5f5",
|
||||
"backgroundTextStyle": "dark"
|
||||
}
|
||||
79
government-mini-program/pages/notification/notification.wxml
Normal file
79
government-mini-program/pages/notification/notification.wxml
Normal file
@@ -0,0 +1,79 @@
|
||||
<!-- 状态栏 -->
|
||||
<view class="status-bar" style="height: {{statusBarHeight}}px;"></view>
|
||||
|
||||
<!-- 页面容器 -->
|
||||
<view class="container">
|
||||
<!-- 头部 -->
|
||||
<view class="header">
|
||||
<view class="header-title">消息通知</view>
|
||||
<view class="header-actions">
|
||||
<view class="action-btn" bindtap="onMarkAllRead">
|
||||
<text class="action-text">全部已读</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 筛选标签 -->
|
||||
<view class="filter-tabs">
|
||||
<view
|
||||
class="tab-item {{selectedTab === item.key ? 'active' : ''}}"
|
||||
wx:for="{{tabs}}"
|
||||
wx:key="key"
|
||||
data-key="{{item.key}}"
|
||||
bindtap="onTabChange"
|
||||
>
|
||||
<text class="tab-text">{{item.name}}</text>
|
||||
<view class="tab-badge" wx:if="{{item.count > 0}}">{{item.count}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 通知列表 -->
|
||||
<scroll-view class="notification-list" scroll-y="{{true}}" bindscrolltolower="onLoadMore">
|
||||
<view
|
||||
class="notification-item {{item.isRead ? 'read' : 'unread'}}"
|
||||
wx:for="{{notificationList}}"
|
||||
wx:key="id"
|
||||
data-item="{{item}}"
|
||||
bindtap="onNotificationTap"
|
||||
>
|
||||
<!-- 通知图标 -->
|
||||
<view class="notification-icon">
|
||||
<text class="icon-text">{{item.icon}}</text>
|
||||
<view class="unread-dot" wx:if="{{!item.isRead}}"></view>
|
||||
</view>
|
||||
|
||||
<!-- 通知内容 -->
|
||||
<view class="notification-content">
|
||||
<view class="notification-title">{{item.title}}</view>
|
||||
<view class="notification-desc">{{item.content}}</view>
|
||||
<view class="notification-meta">
|
||||
<text class="notification-time">{{item.time}}</text>
|
||||
<text class="notification-type">{{item.typeName}}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="notification-actions">
|
||||
<view class="action-btn" data-item="{{item}}" bindtap="onDeleteNotification" catchtap="true">
|
||||
<text class="action-icon">🗑️</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载更多 -->
|
||||
<view class="load-more" wx:if="{{hasMore}}">
|
||||
<text class="load-text">{{loading ? '加载中...' : '上拉加载更多'}}</text>
|
||||
</view>
|
||||
|
||||
<!-- 没有更多数据 -->
|
||||
<view class="no-more" wx:if="{{!hasMore && notificationList.length > 0}}">
|
||||
<text class="no-more-text">没有更多通知了</text>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" wx:if="{{notificationList.length === 0 && !loading}}">
|
||||
<text class="empty-icon">📭</text>
|
||||
<text class="empty-text">暂无通知消息</text>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
250
government-mini-program/pages/notification/notification.wxss
Normal file
250
government-mini-program/pages/notification/notification.wxss
Normal file
@@ -0,0 +1,250 @@
|
||||
/* 页面容器 */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* 状态栏 */
|
||||
.status-bar {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
/* 头部 */
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
padding: 10rpx 20rpx;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 28rpx;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* 筛选标签 */
|
||||
.filter-tabs {
|
||||
display: flex;
|
||||
background-color: white;
|
||||
padding: 0 30rpx;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx 20rpx;
|
||||
margin-right: 40rpx;
|
||||
border-bottom: 4rpx solid transparent;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.tab-item.active {
|
||||
border-bottom-color: #4CAF50;
|
||||
}
|
||||
|
||||
.tab-text {
|
||||
font-size: 30rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.tab-item.active .tab-text {
|
||||
color: #4CAF50;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.tab-badge {
|
||||
position: absolute;
|
||||
top: 20rpx;
|
||||
right: 10rpx;
|
||||
min-width: 32rpx;
|
||||
height: 32rpx;
|
||||
line-height: 32rpx;
|
||||
text-align: center;
|
||||
font-size: 20rpx;
|
||||
color: white;
|
||||
background-color: #ff4757;
|
||||
border-radius: 16rpx;
|
||||
padding: 0 8rpx;
|
||||
}
|
||||
|
||||
/* 通知列表 */
|
||||
.notification-list {
|
||||
height: calc(100vh - 200rpx);
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.notification-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
padding: 30rpx;
|
||||
margin: 0 20rpx 20rpx;
|
||||
background-color: white;
|
||||
border-radius: 16rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.notification-item.unread {
|
||||
border-left: 6rpx solid #4CAF50;
|
||||
}
|
||||
|
||||
.notification-item.read {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 通知图标 */
|
||||
.notification-icon {
|
||||
position: relative;
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f0f9ff;
|
||||
border-radius: 50%;
|
||||
margin-right: 20rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.icon-text {
|
||||
font-size: 40rpx;
|
||||
}
|
||||
|
||||
.unread-dot {
|
||||
position: absolute;
|
||||
top: 10rpx;
|
||||
right: 10rpx;
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
background-color: #ff4757;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/* 通知内容 */
|
||||
.notification-content {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.notification-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.notification-desc {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
line-height: 1.5;
|
||||
margin-bottom: 15rpx;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.notification-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.notification-time {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.notification-type {
|
||||
font-size: 24rpx;
|
||||
color: #4CAF50;
|
||||
background-color: rgba(76, 175, 80, 0.1);
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.notification-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-left: 20rpx;
|
||||
}
|
||||
|
||||
.notification-actions .action-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 加载更多 */
|
||||
.load-more {
|
||||
text-align: center;
|
||||
padding: 40rpx;
|
||||
}
|
||||
|
||||
.load-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 没有更多 */
|
||||
.no-more {
|
||||
text-align: center;
|
||||
padding: 40rpx;
|
||||
}
|
||||
|
||||
.no-more-text {
|
||||
font-size: 28rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 120rpx 40rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 120rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 32rpx;
|
||||
color: #999;
|
||||
}
|
||||
Reference in New Issue
Block a user