修改小程序
This commit is contained in:
@@ -1,42 +0,0 @@
|
||||
// pages/approval/approval.js
|
||||
Page({
|
||||
data: {
|
||||
searchKeyword: '',
|
||||
loading: false,
|
||||
approvalList: []
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadApprovalData()
|
||||
},
|
||||
|
||||
loadApprovalData() {
|
||||
// 模拟数据
|
||||
this.setData({
|
||||
approvalList: [
|
||||
{
|
||||
id: 1,
|
||||
title: '养殖许可证申请',
|
||||
description: '张三申请养殖许可证',
|
||||
applicant: '张三',
|
||||
createTime: '2024-01-15 09:00',
|
||||
status: 'pending',
|
||||
statusText: '待审批'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
handleAdd() {
|
||||
wx.showToast({
|
||||
title: '新增功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<!--pages/approval/approval.wxml-->
|
||||
<view class="approval-container">
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-section">
|
||||
<view class="search-bar">
|
||||
<input
|
||||
value="{{searchKeyword}}"
|
||||
type="text"
|
||||
placeholder="搜索审批记录..."
|
||||
class="search-input"
|
||||
bindinput="onSearchInput"
|
||||
/>
|
||||
<view class="search-icon">🔍</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 审批列表 -->
|
||||
<view class="approval-list">
|
||||
<view class="list-header">
|
||||
<view class="list-title">审批管理</view>
|
||||
<view class="add-btn" bindtap="handleAdd">
|
||||
<text class="add-text">新增</text>
|
||||
<view class="add-icon">+</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{loading}}" class="loading">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view wx:elif="{{approvalList.length === 0}}" class="empty">
|
||||
<view class="empty-icon">📋</view>
|
||||
<view class="empty-text">暂无审批记录</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="list-content">
|
||||
<view
|
||||
wx:for="{{approvalList}}"
|
||||
wx:key="id"
|
||||
class="approval-item"
|
||||
>
|
||||
<view class="item-header">
|
||||
<view class="item-title">{{item.title}}</view>
|
||||
<view class="item-status {{item.status}}">
|
||||
{{item.statusText}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-desc">{{item.description}}</view>
|
||||
<view class="item-meta">
|
||||
<view class="item-applicant">申请人: {{item.applicant}}</view>
|
||||
<view class="item-time">{{item.createTime}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,159 +0,0 @@
|
||||
/* pages/approval/approval.wxss */
|
||||
.approval-container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
background: #f8f9fa;
|
||||
border: none;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 60rpx 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.approval-list {
|
||||
background: #fff;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
background: #1890ff;
|
||||
border-radius: 24rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.add-text {
|
||||
font-size: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.loading-text,
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
space-y: 0;
|
||||
}
|
||||
|
||||
.approval-item {
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.approval-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-status {
|
||||
font-size: 20rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-status.pending {
|
||||
background: #fff7e6;
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 12rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-applicant,
|
||||
.item-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// pages/dashboard/dashboard.js
|
||||
const dashboardService = require('../../services/dashboardService.js')
|
||||
|
||||
Page({
|
||||
data: {
|
||||
overviewCards: [
|
||||
{
|
||||
key: 'supervision',
|
||||
icon: '🔍',
|
||||
label: '监管记录',
|
||||
value: '0',
|
||||
trend: 'up',
|
||||
trendText: '+0%',
|
||||
type: 'primary'
|
||||
},
|
||||
{
|
||||
key: 'approval',
|
||||
icon: '✅',
|
||||
label: '待审批',
|
||||
value: '0',
|
||||
trend: 'up',
|
||||
trendText: '+0%',
|
||||
type: 'success'
|
||||
},
|
||||
{
|
||||
key: 'personnel',
|
||||
icon: '👥',
|
||||
label: '人员总数',
|
||||
value: '0',
|
||||
trend: 'up',
|
||||
trendText: '+0%',
|
||||
type: 'warning'
|
||||
},
|
||||
{
|
||||
key: 'epidemic',
|
||||
icon: '🦠',
|
||||
label: '疫情预警',
|
||||
value: '0',
|
||||
trend: 'down',
|
||||
trendText: '-0%',
|
||||
type: 'danger'
|
||||
}
|
||||
],
|
||||
supervisionStats: [
|
||||
{ key: 'total', name: '总监管数', desc: '累计监管记录', value: '0' },
|
||||
{ key: 'today', name: '今日监管', desc: '今日新增记录', value: '0' },
|
||||
{ key: 'pending', name: '待处理', desc: '待处理事项', value: '0' },
|
||||
{ key: 'completed', name: '已完成', desc: '已完成事项', value: '0' }
|
||||
],
|
||||
recentActivities: [
|
||||
{
|
||||
id: 1,
|
||||
icon: '🔍',
|
||||
title: '监管检查',
|
||||
desc: '完成养殖场A的例行检查',
|
||||
time: '2小时前',
|
||||
status: 'success',
|
||||
statusText: '已完成'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: '✅',
|
||||
title: '审批通过',
|
||||
desc: '通过养殖许可证申请',
|
||||
time: '4小时前',
|
||||
status: 'success',
|
||||
statusText: '已通过'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: '⏳',
|
||||
title: '待审批',
|
||||
desc: '养殖场B的扩建申请',
|
||||
time: '6小时前',
|
||||
status: 'pending',
|
||||
statusText: '待处理'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadDashboardData()
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.loadDashboardData()
|
||||
setTimeout(() => {
|
||||
wx.stopPullDownRefresh()
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
async loadDashboardData() {
|
||||
try {
|
||||
// 加载统计数据
|
||||
const [stats, supervisionStats] = await Promise.all([
|
||||
dashboardService.getStats(),
|
||||
dashboardService.getSupervisionStats()
|
||||
])
|
||||
|
||||
if (stats) {
|
||||
this.updateOverviewCards(stats)
|
||||
}
|
||||
|
||||
if (supervisionStats) {
|
||||
this.updateSupervisionStats(supervisionStats)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载看板数据失败:', error)
|
||||
wx.showToast({
|
||||
title: '加载数据失败',
|
||||
icon: 'error'
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
updateOverviewCards(data) {
|
||||
const overviewCards = this.data.overviewCards.map(card => {
|
||||
const newValue = data[card.key] || card.value
|
||||
return {
|
||||
...card,
|
||||
value: newValue
|
||||
}
|
||||
})
|
||||
this.setData({ overviewCards })
|
||||
},
|
||||
|
||||
updateSupervisionStats(data) {
|
||||
const supervisionStats = this.data.supervisionStats.map(stat => {
|
||||
const newValue = data[stat.key] || stat.value
|
||||
return {
|
||||
...stat,
|
||||
value: newValue
|
||||
}
|
||||
})
|
||||
this.setData({ supervisionStats })
|
||||
}
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<!--pages/dashboard/dashboard.wxml-->
|
||||
<view class="dashboard-container">
|
||||
<!-- 数据概览卡片 -->
|
||||
<view class="overview-cards">
|
||||
<view
|
||||
wx:for="{{overviewCards}}"
|
||||
wx:key="key"
|
||||
class="overview-card {{item.type}}"
|
||||
>
|
||||
<view class="card-icon">{{item.icon}}</view>
|
||||
<view class="card-content">
|
||||
<view class="card-value">{{item.value}}</view>
|
||||
<view class="card-label">{{item.label}}</view>
|
||||
<view class="card-trend {{item.trend}}">
|
||||
{{item.trendText}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图表区域 -->
|
||||
<view class="charts-section">
|
||||
<view class="section-title">数据图表</view>
|
||||
<view class="chart-container">
|
||||
<view class="chart-placeholder">
|
||||
<view class="chart-icon">📊</view>
|
||||
<view class="chart-text">图表数据加载中...</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 监管统计 -->
|
||||
<view class="supervision-stats">
|
||||
<view class="section-title">监管统计</view>
|
||||
<view class="stats-list">
|
||||
<view
|
||||
wx:for="{{supervisionStats}}"
|
||||
wx:key="key"
|
||||
class="stat-item"
|
||||
>
|
||||
<view class="stat-info">
|
||||
<view class="stat-name">{{item.name}}</view>
|
||||
<view class="stat-desc">{{item.desc}}</view>
|
||||
</view>
|
||||
<view class="stat-value">{{item.value}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近活动 -->
|
||||
<view class="recent-activities">
|
||||
<view class="section-title">最近活动</view>
|
||||
<view class="activity-list">
|
||||
<view
|
||||
wx:for="{{recentActivities}}"
|
||||
wx:key="id"
|
||||
class="activity-item"
|
||||
>
|
||||
<view class="activity-icon">{{item.icon}}</view>
|
||||
<view class="activity-content">
|
||||
<view class="activity-title">{{item.title}}</view>
|
||||
<view class="activity-desc">{{item.desc}}</view>
|
||||
<view class="activity-time">{{item.time}}</view>
|
||||
</view>
|
||||
<view class="activity-status {{item.status}}">
|
||||
{{item.statusText}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,210 +0,0 @@
|
||||
/* pages/dashboard/dashboard.wxss */
|
||||
.dashboard-container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.overview-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.overview-card {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.overview-card.primary {
|
||||
border-left: 8rpx solid #1890ff;
|
||||
}
|
||||
|
||||
.overview-card.success {
|
||||
border-left: 8rpx solid #52c41a;
|
||||
}
|
||||
|
||||
.overview-card.warning {
|
||||
border-left: 8rpx solid #faad14;
|
||||
}
|
||||
|
||||
.overview-card.danger {
|
||||
border-left: 8rpx solid #ff4d4f;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
font-size: 48rpx;
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.card-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.card-trend {
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.card-trend.up {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.card-trend.down {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.charts-section,
|
||||
.supervision-stats,
|
||||
.recent-activities {
|
||||
background: #fff;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
height: 400rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.chart-placeholder {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.chart-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.chart-text {
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.stats-list {
|
||||
space-y: 20rpx;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.stat-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.stat-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.stat-name {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #1890ff;
|
||||
}
|
||||
|
||||
.activity-list {
|
||||
space-y: 20rpx;
|
||||
}
|
||||
|
||||
.activity-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.activity-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.activity-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 20rpx;
|
||||
width: 60rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.activity-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.activity-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.activity-desc {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
font-size: 20rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.activity-status {
|
||||
font-size: 20rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.activity-status.success {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.activity-status.pending {
|
||||
background: #fff7e6;
|
||||
color: #faad14;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// pages/epidemic/epidemic.js
|
||||
Page({
|
||||
data: {
|
||||
searchKeyword: '',
|
||||
loading: false,
|
||||
epidemicList: []
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadEpidemicData()
|
||||
},
|
||||
|
||||
loadEpidemicData() {
|
||||
// 模拟数据
|
||||
this.setData({
|
||||
epidemicList: [
|
||||
{
|
||||
id: 1,
|
||||
title: '疫情预警',
|
||||
description: '发现疑似疫情情况',
|
||||
location: '宁夏银川市',
|
||||
level: 'high',
|
||||
levelText: '高风险',
|
||||
createTime: '2024-01-15 14:30'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
handleAdd() {
|
||||
wx.showToast({
|
||||
title: '新增功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<!--pages/epidemic/epidemic.wxml-->
|
||||
<view class="epidemic-container">
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-section">
|
||||
<view class="search-bar">
|
||||
<input
|
||||
value="{{searchKeyword}}"
|
||||
type="text"
|
||||
placeholder="搜索疫情记录..."
|
||||
class="search-input"
|
||||
bindinput="onSearchInput"
|
||||
/>
|
||||
<view class="search-icon">🔍</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 疫情列表 -->
|
||||
<view class="epidemic-list">
|
||||
<view class="list-header">
|
||||
<view class="list-title">疫情监控</view>
|
||||
<view class="add-btn" bindtap="handleAdd">
|
||||
<text class="add-text">新增</text>
|
||||
<view class="add-icon">+</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{loading}}" class="loading">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view wx:elif="{{epidemicList.length === 0}}" class="empty">
|
||||
<view class="empty-icon">🦠</view>
|
||||
<view class="empty-text">暂无疫情记录</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="list-content">
|
||||
<view
|
||||
wx:for="{{epidemicList}}"
|
||||
wx:key="id"
|
||||
class="epidemic-item"
|
||||
>
|
||||
<view class="item-header">
|
||||
<view class="item-title">{{item.title}}</view>
|
||||
<view class="item-level {{item.level}}">
|
||||
{{item.levelText}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-desc">{{item.description}}</view>
|
||||
<view class="item-meta">
|
||||
<view class="item-location">📍 {{item.location}}</view>
|
||||
<view class="item-time">{{item.createTime}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,169 +0,0 @@
|
||||
/* pages/epidemic/epidemic.wxss */
|
||||
.epidemic-container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
background: #f8f9fa;
|
||||
border: none;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 60rpx 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.epidemic-list {
|
||||
background: #fff;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
background: #1890ff;
|
||||
border-radius: 24rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.add-text {
|
||||
font-size: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.loading-text,
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
space-y: 0;
|
||||
}
|
||||
|
||||
.epidemic-item {
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.epidemic-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-level {
|
||||
font-size: 20rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-level.high {
|
||||
background: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.item-level.medium {
|
||||
background: #fff7e6;
|
||||
color: #faad14;
|
||||
}
|
||||
|
||||
.item-level.low {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 12rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-location,
|
||||
.item-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
273
government-mini-program/pages/farmer/add/add.js
Normal file
273
government-mini-program/pages/farmer/add/add.js
Normal file
@@ -0,0 +1,273 @@
|
||||
// pages/farmer/add/add.js
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
|
||||
// 表单数据
|
||||
formData: {
|
||||
name: '',
|
||||
phone: '',
|
||||
idCard: '',
|
||||
area: '',
|
||||
farmName: '',
|
||||
farmAddress: '',
|
||||
animalCount: '',
|
||||
animalType: '',
|
||||
email: '',
|
||||
emergencyContact: '',
|
||||
emergencyPhone: '',
|
||||
remark: ''
|
||||
},
|
||||
|
||||
// 选择器数据
|
||||
areaList: [
|
||||
{ id: 1, name: '银川市' },
|
||||
{ id: 2, name: '石嘴山市' },
|
||||
{ id: 3, name: '吴忠市' },
|
||||
{ id: 4, name: '固原市' },
|
||||
{ id: 5, name: '中卫市' }
|
||||
],
|
||||
areaIndex: -1,
|
||||
|
||||
animalTypeList: [
|
||||
{ id: 1, name: '牛' },
|
||||
{ id: 2, name: '羊' },
|
||||
{ id: 3, name: '猪' },
|
||||
{ id: 4, name: '鸡' },
|
||||
{ id: 5, name: '其他' }
|
||||
],
|
||||
animalTypeIndex: -1,
|
||||
|
||||
// 提交状态
|
||||
isSubmitting: false,
|
||||
canSubmit: false
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 获取状态栏高度
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
this.setData({
|
||||
statusBarHeight: systemInfo.statusBarHeight
|
||||
});
|
||||
|
||||
// 检查登录状态
|
||||
this.checkLoginStatus();
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
wx.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
// 输入框变化处理
|
||||
onInputChange(e) {
|
||||
const { field } = e.currentTarget.dataset;
|
||||
const { value } = e.detail;
|
||||
|
||||
this.setData({
|
||||
[`formData.${field}`]: value
|
||||
}, () => {
|
||||
this.validateForm();
|
||||
});
|
||||
},
|
||||
|
||||
// 区域选择
|
||||
onAreaChange(e) {
|
||||
const index = e.detail.value;
|
||||
const area = this.data.areaList[index];
|
||||
|
||||
this.setData({
|
||||
areaIndex: index,
|
||||
'formData.area': area ? area.name : ''
|
||||
}, () => {
|
||||
this.validateForm();
|
||||
});
|
||||
},
|
||||
|
||||
// 养殖类型选择
|
||||
onAnimalTypeChange(e) {
|
||||
const index = e.detail.value;
|
||||
const animalType = this.data.animalTypeList[index];
|
||||
|
||||
this.setData({
|
||||
animalTypeIndex: index,
|
||||
'formData.animalType': animalType ? animalType.name : ''
|
||||
}, () => {
|
||||
this.validateForm();
|
||||
});
|
||||
},
|
||||
|
||||
// 表单验证
|
||||
validateForm() {
|
||||
const { formData } = this.data;
|
||||
|
||||
// 必填字段验证
|
||||
const requiredFields = ['name', 'phone', 'area', 'farmName'];
|
||||
const isValid = requiredFields.every(field => {
|
||||
return formData[field] && formData[field].trim() !== '';
|
||||
});
|
||||
|
||||
// 手机号格式验证
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
const isPhoneValid = phoneRegex.test(formData.phone);
|
||||
|
||||
// 身份证号验证(如果填写了)
|
||||
let isIdCardValid = true;
|
||||
if (formData.idCard) {
|
||||
const idCardRegex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
|
||||
isIdCardValid = idCardRegex.test(formData.idCard);
|
||||
}
|
||||
|
||||
// 邮箱验证(如果填写了)
|
||||
let isEmailValid = true;
|
||||
if (formData.email) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
isEmailValid = emailRegex.test(formData.email);
|
||||
}
|
||||
|
||||
this.setData({
|
||||
canSubmit: isValid && isPhoneValid && isIdCardValid && isEmailValid
|
||||
});
|
||||
},
|
||||
|
||||
// 取消操作
|
||||
onCancel() {
|
||||
// 检查是否有未保存的数据
|
||||
const hasData = Object.values(this.data.formData).some(value => value && value.trim() !== '');
|
||||
|
||||
if (hasData) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '确定要放弃当前编辑的内容吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.navigateBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.navigateBack();
|
||||
}
|
||||
},
|
||||
|
||||
// 提交表单
|
||||
async onSubmit() {
|
||||
if (!this.data.canSubmit || this.data.isSubmitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 最终验证
|
||||
if (!this.validateFormData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({ isSubmitting: true });
|
||||
|
||||
try {
|
||||
// 模拟API调用
|
||||
await this.submitFarmerData();
|
||||
|
||||
wx.showToast({
|
||||
title: '添加成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 延迟返回,让用户看到成功提示
|
||||
setTimeout(() => {
|
||||
wx.navigateBack();
|
||||
}, 1500);
|
||||
|
||||
} catch (error) {
|
||||
console.error('添加养殖户失败:', error);
|
||||
wx.showToast({
|
||||
title: '添加失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.setData({ isSubmitting: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 验证表单数据
|
||||
validateFormData() {
|
||||
const { formData } = this.data;
|
||||
|
||||
if (!formData.name.trim()) {
|
||||
wx.showToast({ title: '请输入姓名', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!formData.phone.trim()) {
|
||||
wx.showToast({ title: '请输入手机号', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(formData.phone)) {
|
||||
wx.showToast({ title: '手机号格式不正确', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!formData.area.trim()) {
|
||||
wx.showToast({ title: '请选择所属区域', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!formData.farmName.trim()) {
|
||||
wx.showToast({ title: '请输入养殖场名称', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
// 身份证号验证
|
||||
if (formData.idCard && formData.idCard.trim()) {
|
||||
const idCardRegex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
|
||||
if (!idCardRegex.test(formData.idCard)) {
|
||||
wx.showToast({ title: '身份证号格式不正确', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 邮箱验证
|
||||
if (formData.email && formData.email.trim()) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(formData.email)) {
|
||||
wx.showToast({ title: '邮箱格式不正确', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 紧急联系电话验证
|
||||
if (formData.emergencyPhone && formData.emergencyPhone.trim()) {
|
||||
if (!phoneRegex.test(formData.emergencyPhone)) {
|
||||
wx.showToast({ title: '紧急联系电话格式不正确', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// 提交养殖户数据
|
||||
submitFarmerData() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 模拟API请求
|
||||
setTimeout(() => {
|
||||
// 模拟成功/失败
|
||||
const success = Math.random() > 0.1; // 90%成功率
|
||||
|
||||
if (success) {
|
||||
console.log('提交的数据:', this.data.formData);
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('网络错误'));
|
||||
}
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
6
government-mini-program/pages/farmer/add/add.json
Normal file
6
government-mini-program/pages/farmer/add/add.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "添加养殖户",
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColor": "#4CAF50",
|
||||
"backgroundTextStyle": "light"
|
||||
}
|
||||
205
government-mini-program/pages/farmer/add/add.wxml
Normal file
205
government-mini-program/pages/farmer/add/add.wxml
Normal file
@@ -0,0 +1,205 @@
|
||||
<!--pages/farmer/add/add.wxml-->
|
||||
<view class="container">
|
||||
<!-- 状态栏 -->
|
||||
<view class="status-bar" style="height: {{statusBarHeight}}px;"></view>
|
||||
|
||||
<!-- 表单内容 -->
|
||||
<scroll-view class="form-container" scroll-y="true">
|
||||
<!-- 基本信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">基本信息</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
<text>姓名</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入养殖户姓名"
|
||||
value="{{formData.name}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="name"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
<text>手机号</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入手机号"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
value="{{formData.phone}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="phone"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">身份证号</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入身份证号"
|
||||
maxlength="18"
|
||||
value="{{formData.idCard}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="idCard"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
<text>所属区域</text>
|
||||
</view>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{areaList}}"
|
||||
range-key="name"
|
||||
value="{{areaIndex}}"
|
||||
bindchange="onAreaChange"
|
||||
>
|
||||
<view class="form-picker">
|
||||
<text class="{{formData.area ? '' : 'placeholder'}}">
|
||||
{{formData.area || '请选择所属区域'}}
|
||||
</text>
|
||||
<text class="picker-arrow">></text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 养殖场信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">养殖场信息</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
<text>养殖场名称</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入养殖场名称"
|
||||
value="{{formData.farmName}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="farmName"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">养殖场地址</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入养殖场地址"
|
||||
value="{{formData.farmAddress}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="farmAddress"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">养殖规模</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入养殖数量"
|
||||
type="number"
|
||||
value="{{formData.animalCount}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="animalCount"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">养殖类型</view>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{animalTypeList}}"
|
||||
range-key="name"
|
||||
value="{{animalTypeIndex}}"
|
||||
bindchange="onAnimalTypeChange"
|
||||
>
|
||||
<view class="form-picker">
|
||||
<text class="{{formData.animalType ? '' : 'placeholder'}}">
|
||||
{{formData.animalType || '请选择养殖类型'}}
|
||||
</text>
|
||||
<text class="picker-arrow">></text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">联系信息</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">邮箱</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入邮箱地址"
|
||||
value="{{formData.email}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="email"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">紧急联系人</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入紧急联系人姓名"
|
||||
value="{{formData.emergencyContact}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="emergencyContact"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">紧急联系电话</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入紧急联系电话"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
value="{{formData.emergencyPhone}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="emergencyPhone"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 备注信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">备注信息</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">备注</view>
|
||||
<textarea
|
||||
class="form-textarea"
|
||||
placeholder="请输入备注信息"
|
||||
maxlength="200"
|
||||
value="{{formData.remark}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="remark"
|
||||
/>
|
||||
<view class="char-count">{{formData.remark.length}}/200</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部间距 -->
|
||||
<view class="bottom-space"></view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="bottom-bar">
|
||||
<button class="cancel-btn" bindtap="onCancel">取消</button>
|
||||
<button class="submit-btn" bindtap="onSubmit" disabled="{{!canSubmit}}">
|
||||
{{isSubmitting ? '提交中...' : '确认添加'}}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
176
government-mini-program/pages/farmer/add/add.wxss
Normal file
176
government-mini-program/pages/farmer/add/add.wxss
Normal file
@@ -0,0 +1,176 @@
|
||||
/* pages/farmer/add/add.wxss */
|
||||
.container {
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 表单区块 */
|
||||
.form-section {
|
||||
background-color: white;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
padding: 30rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
background-color: #f8f9fa;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
/* 表单项 */
|
||||
.form-item {
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.form-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: #f44336;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
/* 输入框 */
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: #4CAF50;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/* 选择器 */
|
||||
.form-picker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.picker-arrow {
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* 文本域 */
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
min-height: 160rpx;
|
||||
padding: 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-textarea:focus {
|
||||
border-color: #4CAF50;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* 底部间距 */
|
||||
.bottom-space {
|
||||
height: 120rpx;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
padding: 20rpx;
|
||||
background-color: white;
|
||||
border-top: 1rpx solid #eee;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background-color: #f5f5f5;
|
||||
color: #666;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cancel-btn:active {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
flex: 2;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.submit-btn:active {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.submit-btn[disabled] {
|
||||
background-color: #ccc;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.submit-btn[disabled]:active {
|
||||
background-color: #ccc;
|
||||
}
|
||||
195
government-mini-program/pages/farmer/detail/detail.js
Normal file
195
government-mini-program/pages/farmer/detail/detail.js
Normal file
@@ -0,0 +1,195 @@
|
||||
// pages/farmer/detail/detail.js
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
loading: true,
|
||||
farmerId: '',
|
||||
farmerInfo: {},
|
||||
checkRecords: []
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 检查登录状态
|
||||
this.checkLoginStatus();
|
||||
|
||||
// 获取状态栏高度
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
this.setData({
|
||||
statusBarHeight: systemInfo.statusBarHeight
|
||||
});
|
||||
|
||||
// 获取养殖户ID
|
||||
if (options.id) {
|
||||
this.setData({
|
||||
farmerId: options.id
|
||||
});
|
||||
this.loadFarmerDetail();
|
||||
} 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 loadFarmerDetail() {
|
||||
try {
|
||||
this.setData({ loading: true });
|
||||
|
||||
// 模拟API调用
|
||||
const farmerData = await this.fetchFarmerDetail(this.data.farmerId);
|
||||
const checkData = await this.fetchCheckRecords(this.data.farmerId);
|
||||
|
||||
this.setData({
|
||||
farmerInfo: farmerData,
|
||||
checkRecords: checkData,
|
||||
loading: false
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('加载养殖户详情失败:', error);
|
||||
wx.showToast({
|
||||
title: '加载失败',
|
||||
icon: 'error'
|
||||
});
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 模拟获取养殖户详情API
|
||||
fetchFarmerDetail(farmerId) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const mockData = {
|
||||
id: farmerId,
|
||||
name: '张三',
|
||||
phone: '13800138000',
|
||||
idCard: '610104199001011234',
|
||||
area: '西夏区',
|
||||
status: 'normal',
|
||||
farmName: '张三养殖场',
|
||||
farmAddress: '宁夏银川市西夏区兴泾镇',
|
||||
animalCount: 120,
|
||||
animalType: '肉牛',
|
||||
email: 'zhangsan@example.com',
|
||||
emergencyContact: '李四 13900139000',
|
||||
registerTime: '2023-01-15',
|
||||
lastCheckTime: '2024-01-15 14:30',
|
||||
remarks: '该养殖户管理规范,牲畜健康状况良好,配合度高。'
|
||||
};
|
||||
resolve(mockData);
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
|
||||
// 模拟获取检查记录API
|
||||
fetchCheckRecords(farmerId) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const mockRecords = [
|
||||
{
|
||||
id: '1',
|
||||
checkTime: '2024-01-15 14:30',
|
||||
inspector: '王检查员',
|
||||
result: 'normal',
|
||||
description: '牲畜健康状况良好,饲料充足,环境卫生达标。'
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
checkTime: '2024-01-10 09:15',
|
||||
inspector: '李检查员',
|
||||
result: 'warning',
|
||||
description: '发现部分牲畜有轻微感冒症状,已建议及时治疗。'
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
checkTime: '2024-01-05 16:20',
|
||||
inspector: '张检查员',
|
||||
result: 'normal',
|
||||
description: '整体情况良好,建议继续保持现有管理水平。'
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
checkTime: '2023-12-28 11:45',
|
||||
inspector: '王检查员',
|
||||
result: 'error',
|
||||
description: '发现饲料存储不当,已要求立即整改。'
|
||||
}
|
||||
];
|
||||
resolve(mockRecords);
|
||||
}, 800);
|
||||
});
|
||||
},
|
||||
|
||||
// 编辑养殖户信息
|
||||
onEdit() {
|
||||
wx.navigateTo({
|
||||
url: `/pages/farmer/edit/edit?id=${this.data.farmerId}`
|
||||
});
|
||||
},
|
||||
|
||||
// 拨打电话
|
||||
onCall() {
|
||||
const phone = this.data.farmerInfo.phone;
|
||||
if (!phone) {
|
||||
wx.showToast({
|
||||
title: '无联系电话',
|
||||
icon: 'error'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
wx.showModal({
|
||||
title: '拨打电话',
|
||||
content: `确定要拨打 ${phone} 吗?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.makePhoneCall({
|
||||
phoneNumber: phone,
|
||||
fail: (error) => {
|
||||
console.error('拨打电话失败:', error);
|
||||
wx.showToast({
|
||||
title: '拨打失败',
|
||||
icon: 'error'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 添加检查记录
|
||||
onAddCheck() {
|
||||
wx.navigateTo({
|
||||
url: `/pages/check/add/add?farmerId=${this.data.farmerId}&farmerName=${this.data.farmerInfo.name}`
|
||||
});
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
this.loadFarmerDetail().finally(() => {
|
||||
wx.stopPullDownRefresh();
|
||||
});
|
||||
}
|
||||
});
|
||||
7
government-mini-program/pages/farmer/detail/detail.json
Normal file
7
government-mini-program/pages/farmer/detail/detail.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"navigationBarTitleText": "养殖户详情",
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColor": "#f5f5f5",
|
||||
"backgroundTextStyle": "dark",
|
||||
"enablePullDownRefresh": true
|
||||
}
|
||||
125
government-mini-program/pages/farmer/detail/detail.wxml
Normal file
125
government-mini-program/pages/farmer/detail/detail.wxml
Normal file
@@ -0,0 +1,125 @@
|
||||
<!--pages/farmer/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="info-card">
|
||||
<view class="card-header">
|
||||
<view class="farmer-name">{{farmerInfo.name}}</view>
|
||||
<view class="status-badge status-{{farmerInfo.status}}">
|
||||
{{farmerInfo.status === 'normal' ? '正常' : farmerInfo.status === 'error' ? '异常' : '待检查'}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="info-grid">
|
||||
<view class="info-item">
|
||||
<view class="info-label">联系电话</view>
|
||||
<view class="info-value">{{farmerInfo.phone}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">身份证号</view>
|
||||
<view class="info-value">{{farmerInfo.idCard}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">所属区域</view>
|
||||
<view class="info-value">{{farmerInfo.area}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">注册时间</view>
|
||||
<view class="info-value">{{farmerInfo.registerTime}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 养殖场信息 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">养殖场信息</view>
|
||||
<view class="info-grid">
|
||||
<view class="info-item">
|
||||
<view class="info-label">养殖场名称</view>
|
||||
<view class="info-value">{{farmerInfo.farmName}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">养殖场地址</view>
|
||||
<view class="info-value">{{farmerInfo.farmAddress}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">牲畜数量</view>
|
||||
<view class="info-value">{{farmerInfo.animalCount}}头</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">牲畜类型</view>
|
||||
<view class="info-value">{{farmerInfo.animalType}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系信息 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">联系信息</view>
|
||||
<view class="info-grid">
|
||||
<view class="info-item">
|
||||
<view class="info-label">邮箱地址</view>
|
||||
<view class="info-value">{{farmerInfo.email || '未填写'}}</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<view class="info-label">紧急联系人</view>
|
||||
<view class="info-value">{{farmerInfo.emergencyContact || '未填写'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 检查记录 -->
|
||||
<view class="info-card">
|
||||
<view class="card-title">
|
||||
<text>检查记录</text>
|
||||
<text class="record-count">({{checkRecords.length}}条)</text>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{checkRecords.length === 0}}" class="empty-records">
|
||||
<text>暂无检查记录</text>
|
||||
</view>
|
||||
|
||||
<view wx:else class="records-list">
|
||||
<view
|
||||
wx:for="{{checkRecords}}"
|
||||
wx:key="id"
|
||||
class="record-item"
|
||||
>
|
||||
<view class="record-header">
|
||||
<view class="record-time">{{item.checkTime}}</view>
|
||||
<view class="record-status status-{{item.result}}">
|
||||
{{item.result === 'normal' ? '正常' : item.result === 'warning' ? '警告' : '异常'}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="record-content">
|
||||
<view class="record-inspector">检查员:{{item.inspector}}</view>
|
||||
<view class="record-desc">{{item.description}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 备注信息 -->
|
||||
<view wx:if="{{farmerInfo.remarks}}" class="info-card">
|
||||
<view class="card-title">备注信息</view>
|
||||
<view class="remarks-content">{{farmerInfo.remarks}}</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="bottom-bar">
|
||||
<button class="action-btn edit-btn" bindtap="onEdit">编辑信息</button>
|
||||
<button class="action-btn call-btn" bindtap="onCall">拨打电话</button>
|
||||
<button class="action-btn check-btn" bindtap="onAddCheck">添加检查</button>
|
||||
</view>
|
||||
</view>
|
||||
241
government-mini-program/pages/farmer/detail/detail.wxss
Normal file
241
government-mini-program/pages/farmer/detail/detail.wxss
Normal file
@@ -0,0 +1,241 @@
|
||||
/* pages/farmer/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;
|
||||
}
|
||||
|
||||
/* 信息卡片 */
|
||||
.info-card {
|
||||
background-color: white;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.farmer-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-normal {
|
||||
background-color: #e8f5e8;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.status-error {
|
||||
background-color: #fff2f0;
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #fff7e6;
|
||||
color: #fa8c16;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.record-count {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
font-weight: normal;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
|
||||
/* 信息网格 */
|
||||
.info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 24rpx;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.info-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.info-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 备注信息 */
|
||||
.remarks-content {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
line-height: 1.6;
|
||||
background-color: #f8f9fa;
|
||||
padding: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
/* 检查记录 */
|
||||
.empty-records {
|
||||
text-align: center;
|
||||
padding: 60rpx 0;
|
||||
color: #999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.records-list {
|
||||
max-height: 600rpx;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.record-item {
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
padding: 20rpx 0;
|
||||
}
|
||||
|
||||
.record-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.record-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.record-time {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.record-status {
|
||||
padding: 4rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 22rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.record-content {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.record-inspector {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.record-desc {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
.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);
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
background-color: #2c5aa0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.call-btn {
|
||||
background-color: #52c41a;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.check-btn {
|
||||
background-color: #fa8c16;
|
||||
color: white;
|
||||
}
|
||||
406
government-mini-program/pages/farmer/edit/edit.js
Normal file
406
government-mini-program/pages/farmer/edit/edit.js
Normal file
@@ -0,0 +1,406 @@
|
||||
// pages/farmer/edit/edit.js
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
loading: true,
|
||||
farmerId: '',
|
||||
|
||||
// 表单数据
|
||||
formData: {
|
||||
name: '',
|
||||
phone: '',
|
||||
idCard: '',
|
||||
area: '',
|
||||
status: '',
|
||||
farmName: '',
|
||||
farmAddress: '',
|
||||
animalCount: '',
|
||||
animalType: '',
|
||||
email: '',
|
||||
emergencyContact: '',
|
||||
emergencyPhone: '',
|
||||
remark: ''
|
||||
},
|
||||
|
||||
// 原始数据(用于比较是否有修改)
|
||||
originalData: {},
|
||||
|
||||
// 选择器数据
|
||||
areaList: [
|
||||
{ id: 1, name: '银川市' },
|
||||
{ id: 2, name: '石嘴山市' },
|
||||
{ id: 3, name: '吴忠市' },
|
||||
{ id: 4, name: '固原市' },
|
||||
{ id: 5, name: '中卫市' }
|
||||
],
|
||||
areaIndex: -1,
|
||||
|
||||
statusList: [
|
||||
{ id: 1, name: '正常' },
|
||||
{ id: 2, name: '异常' },
|
||||
{ id: 3, name: '待审核' }
|
||||
],
|
||||
statusIndex: -1,
|
||||
|
||||
animalTypeList: [
|
||||
{ id: 1, name: '牛' },
|
||||
{ id: 2, name: '羊' },
|
||||
{ id: 3, name: '猪' },
|
||||
{ id: 4, name: '鸡' },
|
||||
{ id: 5, name: '其他' }
|
||||
],
|
||||
animalTypeIndex: -1,
|
||||
|
||||
// 提交状态
|
||||
isSubmitting: false,
|
||||
canSubmit: false
|
||||
},
|
||||
|
||||
onLoad(options) {
|
||||
// 获取状态栏高度
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
this.setData({
|
||||
statusBarHeight: systemInfo.statusBarHeight,
|
||||
farmerId: options.id || ''
|
||||
});
|
||||
|
||||
// 检查登录状态
|
||||
this.checkLoginStatus();
|
||||
|
||||
// 加载养殖户数据
|
||||
if (this.data.farmerId) {
|
||||
this.loadFarmerData();
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '参数错误',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
wx.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
wx.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载养殖户数据
|
||||
async loadFarmerData() {
|
||||
try {
|
||||
wx.showLoading({ title: '加载中...' });
|
||||
|
||||
// 模拟API调用
|
||||
const farmerData = await this.fetchFarmerData(this.data.farmerId);
|
||||
|
||||
// 设置表单数据
|
||||
this.setData({
|
||||
formData: { ...farmerData },
|
||||
originalData: { ...farmerData },
|
||||
loading: false
|
||||
});
|
||||
|
||||
// 设置选择器索引
|
||||
this.setPickerIndexes(farmerData);
|
||||
|
||||
wx.hideLoading();
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载养殖户数据失败:', error);
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '加载失败',
|
||||
icon: 'none'
|
||||
});
|
||||
setTimeout(() => {
|
||||
wx.navigateBack();
|
||||
}, 1500);
|
||||
}
|
||||
},
|
||||
|
||||
// 模拟获取养殖户数据
|
||||
fetchFarmerData(id) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
// 模拟数据
|
||||
const mockData = {
|
||||
id: id,
|
||||
name: '张三',
|
||||
phone: '13800138000',
|
||||
idCard: '640100199001011234',
|
||||
area: '银川市',
|
||||
status: '正常',
|
||||
farmName: '张三养殖场',
|
||||
farmAddress: '银川市兴庆区某某村',
|
||||
animalCount: '100',
|
||||
animalType: '牛',
|
||||
email: 'zhangsan@example.com',
|
||||
emergencyContact: '李四',
|
||||
emergencyPhone: '13900139000',
|
||||
remark: '优质养殖户,管理规范'
|
||||
};
|
||||
resolve(mockData);
|
||||
}, 1000);
|
||||
});
|
||||
},
|
||||
|
||||
// 设置选择器索引
|
||||
setPickerIndexes(data) {
|
||||
// 设置区域索引
|
||||
const areaIndex = this.data.areaList.findIndex(item => item.name === data.area);
|
||||
|
||||
// 设置状态索引
|
||||
const statusIndex = this.data.statusList.findIndex(item => item.name === data.status);
|
||||
|
||||
// 设置养殖类型索引
|
||||
const animalTypeIndex = this.data.animalTypeList.findIndex(item => item.name === data.animalType);
|
||||
|
||||
this.setData({
|
||||
areaIndex: areaIndex >= 0 ? areaIndex : -1,
|
||||
statusIndex: statusIndex >= 0 ? statusIndex : -1,
|
||||
animalTypeIndex: animalTypeIndex >= 0 ? animalTypeIndex : -1
|
||||
});
|
||||
|
||||
this.validateForm();
|
||||
},
|
||||
|
||||
// 输入框变化处理
|
||||
onInputChange(e) {
|
||||
const { field } = e.currentTarget.dataset;
|
||||
const { value } = e.detail;
|
||||
|
||||
this.setData({
|
||||
[`formData.${field}`]: value
|
||||
}, () => {
|
||||
this.validateForm();
|
||||
});
|
||||
},
|
||||
|
||||
// 区域选择
|
||||
onAreaChange(e) {
|
||||
const index = e.detail.value;
|
||||
const area = this.data.areaList[index];
|
||||
|
||||
this.setData({
|
||||
areaIndex: index,
|
||||
'formData.area': area ? area.name : ''
|
||||
}, () => {
|
||||
this.validateForm();
|
||||
});
|
||||
},
|
||||
|
||||
// 状态选择
|
||||
onStatusChange(e) {
|
||||
const index = e.detail.value;
|
||||
const status = this.data.statusList[index];
|
||||
|
||||
this.setData({
|
||||
statusIndex: index,
|
||||
'formData.status': status ? status.name : ''
|
||||
}, () => {
|
||||
this.validateForm();
|
||||
});
|
||||
},
|
||||
|
||||
// 养殖类型选择
|
||||
onAnimalTypeChange(e) {
|
||||
const index = e.detail.value;
|
||||
const animalType = this.data.animalTypeList[index];
|
||||
|
||||
this.setData({
|
||||
animalTypeIndex: index,
|
||||
'formData.animalType': animalType ? animalType.name : ''
|
||||
}, () => {
|
||||
this.validateForm();
|
||||
});
|
||||
},
|
||||
|
||||
// 表单验证
|
||||
validateForm() {
|
||||
const { formData } = this.data;
|
||||
|
||||
// 必填字段验证
|
||||
const requiredFields = ['name', 'phone', 'area', 'farmName'];
|
||||
const isValid = requiredFields.every(field => {
|
||||
return formData[field] && formData[field].trim() !== '';
|
||||
});
|
||||
|
||||
// 手机号格式验证
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
const isPhoneValid = phoneRegex.test(formData.phone);
|
||||
|
||||
// 身份证号验证(如果填写了)
|
||||
let isIdCardValid = true;
|
||||
if (formData.idCard) {
|
||||
const idCardRegex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
|
||||
isIdCardValid = idCardRegex.test(formData.idCard);
|
||||
}
|
||||
|
||||
// 邮箱验证(如果填写了)
|
||||
let isEmailValid = true;
|
||||
if (formData.email) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
isEmailValid = emailRegex.test(formData.email);
|
||||
}
|
||||
|
||||
// 检查是否有修改
|
||||
const hasChanges = this.hasDataChanged();
|
||||
|
||||
this.setData({
|
||||
canSubmit: isValid && isPhoneValid && isIdCardValid && isEmailValid && hasChanges
|
||||
});
|
||||
},
|
||||
|
||||
// 检查数据是否有修改
|
||||
hasDataChanged() {
|
||||
const { formData, originalData } = this.data;
|
||||
|
||||
return Object.keys(formData).some(key => {
|
||||
return formData[key] !== originalData[key];
|
||||
});
|
||||
},
|
||||
|
||||
// 取消操作
|
||||
onCancel() {
|
||||
// 检查是否有未保存的修改
|
||||
if (this.hasDataChanged()) {
|
||||
wx.showModal({
|
||||
title: '提示',
|
||||
content: '确定要放弃当前修改的内容吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.navigateBack();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.navigateBack();
|
||||
}
|
||||
},
|
||||
|
||||
// 提交表单
|
||||
async onSubmit() {
|
||||
if (!this.data.canSubmit || this.data.isSubmitting) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 最终验证
|
||||
if (!this.validateFormData()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({ isSubmitting: true });
|
||||
|
||||
try {
|
||||
// 模拟API调用
|
||||
await this.updateFarmerData();
|
||||
|
||||
wx.showToast({
|
||||
title: '保存成功',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 延迟返回,让用户看到成功提示
|
||||
setTimeout(() => {
|
||||
wx.navigateBack();
|
||||
}, 1500);
|
||||
|
||||
} catch (error) {
|
||||
console.error('保存养殖户数据失败:', error);
|
||||
wx.showToast({
|
||||
title: '保存失败,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.setData({ isSubmitting: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 验证表单数据
|
||||
validateFormData() {
|
||||
const { formData } = this.data;
|
||||
|
||||
if (!formData.name.trim()) {
|
||||
wx.showToast({ title: '请输入姓名', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!formData.phone.trim()) {
|
||||
wx.showToast({ title: '请输入手机号', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(formData.phone)) {
|
||||
wx.showToast({ title: '手机号格式不正确', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!formData.area.trim()) {
|
||||
wx.showToast({ title: '请选择所属区域', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!formData.farmName.trim()) {
|
||||
wx.showToast({ title: '请输入养殖场名称', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
|
||||
// 身份证号验证
|
||||
if (formData.idCard && formData.idCard.trim()) {
|
||||
const idCardRegex = /(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)/;
|
||||
if (!idCardRegex.test(formData.idCard)) {
|
||||
wx.showToast({ title: '身份证号格式不正确', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 邮箱验证
|
||||
if (formData.email && formData.email.trim()) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(formData.email)) {
|
||||
wx.showToast({ title: '邮箱格式不正确', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 紧急联系电话验证
|
||||
if (formData.emergencyPhone && formData.emergencyPhone.trim()) {
|
||||
const phoneRegex = /^1[3-9]\d{9}$/;
|
||||
if (!phoneRegex.test(formData.emergencyPhone)) {
|
||||
wx.showToast({ title: '紧急联系电话格式不正确', icon: 'none' });
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// 更新养殖户数据
|
||||
updateFarmerData() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// 模拟API请求
|
||||
setTimeout(() => {
|
||||
// 模拟成功/失败
|
||||
const success = Math.random() > 0.1; // 90%成功率
|
||||
|
||||
if (success) {
|
||||
console.log('更新的数据:', {
|
||||
id: this.data.farmerId,
|
||||
...this.data.formData
|
||||
});
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error('网络错误'));
|
||||
}
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
6
government-mini-program/pages/farmer/edit/edit.json
Normal file
6
government-mini-program/pages/farmer/edit/edit.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "编辑养殖户",
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColor": "#4CAF50",
|
||||
"backgroundTextStyle": "light"
|
||||
}
|
||||
229
government-mini-program/pages/farmer/edit/edit.wxml
Normal file
229
government-mini-program/pages/farmer/edit/edit.wxml
Normal file
@@ -0,0 +1,229 @@
|
||||
<!--pages/farmer/edit/edit.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>
|
||||
|
||||
<!-- 表单内容 -->
|
||||
<scroll-view wx:else class="form-container" scroll-y="true">
|
||||
<!-- 基本信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">基本信息</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
<text>姓名</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入养殖户姓名"
|
||||
value="{{formData.name}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="name"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
<text>手机号</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入手机号"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
value="{{formData.phone}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="phone"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">身份证号</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入身份证号"
|
||||
maxlength="18"
|
||||
value="{{formData.idCard}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="idCard"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
<text>所属区域</text>
|
||||
</view>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{areaList}}"
|
||||
range-key="name"
|
||||
value="{{areaIndex}}"
|
||||
bindchange="onAreaChange"
|
||||
>
|
||||
<view class="form-picker">
|
||||
<text class="{{formData.area ? '' : 'placeholder'}}">
|
||||
{{formData.area || '请选择所属区域'}}
|
||||
</text>
|
||||
<text class="picker-arrow">></text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">状态</view>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{statusList}}"
|
||||
range-key="name"
|
||||
value="{{statusIndex}}"
|
||||
bindchange="onStatusChange"
|
||||
>
|
||||
<view class="form-picker">
|
||||
<text class="{{formData.status ? '' : 'placeholder'}}">
|
||||
{{formData.status || '请选择状态'}}
|
||||
</text>
|
||||
<text class="picker-arrow">></text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 养殖场信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">养殖场信息</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">
|
||||
<text class="required">*</text>
|
||||
<text>养殖场名称</text>
|
||||
</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入养殖场名称"
|
||||
value="{{formData.farmName}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="farmName"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">养殖场地址</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入养殖场地址"
|
||||
value="{{formData.farmAddress}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="farmAddress"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">养殖规模</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入养殖数量"
|
||||
type="number"
|
||||
value="{{formData.animalCount}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="animalCount"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">养殖类型</view>
|
||||
<picker
|
||||
mode="selector"
|
||||
range="{{animalTypeList}}"
|
||||
range-key="name"
|
||||
value="{{animalTypeIndex}}"
|
||||
bindchange="onAnimalTypeChange"
|
||||
>
|
||||
<view class="form-picker">
|
||||
<text class="{{formData.animalType ? '' : 'placeholder'}}">
|
||||
{{formData.animalType || '请选择养殖类型'}}
|
||||
</text>
|
||||
<text class="picker-arrow">></text>
|
||||
</view>
|
||||
</picker>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 联系信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">联系信息</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">邮箱</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入邮箱地址"
|
||||
value="{{formData.email}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="email"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">紧急联系人</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入紧急联系人姓名"
|
||||
value="{{formData.emergencyContact}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="emergencyContact"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">紧急联系电话</view>
|
||||
<input
|
||||
class="form-input"
|
||||
placeholder="请输入紧急联系电话"
|
||||
type="number"
|
||||
maxlength="11"
|
||||
value="{{formData.emergencyPhone}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="emergencyPhone"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 备注信息 -->
|
||||
<view class="form-section">
|
||||
<view class="section-title">备注信息</view>
|
||||
|
||||
<view class="form-item">
|
||||
<view class="form-label">备注</view>
|
||||
<textarea
|
||||
class="form-textarea"
|
||||
placeholder="请输入备注信息"
|
||||
maxlength="200"
|
||||
value="{{formData.remark}}"
|
||||
bindinput="onInputChange"
|
||||
data-field="remark"
|
||||
/>
|
||||
<view class="char-count">{{formData.remark.length}}/200</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部间距 -->
|
||||
<view class="bottom-space"></view>
|
||||
</scroll-view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view wx:if="{{!loading}}" class="bottom-bar">
|
||||
<button class="cancel-btn" bindtap="onCancel">取消</button>
|
||||
<button class="submit-btn" bindtap="onSubmit" disabled="{{!canSubmit}}">
|
||||
{{isSubmitting ? '保存中...' : '保存修改'}}
|
||||
</button>
|
||||
</view>
|
||||
</view>
|
||||
205
government-mini-program/pages/farmer/edit/edit.wxss
Normal file
205
government-mini-program/pages/farmer/edit/edit.wxss
Normal file
@@ -0,0 +1,205 @@
|
||||
/* pages/farmer/edit/edit.wxss */
|
||||
.container {
|
||||
height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.status-bar {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loading-spinner {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
border: 4rpx solid #f3f3f3;
|
||||
border-top: 4rpx solid #4CAF50;
|
||||
border-radius: 50%;
|
||||
animation: spin 1s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
margin-top: 20rpx;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.form-container {
|
||||
flex: 1;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
/* 表单区块 */
|
||||
.form-section {
|
||||
background-color: white;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
padding: 30rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
background-color: #f8f9fa;
|
||||
border-bottom: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
/* 表单项 */
|
||||
.form-item {
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.form-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.form-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.required {
|
||||
color: #f44336;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
/* 输入框 */
|
||||
.form-input {
|
||||
width: 100%;
|
||||
height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-input:focus {
|
||||
border-color: #4CAF50;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
/* 选择器 */
|
||||
.form-picker {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 80rpx;
|
||||
padding: 0 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.picker-arrow {
|
||||
color: #999;
|
||||
font-size: 24rpx;
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/* 文本域 */
|
||||
.form-textarea {
|
||||
width: 100%;
|
||||
min-height: 160rpx;
|
||||
padding: 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
border-radius: 8rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-textarea:focus {
|
||||
border-color: #4CAF50;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.char-count {
|
||||
text-align: right;
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
margin-top: 10rpx;
|
||||
}
|
||||
|
||||
/* 底部间距 */
|
||||
.bottom-space {
|
||||
height: 120rpx;
|
||||
}
|
||||
|
||||
/* 底部操作栏 */
|
||||
.bottom-bar {
|
||||
display: flex;
|
||||
padding: 20rpx;
|
||||
background-color: white;
|
||||
border-top: 1rpx solid #eee;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.cancel-btn {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background-color: #f5f5f5;
|
||||
color: #666;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cancel-btn:active {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
flex: 2;
|
||||
height: 88rpx;
|
||||
line-height: 88rpx;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.submit-btn:active {
|
||||
background-color: #45a049;
|
||||
}
|
||||
|
||||
.submit-btn[disabled] {
|
||||
background-color: #ccc;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.submit-btn[disabled]:active {
|
||||
background-color: #ccc;
|
||||
}
|
||||
342
government-mini-program/pages/farmer/farmer.js
Normal file
342
government-mini-program/pages/farmer/farmer.js
Normal file
@@ -0,0 +1,342 @@
|
||||
// pages/farmer/farmer.js
|
||||
const app = getApp();
|
||||
const apiService = require('../../utils/api.js');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
loading: true,
|
||||
|
||||
// 搜索和筛选
|
||||
searchKeyword: '',
|
||||
selectedStatus: 'all',
|
||||
selectedArea: 'all',
|
||||
|
||||
// 筛选选项
|
||||
statusOptions: [
|
||||
{ value: 'all', label: '全部状态' },
|
||||
{ value: 'normal', label: '正常' },
|
||||
{ value: 'warning', label: '异常' },
|
||||
{ value: 'offline', label: '离线' }
|
||||
],
|
||||
|
||||
areaOptions: [
|
||||
{ value: 'all', label: '全部区域' },
|
||||
{ value: 'area1', label: '银川市' },
|
||||
{ value: 'area2', label: '石嘴山市' },
|
||||
{ value: 'area3', label: '吴忠市' },
|
||||
{ value: 'area4', label: '固原市' },
|
||||
{ value: 'area5', label: '中卫市' }
|
||||
],
|
||||
|
||||
// 养殖户列表
|
||||
farmerList: [],
|
||||
|
||||
// 分页
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
totalCount: 0,
|
||||
hasMore: true,
|
||||
|
||||
// 统计信息
|
||||
statistics: {
|
||||
total: 0,
|
||||
normal: 0,
|
||||
warning: 0,
|
||||
offline: 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,
|
||||
farmerList: [],
|
||||
hasMore: true
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
await this.loadFarmers();
|
||||
} catch (error) {
|
||||
console.error('数据加载失败:', error);
|
||||
// 加载模拟数据作为备用
|
||||
this.loadMockData();
|
||||
} finally {
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 加载养殖户列表
|
||||
async loadFarmers() {
|
||||
try {
|
||||
const params = {
|
||||
page: this.data.currentPage,
|
||||
pageSize: this.data.pageSize,
|
||||
keyword: this.data.searchKeyword,
|
||||
status: this.data.selectedStatus === 'all' ? '' : this.data.selectedStatus,
|
||||
area: this.data.selectedArea === 'all' ? '' : this.data.selectedArea
|
||||
};
|
||||
|
||||
const result = await apiService.getFarmers(params);
|
||||
|
||||
if (result.code === 200 || result.code === 0) {
|
||||
const data = result.data || result;
|
||||
const farmers = data.list || data.farmers || [];
|
||||
|
||||
// 处理数据格式
|
||||
const formattedFarmers = farmers.map(farmer => ({
|
||||
id: farmer.id,
|
||||
name: farmer.name || farmer.farmerName,
|
||||
phone: farmer.phone || farmer.mobile,
|
||||
area: farmer.area || farmer.region,
|
||||
farmName: farmer.farmName || farmer.farm_name,
|
||||
animalCount: farmer.animalCount || farmer.animal_count || 0,
|
||||
animalType: farmer.animalType || farmer.animal_type,
|
||||
status: farmer.status || 'normal',
|
||||
lastCheckTime: farmer.lastCheckTime || farmer.last_check_time,
|
||||
avatar: farmer.avatar || '/images/avatar.png'
|
||||
}));
|
||||
|
||||
// 更新列表数据
|
||||
if (this.data.currentPage === 1) {
|
||||
this.setData({
|
||||
farmerList: formattedFarmers,
|
||||
totalCount: data.total || farmers.length
|
||||
});
|
||||
} else {
|
||||
this.setData({
|
||||
farmerList: [...this.data.farmerList, ...formattedFarmers]
|
||||
});
|
||||
}
|
||||
|
||||
// 更新分页状态
|
||||
this.setData({
|
||||
hasMore: formattedFarmers.length >= this.data.pageSize
|
||||
});
|
||||
|
||||
// 更新统计信息
|
||||
if (data.statistics) {
|
||||
this.setData({
|
||||
statistics: data.statistics
|
||||
});
|
||||
} else {
|
||||
this.calculateStatistics();
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取养殖户列表失败:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载模拟数据
|
||||
loadMockData() {
|
||||
const mockFarmers = [
|
||||
{
|
||||
id: 1,
|
||||
name: '张三',
|
||||
phone: '138****1234',
|
||||
area: '银川市',
|
||||
farmName: '张家养殖场',
|
||||
animalCount: 120,
|
||||
animalType: '牛',
|
||||
status: 'normal',
|
||||
lastCheckTime: '2024-01-15 10:30',
|
||||
avatar: '/images/avatar.png'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '李四',
|
||||
phone: '139****5678',
|
||||
area: '石嘴山市',
|
||||
farmName: '李氏牧场',
|
||||
animalCount: 85,
|
||||
animalType: '羊',
|
||||
status: 'warning',
|
||||
lastCheckTime: '2024-01-14 16:20',
|
||||
avatar: '/images/avatar.png'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '王五',
|
||||
phone: '137****9012',
|
||||
area: '吴忠市',
|
||||
farmName: '王家农场',
|
||||
animalCount: 200,
|
||||
animalType: '牛',
|
||||
status: 'normal',
|
||||
lastCheckTime: '2024-01-15 09:15',
|
||||
avatar: '/images/avatar.png'
|
||||
}
|
||||
];
|
||||
|
||||
this.setData({
|
||||
farmerList: mockFarmers,
|
||||
totalCount: mockFarmers.length,
|
||||
hasMore: false,
|
||||
statistics: {
|
||||
total: 3,
|
||||
normal: 2,
|
||||
warning: 1,
|
||||
offline: 0
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 计算统计信息
|
||||
calculateStatistics() {
|
||||
const farmers = this.data.farmerList;
|
||||
const statistics = {
|
||||
total: farmers.length,
|
||||
normal: farmers.filter(f => f.status === 'normal').length,
|
||||
warning: farmers.filter(f => f.status === 'warning').length,
|
||||
offline: farmers.filter(f => f.status === 'offline').length
|
||||
};
|
||||
|
||||
this.setData({ statistics });
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.loadData(true).finally(() => {
|
||||
wx.stopPullDownRefresh();
|
||||
});
|
||||
},
|
||||
|
||||
onReachBottom() {
|
||||
this.onLoadMore();
|
||||
},
|
||||
|
||||
|
||||
|
||||
// 搜索输入
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
// 执行搜索
|
||||
onSearch() {
|
||||
this.loadData(true);
|
||||
},
|
||||
|
||||
// 清空搜索
|
||||
onClearSearch() {
|
||||
this.setData({
|
||||
searchKeyword: ''
|
||||
});
|
||||
this.loadData(true);
|
||||
},
|
||||
|
||||
// 状态筛选
|
||||
onStatusChange(e) {
|
||||
const status = e.currentTarget.dataset.status;
|
||||
this.setData({
|
||||
selectedStatus: status
|
||||
});
|
||||
this.loadData(true);
|
||||
},
|
||||
|
||||
// 区域筛选
|
||||
onAreaChange(e) {
|
||||
const area = e.currentTarget.dataset.area;
|
||||
this.setData({
|
||||
selectedArea: area
|
||||
});
|
||||
this.loadData(true);
|
||||
},
|
||||
|
||||
// 养殖户项点击
|
||||
onFarmerTap(e) {
|
||||
const { farmer } = e.currentTarget.dataset;
|
||||
wx.navigateTo({
|
||||
url: `/pages/farmer/detail/detail?id=${farmer.id}`
|
||||
});
|
||||
},
|
||||
|
||||
// 添加养殖户
|
||||
onAddFarmer() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/farmer/add/add'
|
||||
});
|
||||
},
|
||||
|
||||
// 编辑养殖户
|
||||
onEditFarmer(e) {
|
||||
e.stopPropagation();
|
||||
const { farmer } = e.currentTarget.dataset;
|
||||
wx.navigateTo({
|
||||
url: `/pages/farmer/edit/edit?id=${farmer.id}`
|
||||
});
|
||||
},
|
||||
|
||||
// 拨打电话
|
||||
onCallFarmer(e) {
|
||||
e.stopPropagation();
|
||||
const { farmer } = e.currentTarget.dataset;
|
||||
|
||||
wx.showModal({
|
||||
title: '拨打电话',
|
||||
content: `确定要拨打 ${farmer.name} 的电话吗?`,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.makePhoneCall({
|
||||
phoneNumber: farmer.phone.replace(/\*/g, '1') // 替换掩码
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 加载更多
|
||||
onLoadMore() {
|
||||
if (!this.data.hasMore || this.data.loading) return;
|
||||
|
||||
this.setData({
|
||||
currentPage: this.data.currentPage + 1
|
||||
});
|
||||
|
||||
this.loadData(false);
|
||||
},
|
||||
|
||||
// 分享页面
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '政府监管端 - 养殖户管理',
|
||||
path: '/pages/farmer/farmer'
|
||||
};
|
||||
}
|
||||
});
|
||||
7
government-mini-program/pages/farmer/farmer.json
Normal file
7
government-mini-program/pages/farmer/farmer.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "养殖户管理",
|
||||
"navigationStyle": "custom",
|
||||
"enablePullDownRefresh": true,
|
||||
"onReachBottomDistance": 50
|
||||
}
|
||||
139
government-mini-program/pages/farmer/farmer.wxml
Normal file
139
government-mini-program/pages/farmer/farmer.wxml
Normal file
@@ -0,0 +1,139 @@
|
||||
<!--pages/farmer/farmer.wxml-->
|
||||
<view class="container">
|
||||
<!-- 状态栏 -->
|
||||
<view class="status-bar">
|
||||
<view class="status-left">
|
||||
<text>17:00</text>
|
||||
</view>
|
||||
<view class="status-right">
|
||||
<text>100%</text>
|
||||
<view class="battery-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部标题栏 -->
|
||||
<view class="header">
|
||||
<view class="header-title">养殖户管理</view>
|
||||
<view class="header-actions">
|
||||
<view class="action-btn" bindtap="onMenuTap">
|
||||
<text class="icon-more">⋯</text>
|
||||
</view>
|
||||
<view class="action-btn">
|
||||
<text class="icon-minus">−</text>
|
||||
</view>
|
||||
<view class="action-btn">
|
||||
<text class="icon-circle">●</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 搜索框 -->
|
||||
<view class="search-section">
|
||||
<view class="search-box">
|
||||
<view class="search-icon">🔍</view>
|
||||
<input
|
||||
class="search-input"
|
||||
placeholder="请输入账号、昵称、真实"
|
||||
value="{{searchValue}}"
|
||||
bindinput="onSearchInput"
|
||||
bindconfirm="onSearch"
|
||||
/>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 养殖户列表 -->
|
||||
<view class="farmer-list">
|
||||
<view
|
||||
class="farmer-card"
|
||||
wx:for="{{farmerList}}"
|
||||
wx:key="id"
|
||||
data-farmer="{{item}}"
|
||||
bindtap="viewFarmerDetail"
|
||||
>
|
||||
<!-- 养殖户基本信息 -->
|
||||
<view class="farmer-info">
|
||||
<view class="farmer-header">
|
||||
<view class="farmer-name">{{item.name}}</view>
|
||||
<view class="farmer-status {{item.status === '正常' ? 'status-normal' : item.status === '异常' ? 'status-error' : 'status-pending'}}">
|
||||
{{item.status}}
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="farmer-details">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">手机号码:</text>
|
||||
<text class="detail-value">{{item.phone}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">所在地区:</text>
|
||||
<text class="detail-value">{{item.area}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">养殖场名:</text>
|
||||
<text class="detail-value">{{item.farmName}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">牲畜数量:</text>
|
||||
<text class="detail-value">{{item.animalCount}}头</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">注册时间:</text>
|
||||
<text class="detail-value">{{item.registerTime}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">最近检查:</text>
|
||||
<text class="detail-value">{{item.lastCheckTime}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<view class="farmer-actions">
|
||||
<view
|
||||
class="action-btn edit-btn"
|
||||
data-farmer="{{item}}"
|
||||
bindtap="editFarmer"
|
||||
catchtap="true"
|
||||
>
|
||||
<text class="action-icon">✏️</text>
|
||||
<text class="action-text">编辑</text>
|
||||
</view>
|
||||
<view
|
||||
class="action-btn status-btn"
|
||||
data-farmer="{{item}}"
|
||||
bindtap="toggleFarmerStatus"
|
||||
catchtap="true"
|
||||
>
|
||||
<text class="action-icon">🔄</text>
|
||||
<text class="action-text">{{item.status === '正常' ? '标记异常' : '标记正常'}}</text>
|
||||
</view>
|
||||
<view
|
||||
class="action-btn delete-btn"
|
||||
data-farmer="{{item}}"
|
||||
bindtap="deleteFarmer"
|
||||
catchtap="true"
|
||||
>
|
||||
<text class="action-icon">🗑️</text>
|
||||
<text class="action-text">删除</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" wx:if="{{farmerList.length === 0 && !loading}}">
|
||||
<text class="empty-text">暂无养殖户数据</text>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view class="loading-state" wx:if="{{loading}}">
|
||||
<text>加载中...</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部新增按钮 -->
|
||||
<view class="bottom-section">
|
||||
<view class="add-farmer-btn" bindtap="addFarmer">
|
||||
新增监管养殖户
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
371
government-mini-program/pages/farmer/farmer.wxss
Normal file
371
government-mini-program/pages/farmer/farmer.wxss
Normal file
@@ -0,0 +1,371 @@
|
||||
/* pages/farmer/farmer.wxss */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-bottom: 120rpx; /* 为底部按钮留出空间 */
|
||||
}
|
||||
|
||||
/* 确保状态栏在顶部 */
|
||||
.status-bar {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin-top: 60rpx; /* 为状态栏留出空间 */
|
||||
}
|
||||
|
||||
/* 状态栏 */
|
||||
.status-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
padding: 10rpx 30rpx;
|
||||
height: 60rpx;
|
||||
box-sizing: border-box;
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.status-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.status-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.battery-icon {
|
||||
width: 20rpx;
|
||||
height: 12rpx;
|
||||
background-color: #333333;
|
||||
border-radius: 2rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.battery-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: -4rpx;
|
||||
top: 3rpx;
|
||||
width: 2rpx;
|
||||
height: 6rpx;
|
||||
background-color: #333333;
|
||||
border-radius: 0 1rpx 1rpx 0;
|
||||
}
|
||||
|
||||
/* 顶部标题栏 */
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
padding: 20rpx 30rpx;
|
||||
height: 100rpx;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
color: #333333;
|
||||
font-size: 36rpx;
|
||||
font-weight: 500;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 15rpx;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: #999999;
|
||||
font-size: 20rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* 搜索区域 */
|
||||
.search-section {
|
||||
background-color: #ffffff;
|
||||
padding: 20rpx 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 20rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 70rpx;
|
||||
border: 1rpx solid #e0e0e0;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
margin-right: 12rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
font-size: 26rpx;
|
||||
color: #333333;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* 养殖户列表 */
|
||||
.farmer-list {
|
||||
padding: 20rpx 30rpx;
|
||||
}
|
||||
|
||||
.farmer-card {
|
||||
background-color: white;
|
||||
border-radius: 16rpx;
|
||||
margin: 0 20rpx 20rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.farmer-card:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
/* 养殖户信息 */
|
||||
.farmer-info {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.farmer-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.farmer-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.farmer-status {
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.status-normal {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
.status-error {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
.status-pending {
|
||||
background-color: #ff9800;
|
||||
}
|
||||
|
||||
.farmer-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12rpx;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
width: 160rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* 操作按钮 */
|
||||
.farmer-actions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 20rpx;
|
||||
padding-top: 20rpx;
|
||||
border-top: 1rpx solid #eee;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20rpx 10rpx;
|
||||
border-radius: 12rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
background-color: #e3f2fd;
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
.status-btn {
|
||||
background-color: #fff3e0;
|
||||
color: #f57c00;
|
||||
}
|
||||
|
||||
.delete-btn {
|
||||
background-color: #ffebee;
|
||||
color: #d32f2f;
|
||||
}
|
||||
|
||||
.action-btn:active {
|
||||
transform: scale(0.95);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
font-size: 32rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 24rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 卡片头部 */
|
||||
.card-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 25rpx 25rpx 20rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.farmer-name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.farmer-name .label {
|
||||
font-size: 26rpx;
|
||||
color: #999999;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.farmer-name .value {
|
||||
font-size: 30rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.edit-btn {
|
||||
background-color: #4CAF50;
|
||||
color: #ffffff;
|
||||
padding: 10rpx 20rpx;
|
||||
border-radius: 4rpx;
|
||||
font-size: 22rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 卡片内容 */
|
||||
.card-content {
|
||||
padding: 20rpx 25rpx 25rpx;
|
||||
}
|
||||
|
||||
.info-row {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 14rpx;
|
||||
line-height: 1.3;
|
||||
}
|
||||
|
||||
.info-row:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.info-row .label {
|
||||
font-size: 24rpx;
|
||||
color: #999999;
|
||||
min-width: 140rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.info-row .value {
|
||||
font-size: 24rpx;
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 100rpx 0;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
color: #999999;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading-state {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
padding: 40rpx 0;
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
/* 底部新增按钮 */
|
||||
.bottom-section {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #ffffff;
|
||||
padding: 20rpx 30rpx;
|
||||
border-top: 1rpx solid #f0f0f0;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.add-farmer-btn {
|
||||
background-color: #4CAF50;
|
||||
color: #ffffff;
|
||||
text-align: center;
|
||||
padding: 20rpx 0;
|
||||
border-radius: 6rpx;
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
width: 100%;
|
||||
}
|
||||
125
government-mini-program/pages/farmers/farmers.js
Normal file
125
government-mini-program/pages/farmers/farmers.js
Normal file
@@ -0,0 +1,125 @@
|
||||
// pages/farmers/farmers.js
|
||||
Page({
|
||||
data: {
|
||||
farmers: [],
|
||||
loading: false,
|
||||
searchKeyword: '',
|
||||
currentPage: 1,
|
||||
pageSize: 10,
|
||||
total: 0
|
||||
},
|
||||
|
||||
onLoad: function (options) {
|
||||
this.checkLoginStatus();
|
||||
this.loadFarmers();
|
||||
},
|
||||
|
||||
onShow: function () {
|
||||
this.loadFarmers();
|
||||
},
|
||||
|
||||
checkLoginStatus: function() {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
wx.reLaunch({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
loadFarmers: function() {
|
||||
if (!this.checkLoginStatus()) return;
|
||||
|
||||
this.setData({
|
||||
loading: true
|
||||
});
|
||||
|
||||
// 模拟数据
|
||||
const mockFarmers = [
|
||||
{
|
||||
id: 1,
|
||||
name: '张三',
|
||||
phone: '13800138001',
|
||||
address: '宁夏银川市兴庆区',
|
||||
farmName: '张三养殖场',
|
||||
animalCount: 120,
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '李四',
|
||||
phone: '13800138002',
|
||||
address: '宁夏银川市金凤区',
|
||||
farmName: '李四牧场',
|
||||
animalCount: 85,
|
||||
status: 'active'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '王五',
|
||||
phone: '13800138003',
|
||||
address: '宁夏银川市西夏区',
|
||||
farmName: '王五养殖合作社',
|
||||
animalCount: 200,
|
||||
status: 'inactive'
|
||||
}
|
||||
];
|
||||
|
||||
setTimeout(() => {
|
||||
this.setData({
|
||||
farmers: mockFarmers,
|
||||
loading: false,
|
||||
total: mockFarmers.length
|
||||
});
|
||||
}, 500);
|
||||
},
|
||||
|
||||
onSearchInput: function(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
});
|
||||
},
|
||||
|
||||
onSearch: function() {
|
||||
this.loadFarmers();
|
||||
},
|
||||
|
||||
onFarmerTap: function(e) {
|
||||
const farmerId = e.currentTarget.dataset.id;
|
||||
wx.navigateTo({
|
||||
url: `/pages/farmer/detail/detail?id=${farmerId}`
|
||||
});
|
||||
},
|
||||
|
||||
onAddFarmer: function() {
|
||||
wx.navigateTo({
|
||||
url: '/pages/farmer/add/add'
|
||||
});
|
||||
},
|
||||
|
||||
onPullDownRefresh: function() {
|
||||
this.loadFarmers();
|
||||
wx.stopPullDownRefresh();
|
||||
},
|
||||
|
||||
onReachBottom: function() {
|
||||
// 加载更多数据
|
||||
if (this.data.farmers.length < this.data.total) {
|
||||
this.loadMoreFarmers();
|
||||
}
|
||||
},
|
||||
|
||||
loadMoreFarmers: function() {
|
||||
// 实现分页加载
|
||||
console.log('加载更多养殖户数据');
|
||||
},
|
||||
|
||||
onShareAppMessage: function() {
|
||||
return {
|
||||
title: '养殖户管理',
|
||||
path: '/pages/farmers/farmers'
|
||||
};
|
||||
}
|
||||
});
|
||||
8
government-mini-program/pages/farmers/farmers.json
Normal file
8
government-mini-program/pages/farmers/farmers.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"navigationBarTitleText": "养殖户管理",
|
||||
"navigationBarBackgroundColor": "#7CB342",
|
||||
"navigationBarTextStyle": "white",
|
||||
"backgroundColor": "#f5f5f5",
|
||||
"enablePullDownRefresh": true,
|
||||
"onReachBottomDistance": 50
|
||||
}
|
||||
80
government-mini-program/pages/farmers/farmers.wxml
Normal file
80
government-mini-program/pages/farmers/farmers.wxml
Normal file
@@ -0,0 +1,80 @@
|
||||
<!--pages/farmers/farmers.wxml-->
|
||||
<view class="container">
|
||||
<!-- 顶部搜索栏 -->
|
||||
<view class="search-bar">
|
||||
<view class="search-input-wrapper">
|
||||
<input
|
||||
class="search-input"
|
||||
placeholder="搜索养殖户姓名或农场名称"
|
||||
value="{{searchKeyword}}"
|
||||
bindinput="onSearchInput"
|
||||
bindconfirm="onSearch"
|
||||
/>
|
||||
<view class="search-btn" bindtap="onSearch">
|
||||
<text class="search-icon">🔍</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="add-btn" bindtap="onAddFarmer">
|
||||
<text class="add-icon">+</text>
|
||||
<text class="add-text">新增</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 养殖户列表 -->
|
||||
<view class="farmers-list">
|
||||
<view
|
||||
class="farmer-item"
|
||||
wx:for="{{farmers}}"
|
||||
wx:key="id"
|
||||
data-id="{{item.id}}"
|
||||
bindtap="onFarmerTap"
|
||||
>
|
||||
<view class="farmer-avatar">
|
||||
<text class="avatar-text">{{item.name.charAt(0)}}</text>
|
||||
</view>
|
||||
<view class="farmer-info">
|
||||
<view class="farmer-header">
|
||||
<text class="farmer-name">{{item.name}}</text>
|
||||
<view class="farmer-status {{item.status}}">
|
||||
<text class="status-text">{{item.status === 'active' ? '正常' : '停用'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="farmer-details">
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">农场:</text>
|
||||
<text class="detail-value">{{item.farmName}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">电话:</text>
|
||||
<text class="detail-value">{{item.phone}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">地址:</text>
|
||||
<text class="detail-value">{{item.address}}</text>
|
||||
</view>
|
||||
<view class="detail-item">
|
||||
<text class="detail-label">牲畜数量:</text>
|
||||
<text class="detail-value animal-count">{{item.animalCount}}头</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="farmer-arrow">
|
||||
<text class="arrow-icon">></text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view class="loading" wx:if="{{loading}}">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<!-- 空状态 -->
|
||||
<view class="empty-state" wx:if="{{!loading && farmers.length === 0}}">
|
||||
<text class="empty-icon">📋</text>
|
||||
<text class="empty-text">暂无养殖户数据</text>
|
||||
<view class="empty-btn" bindtap="onAddFarmer">
|
||||
<text>添加养殖户</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
220
government-mini-program/pages/farmers/farmers.wxss
Normal file
220
government-mini-program/pages/farmers/farmers.wxss
Normal file
@@ -0,0 +1,220 @@
|
||||
/* pages/farmers/farmers.wxss */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* 搜索栏样式 */
|
||||
.search-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
padding: 20rpx 30rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.search-input-wrapper {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #f8f8f8;
|
||||
border-radius: 25rpx;
|
||||
padding: 0 20rpx;
|
||||
height: 70rpx;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
flex: 1;
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.search-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #7CB342;
|
||||
border-radius: 50%;
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
color: white;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #7CB342;
|
||||
color: white;
|
||||
padding: 15rpx 25rpx;
|
||||
border-radius: 35rpx;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.add-text {
|
||||
font-size: 26rpx;
|
||||
}
|
||||
|
||||
/* 养殖户列表样式 */
|
||||
.farmers-list {
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.farmer-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background-color: #ffffff;
|
||||
border-radius: 12rpx;
|
||||
padding: 25rpx;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.farmer-avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
background-color: #7CB342;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
color: white;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.farmer-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.farmer-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 15rpx;
|
||||
}
|
||||
|
||||
.farmer-name {
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.farmer-status {
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.farmer-status.active {
|
||||
background-color: #e8f5e8;
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.farmer-status.inactive {
|
||||
background-color: #ffeaea;
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
.farmer-details {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8rpx;
|
||||
}
|
||||
|
||||
.detail-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
.detail-label {
|
||||
color: #666666;
|
||||
width: 120rpx;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.detail-value {
|
||||
color: #333333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.animal-count {
|
||||
color: #7CB342;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.farmer-arrow {
|
||||
width: 30rpx;
|
||||
height: 30rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.arrow-icon {
|
||||
color: #cccccc;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* 加载状态 */
|
||||
.loading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 40rpx;
|
||||
}
|
||||
|
||||
.loading-text {
|
||||
color: #999999;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 空状态 */
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 100rpx 40rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 120rpx;
|
||||
margin-bottom: 30rpx;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.empty-text {
|
||||
color: #999999;
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.empty-btn {
|
||||
background-color: #7CB342;
|
||||
color: white;
|
||||
padding: 20rpx 40rpx;
|
||||
border-radius: 25rpx;
|
||||
font-size: 28rpx;
|
||||
}
|
||||
@@ -1,102 +1,251 @@
|
||||
// pages/index/index.js
|
||||
const auth = require('../../utils/auth.js')
|
||||
const dashboardService = require('../../services/dashboardService.js')
|
||||
const app = getApp();
|
||||
|
||||
Page({
|
||||
data: {
|
||||
userInfo: {},
|
||||
quickActions: [
|
||||
{ key: 'dashboard', name: '数据看板', icon: '📊', path: '/pages/dashboard/dashboard' },
|
||||
{ key: 'supervision', name: '监管管理', icon: '🔍', path: '/pages/supervision/supervision' },
|
||||
{ key: 'approval', name: '审批管理', icon: '✅', path: '/pages/approval/approval' },
|
||||
{ key: 'personnel', name: '人员管理', icon: '👥', path: '/pages/personnel/personnel' },
|
||||
{ key: 'epidemic', name: '疫情监控', icon: '🦠', path: '/pages/epidemic/epidemic' },
|
||||
{ key: 'service', name: '服务管理', icon: '🛠️', path: '/pages/service/service' },
|
||||
{ key: 'warehouse', name: '仓库管理', icon: '📦', path: '/pages/warehouse/warehouse' },
|
||||
{ key: 'profile', name: '个人中心', icon: '👤', path: '/pages/profile/profile' }
|
||||
],
|
||||
statsData: [
|
||||
{ key: 'supervision', label: '监管记录', value: '0', trend: 'up', trendText: '+0%' },
|
||||
{ key: 'approval', label: '待审批', value: '0', trend: 'up', trendText: '+0%' },
|
||||
{ key: 'personnel', label: '人员总数', value: '0', trend: 'up', trendText: '+0%' },
|
||||
{ key: 'epidemic', label: '疫情预警', value: '0', trend: 'down', trendText: '-0%' }
|
||||
],
|
||||
recentActivities: [
|
||||
currentTime: '',
|
||||
|
||||
// 用户信息
|
||||
userInfo: {
|
||||
name: '政府管理员',
|
||||
role: '监管人员'
|
||||
},
|
||||
|
||||
// 智能硬件设备(图一样式:使用图片图标)
|
||||
hardwareDevices: [
|
||||
{
|
||||
id: 1,
|
||||
icon: '🔍',
|
||||
title: '监管检查',
|
||||
desc: '完成养殖场A的例行检查',
|
||||
time: '2小时前'
|
||||
name: '项圈仓库',
|
||||
img: '/images/collar.png',
|
||||
color: '#1890ff',
|
||||
type: 'collar'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
icon: '✅',
|
||||
title: '审批通过',
|
||||
desc: '通过养殖许可证申请',
|
||||
time: '4小时前'
|
||||
name: '耳标仓库',
|
||||
img: '/images/ear-tag.png',
|
||||
color: '#ff7a45',
|
||||
type: 'eartag'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
icon: '👥',
|
||||
title: '人员管理',
|
||||
desc: '新增监管员张三',
|
||||
time: '6小时前'
|
||||
name: '脚环仓库',
|
||||
img: '/images/ankle-ring.png',
|
||||
color: '#52c41a',
|
||||
type: 'anklet'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '主机仓库',
|
||||
img: '/images/host.png',
|
||||
color: '#faad14',
|
||||
type: 'host'
|
||||
}
|
||||
],
|
||||
|
||||
// 其它功能(图一样式:使用图片图标)
|
||||
otherFunctions: [
|
||||
{
|
||||
id: 1,
|
||||
name: '牲畜身份认证',
|
||||
img: '/images/identity.png',
|
||||
color: '#1890ff',
|
||||
type: 'livestock_auth'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: '无害化检验',
|
||||
img: '/images/epidemic.png',
|
||||
color: '#ff7a45',
|
||||
type: 'harmless_check'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: '检疫证查询',
|
||||
img: '/images/quarantine.png',
|
||||
color: '#52c41a',
|
||||
type: 'quarantine_query'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '金融保险监管',
|
||||
img: '/images/finance.png',
|
||||
color: '#faad14',
|
||||
type: 'finance_insurance'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: '屠宰场监管',
|
||||
img: '/images/slaughter.png',
|
||||
color: '#722ed1',
|
||||
type: 'slaughter_supervision'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: '检疫站监管',
|
||||
img: '/images/epidemic-station.png',
|
||||
color: '#eb2f96',
|
||||
type: 'quarantine_supervision'
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: '无害化防疫',
|
||||
img: '/images/certificate.png',
|
||||
color: '#13c2c2',
|
||||
type: 'harmless_prevention'
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: '防疫站监管',
|
||||
img: '/images/station.png',
|
||||
color: '#1890ff',
|
||||
type: 'prevention_supervision'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.initData()
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.loadData()
|
||||
console.log('首页加载完成');
|
||||
// 延迟检查登录状态,避免与登录跳转冲突
|
||||
setTimeout(() => {
|
||||
wx.stopPullDownRefresh()
|
||||
}, 1000)
|
||||
this.checkLoginStatus();
|
||||
}, 100);
|
||||
this.updateTime();
|
||||
this.startTimeUpdate();
|
||||
},
|
||||
|
||||
initData() {
|
||||
// 获取用户信息
|
||||
this.setData({
|
||||
userInfo: auth.getUser() || {}
|
||||
})
|
||||
onShow() {
|
||||
console.log('首页显示');
|
||||
// 延迟检查登录状态,避免与登录跳转冲突
|
||||
setTimeout(() => {
|
||||
this.checkLoginStatus();
|
||||
}, 100);
|
||||
this.updateTime();
|
||||
},
|
||||
|
||||
onUnload() {
|
||||
// 清除定时器
|
||||
if (this.timeInterval) {
|
||||
clearInterval(this.timeInterval);
|
||||
}
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token');
|
||||
console.log('首页检查登录状态,token:', token);
|
||||
if (!token) {
|
||||
console.log('未找到token,跳转到登录页');
|
||||
// 未登录,跳转到登录页
|
||||
wx.reLaunch({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
return false;
|
||||
}
|
||||
console.log('token验证通过,用户已登录');
|
||||
return true;
|
||||
},
|
||||
|
||||
// 更新时间显示
|
||||
updateTime() {
|
||||
const now = new Date();
|
||||
const hours = now.getHours().toString().padStart(2, '0');
|
||||
const minutes = now.getMinutes().toString().padStart(2, '0');
|
||||
const timeString = `${hours}:${minutes}`;
|
||||
|
||||
// 加载数据
|
||||
this.loadData()
|
||||
this.setData({
|
||||
currentTime: timeString
|
||||
});
|
||||
},
|
||||
|
||||
async loadData() {
|
||||
try {
|
||||
// 加载统计数据
|
||||
const stats = await dashboardService.getStats()
|
||||
if (stats) {
|
||||
this.updateStatsData(stats)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载数据失败:', error)
|
||||
|
||||
// 开始时间更新定时器
|
||||
startTimeUpdate() {
|
||||
this.timeInterval = setInterval(() => {
|
||||
this.updateTime();
|
||||
}, 60000); // 每分钟更新一次
|
||||
},
|
||||
|
||||
// 智能硬件设备点击
|
||||
onHardwareDeviceTap(e) {
|
||||
const { type } = e.currentTarget.dataset;
|
||||
console.log('点击硬件设备:', type);
|
||||
|
||||
wx.showToast({
|
||||
title: `进入${type}管理`,
|
||||
icon: 'none'
|
||||
});
|
||||
|
||||
// 根据不同类型跳转到相应页面
|
||||
switch (type) {
|
||||
case 'collar':
|
||||
// 跳转到项圈管理页面
|
||||
break;
|
||||
case 'eartag':
|
||||
// 跳转到耳标管理页面
|
||||
break;
|
||||
case 'anklet':
|
||||
// 跳转到脚环管理页面
|
||||
break;
|
||||
case 'host':
|
||||
// 跳转到主机管理页面
|
||||
break;
|
||||
default:
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
updateStatsData(data) {
|
||||
const statsData = this.data.statsData.map(stat => {
|
||||
const newValue = data[stat.key] || stat.value
|
||||
return {
|
||||
...stat,
|
||||
value: newValue
|
||||
}
|
||||
})
|
||||
this.setData({ statsData })
|
||||
},
|
||||
|
||||
handleAction(e) {
|
||||
const { action } = e.currentTarget.dataset
|
||||
const actionItem = this.data.quickActions.find(item => item.key === action)
|
||||
if (actionItem && actionItem.path) {
|
||||
wx.navigateTo({
|
||||
url: actionItem.path
|
||||
})
|
||||
|
||||
// 其它功能点击
|
||||
onOtherFunctionTap(e) {
|
||||
const { type } = e.currentTarget.dataset;
|
||||
console.log('点击其它功能:', type);
|
||||
|
||||
wx.showToast({
|
||||
title: `进入${type}`,
|
||||
icon: 'none'
|
||||
});
|
||||
|
||||
// 根据不同类型跳转到相应页面
|
||||
switch (type) {
|
||||
case 'livestock_auth':
|
||||
// 跳转到牲畜身份认证页面
|
||||
break;
|
||||
case 'harmless_check':
|
||||
// 跳转到无害化检验页面
|
||||
break;
|
||||
case 'quarantine_query':
|
||||
// 跳转到检疫证查询页面
|
||||
break;
|
||||
case 'finance_insurance':
|
||||
// 跳转到金融保险监管页面
|
||||
break;
|
||||
case 'slaughter_supervision':
|
||||
// 跳转到屠宰场监管页面
|
||||
break;
|
||||
case 'quarantine_supervision':
|
||||
// 跳转到检疫站监管页面
|
||||
break;
|
||||
case 'harmless_prevention':
|
||||
// 跳转到无害化防疫页面
|
||||
break;
|
||||
case 'prevention_supervision':
|
||||
// 跳转到防疫站监管页面
|
||||
break;
|
||||
default:
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 分享功能
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '政府监管系统',
|
||||
path: '/pages/index/index'
|
||||
};
|
||||
}
|
||||
})
|
||||
@@ -1,3 +1,5 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "首页",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
|
||||
@@ -1,75 +1,72 @@
|
||||
<!--pages/index/index.wxml-->
|
||||
<view class="home-container">
|
||||
<!-- 头部欢迎区域 -->
|
||||
<view class="welcome-section">
|
||||
<view class="welcome-content">
|
||||
<view class="user-info">
|
||||
<view class="avatar">
|
||||
<image src="/images/avatar.png" class="avatar-img" />
|
||||
</view>
|
||||
<view class="user-details">
|
||||
<view class="username">{{userInfo.name || '管理员'}}</view>
|
||||
<view class="user-role">{{userInfo.role || '系统管理员'}}</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="weather-info">
|
||||
<view class="weather-icon">☀️</view>
|
||||
<view class="weather-text">晴 25°C</view>
|
||||
</view>
|
||||
<view class="container">
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="nav-bar">
|
||||
<view class="nav-title">首页</view>
|
||||
<view class="nav-actions">
|
||||
<view class="nav-icon">⋯</view>
|
||||
<view class="nav-icon">—</view>
|
||||
<view class="nav-icon">⊙</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 快捷功能区域 -->
|
||||
<view class="quick-actions">
|
||||
<view class="section-title">快捷功能</view>
|
||||
<view class="action-grid">
|
||||
<view
|
||||
wx:for="{{quickActions}}"
|
||||
wx:key="key"
|
||||
class="action-item"
|
||||
data-action="{{item.key}}"
|
||||
bindtap="handleAction"
|
||||
>
|
||||
<view class="action-icon">{{item.icon}}</view>
|
||||
<view class="action-text">{{item.name}}</view>
|
||||
</view>
|
||||
<!-- 智能硬件设备区域 -->
|
||||
<view class="section">
|
||||
<view class="section-header">
|
||||
<view class="section-indicator"></view>
|
||||
<text class="section-title">智能硬件设备</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 数据概览区域 -->
|
||||
<view class="stats-section">
|
||||
<view class="section-title">数据概览</view>
|
||||
<view class="stats-grid">
|
||||
<view
|
||||
wx:for="{{statsData}}"
|
||||
wx:key="key"
|
||||
class="stat-item"
|
||||
>
|
||||
<view class="stat-value">{{item.value}}</view>
|
||||
<view class="stat-label">{{item.label}}</view>
|
||||
<view class="stat-trend {{item.trend}}">
|
||||
{{item.trendText}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 最近活动区域 -->
|
||||
<view class="recent-activities">
|
||||
<view class="section-title">最近活动</view>
|
||||
<view class="activity-list">
|
||||
<view
|
||||
wx:for="{{recentActivities}}"
|
||||
<view class="hardware-grid">
|
||||
<view
|
||||
class="hardware-item"
|
||||
wx:for="{{hardwareDevices}}"
|
||||
wx:key="id"
|
||||
class="activity-item"
|
||||
data-type="{{item.type}}"
|
||||
bindtap="onHardwareDeviceTap"
|
||||
>
|
||||
<view class="activity-icon">{{item.icon}}</view>
|
||||
<view class="activity-content">
|
||||
<view class="activity-title">{{item.title}}</view>
|
||||
<view class="activity-desc">{{item.desc}}</view>
|
||||
<view class="activity-time">{{item.time}}</view>
|
||||
<view class="hardware-icon" style="background-color: {{item.color}}">
|
||||
<image class="icon-image" src="{{item.img}}" mode="aspectFit"/>
|
||||
</view>
|
||||
<text class="hardware-name">{{item.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 其它功能区域 -->
|
||||
<view class="section">
|
||||
<view class="section-header">
|
||||
<view class="section-indicator"></view>
|
||||
<text class="section-title">其它</text>
|
||||
</view>
|
||||
<view class="other-grid">
|
||||
<view
|
||||
class="other-item"
|
||||
wx:for="{{otherFunctions}}"
|
||||
wx:key="id"
|
||||
data-type="{{item.type}}"
|
||||
bindtap="onOtherFunctionTap"
|
||||
>
|
||||
<view class="other-icon" style="background-color: {{item.color}}">
|
||||
<image class="icon-image" src="{{item.img}}" mode="aspectFit"/>
|
||||
</view>
|
||||
<text class="other-name">{{item.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部标签栏 -->
|
||||
<view class="tab-bar">
|
||||
<view class="tab-item active">
|
||||
<image class="tab-icon" src="/images/home-active.png" mode="aspectFit"/>
|
||||
<text class="tab-text">首页</text>
|
||||
</view>
|
||||
<view class="tab-item">
|
||||
<image class="tab-icon" src="/images/farmers.png" mode="aspectFit"/>
|
||||
<text class="tab-text">养殖户</text>
|
||||
</view>
|
||||
<view class="tab-item">
|
||||
<image class="tab-icon" src="/images/profile.png" mode="aspectFit"/>
|
||||
<text class="tab-text">我的</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,187 +1,199 @@
|
||||
/* pages/index/index.wxss */
|
||||
.home-container {
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
background: #f5f5f5;
|
||||
padding-bottom: 120rpx; /* 为底部标签栏留出空间 */
|
||||
}
|
||||
|
||||
.welcome-section {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
padding: 40rpx 30rpx 60rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.welcome-content {
|
||||
/* 顶部导航栏 */
|
||||
.nav-bar {
|
||||
background: linear-gradient(135deg, #7CB342 0%, #8BC34A 100%);
|
||||
height: 88rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 30rpx;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.avatar {
|
||||
margin-right: 24rpx;
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.username {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.user-role {
|
||||
font-size: 24rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.weather-info {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.weather-icon {
|
||||
.nav-title {
|
||||
font-size: 32rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.weather-text {
|
||||
font-size: 24rpx;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.quick-actions,
|
||||
.stats-section,
|
||||
.recent-activities {
|
||||
padding: 30rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.action-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 30rpx;
|
||||
}
|
||||
|
||||
.action-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 30rpx 20rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 16rpx;
|
||||
transition: all 0.3s;
|
||||
}
|
||||
|
||||
.action-item:active {
|
||||
transform: scale(0.95);
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
font-size: 48rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.action-text {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
padding: 30rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 16rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stat-value {
|
||||
font-size: 48rpx;
|
||||
font-weight: 600;
|
||||
color: #1890ff;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-trend {
|
||||
font-size: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.stat-trend.up {
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.stat-trend.down {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
.activity-list {
|
||||
space-y: 20rpx;
|
||||
}
|
||||
|
||||
.activity-item {
|
||||
.nav-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
border-radius: 44rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
}
|
||||
|
||||
.activity-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.activity-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 20rpx;
|
||||
width: 60rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.activity-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.activity-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.activity-desc {
|
||||
.nav-icon {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin: 0 8rpx;
|
||||
width: 24rpx;
|
||||
height: 24rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* 区域样式 */
|
||||
.section {
|
||||
background: white;
|
||||
margin: 20rpx 0;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx 30rpx;
|
||||
background: #f8f8f8;
|
||||
border-bottom: 1rpx solid #e8e8e8;
|
||||
}
|
||||
|
||||
.section-indicator {
|
||||
width: 6rpx;
|
||||
height: 28rpx;
|
||||
background: #2c5aa0;
|
||||
margin-right: 16rpx;
|
||||
border-radius: 3rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
/* 智能硬件设备网格 */
|
||||
.hardware-grid {
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
padding: 30rpx 20rpx;
|
||||
background: white;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.hardware-item {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin: 0 10rpx;
|
||||
}
|
||||
|
||||
.hardware-icon {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 20rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.icon-image {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
.hardware-name {
|
||||
font-size: 26rpx;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
line-height: 1.3;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
/* 其它功能网格 */
|
||||
.other-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
padding: 30rpx;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.other-item {
|
||||
width: 25%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.other-icon {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.other-name {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.icon-image {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
}
|
||||
|
||||
/* 底部标签栏 */
|
||||
.tab-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 120rpx;
|
||||
background: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-around;
|
||||
border-top: 1rpx solid #e8e8e8;
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tab-icon {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.activity-time {
|
||||
.tab-text {
|
||||
font-size: 20rpx;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.tab-item.active .tab-text {
|
||||
color: #7CB342;
|
||||
}
|
||||
|
||||
/* 点击效果 */
|
||||
.hardware-item:active,
|
||||
.other-item:active {
|
||||
transform: scale(0.95);
|
||||
transition: transform 0.1s;
|
||||
}
|
||||
|
||||
.tab-item:active {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
@@ -1,85 +1,274 @@
|
||||
// pages/login/login.js
|
||||
const authService = require('../../services/authService.js')
|
||||
const auth = require('../../utils/auth.js')
|
||||
const app = getApp();
|
||||
const apiService = require('../../utils/api.js');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
username: '',
|
||||
password: '',
|
||||
showPassword: false,
|
||||
loading: false
|
||||
rememberMe: false,
|
||||
loading: false,
|
||||
canLogin: false
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
onLoad(options) {
|
||||
console.log('登录页面加载');
|
||||
this.loadSavedCredentials();
|
||||
},
|
||||
|
||||
onShow() {
|
||||
// 检查是否已登录
|
||||
if (auth.isAuthenticated()) {
|
||||
wx.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
this.checkLoginStatus();
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (token) {
|
||||
// 已登录,跳转到首页(数据统计页面)
|
||||
wx.switchTab({
|
||||
url: '/pages/statistics/statistics'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 加载保存的登录信息
|
||||
loadSavedCredentials() {
|
||||
try {
|
||||
const savedUsername = wx.getStorageSync('savedUsername');
|
||||
const savedPassword = wx.getStorageSync('savedPassword');
|
||||
const rememberMe = wx.getStorageSync('rememberMe');
|
||||
|
||||
if (rememberMe && savedUsername) {
|
||||
this.setData({
|
||||
username: savedUsername,
|
||||
password: savedPassword || '',
|
||||
rememberMe: rememberMe
|
||||
});
|
||||
this.checkCanLogin();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载保存的登录信息失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 用户名输入
|
||||
onUsernameInput(e) {
|
||||
this.setData({
|
||||
username: e.detail.value
|
||||
})
|
||||
});
|
||||
this.checkCanLogin();
|
||||
},
|
||||
|
||||
|
||||
// 密码输入
|
||||
onPasswordInput(e) {
|
||||
this.setData({
|
||||
password: e.detail.value
|
||||
})
|
||||
});
|
||||
this.checkCanLogin();
|
||||
},
|
||||
|
||||
|
||||
// 切换密码显示
|
||||
togglePassword() {
|
||||
this.setData({
|
||||
showPassword: !this.data.showPassword
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
async handleLogin() {
|
||||
const { username, password, loading } = this.data
|
||||
|
||||
if (!username.trim() || !password.trim() || loading) return
|
||||
|
||||
this.setData({ loading: true })
|
||||
|
||||
|
||||
// 记住密码选择
|
||||
onRememberChange(e) {
|
||||
this.setData({
|
||||
rememberMe: e.detail.value.includes('remember')
|
||||
});
|
||||
},
|
||||
|
||||
// 检查是否可以登录
|
||||
checkCanLogin() {
|
||||
const { username, password } = this.data;
|
||||
const canLogin = username.trim().length > 0 && password.trim().length > 0;
|
||||
this.setData({ canLogin });
|
||||
},
|
||||
|
||||
// 登录
|
||||
async onLogin() {
|
||||
if (!this.data.canLogin || this.data.loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { username, password, rememberMe } = this.data;
|
||||
|
||||
// 基本验证
|
||||
if (username.trim().length < 3) {
|
||||
wx.showToast({
|
||||
title: '用户名至少3个字符',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (password.trim().length < 6) {
|
||||
wx.showToast({
|
||||
title: '密码至少6个字符',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
this.setData({ loading: true });
|
||||
|
||||
try {
|
||||
const response = await authService.login(username, password)
|
||||
// 模拟登录请求
|
||||
const loginResult = await this.performLogin(username, password);
|
||||
|
||||
if (response && response.token) {
|
||||
// 保存token
|
||||
auth.setToken(response.token)
|
||||
if (loginResult.success) {
|
||||
// 保存登录状态
|
||||
wx.setStorageSync('token', loginResult.token);
|
||||
wx.setStorageSync('userInfo', loginResult.userInfo);
|
||||
|
||||
// 获取用户信息
|
||||
const userInfo = await authService.getUserInfo()
|
||||
if (userInfo) {
|
||||
auth.setUser(userInfo)
|
||||
// 保存登录信息(如果选择记住密码)
|
||||
if (rememberMe) {
|
||||
wx.setStorageSync('savedUsername', username);
|
||||
wx.setStorageSync('savedPassword', password);
|
||||
wx.setStorageSync('rememberMe', true);
|
||||
} else {
|
||||
wx.removeStorageSync('savedUsername');
|
||||
wx.removeStorageSync('savedPassword');
|
||||
wx.removeStorageSync('rememberMe');
|
||||
}
|
||||
|
||||
// 显示成功提示
|
||||
|
||||
wx.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success',
|
||||
duration: 2000
|
||||
})
|
||||
|
||||
duration: 1000
|
||||
});
|
||||
|
||||
// 跳转到首页
|
||||
setTimeout(() => {
|
||||
wx.reLaunch({
|
||||
url: '/pages/index/index'
|
||||
})
|
||||
}, 1000)
|
||||
console.log('开始跳转流程,当前loading状态:', this.data.loading);
|
||||
|
||||
// 直接使用reLaunch跳转,不使用setTimeout延迟
|
||||
wx.reLaunch({
|
||||
url: '/pages/index/index',
|
||||
success: () => {
|
||||
console.log('reLaunch跳转成功');
|
||||
// 确保登录页面状态重置
|
||||
this.setData({
|
||||
loading: false,
|
||||
username: '',
|
||||
password: ''
|
||||
});
|
||||
},
|
||||
fail: (err) => {
|
||||
console.error('reLaunch跳转失败:', err);
|
||||
// 备用方案:使用navigateTo
|
||||
wx.navigateTo({
|
||||
url: '/pages/index/index'
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: loginResult.message || '登录失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('登录失败:', error)
|
||||
console.error('登录错误:', error);
|
||||
wx.showToast({
|
||||
title: error.message || '登录失败',
|
||||
icon: 'error',
|
||||
duration: 3000
|
||||
})
|
||||
title: '网络错误,请重试',
|
||||
icon: 'none'
|
||||
});
|
||||
} finally {
|
||||
this.setData({ loading: false })
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 执行登录请求
|
||||
async performLogin(username, password) {
|
||||
try {
|
||||
// 调用真实的登录API
|
||||
const response = await apiService.login(username, password);
|
||||
|
||||
console.log('登录API响应:', response);
|
||||
|
||||
if (response.success || response.code === 200 || response.code === 0) {
|
||||
// 处理不同的响应数据结构
|
||||
let token, userInfo;
|
||||
|
||||
if (response.data) {
|
||||
token = response.data.token || response.token;
|
||||
userInfo = response.data.userInfo || response.data.user || response.userInfo;
|
||||
} else {
|
||||
token = response.token;
|
||||
userInfo = response.userInfo || response.user;
|
||||
}
|
||||
|
||||
// 如果没有token,生成一个临时token
|
||||
if (!token) {
|
||||
token = 'temp_token_' + Date.now();
|
||||
console.log('API未返回token,生成临时token:', token);
|
||||
}
|
||||
|
||||
// 如果没有用户信息,使用默认信息
|
||||
if (!userInfo) {
|
||||
userInfo = {
|
||||
id: 1,
|
||||
username: username,
|
||||
name: '政府管理员',
|
||||
phone: '13800138000',
|
||||
department: '政府管理部门',
|
||||
avatar: '/images/avatar.png',
|
||||
role: 'admin'
|
||||
};
|
||||
console.log('API未返回用户信息,使用默认信息:', userInfo);
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
token: token,
|
||||
userInfo: userInfo
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: response.message || '登录失败'
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('API登录请求失败:', error);
|
||||
|
||||
// 如果网络请求失败,提供离线登录模式
|
||||
if (username === 'admin' && password === '123456') {
|
||||
console.log('使用离线登录模式');
|
||||
return {
|
||||
success: true,
|
||||
token: 'offline_token_' + Date.now(),
|
||||
userInfo: {
|
||||
id: 1,
|
||||
username: 'admin',
|
||||
name: '系统管理员',
|
||||
phone: '13800138000',
|
||||
department: '政府管理部门',
|
||||
avatar: '/images/avatar.png',
|
||||
role: 'admin'
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
success: false,
|
||||
message: '网络连接失败,请检查网络后重试'
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 忘记密码
|
||||
onForgotPassword() {
|
||||
wx.showModal({
|
||||
title: '忘记密码',
|
||||
content: '请联系系统管理员重置密码\n联系电话:400-123-4567',
|
||||
showCancel: false,
|
||||
confirmText: '我知道了'
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
@@ -1,3 +1,6 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
"navigationBarTitleText": "登录",
|
||||
"navigationStyle": "custom",
|
||||
"backgroundColor": "#667eea",
|
||||
"backgroundTextStyle": "light"
|
||||
}
|
||||
@@ -1,53 +1,83 @@
|
||||
<!--pages/login/login.wxml-->
|
||||
<view class="login-container">
|
||||
<view class="login-header">
|
||||
<view class="logo">
|
||||
<image src="/images/logo.png" class="logo-img" />
|
||||
</view>
|
||||
<view class="title">政府管理系统</view>
|
||||
<view class="subtitle">Government Management System</view>
|
||||
<view class="container">
|
||||
<!-- 背景装饰 -->
|
||||
<view class="bg-decoration">
|
||||
<view class="circle circle-1"></view>
|
||||
<view class="circle circle-2"></view>
|
||||
<view class="circle circle-3"></view>
|
||||
</view>
|
||||
|
||||
<!-- 登录表单 -->
|
||||
<view class="login-form">
|
||||
<view class="form-item">
|
||||
<input
|
||||
value="{{username}}"
|
||||
type="text"
|
||||
placeholder="请输入用户名"
|
||||
class="input"
|
||||
bindinput="onUsernameInput"
|
||||
/>
|
||||
<!-- Logo和标题 -->
|
||||
<view class="header-section">
|
||||
<view class="logo">
|
||||
<image src="/images/logo.png" class="logo-img" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="title">政府监管系统</view>
|
||||
<view class="subtitle">智慧牧场管理平台</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<input
|
||||
value="{{password}}"
|
||||
type="{{showPassword ? 'text' : 'password'}}"
|
||||
placeholder="请输入密码"
|
||||
class="input"
|
||||
bindinput="onPasswordInput"
|
||||
/>
|
||||
<view class="password-toggle" bindtap="togglePassword">
|
||||
<text class="toggle-icon">{{showPassword ? '👁️' : '👁️🗨️'}}</text>
|
||||
|
||||
<!-- 输入框区域 -->
|
||||
<view class="input-section">
|
||||
<view class="input-group">
|
||||
<view class="input-icon">👤</view>
|
||||
<input
|
||||
class="input-field"
|
||||
placeholder="请输入用户名"
|
||||
value="{{username}}"
|
||||
bindinput="onUsernameInput"
|
||||
maxlength="20"
|
||||
/>
|
||||
</view>
|
||||
|
||||
<view class="input-group">
|
||||
<view class="input-icon">🔒</view>
|
||||
<input
|
||||
class="input-field"
|
||||
placeholder="请输入密码"
|
||||
password="{{!showPassword}}"
|
||||
value="{{password}}"
|
||||
bindinput="onPasswordInput"
|
||||
maxlength="20"
|
||||
/>
|
||||
<view class="password-toggle" bindtap="togglePassword">
|
||||
<text>{{showPassword ? '👁️' : '👁️🗨️'}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="form-item">
|
||||
<button
|
||||
class="login-btn {{(!username || !password || loading) ? 'disabled' : ''}}"
|
||||
disabled="{{!username || !password || loading}}"
|
||||
bindtap="handleLogin"
|
||||
<!-- 登录按钮 -->
|
||||
<view class="button-section">
|
||||
<button
|
||||
class="login-btn {{canLogin ? 'active' : 'disabled'}}"
|
||||
bindtap="onLogin"
|
||||
disabled="{{!canLogin || loading}}"
|
||||
>
|
||||
{{loading ? '登录中...' : '登录'}}
|
||||
<text wx:if="{{!loading}}">登录</text>
|
||||
<text wx:else>登录中...</text>
|
||||
</button>
|
||||
</view>
|
||||
|
||||
<view class="login-tips">
|
||||
<text class="tips-text">默认账号:admin / 123456</text>
|
||||
<!-- 其他选项 -->
|
||||
<view class="options-section">
|
||||
<view class="remember-section">
|
||||
<checkbox-group bindchange="onRememberChange">
|
||||
<label class="checkbox-label">
|
||||
<checkbox value="remember" checked="{{rememberMe}}"/>
|
||||
<text class="checkbox-text">记住密码</text>
|
||||
</label>
|
||||
</checkbox-group>
|
||||
</view>
|
||||
|
||||
<view class="forgot-password" bindtap="onForgotPassword">
|
||||
忘记密码?
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 版本信息 -->
|
||||
<view class="version-info">
|
||||
<text class="version-text">版本 v1.0.0</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="login-footer">
|
||||
<text class="footer-text">© 2024 政府管理系统</text>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,116 +1,214 @@
|
||||
/* pages/login/login.wxss */
|
||||
.login-container {
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 40rpx;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.login-header {
|
||||
/* 背景装饰 */
|
||||
.bg-decoration {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.circle {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.1);
|
||||
animation: float 6s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.circle-1 {
|
||||
width: 200rpx;
|
||||
height: 200rpx;
|
||||
top: 10%;
|
||||
left: 10%;
|
||||
animation-delay: 0s;
|
||||
}
|
||||
|
||||
.circle-2 {
|
||||
width: 150rpx;
|
||||
height: 150rpx;
|
||||
top: 60%;
|
||||
right: 15%;
|
||||
animation-delay: 2s;
|
||||
}
|
||||
|
||||
.circle-3 {
|
||||
width: 100rpx;
|
||||
height: 100rpx;
|
||||
top: 30%;
|
||||
right: 30%;
|
||||
animation-delay: 4s;
|
||||
}
|
||||
|
||||
@keyframes float {
|
||||
0%, 100% { transform: translateY(0px); }
|
||||
50% { transform: translateY(-20px); }
|
||||
}
|
||||
|
||||
/* 登录表单 */
|
||||
.login-form {
|
||||
width: 600rpx;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
border-radius: 20rpx;
|
||||
padding: 60rpx 40rpx;
|
||||
box-shadow: 0 20rpx 40rpx rgba(0, 0, 0, 0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
/* 头部区域 */
|
||||
.header-section {
|
||||
text-align: center;
|
||||
margin-bottom: 80rpx;
|
||||
margin-bottom: 60rpx;
|
||||
}
|
||||
|
||||
.logo {
|
||||
margin-bottom: 40rpx;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.logo-img {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: 48rpx;
|
||||
font-weight: 600;
|
||||
color: #fff;
|
||||
margin-bottom: 16rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
font-size: 28rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.login-form {
|
||||
width: 100%;
|
||||
max-width: 600rpx;
|
||||
}
|
||||
|
||||
.form-item {
|
||||
/* 输入框区域 */
|
||||
.input-section {
|
||||
margin-bottom: 40rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 100%;
|
||||
.input-group {
|
||||
position: relative;
|
||||
margin-bottom: 30rpx;
|
||||
background: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
border: 2rpx solid #e9ecef;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.input-group:focus-within {
|
||||
border-color: #4CAF50;
|
||||
background: #fff;
|
||||
box-shadow: 0 0 0 6rpx rgba(76, 175, 80, 0.1);
|
||||
}
|
||||
|
||||
.input-icon {
|
||||
font-size: 32rpx;
|
||||
margin-right: 20rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.input-field {
|
||||
flex: 1;
|
||||
height: 88rpx;
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
padding: 0 40rpx;
|
||||
font-size: 32rpx;
|
||||
color: #333;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.input::placeholder {
|
||||
.input-field::placeholder {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.password-toggle {
|
||||
position: absolute;
|
||||
right: 40rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
padding: 20rpx;
|
||||
padding: 10rpx;
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.toggle-icon {
|
||||
font-size: 32rpx;
|
||||
color: #999;
|
||||
/* 按钮区域 */
|
||||
.button-section {
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.login-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #1890ff;
|
||||
color: #fff;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
border-radius: 12rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
transition: all 0.3s ease;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.login-btn.active {
|
||||
background: linear-gradient(135deg, #4CAF50, #45a049);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.login-btn.active:active {
|
||||
transform: translateY(2rpx);
|
||||
box-shadow: 0 4rpx 8rpx rgba(76, 175, 80, 0.3);
|
||||
}
|
||||
|
||||
.login-btn.disabled {
|
||||
background: #ccc;
|
||||
background: #e9ecef;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.login-tips {
|
||||
text-align: center;
|
||||
margin-top: 40rpx;
|
||||
/* 选项区域 */
|
||||
.options-section {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 40rpx;
|
||||
}
|
||||
|
||||
.tips-text {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
.remember-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.login-footer {
|
||||
position: absolute;
|
||||
bottom: 40rpx;
|
||||
.checkbox-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.checkbox-text {
|
||||
margin-left: 10rpx;
|
||||
}
|
||||
|
||||
.forgot-password {
|
||||
font-size: 28rpx;
|
||||
color: #4CAF50;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 版本信息 */
|
||||
.version-info {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-text {
|
||||
.version-text {
|
||||
font-size: 24rpx;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
color: #999;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// pages/personnel/personnel.js
|
||||
Page({
|
||||
data: {
|
||||
searchKeyword: '',
|
||||
loading: false,
|
||||
personnelList: []
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadPersonnelData()
|
||||
},
|
||||
|
||||
loadPersonnelData() {
|
||||
// 模拟数据
|
||||
this.setData({
|
||||
personnelList: [
|
||||
{
|
||||
id: 1,
|
||||
name: '张三',
|
||||
position: '监管员',
|
||||
department: '监管部',
|
||||
phone: '13800138000',
|
||||
status: 'active',
|
||||
statusText: '在职'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
handleAdd() {
|
||||
wx.showToast({
|
||||
title: '新增功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
<!--pages/personnel/personnel.wxml-->
|
||||
<view class="personnel-container">
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-section">
|
||||
<view class="search-bar">
|
||||
<input
|
||||
value="{{searchKeyword}}"
|
||||
type="text"
|
||||
placeholder="搜索人员..."
|
||||
class="search-input"
|
||||
bindinput="onSearchInput"
|
||||
/>
|
||||
<view class="search-icon">🔍</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 人员列表 -->
|
||||
<view class="personnel-list">
|
||||
<view class="list-header">
|
||||
<view class="list-title">人员管理</view>
|
||||
<view class="add-btn" bindtap="handleAdd">
|
||||
<text class="add-text">新增</text>
|
||||
<view class="add-icon">+</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{loading}}" class="loading">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view wx:elif="{{personnelList.length === 0}}" class="empty">
|
||||
<view class="empty-icon">👥</view>
|
||||
<view class="empty-text">暂无人员记录</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="list-content">
|
||||
<view
|
||||
wx:for="{{personnelList}}"
|
||||
wx:key="id"
|
||||
class="personnel-item"
|
||||
>
|
||||
<view class="item-avatar">
|
||||
<image src="/images/avatar.png" class="avatar-img" />
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-header">
|
||||
<view class="item-name">{{item.name}}</view>
|
||||
<view class="item-status {{item.status}}">
|
||||
{{item.statusText}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-info">
|
||||
<view class="item-position">{{item.position}}</view>
|
||||
<view class="item-department">{{item.department}}</view>
|
||||
<view class="item-phone">{{item.phone}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,165 +0,0 @@
|
||||
/* pages/personnel/personnel.wxss */
|
||||
.personnel-container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
background: #f8f9fa;
|
||||
border: none;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 60rpx 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.personnel-list {
|
||||
background: #fff;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
background: #1890ff;
|
||||
border-radius: 24rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.add-text {
|
||||
font-size: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.loading-text,
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
space-y: 0;
|
||||
}
|
||||
|
||||
.personnel-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.personnel-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-avatar {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 40rpx;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.item-status {
|
||||
font-size: 20rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-status.active {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.item-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
space-y: 8rpx;
|
||||
}
|
||||
|
||||
.item-position,
|
||||
.item-department,
|
||||
.item-phone {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
@@ -1,88 +1,584 @@
|
||||
// pages/profile/profile.js
|
||||
const auth = require('../../utils/auth.js')
|
||||
const app = getApp();
|
||||
const apiService = require('../../utils/api.js');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
userInfo: {},
|
||||
menuItems: [
|
||||
statusBarHeight: 0,
|
||||
loading: true,
|
||||
|
||||
// 用户信息
|
||||
userInfo: {
|
||||
id: '',
|
||||
username: '',
|
||||
name: '',
|
||||
avatar: '/images/avatar.png',
|
||||
phone: '',
|
||||
email: '',
|
||||
department: '',
|
||||
position: '',
|
||||
lastLoginTime: ''
|
||||
},
|
||||
|
||||
// 统计数据
|
||||
statistics: {
|
||||
totalFarmers: 0,
|
||||
totalChecks: 0,
|
||||
totalAlerts: 0,
|
||||
totalTasks: 0
|
||||
},
|
||||
|
||||
// 快捷操作
|
||||
quickActions: [
|
||||
{
|
||||
key: 'settings',
|
||||
title: '设置',
|
||||
icon: '⚙️',
|
||||
path: ''
|
||||
id: 'farmer_manage',
|
||||
title: '养殖户管理',
|
||||
icon: 'farmer',
|
||||
color: '#1890ff',
|
||||
path: '/pages/farmer/farmer'
|
||||
},
|
||||
{
|
||||
key: 'about',
|
||||
title: '关于',
|
||||
icon: 'ℹ️',
|
||||
path: ''
|
||||
id: 'data_stats',
|
||||
title: '数据统计',
|
||||
icon: 'chart',
|
||||
color: '#52c41a',
|
||||
path: '/pages/statistics/statistics'
|
||||
},
|
||||
{
|
||||
key: 'help',
|
||||
title: '帮助',
|
||||
icon: '❓',
|
||||
path: ''
|
||||
id: 'notification',
|
||||
title: '消息通知',
|
||||
icon: 'notification',
|
||||
color: '#fa8c16',
|
||||
path: '/pages/notification/notification'
|
||||
},
|
||||
{
|
||||
key: 'feedback',
|
||||
title: '反馈',
|
||||
icon: '💬',
|
||||
path: ''
|
||||
id: 'settings',
|
||||
title: '系统设置',
|
||||
icon: 'settings',
|
||||
color: '#722ed1',
|
||||
path: '/pages/settings/settings'
|
||||
}
|
||||
],
|
||||
|
||||
// 功能菜单
|
||||
menuList: [
|
||||
{
|
||||
id: 'profile_edit',
|
||||
title: '个人资料',
|
||||
icon: 'user',
|
||||
arrow: true,
|
||||
path: '/pages/profile/edit/edit'
|
||||
},
|
||||
{
|
||||
id: 'password_change',
|
||||
title: '修改密码',
|
||||
icon: 'lock',
|
||||
arrow: true,
|
||||
path: '/pages/profile/password/password'
|
||||
},
|
||||
{
|
||||
id: 'notification_settings',
|
||||
title: '通知设置',
|
||||
icon: 'bell',
|
||||
arrow: true,
|
||||
path: '/pages/profile/notification/notification'
|
||||
},
|
||||
{
|
||||
id: 'about',
|
||||
title: '关于我们',
|
||||
icon: 'info',
|
||||
arrow: true,
|
||||
path: '/pages/profile/about/about'
|
||||
},
|
||||
{
|
||||
id: 'help',
|
||||
title: '帮助中心',
|
||||
icon: 'help',
|
||||
arrow: true,
|
||||
path: '/pages/profile/help/help'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadUserInfo()
|
||||
},
|
||||
|
||||
loadUserInfo() {
|
||||
const userInfo = auth.getUser()
|
||||
// 获取状态栏高度
|
||||
const systemInfo = wx.getSystemInfoSync();
|
||||
this.setData({
|
||||
userInfo: userInfo || {}
|
||||
})
|
||||
statusBarHeight: systemInfo.statusBarHeight
|
||||
});
|
||||
|
||||
// 检查登录状态
|
||||
this.checkLoginStatus();
|
||||
},
|
||||
|
||||
handleMenuTap(e) {
|
||||
const { key } = e.currentTarget.dataset
|
||||
|
||||
switch (key) {
|
||||
case 'settings':
|
||||
wx.showToast({
|
||||
title: '设置功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
break
|
||||
case 'about':
|
||||
wx.showToast({
|
||||
title: '关于功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
break
|
||||
case 'help':
|
||||
wx.showToast({
|
||||
title: '帮助功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
break
|
||||
case 'feedback':
|
||||
wx.showToast({
|
||||
title: '反馈功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
break
|
||||
onShow() {
|
||||
// 每次显示页面时刷新数据
|
||||
this.loadData();
|
||||
},
|
||||
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = wx.getStorageSync('token');
|
||||
if (!token) {
|
||||
wx.redirectTo({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
return;
|
||||
}
|
||||
},
|
||||
|
||||
handleLogout() {
|
||||
wx.showModal({
|
||||
title: '确认退出',
|
||||
content: '确定要退出登录吗?',
|
||||
// 加载用户数据
|
||||
async loadUserData() {
|
||||
try {
|
||||
// 从本地存储获取用户信息
|
||||
const userInfo = wx.getStorageSync('userInfo');
|
||||
if (userInfo) {
|
||||
this.setData({
|
||||
userInfo: {
|
||||
...this.data.userInfo,
|
||||
...userInfo
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 模拟从服务器获取最新数据
|
||||
await this.fetchUserProfile();
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载用户数据失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 获取用户资料
|
||||
fetchUserProfile() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
// 模拟API返回的用户数据
|
||||
const profileData = {
|
||||
name: '张管理员',
|
||||
department: '宁夏畜牧管理局',
|
||||
position: '高级管理员',
|
||||
lastLoginTime: this.formatTime(new Date())
|
||||
};
|
||||
|
||||
this.setData({
|
||||
userInfo: {
|
||||
...this.data.userInfo,
|
||||
...profileData
|
||||
}
|
||||
});
|
||||
|
||||
resolve();
|
||||
}, 500);
|
||||
});
|
||||
},
|
||||
|
||||
// 刷新统计数据
|
||||
async refreshStats() {
|
||||
try {
|
||||
const stats = await this.fetchStatsData();
|
||||
this.setData({ statsData: stats });
|
||||
} catch (error) {
|
||||
console.error('刷新统计数据失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 获取统计数据
|
||||
fetchStatsData() {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
const stats = {
|
||||
todayCheck: Math.floor(Math.random() * 20) + 5,
|
||||
totalFarmers: Math.floor(Math.random() * 50) + 150,
|
||||
totalAlerts: Math.floor(Math.random() * 10),
|
||||
completedTasks: Math.floor(Math.random() * 20) + 20
|
||||
};
|
||||
resolve(stats);
|
||||
}, 300);
|
||||
});
|
||||
},
|
||||
|
||||
// 头像点击
|
||||
onAvatarTap() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['查看头像', '更换头像'],
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
auth.logout()
|
||||
if (res.tapIndex === 0) {
|
||||
this.viewAvatar();
|
||||
} else if (res.tapIndex === 1) {
|
||||
this.changeAvatar();
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
// 查看头像
|
||||
viewAvatar() {
|
||||
if (this.data.userInfo.avatar) {
|
||||
wx.previewImage({
|
||||
urls: [this.data.userInfo.avatar]
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '暂无头像',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 更换头像
|
||||
changeAvatar() {
|
||||
wx.chooseImage({
|
||||
count: 1,
|
||||
sizeType: ['compressed'],
|
||||
sourceType: ['album', 'camera'],
|
||||
success: (res) => {
|
||||
const tempFilePath = res.tempFilePaths[0];
|
||||
|
||||
// 模拟上传头像
|
||||
wx.showLoading({ title: '上传中...' });
|
||||
|
||||
setTimeout(() => {
|
||||
this.setData({
|
||||
'userInfo.avatar': tempFilePath
|
||||
});
|
||||
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '头像更新成功',
|
||||
icon: 'success'
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 菜单项点击
|
||||
onMenuItemTap(e) {
|
||||
const { id } = e.currentTarget.dataset;
|
||||
|
||||
switch (id) {
|
||||
case 'personal_info':
|
||||
this.editPersonalInfo();
|
||||
break;
|
||||
case 'change_password':
|
||||
this.changePassword();
|
||||
break;
|
||||
case 'notification_settings':
|
||||
this.openNotificationSettings();
|
||||
break;
|
||||
case 'work_report':
|
||||
this.viewWorkReport();
|
||||
break;
|
||||
case 'help_feedback':
|
||||
this.openHelpFeedback();
|
||||
break;
|
||||
case 'about':
|
||||
this.showAbout();
|
||||
break;
|
||||
default:
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 编辑个人信息
|
||||
editPersonalInfo() {
|
||||
wx.showModal({
|
||||
title: '个人信息',
|
||||
content: '此功能将跳转到个人信息编辑页面',
|
||||
showCancel: false
|
||||
});
|
||||
},
|
||||
|
||||
// 修改密码
|
||||
changePassword() {
|
||||
wx.showModal({
|
||||
title: '修改密码',
|
||||
content: '请输入原密码和新密码',
|
||||
editable: true,
|
||||
placeholderText: '请输入原密码',
|
||||
success: (res) => {
|
||||
if (res.confirm && res.content) {
|
||||
wx.showModal({
|
||||
title: '新密码',
|
||||
content: '请输入新密码',
|
||||
editable: true,
|
||||
placeholderText: '请输入新密码',
|
||||
success: (newRes) => {
|
||||
if (newRes.confirm && newRes.content) {
|
||||
wx.showLoading({ title: '修改中...' });
|
||||
|
||||
setTimeout(() => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '密码修改成功',
|
||||
icon: 'success'
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 消息设置
|
||||
openNotificationSettings() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['推送通知', '声音提醒', '震动提醒', '免打扰时间'],
|
||||
success: (res) => {
|
||||
const settings = ['推送通知', '声音提醒', '震动提醒', '免打扰时间'];
|
||||
wx.showToast({
|
||||
title: `${settings[res.tapIndex]}设置`,
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 工作报告
|
||||
viewWorkReport() {
|
||||
wx.showModal({
|
||||
title: '工作报告',
|
||||
content: `本月检查: ${this.data.statsData.todayCheck * 30}次\n管理养殖户: ${this.data.statsData.totalFarmers}户\n处理告警: ${this.data.statsData.totalAlerts * 10}次\n完成任务: ${this.data.statsData.completedTasks * 5}个`,
|
||||
showCancel: false
|
||||
});
|
||||
},
|
||||
|
||||
// 帮助反馈
|
||||
openHelpFeedback() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['使用帮助', '问题反馈', '联系客服'],
|
||||
success: (res) => {
|
||||
const actions = ['使用帮助', '问题反馈', '联系客服'];
|
||||
if (res.tapIndex === 2) {
|
||||
wx.makePhoneCall({
|
||||
phoneNumber: '400-123-4567'
|
||||
});
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: `${actions[res.tapIndex]}功能开发中`,
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 关于应用
|
||||
showAbout() {
|
||||
wx.showModal({
|
||||
title: '关于应用',
|
||||
content: '宁夏智慧牧场政府端\n版本: v1.0.0\n更新时间: 2024-01-15\n\n智慧畜牧管理系统,助力现代化养殖业发展',
|
||||
showCancel: false
|
||||
});
|
||||
},
|
||||
|
||||
// 快捷操作点击
|
||||
onQuickActionTap(e) {
|
||||
const { id } = e.currentTarget.dataset;
|
||||
|
||||
switch (id) {
|
||||
case 'scan_qr':
|
||||
this.scanQRCode();
|
||||
break;
|
||||
case 'emergency_report':
|
||||
this.emergencyReport();
|
||||
break;
|
||||
case 'data_export':
|
||||
this.exportData();
|
||||
break;
|
||||
case 'system_settings':
|
||||
this.systemSettings();
|
||||
break;
|
||||
default:
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 扫码检查
|
||||
scanQRCode() {
|
||||
wx.scanCode({
|
||||
success: (res) => {
|
||||
wx.showModal({
|
||||
title: '扫码结果',
|
||||
content: `扫码内容: ${res.result}`,
|
||||
showCancel: false
|
||||
});
|
||||
},
|
||||
fail: () => {
|
||||
wx.showToast({
|
||||
title: '扫码失败',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 紧急上报
|
||||
emergencyReport() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['疫情报告', '设备故障', '安全事故', '其他紧急情况'],
|
||||
success: (res) => {
|
||||
const types = ['疫情报告', '设备故障', '安全事故', '其他紧急情况'];
|
||||
wx.showModal({
|
||||
title: '紧急上报',
|
||||
content: `上报类型: ${types[res.tapIndex]}\n请描述具体情况`,
|
||||
editable: true,
|
||||
placeholderText: '请输入详细描述',
|
||||
success: (modalRes) => {
|
||||
if (modalRes.confirm) {
|
||||
wx.showLoading({ title: '上报中...' });
|
||||
|
||||
setTimeout(() => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '上报成功',
|
||||
icon: 'success'
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 数据导出
|
||||
exportData() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['养殖户数据', '检查记录', '告警记录', '统计报表'],
|
||||
success: (res) => {
|
||||
const types = ['养殖户数据', '检查记录', '告警记录', '统计报表'];
|
||||
|
||||
wx.showLoading({ title: '导出中...' });
|
||||
|
||||
setTimeout(() => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: `${types[res.tapIndex]}导出成功`,
|
||||
icon: 'success'
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 系统设置
|
||||
systemSettings() {
|
||||
wx.showActionSheet({
|
||||
itemList: ['清除缓存', '检查更新', '重置设置'],
|
||||
success: (res) => {
|
||||
if (res.tapIndex === 0) {
|
||||
this.clearCache();
|
||||
} else if (res.tapIndex === 1) {
|
||||
this.checkUpdate();
|
||||
} else if (res.tapIndex === 2) {
|
||||
this.resetSettings();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 清除缓存
|
||||
clearCache() {
|
||||
wx.showModal({
|
||||
title: '清除缓存',
|
||||
content: '确定要清除应用缓存吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.showLoading({ title: '清除中...' });
|
||||
|
||||
setTimeout(() => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '缓存清除成功',
|
||||
icon: 'success'
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 检查更新
|
||||
checkUpdate() {
|
||||
wx.showLoading({ title: '检查中...' });
|
||||
|
||||
setTimeout(() => {
|
||||
wx.hideLoading();
|
||||
wx.showModal({
|
||||
title: '检查更新',
|
||||
content: '当前已是最新版本',
|
||||
showCancel: false
|
||||
});
|
||||
}, 2000);
|
||||
},
|
||||
|
||||
// 重置设置
|
||||
resetSettings() {
|
||||
wx.showModal({
|
||||
title: '重置设置',
|
||||
content: '确定要重置所有设置吗?此操作不可恢复',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
wx.showLoading({ title: '重置中...' });
|
||||
|
||||
setTimeout(() => {
|
||||
wx.hideLoading();
|
||||
wx.showToast({
|
||||
title: '设置重置成功',
|
||||
icon: 'success'
|
||||
});
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 退出登录
|
||||
onLogout() {
|
||||
wx.showModal({
|
||||
title: '退出登录',
|
||||
content: '确定要退出当前账号吗?',
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
// 清除本地存储
|
||||
wx.removeStorageSync('token');
|
||||
wx.removeStorageSync('userInfo');
|
||||
|
||||
wx.showToast({
|
||||
title: '已退出登录',
|
||||
icon: 'success'
|
||||
});
|
||||
|
||||
// 跳转到登录页
|
||||
setTimeout(() => {
|
||||
wx.reLaunch({
|
||||
url: '/pages/login/login'
|
||||
});
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 格式化时间
|
||||
formatTime(date) {
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, '0');
|
||||
const day = date.getDate().toString().padStart(2, '0');
|
||||
const hour = date.getHours().toString().padStart(2, '0');
|
||||
const minute = date.getMinutes().toString().padStart(2, '0');
|
||||
const second = date.getSeconds().toString().padStart(2, '0');
|
||||
|
||||
return `${year}-${month}-${day} ${hour}:${minute}:${second}`;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
"usingComponents": {},
|
||||
"navigationBarTitleText": "我的"
|
||||
}
|
||||
|
||||
@@ -1,36 +1,93 @@
|
||||
<!--pages/profile/profile.wxml-->
|
||||
<view class="profile-container">
|
||||
<!-- 用户信息区域 -->
|
||||
<view class="user-section">
|
||||
<view class="user-avatar">
|
||||
<image src="/images/avatar.png" class="avatar-img" />
|
||||
</view>
|
||||
<view class="container">
|
||||
<!-- 状态栏 -->
|
||||
<view class="status-bar" style="height: {{statusBarHeight}}px;"></view>
|
||||
|
||||
<!-- 用户信息卡片 -->
|
||||
<view class="user-card">
|
||||
<view class="user-info">
|
||||
<view class="username">{{userInfo.name || '管理员'}}</view>
|
||||
<view class="user-role">{{userInfo.role || '系统管理员'}}</view>
|
||||
<view class="user-phone">{{userInfo.phone || '13800138000'}}</view>
|
||||
<view class="avatar-container" bindtap="onAvatarTap">
|
||||
<image wx:if="{{userInfo.avatar}}" class="avatar" src="{{userInfo.avatar}}" mode="aspectFill" />
|
||||
<view wx:else class="avatar-placeholder">
|
||||
<text class="avatar-text">{{userInfo.name.charAt(0)}}</text>
|
||||
</view>
|
||||
<view class="avatar-badge">📷</view>
|
||||
</view>
|
||||
|
||||
<view class="user-details">
|
||||
<view class="user-name">{{userInfo.name}}</view>
|
||||
<view class="user-account">账号: {{userInfo.account}}</view>
|
||||
<view class="user-department">{{userInfo.department}}</view>
|
||||
<view class="user-position">{{userInfo.position}}</view>
|
||||
<view class="last-login">最后登录: {{userInfo.lastLoginTime}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 统计数据 -->
|
||||
<view class="stats-section">
|
||||
<view class="section-title">今日数据</view>
|
||||
<view class="stats-grid">
|
||||
<view class="stat-item">
|
||||
<view class="stat-number">{{statsData.todayCheck}}</view>
|
||||
<view class="stat-label">今日检查</view>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-number">{{statsData.totalFarmers}}</view>
|
||||
<view class="stat-label">管理养殖户</view>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-number">{{statsData.totalAlerts}}</view>
|
||||
<view class="stat-label">待处理告警</view>
|
||||
</view>
|
||||
<view class="stat-item">
|
||||
<view class="stat-number">{{statsData.completedTasks}}</view>
|
||||
<view class="stat-label">完成任务</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 快捷操作 -->
|
||||
<view class="quick-actions-section">
|
||||
<view class="section-title">快捷操作</view>
|
||||
<view class="quick-actions">
|
||||
<view
|
||||
wx:for="{{quickActions}}"
|
||||
wx:key="id"
|
||||
class="quick-action-item"
|
||||
style="background-color: {{item.color}}20;"
|
||||
bindtap="onQuickActionTap"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="quick-action-icon" style="color: {{item.color}};">{{item.icon}}</view>
|
||||
<view class="quick-action-title">{{item.title}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 功能菜单 -->
|
||||
<view class="menu-section">
|
||||
<view
|
||||
wx:for="{{menuItems}}"
|
||||
wx:key="key"
|
||||
class="menu-item"
|
||||
data-key="{{item.key}}"
|
||||
bindtap="handleMenuTap"
|
||||
>
|
||||
<view class="menu-icon">{{item.icon}}</view>
|
||||
<view class="menu-title">{{item.title}}</view>
|
||||
<view class="menu-arrow">></view>
|
||||
<view class="section-title">功能设置</view>
|
||||
<view class="menu-list">
|
||||
<view
|
||||
wx:for="{{menuItems}}"
|
||||
wx:key="id"
|
||||
class="menu-item"
|
||||
bindtap="onMenuItemTap"
|
||||
data-id="{{item.id}}"
|
||||
>
|
||||
<view class="menu-icon">{{item.icon}}</view>
|
||||
<view class="menu-content">
|
||||
<view class="menu-title">{{item.title}}</view>
|
||||
<view class="menu-desc">{{item.desc}}</view>
|
||||
</view>
|
||||
<view wx:if="{{item.arrow}}" class="menu-arrow">></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
|
||||
<!-- 退出登录 -->
|
||||
<view class="logout-section">
|
||||
<button class="logout-btn" bindtap="handleLogout">
|
||||
退出登录
|
||||
</button>
|
||||
<button class="logout-btn" bindtap="onLogout">退出登录</button>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
@@ -1,61 +1,200 @@
|
||||
/* pages/profile/profile.wxss */
|
||||
.profile-container {
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.user-section {
|
||||
background: #fff;
|
||||
padding: 60rpx 30rpx;
|
||||
margin-bottom: 20rpx;
|
||||
.status-bar {
|
||||
background-color: #2c5aa0;
|
||||
}
|
||||
|
||||
/* 用户信息卡片 */
|
||||
.user-card {
|
||||
background: linear-gradient(135deg, #2c5aa0 0%, #4a7bc8 100%);
|
||||
padding: 40rpx 30rpx 30rpx;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.user-avatar {
|
||||
.avatar-container {
|
||||
position: relative;
|
||||
margin-right: 30rpx;
|
||||
}
|
||||
|
||||
.avatar-img {
|
||||
.avatar {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
background: #f0f0f0;
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.user-info {
|
||||
.avatar-placeholder {
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
border-radius: 60rpx;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 4rpx solid rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
.avatar-text {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.avatar-badge {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 36rpx;
|
||||
height: 36rpx;
|
||||
background-color: #fff;
|
||||
border-radius: 18rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 20rpx;
|
||||
}
|
||||
|
||||
.user-details {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.username {
|
||||
.user-name {
|
||||
font-size: 36rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.user-role {
|
||||
font-size: 28rpx;
|
||||
color: #666;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.user-phone {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
.user-account {
|
||||
font-size: 28rpx;
|
||||
opacity: 0.9;
|
||||
margin-bottom: 6rpx;
|
||||
}
|
||||
|
||||
.menu-section {
|
||||
background: #fff;
|
||||
.user-department {
|
||||
font-size: 26rpx;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.user-position {
|
||||
font-size: 26rpx;
|
||||
opacity: 0.8;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.last-login {
|
||||
font-size: 24rpx;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
/* 统计数据 */
|
||||
.stats-section {
|
||||
background-color: white;
|
||||
margin: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.stats-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.stat-item {
|
||||
text-align: center;
|
||||
padding: 20rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 48rpx;
|
||||
font-weight: bold;
|
||||
color: #2c5aa0;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.stat-label {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 快捷操作 */
|
||||
.quick-actions-section {
|
||||
background-color: white;
|
||||
margin: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.quick-actions {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.quick-action-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.quick-action-item:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.quick-action-icon {
|
||||
font-size: 40rpx;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.quick-action-title {
|
||||
font-size: 24rpx;
|
||||
color: #333;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* 功能菜单 */
|
||||
.menu-section {
|
||||
background-color: white;
|
||||
margin: 20rpx;
|
||||
border-radius: 16rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.menu-list {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
padding: 24rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background 0.3s;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.menu-item:last-child {
|
||||
@@ -63,41 +202,60 @@
|
||||
}
|
||||
|
||||
.menu-item:active {
|
||||
background: #f8f9fa;
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
font-size: 32rpx;
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
margin-right: 24rpx;
|
||||
width: 40rpx;
|
||||
text-align: center;
|
||||
font-size: 36rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.menu-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
flex: 1;
|
||||
font-size: 30rpx;
|
||||
color: #333;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
|
||||
.menu-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.menu-arrow {
|
||||
font-size: 24rpx;
|
||||
font-size: 28rpx;
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
/* 退出登录 */
|
||||
.logout-section {
|
||||
padding: 30rpx;
|
||||
padding: 40rpx 20rpx;
|
||||
}
|
||||
|
||||
.logout-btn {
|
||||
width: 100%;
|
||||
height: 88rpx;
|
||||
background: #ff4d4f;
|
||||
color: #fff;
|
||||
background-color: #ff4757;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 44rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.logout-btn:active {
|
||||
background-color: #ff3742;
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
// pages/service/service.js
|
||||
Page({
|
||||
data: {
|
||||
searchKeyword: '',
|
||||
loading: false,
|
||||
serviceList: []
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadServiceData()
|
||||
},
|
||||
|
||||
loadServiceData() {
|
||||
// 模拟数据
|
||||
this.setData({
|
||||
serviceList: [
|
||||
{
|
||||
id: 1,
|
||||
title: '技术服务',
|
||||
description: '为养殖户提供技术指导',
|
||||
type: 'technical',
|
||||
typeText: '技术服务',
|
||||
status: 'active',
|
||||
statusText: '进行中'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
handleAdd() {
|
||||
wx.showToast({
|
||||
title: '新增功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<!--pages/service/service.wxml-->
|
||||
<view class="service-container">
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-section">
|
||||
<view class="search-bar">
|
||||
<input
|
||||
value="{{searchKeyword}}"
|
||||
type="text"
|
||||
placeholder="搜索服务记录..."
|
||||
class="search-input"
|
||||
bindinput="onSearchInput"
|
||||
/>
|
||||
<view class="search-icon">🔍</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 服务列表 -->
|
||||
<view class="service-list">
|
||||
<view class="list-header">
|
||||
<view class="list-title">服务管理</view>
|
||||
<view class="add-btn" bindtap="handleAdd">
|
||||
<text class="add-text">新增</text>
|
||||
<view class="add-icon">+</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{loading}}" class="loading">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view wx:elif="{{serviceList.length === 0}}" class="empty">
|
||||
<view class="empty-icon">🛠️</view>
|
||||
<view class="empty-text">暂无服务记录</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="list-content">
|
||||
<view
|
||||
wx:for="{{serviceList}}"
|
||||
wx:key="id"
|
||||
class="service-item"
|
||||
>
|
||||
<view class="item-header">
|
||||
<view class="item-title">{{item.title}}</view>
|
||||
<view class="item-status {{item.status}}">
|
||||
{{item.statusText}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-desc">{{item.description}}</view>
|
||||
<view class="item-meta">
|
||||
<view class="item-type">{{item.typeText}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,158 +0,0 @@
|
||||
/* pages/service/service.wxss */
|
||||
.service-container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
background: #f8f9fa;
|
||||
border: none;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 60rpx 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.service-list {
|
||||
background: #fff;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
background: #1890ff;
|
||||
border-radius: 24rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.add-text {
|
||||
font-size: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.loading-text,
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
space-y: 0;
|
||||
}
|
||||
|
||||
.service-item {
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.service-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-status {
|
||||
font-size: 20rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-status.active {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 12rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-type {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
296
government-mini-program/pages/statistics/statistics.js
Normal file
296
government-mini-program/pages/statistics/statistics.js
Normal file
@@ -0,0 +1,296 @@
|
||||
// pages/statistics/statistics.js
|
||||
const app = getApp();
|
||||
const apiService = require('../../utils/api.js');
|
||||
|
||||
Page({
|
||||
data: {
|
||||
statusBarHeight: 0,
|
||||
loading: true,
|
||||
|
||||
// 统计数据
|
||||
todayStats: {
|
||||
totalFarmers: 0,
|
||||
activeFarmers: 0,
|
||||
totalAnimals: 0,
|
||||
alertCount: 0
|
||||
},
|
||||
|
||||
// 趋势数据
|
||||
trendData: {
|
||||
farmerGrowth: 0,
|
||||
animalGrowth: 0,
|
||||
alertTrend: 0
|
||||
},
|
||||
|
||||
// 快捷操作
|
||||
quickActions: [
|
||||
{
|
||||
id: 'farmer_manage',
|
||||
title: '养殖户管理',
|
||||
icon: 'farmer',
|
||||
color: '#2c5aa0',
|
||||
path: '/pages/farmer/farmer'
|
||||
},
|
||||
{
|
||||
id: 'device_monitor',
|
||||
title: '设备监控',
|
||||
icon: 'settings',
|
||||
color: '#52c41a',
|
||||
path: '/pages/statistics/statistics'
|
||||
},
|
||||
{
|
||||
id: 'epidemic_control',
|
||||
title: '疫情防控',
|
||||
icon: 'epidemic',
|
||||
color: '#fa8c16',
|
||||
path: '/pages/statistics/statistics'
|
||||
},
|
||||
{
|
||||
id: 'data_analysis',
|
||||
title: '数据分析',
|
||||
icon: 'home',
|
||||
color: '#722ed1',
|
||||
path: '/pages/statistics/statistics'
|
||||
}
|
||||
],
|
||||
|
||||
// 最新动态
|
||||
recentActivities: [],
|
||||
|
||||
// 市场价格
|
||||
marketPrice: {
|
||||
beef: { price: 0, trend: 0 },
|
||||
mutton: { price: 0, trend: 0 },
|
||||
milk: { price: 0, trend: 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() {
|
||||
if (!this.checkLoginStatus()) return;
|
||||
|
||||
this.setData({ loading: true });
|
||||
|
||||
try {
|
||||
// 并行加载多个数据
|
||||
const [statsResult, marketResult] = await Promise.allSettled([
|
||||
this.loadStatisticsData(),
|
||||
this.loadMarketPrice()
|
||||
]);
|
||||
|
||||
// 处理统计数据结果
|
||||
if (statsResult.status === 'fulfilled') {
|
||||
console.log('统计数据加载成功');
|
||||
} else {
|
||||
console.error('统计数据加载失败:', statsResult.reason);
|
||||
this.loadMockStatistics();
|
||||
}
|
||||
|
||||
// 处理市场价格结果
|
||||
if (marketResult.status === 'fulfilled') {
|
||||
console.log('市场价格加载成功');
|
||||
} else {
|
||||
console.error('市场价格加载失败:', marketResult.reason);
|
||||
this.loadMockMarketPrice();
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('数据加载失败:', error);
|
||||
// 加载模拟数据作为备用
|
||||
this.loadMockData();
|
||||
} finally {
|
||||
this.setData({ loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
// 加载统计数据
|
||||
async loadStatisticsData() {
|
||||
try {
|
||||
const result = await apiService.getDataCenterStats();
|
||||
|
||||
if (result.code === 200 || result.code === 0) {
|
||||
const data = result.data || result;
|
||||
|
||||
this.setData({
|
||||
todayStats: {
|
||||
totalFarmers: data.totalFarmers || 0,
|
||||
activeFarmers: data.activeFarmers || 0,
|
||||
totalAnimals: data.totalAnimals || 0,
|
||||
alertCount: data.alertCount || 0
|
||||
},
|
||||
trendData: {
|
||||
farmerGrowth: data.farmerGrowth || 0,
|
||||
animalGrowth: data.animalGrowth || 0,
|
||||
alertTrend: data.alertTrend || 0
|
||||
}
|
||||
});
|
||||
|
||||
// 如果有最新动态数据
|
||||
if (data.recentActivities) {
|
||||
this.setData({
|
||||
recentActivities: data.recentActivities
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取统计数据失败:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载市场价格
|
||||
async loadMarketPrice() {
|
||||
try {
|
||||
const result = await apiService.getMarketPrice();
|
||||
|
||||
if (result.code === 200 || result.code === 0) {
|
||||
const data = result.data || result;
|
||||
|
||||
this.setData({
|
||||
marketPrice: {
|
||||
beef: data.beef || { price: 0, trend: 0 },
|
||||
mutton: data.mutton || { price: 0, trend: 0 },
|
||||
milk: data.milk || { price: 0, trend: 0 }
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取市场价格失败:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载模拟统计数据
|
||||
loadMockStatistics() {
|
||||
this.setData({
|
||||
todayStats: {
|
||||
totalFarmers: 156,
|
||||
activeFarmers: 142,
|
||||
totalAnimals: 3248,
|
||||
alertCount: 8
|
||||
},
|
||||
trendData: {
|
||||
farmerGrowth: 12,
|
||||
animalGrowth: 156,
|
||||
alertTrend: -3
|
||||
},
|
||||
recentActivities: [
|
||||
{
|
||||
id: 1,
|
||||
type: 'farmer',
|
||||
title: '新增养殖户',
|
||||
content: '张三申请加入养殖户管理',
|
||||
time: '2小时前'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
type: 'alert',
|
||||
title: '设备告警',
|
||||
content: '智能项圈001离线超过30分钟',
|
||||
time: '3小时前'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
type: 'epidemic',
|
||||
title: '疫情防控',
|
||||
content: '完成第三季度疫苗接种统计',
|
||||
time: '5小时前'
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
|
||||
// 加载模拟市场价格
|
||||
loadMockMarketPrice() {
|
||||
this.setData({
|
||||
marketPrice: {
|
||||
beef: { price: 68.5, trend: 2.3 },
|
||||
mutton: { price: 72.8, trend: -1.2 },
|
||||
milk: { price: 4.2, trend: 0.8 }
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
// 加载所有模拟数据
|
||||
loadMockData() {
|
||||
this.loadMockStatistics();
|
||||
this.loadMockMarketPrice();
|
||||
},
|
||||
|
||||
// 快捷操作点击
|
||||
onQuickActionTap(e) {
|
||||
const { action } = e.currentTarget.dataset;
|
||||
const actionItem = this.data.quickActions.find(item => item.id === action);
|
||||
|
||||
if (actionItem && actionItem.path) {
|
||||
if (actionItem.path.startsWith('/pages/')) {
|
||||
// 如果是tabBar页面,使用switchTab
|
||||
if (actionItem.path.includes('/farmer/farmer')) {
|
||||
wx.switchTab({
|
||||
url: actionItem.path
|
||||
});
|
||||
} else {
|
||||
wx.navigateTo({
|
||||
url: actionItem.path
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
// 查看更多动态
|
||||
onViewMoreActivities() {
|
||||
wx.showToast({
|
||||
title: '功能开发中',
|
||||
icon: 'none'
|
||||
});
|
||||
},
|
||||
|
||||
// 下拉刷新
|
||||
onPullDownRefresh() {
|
||||
this.loadData().finally(() => {
|
||||
wx.stopPullDownRefresh();
|
||||
});
|
||||
},
|
||||
|
||||
// 分享页面
|
||||
onShareAppMessage() {
|
||||
return {
|
||||
title: '政府监管端 - 数据统计',
|
||||
path: '/pages/statistics/statistics'
|
||||
};
|
||||
}
|
||||
});
|
||||
6
government-mini-program/pages/statistics/statistics.json
Normal file
6
government-mini-program/pages/statistics/statistics.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"navigationBarTitleText": "数据统计",
|
||||
"enablePullDownRefresh": true,
|
||||
"backgroundColor": "#f5f5f5",
|
||||
"backgroundTextStyle": "dark"
|
||||
}
|
||||
121
government-mini-program/pages/statistics/statistics.wxml
Normal file
121
government-mini-program/pages/statistics/statistics.wxml
Normal file
@@ -0,0 +1,121 @@
|
||||
<!--pages/statistics/statistics.wxml-->
|
||||
<view class="container">
|
||||
<!-- 状态栏 -->
|
||||
<view class="status-bar">
|
||||
<view class="status-left">
|
||||
<text>{{currentTime || '17:05'}}</text>
|
||||
</view>
|
||||
<view class="status-right">
|
||||
<text>100%</text>
|
||||
<view class="battery-icon"></view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 顶部导航栏 -->
|
||||
<view class="header">
|
||||
<view class="header-title">数据统计</view>
|
||||
<view class="header-actions">
|
||||
<view class="action-btn" bindtap="onRefresh">
|
||||
<text class="icon-refresh">🔄</text>
|
||||
</view>
|
||||
<view class="action-btn" bindtap="onExport">
|
||||
<text class="icon-export">📊</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 统计卡片区域 -->
|
||||
<view class="stats-cards">
|
||||
<view
|
||||
class="stat-card"
|
||||
wx:for="{{statsData}}"
|
||||
wx:key="id"
|
||||
data-item="{{item}}"
|
||||
bindtap="onStatCardTap"
|
||||
>
|
||||
<view class="card-icon" style="background-color: {{item.color}}">
|
||||
<text class="icon">{{item.icon}}</text>
|
||||
</view>
|
||||
<view class="card-content">
|
||||
<view class="card-title">{{item.title}}</view>
|
||||
<view class="card-value">{{item.value}}</view>
|
||||
<view class="card-trend {{item.trend > 0 ? 'up' : item.trend < 0 ? 'down' : 'stable'}}">
|
||||
<text class="trend-icon">{{item.trend > 0 ? '↗' : item.trend < 0 ? '↘' : '→'}}</text>
|
||||
<text class="trend-text">{{item.trendText}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 图表区域 -->
|
||||
<view class="chart-section">
|
||||
<view class="section-header">
|
||||
<text class="section-title">监管趋势</text>
|
||||
<view class="time-filter">
|
||||
<view
|
||||
class="filter-item {{selectedPeriod === item ? 'active' : ''}}"
|
||||
wx:for="{{timePeriods}}"
|
||||
wx:key="*this"
|
||||
data-period="{{item}}"
|
||||
bindtap="onPeriodChange"
|
||||
>
|
||||
{{item}}
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 模拟图表 -->
|
||||
<view class="chart-container">
|
||||
<view class="chart-placeholder">
|
||||
<text class="chart-text">📈 监管数据趋势图</text>
|
||||
<text class="chart-desc">显示最近{{selectedPeriod}}的监管活动统计</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 详细列表 -->
|
||||
<view class="detail-section">
|
||||
<view class="section-header">
|
||||
<text class="section-title">最新监管记录</text>
|
||||
<view class="more-btn" bindtap="onViewMore">
|
||||
查看更多 >
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="record-list">
|
||||
<view
|
||||
class="record-item"
|
||||
wx:for="{{recentRecords}}"
|
||||
wx:key="id"
|
||||
data-item="{{item}}"
|
||||
bindtap="onRecordTap"
|
||||
>
|
||||
<view class="record-icon">
|
||||
<text class="status-dot {{item.status}}"></text>
|
||||
</view>
|
||||
<view class="record-content">
|
||||
<view class="record-title">{{item.title}}</view>
|
||||
<view class="record-desc">{{item.description}}</view>
|
||||
<view class="record-time">{{item.time}}</view>
|
||||
</view>
|
||||
<view class="record-arrow">></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 快捷操作 -->
|
||||
<view class="quick-actions">
|
||||
<view
|
||||
class="action-item"
|
||||
wx:for="{{quickActions}}"
|
||||
wx:key="id"
|
||||
data-item="{{item}}"
|
||||
bindtap="onQuickAction"
|
||||
>
|
||||
<view class="action-icon" style="background-color: {{item.color}}">
|
||||
<text>{{item.icon}}</text>
|
||||
</view>
|
||||
<text class="action-name">{{item.name}}</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
313
government-mini-program/pages/statistics/statistics.wxss
Normal file
313
government-mini-program/pages/statistics/statistics.wxss
Normal file
@@ -0,0 +1,313 @@
|
||||
/* pages/statistics/statistics.wxss */
|
||||
.container {
|
||||
min-height: 100vh;
|
||||
background-color: #f5f5f5;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
|
||||
/* 状态栏样式 */
|
||||
.status-bar {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 20rpx 30rpx;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
font-size: 28rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.status-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.battery-icon {
|
||||
width: 40rpx;
|
||||
height: 20rpx;
|
||||
border: 2rpx solid white;
|
||||
border-radius: 4rpx;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.battery-icon::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: -6rpx;
|
||||
top: 6rpx;
|
||||
width: 4rpx;
|
||||
height: 8rpx;
|
||||
background-color: white;
|
||||
border-radius: 0 2rpx 2rpx 0;
|
||||
}
|
||||
|
||||
/* 顶部导航栏 */
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 15rpx 30rpx;
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
height: 80rpx;
|
||||
}
|
||||
|
||||
.header-title {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
width: 60rpx;
|
||||
height: 60rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 50%;
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
/* 统计卡片 */
|
||||
.stats-cards {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 20rpx;
|
||||
padding: 20rpx;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
background-color: white;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20rpx;
|
||||
}
|
||||
|
||||
.card-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.card-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.card-title {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.card-value {
|
||||
font-size: 36rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.card-trend {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4rpx;
|
||||
font-size: 22rpx;
|
||||
}
|
||||
|
||||
.card-trend.up {
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.card-trend.down {
|
||||
color: #f44336;
|
||||
}
|
||||
|
||||
.card-trend.stable {
|
||||
color: #666;
|
||||
}
|
||||
|
||||
/* 图表区域 */
|
||||
.chart-section {
|
||||
margin: 20rpx;
|
||||
background-color: white;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 30rpx;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.time-filter {
|
||||
display: flex;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.filter-item {
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
background-color: #f5f5f5;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.filter-item.active {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
height: 400rpx;
|
||||
background-color: #f8f9fa;
|
||||
border-radius: 8rpx;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 2rpx dashed #ddd;
|
||||
}
|
||||
|
||||
.chart-text {
|
||||
font-size: 32rpx;
|
||||
color: #666;
|
||||
margin-bottom: 10rpx;
|
||||
}
|
||||
|
||||
.chart-desc {
|
||||
font-size: 24rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/* 详细列表 */
|
||||
.detail-section {
|
||||
margin: 20rpx;
|
||||
background-color: white;
|
||||
border-radius: 12rpx;
|
||||
padding: 30rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.more-btn {
|
||||
font-size: 28rpx;
|
||||
color: #4CAF50;
|
||||
}
|
||||
|
||||
.record-list {
|
||||
margin-top: 20rpx;
|
||||
}
|
||||
|
||||
.record-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 20rpx 0;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.record-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.record-icon {
|
||||
margin-right: 20rpx;
|
||||
}
|
||||
|
||||
.status-dot {
|
||||
width: 16rpx;
|
||||
height: 16rpx;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.status-dot.success {
|
||||
background-color: #4CAF50;
|
||||
}
|
||||
|
||||
.status-dot.warning {
|
||||
background-color: #ff9800;
|
||||
}
|
||||
|
||||
.status-dot.error {
|
||||
background-color: #f44336;
|
||||
}
|
||||
|
||||
.record-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.record-title {
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.record-desc {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
margin-bottom: 8rpx;
|
||||
}
|
||||
|
||||
.record-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.record-arrow {
|
||||
color: #ccc;
|
||||
font-size: 24rpx;
|
||||
}
|
||||
|
||||
/* 快捷操作 */
|
||||
.quick-actions {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
padding: 30rpx 20rpx;
|
||||
background-color: white;
|
||||
margin: 20rpx;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.action-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 10rpx;
|
||||
}
|
||||
|
||||
.action-icon {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 36rpx;
|
||||
}
|
||||
|
||||
.action-name {
|
||||
font-size: 24rpx;
|
||||
color: #666;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// pages/supervision/supervision.js
|
||||
Page({
|
||||
data: {
|
||||
searchKeyword: '',
|
||||
loading: false,
|
||||
supervisionList: []
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadSupervisionData()
|
||||
},
|
||||
|
||||
onPullDownRefresh() {
|
||||
this.loadSupervisionData()
|
||||
setTimeout(() => {
|
||||
wx.stopPullDownRefresh()
|
||||
}, 1000)
|
||||
},
|
||||
|
||||
loadSupervisionData() {
|
||||
// 模拟数据
|
||||
this.setData({
|
||||
supervisionList: [
|
||||
{
|
||||
id: 1,
|
||||
title: '养殖场A例行检查',
|
||||
description: '完成对养殖场A的例行监管检查',
|
||||
location: '宁夏银川市',
|
||||
createTime: '2024-01-15 10:30',
|
||||
status: 'completed',
|
||||
statusText: '已完成'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
handleAdd() {
|
||||
wx.showToast({
|
||||
title: '新增功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
<!--pages/supervision/supervision.wxml-->
|
||||
<view class="supervision-container">
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-section">
|
||||
<view class="search-bar">
|
||||
<input
|
||||
value="{{searchKeyword}}"
|
||||
type="text"
|
||||
placeholder="搜索监管记录..."
|
||||
class="search-input"
|
||||
bindinput="onSearchInput"
|
||||
/>
|
||||
<view class="search-icon">🔍</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 监管列表 -->
|
||||
<view class="supervision-list">
|
||||
<view class="list-header">
|
||||
<view class="list-title">监管记录</view>
|
||||
<view class="add-btn" bindtap="handleAdd">
|
||||
<text class="add-text">新增</text>
|
||||
<view class="add-icon">+</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{loading}}" class="loading">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view wx:elif="{{supervisionList.length === 0}}" class="empty">
|
||||
<view class="empty-icon">📋</view>
|
||||
<view class="empty-text">暂无监管记录</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="list-content">
|
||||
<view
|
||||
wx:for="{{supervisionList}}"
|
||||
wx:key="id"
|
||||
class="supervision-item"
|
||||
>
|
||||
<view class="item-header">
|
||||
<view class="item-title">{{item.title}}</view>
|
||||
<view class="item-status {{item.status}}">
|
||||
{{item.statusText}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-desc">{{item.description}}</view>
|
||||
<view class="item-meta">
|
||||
<view class="item-location">📍 {{item.location}}</view>
|
||||
<view class="item-time">{{item.createTime}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,158 +0,0 @@
|
||||
/* pages/supervision/supervision.wxss */
|
||||
.supervision-container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
background: #f8f9fa;
|
||||
border: none;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 60rpx 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.supervision-list {
|
||||
background: #fff;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
background: #1890ff;
|
||||
border-radius: 24rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.add-text {
|
||||
font-size: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.empty {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.loading-text,
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
space-y: 0;
|
||||
}
|
||||
|
||||
.supervision-item {
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.supervision-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-status {
|
||||
font-size: 20rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-status.completed {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 12rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-location,
|
||||
.item-time {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
// pages/warehouse/warehouse.js
|
||||
Page({
|
||||
data: {
|
||||
searchKeyword: '',
|
||||
loading: false,
|
||||
warehouseList: []
|
||||
},
|
||||
|
||||
onLoad() {
|
||||
this.loadWarehouseData()
|
||||
},
|
||||
|
||||
loadWarehouseData() {
|
||||
// 模拟数据
|
||||
this.setData({
|
||||
warehouseList: [
|
||||
{
|
||||
id: 1,
|
||||
title: '疫苗库存',
|
||||
description: '各类疫苗库存管理',
|
||||
quantity: 100,
|
||||
unit: '支',
|
||||
status: 'normal',
|
||||
statusText: '正常'
|
||||
}
|
||||
]
|
||||
})
|
||||
},
|
||||
|
||||
onSearchInput(e) {
|
||||
this.setData({
|
||||
searchKeyword: e.detail.value
|
||||
})
|
||||
},
|
||||
|
||||
handleAdd() {
|
||||
wx.showToast({
|
||||
title: '新增功能待实现',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"usingComponents": {}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<!--pages/warehouse/warehouse.wxml-->
|
||||
<view class="warehouse-container">
|
||||
<!-- 搜索栏 -->
|
||||
<view class="search-section">
|
||||
<view class="search-bar">
|
||||
<input
|
||||
value="{{searchKeyword}}"
|
||||
type="text"
|
||||
placeholder="搜索库存记录..."
|
||||
class="search-input"
|
||||
bindinput="onSearchInput"
|
||||
/>
|
||||
<view class="search-icon">🔍</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 库存列表 -->
|
||||
<view class="warehouse-list">
|
||||
<view class="list-header">
|
||||
<view class="list-title">仓库管理</view>
|
||||
<view class="add-btn" bindtap="handleAdd">
|
||||
<text class="add-text">新增</text>
|
||||
<view class="add-icon">+</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view wx:if="{{loading}}" class="loading">
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view wx:elif="{{warehouseList.length === 0}}" class="empty">
|
||||
<view class="empty-icon">📦</view>
|
||||
<view class="empty-text">暂无库存记录</view>
|
||||
</view>
|
||||
|
||||
<view wx:else class="list-content">
|
||||
<view
|
||||
wx:for="{{warehouseList}}"
|
||||
wx:key="id"
|
||||
class="warehouse-item"
|
||||
>
|
||||
<view class="item-header">
|
||||
<view class="item-title">{{item.title}}</view>
|
||||
<view class="item-status {{item.status}}">
|
||||
{{item.statusText}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="item-content">
|
||||
<view class="item-desc">{{item.description}}</view>
|
||||
<view class="item-meta">
|
||||
<view class="item-quantity">{{item.quantity}} {{item.unit}}</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -1,158 +0,0 @@
|
||||
/* pages/warehouse/warehouse.wxss */
|
||||
.warehouse-container {
|
||||
min-height: 100vh;
|
||||
background: #f6f6f6;
|
||||
}
|
||||
|
||||
.search-section {
|
||||
padding: 20rpx;
|
||||
background: #fff;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.search-bar {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
height: 72rpx;
|
||||
background: #f8f9fa;
|
||||
border: none;
|
||||
border-radius: 36rpx;
|
||||
padding: 0 60rpx 0 30rpx;
|
||||
font-size: 28rpx;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
font-size: 28rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.warehouse-list {
|
||||
background: #fff;
|
||||
margin: 0 20rpx;
|
||||
border-radius: 16rpx;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.list-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
}
|
||||
|
||||
.list-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.add-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 16rpx 24rpx;
|
||||
background: #1890ff;
|
||||
border-radius: 24rpx;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.add-text {
|
||||
font-size: 24rpx;
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
.add-icon {
|
||||
font-size: 24rpx;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.loading,
|
||||
.empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 80rpx;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.loading-text,
|
||||
.empty-text {
|
||||
font-size: 28rpx;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 80rpx;
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.list-content {
|
||||
space-y: 0;
|
||||
}
|
||||
|
||||
.warehouse-item {
|
||||
padding: 30rpx;
|
||||
border-bottom: 1rpx solid #f0f0f0;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.warehouse-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.item-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.item-title {
|
||||
font-size: 30rpx;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.item-status {
|
||||
font-size: 20rpx;
|
||||
padding: 8rpx 16rpx;
|
||||
border-radius: 20rpx;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.item-status.normal {
|
||||
background: #f6ffed;
|
||||
color: #52c41a;
|
||||
}
|
||||
|
||||
.item-content {
|
||||
margin-bottom: 20rpx;
|
||||
}
|
||||
|
||||
.item-desc {
|
||||
font-size: 26rpx;
|
||||
color: #666;
|
||||
margin-bottom: 12rpx;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.item-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item-quantity {
|
||||
font-size: 22rpx;
|
||||
color: #999;
|
||||
}
|
||||
Reference in New Issue
Block a user