修改文件结构,统一文档格式
This commit is contained in:
121
README.md
Normal file
121
README.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# 宁夏智慧养殖监管平台
|
||||
|
||||
## 项目概述
|
||||
|
||||
宁夏智慧养殖监管平台是一个现代化的农场管理系统,提供实时监控、数据分析和多终端访问功能。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```
|
||||
nxxmdata/
|
||||
├── backend/ # 后端服务 (Node.js + Express + Sequelize)
|
||||
│ ├── config/ # 配置文件
|
||||
│ ├── controllers/ # 业务逻辑控制器
|
||||
│ ├── models/ # 数据模型
|
||||
│ ├── routes/ # API路由
|
||||
│ ├── middleware/ # 中间件
|
||||
│ ├── utils/ # 工具类
|
||||
│ ├── migrations/ # 数据库迁移
|
||||
│ ├── seeds/ # 种子数据
|
||||
│ └── server.js # 服务器入口
|
||||
├── admin-system/ # 管理后台 (Vue.js 3.x)
|
||||
│ └── frontend/ # 前端项目
|
||||
├── website/ # 官网 (Vue.js 3.x)
|
||||
│ └── data-screen/ # 数据大屏展示
|
||||
├── mini_program/ # 微信小程序矩阵
|
||||
│ └── farm-monitor-dashboard/ # 监控仪表盘小程序
|
||||
├── scripts/ # 执行脚本目录
|
||||
│ ├── init-db.js # 数据库初始化
|
||||
│ ├── migration-manager.js # 迁移管理
|
||||
│ ├── seed-manager.js # 种子数据管理
|
||||
│ ├── test-connection.js # 连接测试
|
||||
│ └── test-map-api.js # 地图API测试
|
||||
├── docs/ # 文档目录
|
||||
│ ├── baidu-map-license.md # 百度地图许可
|
||||
│ └── performance-monitoring.md # 性能监控文档
|
||||
├── test/ # 测试文件目录
|
||||
│ └── performance-monitor-test.js # 性能监控测试
|
||||
├── examples/ # 示例代码
|
||||
└── 配置文件
|
||||
├── arch.md # 架构文档
|
||||
├── design.md # 详细设计
|
||||
├── dev-plan.md # 开发计划
|
||||
├── task.md # 任务列表
|
||||
├── schema.sql # 数据库架构
|
||||
└── create_tables.sql # 建表脚本
|
||||
```
|
||||
|
||||
## 技术栈
|
||||
|
||||
### 后端技术栈
|
||||
- **运行环境**: Node.js 18.0+
|
||||
- **Web框架**: Express.js 4.18+
|
||||
- **ORM框架**: Sequelize 6.30+
|
||||
- **数据库**: MySQL (mysql2 3.0+)
|
||||
- **认证**: JWT (jsonwebtoken 9.0+)
|
||||
- **密码加密**: bcrypt 5.1+
|
||||
- **API文档**: Swagger (swagger-jsdoc + swagger-ui-express)
|
||||
- **日志管理**: Winston 3.17+
|
||||
- **开发工具**: nodemon 3.0+
|
||||
- **跨域处理**: CORS 2.8+
|
||||
- **数据验证**: express-validator 7.2+
|
||||
- **环境变量**: dotenv 16.0+
|
||||
- **HTTP客户端**: Axios 1.4+
|
||||
- **服务器端口**: 5350
|
||||
|
||||
### 前端技术栈
|
||||
- **管理后台**: Vue.js 3.4+ + Ant Design Vue 4.0+
|
||||
- **官网**: Vue.js 3.4+ + ECharts 5.4+
|
||||
- **微信小程序**: React + TypeScript + Tailwind CSS
|
||||
- **构建工具**: Vite 5.0+
|
||||
- **状态管理**: Pinia 2.0+
|
||||
- **路由管理**: Vue Router 4.0+
|
||||
|
||||
## 核心功能
|
||||
|
||||
- ✅ 实时设备监控
|
||||
- ✅ 动物健康管理
|
||||
- ✅ 地图可视化展示
|
||||
- ✅ 数据分析报表
|
||||
- ✅ 多角色权限系统
|
||||
- ✅ 订单管理功能
|
||||
- ✅ 预警管理系统
|
||||
- ✅ 性能监控分析
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 后端启动
|
||||
```bash
|
||||
cd backend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 管理后台启动
|
||||
```bash
|
||||
cd admin-system/frontend
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
### 官网启动
|
||||
```bash
|
||||
cd website/data-screen
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## 开发规范
|
||||
|
||||
1. 遵循模块化开发原则
|
||||
2. 代码注释规范清晰
|
||||
3. API接口文档完整
|
||||
4. 数据库迁移脚本可重复执行
|
||||
5. 测试用例覆盖核心功能
|
||||
|
||||
## 部署说明
|
||||
|
||||
生产环境建议使用Docker容器化部署,具体部署流程参考各模块的部署文档。
|
||||
|
||||
---
|
||||
*最后更新: 2025年8月*
|
||||
130
arch.md
130
arch.md
@@ -57,12 +57,6 @@
|
||||
- `middleware/`: 中间件
|
||||
- `auth.js`: 认证中间件
|
||||
- `performance-middleware.js`: 性能监控中间件
|
||||
- `scripts/`: 数据库管理脚本
|
||||
- `init-db.js`: 数据库初始化
|
||||
- `migration-manager.js`: 迁移管理
|
||||
- `seed-manager.js`: 种子数据管理
|
||||
- `test-connection.js`: 连接测试
|
||||
- `test-map-api.js`: 地图API测试
|
||||
- `utils/`: 工具类
|
||||
- `logger.js`: 日志工具
|
||||
- `performance-monitor.js`: 性能监控
|
||||
@@ -72,59 +66,77 @@
|
||||
- `seeds/`: 种子数据文件
|
||||
- `logs/`: 日志文件目录
|
||||
|
||||
### 2.2 前端 (`frontend/`)
|
||||
- `src/components/`: 可复用的UI组件
|
||||
- `BaiduMap.vue`: 百度地图组件
|
||||
- `EChart.vue`: 图表组件
|
||||
- `Menu.vue`: 导航菜单
|
||||
- `Dashboard.vue`: 仪表盘组件
|
||||
- `AlertStats.vue`: 告警统计组件
|
||||
- `AnimalStats.vue`: 动物统计组件
|
||||
- `DeviceStats.vue`: 设备统计组件
|
||||
- `FarmDetail.vue`: 农场详情组件
|
||||
- `MonitorChart.vue`: 监控图表组件
|
||||
- `ChartPerformanceMonitor.vue`: 性能监控图表
|
||||
- `VirtualScrollChart.vue`: 虚拟滚动图表
|
||||
- `src/views/`: 页面级组件
|
||||
- `Home.vue`: 首页
|
||||
- `Dashboard.vue`: 系统概览
|
||||
- `MapView.vue`: 地图监控
|
||||
- `Analytics.vue`: 数据分析
|
||||
- `Monitor.vue`: 实时监控
|
||||
- `Login.vue`: 登录页面
|
||||
- `Users.vue`: 用户管理
|
||||
- `Products.vue`: 产品管理
|
||||
- `Orders.vue`: 订单管理
|
||||
- `Devices.vue`: 设备管理
|
||||
- `Animals.vue`: 动物管理
|
||||
- `Alerts.vue`: 预警管理
|
||||
- `TestAnalytics.vue`: 测试分析页面
|
||||
- `MapZoomDemo.vue`: 地图缩放演示
|
||||
- `NotFound.vue`: 404页面
|
||||
- `src/stores/`: 状态管理(Pinia)
|
||||
- `user.js`: 用户状态管理
|
||||
- `data.js`: 数据状态管理
|
||||
- `settings.js`: 设置状态管理
|
||||
- `index.js`: 状态管理入口
|
||||
- `src/router/`: 路由配置
|
||||
- `index.js`: 路由实例和守卫
|
||||
- `routes.js`: 路由定义
|
||||
- `src/utils/`: 工具类(API调用、图表服务等)
|
||||
- `api.js`: API请求封装
|
||||
- `src/config/`: 配置文件
|
||||
- `public/`: 静态资源和测试页面
|
||||
- `debug-devices.html`: 设备调试页面
|
||||
- `debug-users.html`: 用户调试页面
|
||||
- `map-test.html`: 地图测试页面
|
||||
- `test-auto-login.html`: 自动登录测试
|
||||
- `test-users-display.html`: 用户显示测试
|
||||
### 2.2 管理后台 (`admin-system/`)
|
||||
- `frontend/`: 管理后台前端项目
|
||||
- `src/components/`: 可复用的UI组件
|
||||
- `BaiduMap.vue`: 百度地图组件
|
||||
- `EChart.vue`: 图表组件
|
||||
- `Menu.vue`: 导航菜单
|
||||
- `Dashboard.vue`: 仪表盘组件
|
||||
- `AlertStats.vue`: 告警统计组件
|
||||
- `AnimalStats.vue`: 动物统计组件
|
||||
- `DeviceStats.vue`: 设备统计组件
|
||||
- `FarmDetail.vue`: 农场详情组件
|
||||
- `MonitorChart.vue`: 监控图表组件
|
||||
- `ChartPerformanceMonitor.vue`: 性能监控图表
|
||||
- `VirtualScrollChart.vue`: 虚拟滚动图表
|
||||
- `src/views/`: 页面级组件
|
||||
- `Home.vue`: 首页
|
||||
- `Dashboard.vue`: 系统概览
|
||||
- `MapView.vue`: 地图监控
|
||||
- `Analytics.vue`: 数据分析
|
||||
- `Monitor.vue`: 实时监控
|
||||
- `Login.vue`: 登录页面
|
||||
- `Users.vue`: 用户管理
|
||||
- `Products.vue`: 产品管理
|
||||
- `Orders.vue`: 订单管理
|
||||
- `Devices.vue`: 设备管理
|
||||
- `Animals.vue`: 动物管理
|
||||
- `Alerts.vue`: 预警管理
|
||||
- `TestAnalytics.vue`: 测试分析页面
|
||||
- `MapZoomDemo.vue`: 地图缩放演示
|
||||
- `NotFound.vue`: 404页面
|
||||
- `src/stores/`: 状态管理(Pinia)
|
||||
- `user.js`: 用户状态管理
|
||||
- `data.js`: 数据状态管理
|
||||
- `settings.js`: 设置状态管理
|
||||
- `index.js`: 状态管理入口
|
||||
- `src/router/`: 路由配置
|
||||
- `index.js`: 路由实例和守卫
|
||||
- `routes.js`: 路由定义
|
||||
- `src/utils/`: 工具类(API调用、图表服务等)
|
||||
- `api.js`: API请求封装
|
||||
- `src/config/`: 配置文件
|
||||
- `public/`: 静态资源和测试页面
|
||||
- `debug-devices.html`: 设备调试页面
|
||||
- `debug-users.html`: 用户调试页面
|
||||
- `map-test.html`: 地图测试页面
|
||||
- `test-auto-login.html`: 自动登录测试
|
||||
- `test-users-display.html`: 用户显示测试
|
||||
|
||||
### 2.3 其他
|
||||
- `docs/`: 项目文档
|
||||
- `baidu-map-license.md`: 百度地图许可文档
|
||||
- `performance-monitoring.md`: 性能监控文档
|
||||
- `tests/`: 测试脚本
|
||||
- `performance-monitor-test.js`: 性能监控测试
|
||||
### 2.3 官网 (`website/`)
|
||||
- `data-screen/`: 官网前端项目
|
||||
- 包含官网展示页面和数据大屏功能
|
||||
|
||||
### 2.4 微信小程序 (`mini_program/`)
|
||||
- `farm-monitor-dashboard/`: 微信小程序项目
|
||||
- 包含移动端监控仪表盘功能
|
||||
|
||||
### 2.5 脚本目录 (`scripts/`)
|
||||
- `init-db.js`: 数据库初始化
|
||||
- `migration-manager.js`: 迁移管理
|
||||
- `seed-manager.js`: 种子数据管理
|
||||
- `test-connection.js`: 连接测试
|
||||
- `test-map-api.js`: 地图API测试
|
||||
|
||||
### 2.6 文档目录 (`docs/`)
|
||||
- `baidu-map-license.md`: 百度地图许可文档
|
||||
- `performance-monitoring.md`: 性能监控文档
|
||||
|
||||
### 2.7 测试目录 (`test/`)
|
||||
- `performance-monitor-test.js`: 性能监控测试
|
||||
|
||||
### 2.8 其他文件
|
||||
- `examples/`: 示例代码
|
||||
- `performance-monitor-integration.js`: 性能监控集成示例
|
||||
- `create_tables.sql`: 数据库表创建脚本
|
||||
@@ -162,7 +174,7 @@
|
||||
## 4. 核心架构
|
||||
### 4.1 技术栈
|
||||
**后端技术栈:**
|
||||
- **运行环境**: Node.js
|
||||
- **运行环境**: Node.js 18.0+
|
||||
- **Web框架**: Express.js 4.18+
|
||||
- **ORM框架**: Sequelize 6.30+
|
||||
- **数据库**: MySQL (mysql2 3.0+)
|
||||
|
||||
@@ -306,6 +306,55 @@ const options = {
|
||||
description: '更新时间'
|
||||
}
|
||||
}
|
||||
},
|
||||
FarmInput: {
|
||||
type: 'object',
|
||||
required: ['name', 'type', 'location'],
|
||||
properties: {
|
||||
name: {
|
||||
type: 'string',
|
||||
description: '养殖场名称'
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
description: '养殖场类型'
|
||||
},
|
||||
location: {
|
||||
type: 'object',
|
||||
required: ['latitude', 'longitude'],
|
||||
properties: {
|
||||
latitude: {
|
||||
type: 'number',
|
||||
format: 'float',
|
||||
description: '纬度'
|
||||
},
|
||||
longitude: {
|
||||
type: 'number',
|
||||
format: 'float',
|
||||
description: '经度'
|
||||
}
|
||||
},
|
||||
description: '地理位置'
|
||||
},
|
||||
address: {
|
||||
type: 'string',
|
||||
description: '详细地址'
|
||||
},
|
||||
contact: {
|
||||
type: 'string',
|
||||
description: '联系人'
|
||||
},
|
||||
phone: {
|
||||
type: 'string',
|
||||
description: '联系电话'
|
||||
},
|
||||
status: {
|
||||
type: 'string',
|
||||
enum: ['active', 'inactive', 'maintenance'],
|
||||
description: '养殖场状态',
|
||||
default: 'active'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -20,6 +20,7 @@ const userController = require('../controllers/userController');
|
||||
* - id
|
||||
* - username
|
||||
* - email
|
||||
* - password
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
@@ -30,10 +31,36 @@ const userController = require('../controllers/userController');
|
||||
* email:
|
||||
* type: string
|
||||
* description: 邮箱地址
|
||||
* password:
|
||||
* type: string
|
||||
* description: 密码(加密存储)
|
||||
* phone:
|
||||
* type: string
|
||||
* description: 手机号码
|
||||
* avatar:
|
||||
* type: string
|
||||
* description: 头像URL
|
||||
* status:
|
||||
* type: string
|
||||
* enum: [active, inactive, suspended]
|
||||
* description: 用户状态
|
||||
* createdAt:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* description: 创建时间
|
||||
* updatedAt:
|
||||
* type: string
|
||||
* format: date-time
|
||||
* description: 更新时间
|
||||
* example:
|
||||
* id: 1
|
||||
* username: "john_doe"
|
||||
* email: "john@example.com"
|
||||
* phone: "13800138000"
|
||||
* avatar: "/uploads/avatars/default.png"
|
||||
* status: "active"
|
||||
* createdAt: "2024-01-01T00:00:00.000Z"
|
||||
* updatedAt: "2024-01-01T00:00:00.000Z"
|
||||
*/
|
||||
|
||||
/**
|
||||
|
||||
136
design.md
136
design.md
@@ -26,7 +26,14 @@
|
||||
## 2. 技术架构设计
|
||||
|
||||
### 2.1 整体架构
|
||||
本项目采用前后端分离的架构设计模式,前端使用Vue.js框架,后端采用Python技术栈,数据库使用MySQL进行数据存储。
|
||||
本项目采用前后端分离的架构设计模式,包含以下主要模块:
|
||||
- **后端服务** (`backend/`): Node.js + Express + Sequelize ORM
|
||||
- **管理后台** (`admin-system/`): Vue.js 3.x + Ant Design Vue
|
||||
- **官网** (`website/`): Vue.js 3.x + 数据大屏展示
|
||||
- **微信小程序** (`mini_program/`): React + TypeScript + Tailwind CSS
|
||||
- **脚本工具** (`scripts/`): 数据库管理和维护脚本
|
||||
- **文档** (`docs/`): 项目技术文档
|
||||
- **测试** (`test/`): 测试脚本和用例
|
||||
|
||||
### 2.2 前端技术栈
|
||||
- **核心框架**: Vue.js 3.x
|
||||
@@ -38,23 +45,23 @@
|
||||
- **图表库**: ECharts
|
||||
|
||||
### 2.3 后端技术栈
|
||||
- **运行环境**: Python 3.8+
|
||||
- **Web框架**: FastAPI 或 Flask(可选)
|
||||
- **运行环境**: Node.js
|
||||
- **Web框架**: Express.js 4.18+
|
||||
- **API风格**: RESTful API
|
||||
- **认证授权**: JWT
|
||||
- **数据库访问**: SQLAlchemy 或 Peewee ORM
|
||||
- **依赖管理**: uv 工具
|
||||
- **认证授权**: JWT (jsonwebtoken 9.0+)
|
||||
- **数据库访问**: Sequelize ORM 6.30+
|
||||
- **数据库**: MySQL (mysql2 3.0+)
|
||||
- **密码加密**: bcrypt 5.1+
|
||||
- **API文档**: Swagger (swagger-jsdoc + swagger-ui-express)
|
||||
- **日志管理**: Winston 3.17+
|
||||
- **开发工具**: nodemon 3.0+
|
||||
- **跨域处理**: CORS 2.8+
|
||||
- **数据验证**: express-validator 7.2+
|
||||
- **环境变量**: dotenv 16.0+
|
||||
- **HTTP客户端**: Axios 1.4+
|
||||
- **服务器端口**: 5350
|
||||
|
||||
|
||||
#### 2.3.1 Python环境配置与依赖管理
|
||||
1. `uv` 是一个快速的 Python 包和虚拟环境管理工具
|
||||
2. MCP Server 依赖 `uv` 工具运行,必须确保系统环境中已安装 uv
|
||||
3. 安装 `uv` 的推荐方法:
|
||||
- 使用官方安装脚本:`powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"`
|
||||
- 或通过 pip 安装:`pip install uv`
|
||||
4. 设置国内镜像源加速下载:
|
||||
```bash
|
||||
$env:UV_INDEX_URL="https://mirrors.aliyun.com/pypi/simple/"
|
||||
```
|
||||
|
||||
### 2.4 部署架构
|
||||
- **开发环境**: 本地运行
|
||||
@@ -111,45 +118,52 @@
|
||||
| username | VARCHAR(50) | UNIQUE, NOT NULL | 用户名 |
|
||||
| email | VARCHAR(100) | UNIQUE, NOT NULL | 邮箱地址 |
|
||||
| password | VARCHAR(255) | NOT NULL | 密码(加密后) |
|
||||
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
| phone | VARCHAR(20) | NULL | 手机号 |
|
||||
| avatar | VARCHAR(255) | NULL | 头像URL |
|
||||
| status | ENUM('active','inactive','banned') | DEFAULT 'active' | 用户状态 |
|
||||
| last_login | DATETIME | NULL | 最后登录时间 |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
#### 3.3.2 角色表 (roles)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 角色ID |
|
||||
| name | VARCHAR(50) | UNIQUE, NOT NULL | 角色名称 |
|
||||
| description | TEXT | | 角色描述 |
|
||||
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| description | TEXT | NULL | 角色描述 |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
#### 3.3.3 用户角色关联表 (user_roles)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| user_id | INT | FOREIGN KEY (users.id), NOT NULL | 用户ID |
|
||||
| role_id | INT | FOREIGN KEY (roles.id), NOT NULL | 角色ID |
|
||||
| assigned_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 分配时间 |
|
||||
| assigned_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 分配时间 |
|
||||
|
||||
#### 3.3.4 产品表 (products)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 产品ID |
|
||||
| name | VARCHAR(100) | NOT NULL | 产品名称 |
|
||||
| description | TEXT | | 产品描述 |
|
||||
| price | DECIMAL(10,2) | NOT NULL | 产品价格 |
|
||||
| description | TEXT | NULL | 产品描述 |
|
||||
| price | INT | NOT NULL | 产品价格(单位:分) |
|
||||
| stock | INT | DEFAULT 0 | 库存数量 |
|
||||
| status | ENUM('active', 'inactive') | DEFAULT 'active' | 产品状态 |
|
||||
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
| image_url | VARCHAR(255) | NULL | 产品图片URL |
|
||||
| is_active | TINYINT(1) | DEFAULT 1 | 是否激活 |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
#### 3.3.5 订单表 (orders)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 订单ID |
|
||||
| user_id | INT | FOREIGN KEY (users.id), NOT NULL | 用户ID |
|
||||
| total_amount | DECIMAL(10,2) | NOT NULL | 订单总金额 |
|
||||
| status | ENUM('pending', 'paid', 'shipped', 'delivered', 'cancelled') | DEFAULT 'pending' | 订单状态 |
|
||||
| created_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | TIMESTAMP | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
| total_amount | INT | DEFAULT 0 | 订单总金额(单位:分) |
|
||||
| status | ENUM('pending','processing','shipped','delivered','cancelled') | DEFAULT 'pending' | 订单状态 |
|
||||
| payment_status | ENUM('unpaid','paid','refunded') | DEFAULT 'unpaid' | 支付状态 |
|
||||
| shipping_address | TEXT | NULL | 收货地址 |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
#### 3.3.6 订单项表 (order_items)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
@@ -157,8 +171,66 @@
|
||||
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 订单项ID |
|
||||
| order_id | INT | FOREIGN KEY (orders.id), NOT NULL | 订单ID |
|
||||
| product_id | INT | FOREIGN KEY (products.id), NOT NULL | 产品ID |
|
||||
| quantity | INT | NOT NULL | 数量 |
|
||||
| price | DECIMAL(10,2) | NOT NULL | 单价 |
|
||||
| quantity | INT | DEFAULT 1 | 数量 |
|
||||
| price | INT | NOT NULL | 单价(单位:分) |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
|
||||
#### 3.3.7 养殖场表 (farms)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 养殖场ID |
|
||||
| name | VARCHAR(100) | NOT NULL | 养殖场名称 |
|
||||
| type | VARCHAR(50) | NOT NULL | 养殖场类型 |
|
||||
| location | JSON | NOT NULL | 地理位置信息 |
|
||||
| address | VARCHAR(255) | NULL | 详细地址 |
|
||||
| contact | VARCHAR(50) | NULL | 联系人 |
|
||||
| phone | VARCHAR(20) | NULL | 联系电话 |
|
||||
| status | ENUM('active','inactive','maintenance') | DEFAULT 'active' | 养殖场状态 |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
#### 3.3.8 动物表 (animals)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 动物ID |
|
||||
| type | VARCHAR(50) | NOT NULL | 动物类型 |
|
||||
| count | INT | DEFAULT 0 | 数量 |
|
||||
| farm_id | INT | FOREIGN KEY (farms.id), NOT NULL | 所属养殖场ID |
|
||||
| health_status | ENUM('healthy','sick','quarantine') | DEFAULT 'healthy' | 健康状态 |
|
||||
| last_inspection | DATETIME | NULL | 最后检查时间 |
|
||||
| notes | TEXT | NULL | 备注信息 |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
#### 3.3.9 设备表 (devices)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 设备ID |
|
||||
| name | VARCHAR(100) | NOT NULL | 设备名称 |
|
||||
| type | VARCHAR(50) | NOT NULL | 设备类型 |
|
||||
| status | ENUM('online','offline','maintenance') | DEFAULT 'offline' | 设备状态 |
|
||||
| farm_id | INT | FOREIGN KEY (farms.id), NOT NULL | 所属养殖场ID |
|
||||
| last_maintenance | DATETIME | NULL | 最后维护时间 |
|
||||
| installation_date | DATETIME | NULL | 安装日期 |
|
||||
| metrics | JSON | NULL | 设备指标数据 |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
#### 3.3.10 预警表 (alerts)
|
||||
| 字段名 | 类型 | 约束 | 描述 |
|
||||
|--------|------|------|------|
|
||||
| id | INT | PRIMARY KEY, AUTO_INCREMENT | 预警ID |
|
||||
| type | VARCHAR(50) | NOT NULL | 预警类型 |
|
||||
| level | ENUM('low','medium','high','critical') | DEFAULT 'medium' | 预警级别 |
|
||||
| message | TEXT | NOT NULL | 预警消息 |
|
||||
| status | ENUM('active','acknowledged','resolved') | DEFAULT 'active' | 预警状态 |
|
||||
| farm_id | INT | FOREIGN KEY (farms.id), NOT NULL | 所属养殖场ID |
|
||||
| device_id | INT | FOREIGN KEY (devices.id), NULL | 关联设备ID |
|
||||
| resolved_at | DATETIME | NULL | 解决时间 |
|
||||
| resolved_by | INT | FOREIGN KEY (users.id), NULL | 解决人ID |
|
||||
| resolution_notes | TEXT | NULL | 解决说明 |
|
||||
| created_at | DATETIME | DEFAULT CURRENT_TIMESTAMP | 创建时间 |
|
||||
| updated_at | DATETIME | DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP | 更新时间 |
|
||||
|
||||
### 3.4 初始数据
|
||||
|
||||
|
||||
@@ -1,286 +1,286 @@
|
||||
'use client'
|
||||
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Progress } from "@/components/ui/progress"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { FarmMap } from "@/components/farm-map"
|
||||
import {
|
||||
TrendingUp,
|
||||
Users,
|
||||
MapPin,
|
||||
AlertTriangle,
|
||||
Thermometer,
|
||||
Droplets,
|
||||
Sun,
|
||||
Wifi,
|
||||
Server
|
||||
} from "lucide-react"
|
||||
|
||||
// Mock data for the dashboard
|
||||
const mockData = {
|
||||
farms: {
|
||||
total: 12,
|
||||
online: 9,
|
||||
offline: 3
|
||||
},
|
||||
animals: {
|
||||
total: 2456,
|
||||
cattle: 890,
|
||||
pigs: 756,
|
||||
chickens: 810
|
||||
},
|
||||
environment: {
|
||||
temperature: 25.6,
|
||||
humidity: 65,
|
||||
light: 1200
|
||||
},
|
||||
alerts: [
|
||||
{ id: 1, type: 'critical', message: '温度异常: 农场3号温度超过阈值', time: '10:30' },
|
||||
{ id: 2, type: 'warning', message: '湿度偏低: 农场5号湿度低于正常值', time: '09:45' },
|
||||
{ id: 3, type: 'info', message: '设备维护: 农场2号传感器需要校准', time: '08:15' }
|
||||
],
|
||||
devices: {
|
||||
total: 156,
|
||||
online: 142,
|
||||
offline: 14,
|
||||
types: {
|
||||
sensor: 89,
|
||||
camera: 32,
|
||||
controller: 35
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function Dashboard() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-blue-950 to-slate-900 text-white">
|
||||
{/* Header */}
|
||||
<header className="border-b border-slate-700/50 bg-slate-900/50 backdrop-blur-sm">
|
||||
<div className="container mx-auto px-6 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="w-3 h-3 bg-green-400 rounded-full animate-pulse"></div>
|
||||
<h1 className="text-2xl font-bold bg-gradient-to-r from-blue-400 to-cyan-400 bg-clip-text text-transparent">
|
||||
智慧农业监控平台
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="text-sm text-slate-400">
|
||||
{new Date().toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
})}
|
||||
</div>
|
||||
<Badge variant="secondary" className="bg-green-500/20 text-green-400">
|
||||
<Wifi className="w-3 h-3 mr-1" />
|
||||
系统在线
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="container mx-auto px-6 py-8">
|
||||
{/* Stats Overview */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-300">农场总数</CardTitle>
|
||||
<MapPin className="h-4 w-4 text-blue-400" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-white">{mockData.farms.total}</div>
|
||||
<div className="flex items-center text-xs text-slate-400 mt-2">
|
||||
<TrendingUp className="h-3 w-3 mr-1 text-green-400" />
|
||||
<span>在线: {mockData.farms.online}</span>
|
||||
<span className="mx-2">|</span>
|
||||
<span className="text-red-400">离线: {mockData.farms.offline}</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-300">动物总数</CardTitle>
|
||||
<Users className="h-4 w-4 text-green-400" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-white">{mockData.animals.total.toLocaleString()}</div>
|
||||
<div className="text-xs text-slate-400 mt-2">
|
||||
牛: {mockData.animals.cattle} | 猪: {mockData.animals.pigs} | 鸡: {mockData.animals.chickens}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-300">设备状态</CardTitle>
|
||||
<Server className="h-4 w-4 text-cyan-400" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-white">{mockData.devices.online}/{mockData.devices.total}</div>
|
||||
<div className="text-xs text-slate-400 mt-2">
|
||||
在线率: {((mockData.devices.online / mockData.devices.total) * 100).toFixed(1)}%
|
||||
</div>
|
||||
<Progress
|
||||
value={(mockData.devices.online / mockData.devices.total) * 100}
|
||||
className="h-2 mt-2 bg-slate-700"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-300">环境数据</CardTitle>
|
||||
<Thermometer className="h-4 w-4 text-orange-400" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<div className="flex items-center">
|
||||
<Thermometer className="h-3 w-3 mr-1 text-orange-400" />
|
||||
<span>{mockData.environment.temperature}°C</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Droplets className="h-3 w-3 mr-1 text-blue-400" />
|
||||
<span>{mockData.environment.humidity}%</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Sun className="h-3 w-3 mr-1 text-yellow-400" />
|
||||
<span>{mockData.environment.light}lux</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Main Dashboard Grid */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
{/* Left Column - Alerts */}
|
||||
<div className="lg:col-span-1">
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm h-full">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center text-lg">
|
||||
<AlertTriangle className="h-5 w-5 mr-2 text-red-400" />
|
||||
实时告警
|
||||
</CardTitle>
|
||||
<CardDescription className="text-slate-400">
|
||||
最近系统检测到的异常情况
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{mockData.alerts.map((alert) => (
|
||||
<div
|
||||
key={alert.id}
|
||||
className="p-3 rounded-lg border border-slate-700 bg-slate-800/50 backdrop-blur-sm"
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center mb-1">
|
||||
<Badge
|
||||
variant={
|
||||
alert.type === 'critical'
|
||||
? 'destructive'
|
||||
: alert.type === 'warning'
|
||||
? 'secondary'
|
||||
: 'default'
|
||||
}
|
||||
className="mr-2"
|
||||
>
|
||||
{alert.type === 'critical' ? '严重' : alert.type === 'warning' ? '警告' : '信息'}
|
||||
</Badge>
|
||||
<span className="text-xs text-slate-400">{alert.time}</span>
|
||||
</div>
|
||||
<p className="text-sm text-slate-200">{alert.message}</p>
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" className="text-slate-400 hover:text-white">
|
||||
处理
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Middle Column - Charts and Data */}
|
||||
<div className="lg:col-span-2">
|
||||
<Tabs defaultValue="overview" className="w-full">
|
||||
<TabsList className="bg-slate-800/50 border border-slate-700 backdrop-blur-sm">
|
||||
<TabsTrigger value="overview">概览</TabsTrigger>
|
||||
<TabsTrigger value="environment">环境监控</TabsTrigger>
|
||||
<TabsTrigger value="devices">设备管理</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="overview" className="mt-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<FarmMap />
|
||||
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>设备类型分布</CardTitle>
|
||||
<CardDescription>各类设备数量统计</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-64 flex items-center justify-center bg-slate-900/50 rounded-lg">
|
||||
<div className="text-center text-slate-400">
|
||||
<Server className="h-12 w-12 mx-auto mb-2" />
|
||||
<p>设备类型饼图</p>
|
||||
<p className="text-sm">传感器: {mockData.devices.types.sensor} | 摄像头: {mockData.devices.types.camera} | 控制器: {mockData.devices.types.controller}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="environment" className="mt-6">
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>环境数据趋势</CardTitle>
|
||||
<CardDescription>温湿度及光照强度变化</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-80 flex items-center justify-center bg-slate-900/50 rounded-lg">
|
||||
<div className="text-center text-slate-400">
|
||||
<TrendingUp className="h-12 w-12 mx-auto mb-2" />
|
||||
<p>环境数据折线图</p>
|
||||
<p className="text-sm">显示最近24小时温湿度变化趋势</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="devices" className="mt-6">
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>设备状态监控</CardTitle>
|
||||
<CardDescription>所有设备运行状态</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-80 flex items-center justify-center bg-slate-900/50 rounded-lg">
|
||||
<div className="text-center text-slate-400">
|
||||
<Wifi className="h-12 w-12 mx-auto mb-2" />
|
||||
<p>设备状态表格</p>
|
||||
<p className="text-sm">在线: {mockData.devices.online} | 离线: {mockData.devices.offline}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
'use client'
|
||||
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { Progress } from "@/components/ui/progress"
|
||||
import { Badge } from "@/components/ui/badge"
|
||||
import { Button } from "@/components/ui/button"
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"
|
||||
import { FarmMap } from "@/components/farm-map"
|
||||
import {
|
||||
TrendingUp,
|
||||
Users,
|
||||
MapPin,
|
||||
AlertTriangle,
|
||||
Thermometer,
|
||||
Droplets,
|
||||
Sun,
|
||||
Wifi,
|
||||
Server
|
||||
} from "lucide-react"
|
||||
|
||||
// Mock data for the dashboard
|
||||
const mockData = {
|
||||
farms: {
|
||||
total: 12,
|
||||
online: 9,
|
||||
offline: 3
|
||||
},
|
||||
animals: {
|
||||
total: 2456,
|
||||
cattle: 890,
|
||||
pigs: 756,
|
||||
chickens: 810
|
||||
},
|
||||
environment: {
|
||||
temperature: 25.6,
|
||||
humidity: 65,
|
||||
light: 1200
|
||||
},
|
||||
alerts: [
|
||||
{ id: 1, type: 'critical', message: '温度异常: 农场3号温度超过阈值', time: '10:30' },
|
||||
{ id: 2, type: 'warning', message: '湿度偏低: 农场5号湿度低于正常值', time: '09:45' },
|
||||
{ id: 3, type: 'info', message: '设备维护: 农场2号传感器需要校准', time: '08:15' }
|
||||
],
|
||||
devices: {
|
||||
total: 156,
|
||||
online: 142,
|
||||
offline: 14,
|
||||
types: {
|
||||
sensor: 89,
|
||||
camera: 32,
|
||||
controller: 35
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default function Dashboard() {
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-950 via-blue-950 to-slate-900 text-white">
|
||||
{/* Header */}
|
||||
<header className="border-b border-slate-700/50 bg-slate-900/50 backdrop-blur-sm">
|
||||
<div className="container mx-auto px-6 py-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="w-3 h-3 bg-green-400 rounded-full animate-pulse"></div>
|
||||
<h1 className="text-2xl font-bold bg-gradient-to-r from-blue-400 to-cyan-400 bg-clip-text text-transparent">
|
||||
智慧农业监控平台
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="text-sm text-slate-400">
|
||||
{new Date().toLocaleString('zh-CN', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric',
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
second: '2-digit'
|
||||
})}
|
||||
</div>
|
||||
<Badge variant="secondary" className="bg-green-500/20 text-green-400">
|
||||
<Wifi className="w-3 h-3 mr-1" />
|
||||
系统在线
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main Content */}
|
||||
<main className="container mx-auto px-6 py-8">
|
||||
{/* Stats Overview */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6 mb-8">
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-300">农场总数</CardTitle>
|
||||
<MapPin className="h-4 w-4 text-blue-400" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-white">{mockData.farms.total}</div>
|
||||
<div className="flex items-center text-xs text-slate-400 mt-2">
|
||||
<TrendingUp className="h-3 w-3 mr-1 text-green-400" />
|
||||
<span>在线: {mockData.farms.online}</span>
|
||||
<span className="mx-2">|</span>
|
||||
<span className="text-red-400">离线: {mockData.farms.offline}</span>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-300">动物总数</CardTitle>
|
||||
<Users className="h-4 w-4 text-green-400" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-white">{mockData.animals.total.toLocaleString()}</div>
|
||||
<div className="text-xs text-slate-400 mt-2">
|
||||
牛: {mockData.animals.cattle} | 猪: {mockData.animals.pigs} | 鸡: {mockData.animals.chickens}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-300">设备状态</CardTitle>
|
||||
<Server className="h-4 w-4 text-cyan-400" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="text-2xl font-bold text-white">{mockData.devices.online}/{mockData.devices.total}</div>
|
||||
<div className="text-xs text-slate-400 mt-2">
|
||||
在线率: {((mockData.devices.online / mockData.devices.total) * 100).toFixed(1)}%
|
||||
</div>
|
||||
<Progress
|
||||
value={(mockData.devices.online / mockData.devices.total) * 100}
|
||||
className="h-2 mt-2 bg-slate-700"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
|
||||
<CardTitle className="text-sm font-medium text-slate-300">环境数据</CardTitle>
|
||||
<Thermometer className="h-4 w-4 text-orange-400" />
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="flex items-center justify-between text-sm">
|
||||
<div className="flex items-center">
|
||||
<Thermometer className="h-3 w-3 mr-1 text-orange-400" />
|
||||
<span>{mockData.environment.temperature}°C</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Droplets className="h-3 w-3 mr-1 text-blue-400" />
|
||||
<span>{mockData.environment.humidity}%</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Sun className="h-3 w-3 mr-1 text-yellow-400" />
|
||||
<span>{mockData.environment.light}lux</span>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Main Dashboard Grid */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
{/* Left Column - Alerts */}
|
||||
<div className="lg:col-span-1">
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm h-full">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center text-lg">
|
||||
<AlertTriangle className="h-5 w-5 mr-2 text-red-400" />
|
||||
实时告警
|
||||
</CardTitle>
|
||||
<CardDescription className="text-slate-400">
|
||||
最近系统检测到的异常情况
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="space-y-4">
|
||||
{mockData.alerts.map((alert) => (
|
||||
<div
|
||||
key={alert.id}
|
||||
className="p-3 rounded-lg border border-slate-700 bg-slate-800/50 backdrop-blur-sm"
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center mb-1">
|
||||
<Badge
|
||||
variant={
|
||||
alert.type === 'critical'
|
||||
? 'destructive'
|
||||
: alert.type === 'warning'
|
||||
? 'secondary'
|
||||
: 'default'
|
||||
}
|
||||
className="mr-2"
|
||||
>
|
||||
{alert.type === 'critical' ? '严重' : alert.type === 'warning' ? '警告' : '信息'}
|
||||
</Badge>
|
||||
<span className="text-xs text-slate-400">{alert.time}</span>
|
||||
</div>
|
||||
<p className="text-sm text-slate-200">{alert.message}</p>
|
||||
</div>
|
||||
<Button variant="ghost" size="sm" className="text-slate-400 hover:text-white">
|
||||
处理
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Middle Column - Charts and Data */}
|
||||
<div className="lg:col-span-2">
|
||||
<Tabs defaultValue="overview" className="w-full">
|
||||
<TabsList className="bg-slate-800/50 border border-slate-700 backdrop-blur-sm">
|
||||
<TabsTrigger value="overview">概览</TabsTrigger>
|
||||
<TabsTrigger value="environment">环境监控</TabsTrigger>
|
||||
<TabsTrigger value="devices">设备管理</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="overview" className="mt-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<FarmMap />
|
||||
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>设备类型分布</CardTitle>
|
||||
<CardDescription>各类设备数量统计</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-64 flex items-center justify-center bg-slate-900/50 rounded-lg">
|
||||
<div className="text-center text-slate-400">
|
||||
<Server className="h-12 w-12 mx-auto mb-2" />
|
||||
<p>设备类型饼图</p>
|
||||
<p className="text-sm">传感器: {mockData.devices.types.sensor} | 摄像头: {mockData.devices.types.camera} | 控制器: {mockData.devices.types.controller}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="environment" className="mt-6">
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>环境数据趋势</CardTitle>
|
||||
<CardDescription>温湿度及光照强度变化</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-80 flex items-center justify-center bg-slate-900/50 rounded-lg">
|
||||
<div className="text-center text-slate-400">
|
||||
<TrendingUp className="h-12 w-12 mx-auto mb-2" />
|
||||
<p>环境数据折线图</p>
|
||||
<p className="text-sm">显示最近24小时温湿度变化趋势</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
|
||||
<TabsContent value="devices" className="mt-6">
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader>
|
||||
<CardTitle>设备状态监控</CardTitle>
|
||||
<CardDescription>所有设备运行状态</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-80 flex items-center justify-center bg-slate-900/50 rounded-lg">
|
||||
<div className="text-center text-slate-400">
|
||||
<Wifi className="h-12 w-12 mx-auto mb-2" />
|
||||
<p>设备状态表格</p>
|
||||
<p className="text-sm">在线: {mockData.devices.online} | 离线: {mockData.devices.offline}</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
</Tabs>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,21 +1,21 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
export default function Home() {
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
router.push('/dashboard')
|
||||
}, [router])
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-slate-950">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-400 mx-auto mb-4"></div>
|
||||
<p className="text-slate-400">正在跳转到智慧农业监控平台...</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { useRouter } from 'next/navigation'
|
||||
|
||||
export default function Home() {
|
||||
const router = useRouter()
|
||||
|
||||
useEffect(() => {
|
||||
router.push('/dashboard')
|
||||
}, [router])
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex items-center justify-center bg-slate-950">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-400 mx-auto mb-4"></div>
|
||||
<p className="text-slate-400">正在跳转到智慧农业监控平台...</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,190 +1,190 @@
|
||||
'use client'
|
||||
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { MapPin } from "lucide-react"
|
||||
|
||||
interface FarmLocation {
|
||||
id: number
|
||||
name: string
|
||||
type: string
|
||||
address: string
|
||||
contact: string
|
||||
phone: string
|
||||
position: { left: string; top: string }
|
||||
status: 'online' | 'offline' | 'warning'
|
||||
}
|
||||
|
||||
// const farmLocations: FarmLocation[] = [
|
||||
// {
|
||||
// id: 1,
|
||||
// name: "宁夏农场1",
|
||||
// type: "综合农场",
|
||||
// address: "宁夏回族自治区银川市",
|
||||
// contact: "管理员",
|
||||
// phone: "400-000-0000",
|
||||
// position: { left: "45%", top: "25%" },
|
||||
// status: "online"
|
||||
// },
|
||||
// {
|
||||
// id: 2,
|
||||
// name: "宁夏农场2",
|
||||
// type: "综合农场",
|
||||
// address: "宁夏回族自治区石嘴山市",
|
||||
// contact: "管理员",
|
||||
// phone: "400-000-0000",
|
||||
// position: { left: "40%", top: "15%" },
|
||||
// status: "online"
|
||||
// },
|
||||
// {
|
||||
// id: 3,
|
||||
// name: "宁夏农场3",
|
||||
// type: "综合农场",
|
||||
// address: "宁夏回族自治区吴忠市",
|
||||
// contact: "管理员",
|
||||
// phone: "400-000-0000",
|
||||
// position: { left: "50%", top: "45%" },
|
||||
// status: "warning"
|
||||
// },
|
||||
// {
|
||||
// id: 4,
|
||||
// name: "阳光农场",
|
||||
// type: "养猪场",
|
||||
// address: "北京市朝阳区农场路1号",
|
||||
// contact: "张三",
|
||||
// phone: "13800138001",
|
||||
// position: { left: "75%", top: "20%" },
|
||||
// status: "online"
|
||||
// },
|
||||
// {
|
||||
// id: 5,
|
||||
// name: "绿野牧场",
|
||||
// type: "养牛场",
|
||||
// address: "上海市浦东新区牧场路2号",
|
||||
// contact: "李四",
|
||||
// phone: "13800138002",
|
||||
// position: { left: "30%", top: "40%" },
|
||||
// status: "online"
|
||||
// },
|
||||
// {
|
||||
// id: 6,
|
||||
// name: "山谷羊场",
|
||||
// type: "养羊场",
|
||||
// address: "广州市天河区山谷路3号",
|
||||
// contact: "王五",
|
||||
// phone: "13800138003",
|
||||
// position: { left: "45%", top: "60%" },
|
||||
// status: "offline"
|
||||
// }
|
||||
// ]
|
||||
|
||||
export function FarmMap() {
|
||||
const getStatusColor = (status: FarmLocation['status']) => {
|
||||
switch (status) {
|
||||
case 'online': return 'bg-green-400'
|
||||
case 'offline': return 'bg-red-400'
|
||||
case 'warning': return 'bg-yellow-400'
|
||||
default: return 'bg-gray-400'
|
||||
}
|
||||
}
|
||||
|
||||
const getStatusText = (status: FarmLocation['status']) => {
|
||||
switch (status) {
|
||||
case 'online': return '在线'
|
||||
case 'offline': return '离线'
|
||||
case 'warning': return '警告'
|
||||
default: return '未知'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center text-lg">
|
||||
<MapPin className="h-5 w-5 mr-2 text-blue-400" />
|
||||
养殖场地理分布
|
||||
</CardTitle>
|
||||
<CardDescription className="text-slate-400">
|
||||
全国农场分布及实时状态监控
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="relative h-96 bg-gradient-to-br from-blue-900/50 to-green-900/50 rounded-lg border border-slate-600/50 overflow-hidden">
|
||||
{/* Map Background */}
|
||||
<div className="absolute inset-0 bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAwIiBoZWlnaHQ9IjQwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjMEE0QjZDIi8+PHBhdGggZD0iTTAgMCBMNjAwIDAgTDYwMCA0MDAgTDAgNDAwIFoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFFNUI4QyIgc3Ryb2tlLXdpZHRoPSIwLjUiLz48L3N2Zz4=')] bg-cover bg-center opacity-30"></div>
|
||||
|
||||
{/* Grid Lines */}
|
||||
<div className="absolute inset-0 bg-grid-pattern opacity-20"></div>
|
||||
|
||||
{/* Farm Markers */}
|
||||
{/* 需要从props或状态管理中获取farmLocations数据 */}
|
||||
{([] as FarmLocation[]).map((farm) => (
|
||||
<div
|
||||
key={farm.id}
|
||||
className="absolute transform -translate-x-1/2 -translate-y-1/2 group cursor-pointer"
|
||||
style={{ left: farm.position.left, top: farm.position.top }}
|
||||
>
|
||||
<div className="relative">
|
||||
<div className={`w-4 h-4 rounded-full border-2 border-white ${getStatusColor(farm.status)} animate-pulse`}></div>
|
||||
<div className="absolute -top-6 left-1/2 transform -translate-x-1/2 bg-slate-800/90 backdrop-blur-sm text-white text-xs px-2 py-1 rounded border border-slate-600 opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap">
|
||||
{farm.name}
|
||||
</div>
|
||||
|
||||
{/* Tooltip on hover */}
|
||||
<div className="absolute -top-32 left-1/2 transform -translate-x-1/2 bg-slate-800/95 backdrop-blur-sm text-white p-3 rounded-lg border border-slate-600 shadow-lg opacity-0 group-hover:opacity-100 transition-opacity w-48 z-50">
|
||||
<div className="text-sm font-semibold mb-2">{farm.name}</div>
|
||||
<div className="text-xs space-y-1 text-slate-300">
|
||||
<div>类型: {farm.type}</div>
|
||||
<div>地址: {farm.address}</div>
|
||||
<div>联系人: {farm.contact}</div>
|
||||
<div>电话: {farm.phone}</div>
|
||||
<div className={`inline-flex items-center px-2 py-1 rounded text-xs ${
|
||||
farm.status === 'online' ? 'bg-green-500/20 text-green-400' :
|
||||
farm.status === 'offline' ? 'bg-red-500/20 text-red-400' :
|
||||
'bg-yellow-500/20 text-yellow-400'
|
||||
}`}>
|
||||
<div className={`w-2 h-2 rounded-full mr-1 ${
|
||||
farm.status === 'online' ? 'bg-green-400' :
|
||||
farm.status === 'offline' ? 'bg-red-400' :
|
||||
'bg-yellow-400'
|
||||
}`}></div>
|
||||
{getStatusText(farm.status)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Map Controls */}
|
||||
<div className="absolute top-4 right-4 flex flex-col space-y-2">
|
||||
<button className="w-8 h-8 bg-slate-800/80 backdrop-blur-sm border border-slate-600 rounded text-white font-bold hover:bg-slate-700 transition-colors">
|
||||
+
|
||||
</button>
|
||||
<button className="w-8 h-8 bg-slate-800/80 backdrop-blur-sm border border-slate-600 rounded text-white font-bold hover:bg-slate-700 transition-colors">
|
||||
-
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="absolute bottom-4 left-4 bg-slate-800/80 backdrop-blur-sm border border-slate-600 rounded-lg p-3 text-xs text-white">
|
||||
<div className="font-semibold mb-2">图例</div>
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center">
|
||||
<div className="w-3 h-3 bg-green-400 rounded-full mr-2"></div>
|
||||
<span>在线</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="w-3 h-3 bg-red-400 rounded-full mr-2"></div>
|
||||
<span>离线</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="w-3 h-3 bg-yellow-400 rounded-full mr-2"></div>
|
||||
<span>警告</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
'use client'
|
||||
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
||||
import { MapPin } from "lucide-react"
|
||||
|
||||
interface FarmLocation {
|
||||
id: number
|
||||
name: string
|
||||
type: string
|
||||
address: string
|
||||
contact: string
|
||||
phone: string
|
||||
position: { left: string; top: string }
|
||||
status: 'online' | 'offline' | 'warning'
|
||||
}
|
||||
|
||||
// const farmLocations: FarmLocation[] = [
|
||||
// {
|
||||
// id: 1,
|
||||
// name: "宁夏农场1",
|
||||
// type: "综合农场",
|
||||
// address: "宁夏回族自治区银川市",
|
||||
// contact: "管理员",
|
||||
// phone: "400-000-0000",
|
||||
// position: { left: "45%", top: "25%" },
|
||||
// status: "online"
|
||||
// },
|
||||
// {
|
||||
// id: 2,
|
||||
// name: "宁夏农场2",
|
||||
// type: "综合农场",
|
||||
// address: "宁夏回族自治区石嘴山市",
|
||||
// contact: "管理员",
|
||||
// phone: "400-000-0000",
|
||||
// position: { left: "40%", top: "15%" },
|
||||
// status: "online"
|
||||
// },
|
||||
// {
|
||||
// id: 3,
|
||||
// name: "宁夏农场3",
|
||||
// type: "综合农场",
|
||||
// address: "宁夏回族自治区吴忠市",
|
||||
// contact: "管理员",
|
||||
// phone: "400-000-0000",
|
||||
// position: { left: "50%", top: "45%" },
|
||||
// status: "warning"
|
||||
// },
|
||||
// {
|
||||
// id: 4,
|
||||
// name: "阳光农场",
|
||||
// type: "养猪场",
|
||||
// address: "北京市朝阳区农场路1号",
|
||||
// contact: "张三",
|
||||
// phone: "13800138001",
|
||||
// position: { left: "75%", top: "20%" },
|
||||
// status: "online"
|
||||
// },
|
||||
// {
|
||||
// id: 5,
|
||||
// name: "绿野牧场",
|
||||
// type: "养牛场",
|
||||
// address: "上海市浦东新区牧场路2号",
|
||||
// contact: "李四",
|
||||
// phone: "13800138002",
|
||||
// position: { left: "30%", top: "40%" },
|
||||
// status: "online"
|
||||
// },
|
||||
// {
|
||||
// id: 6,
|
||||
// name: "山谷羊场",
|
||||
// type: "养羊场",
|
||||
// address: "广州市天河区山谷路3号",
|
||||
// contact: "王五",
|
||||
// phone: "13800138003",
|
||||
// position: { left: "45%", top: "60%" },
|
||||
// status: "offline"
|
||||
// }
|
||||
// ]
|
||||
|
||||
export function FarmMap() {
|
||||
const getStatusColor = (status: FarmLocation['status']) => {
|
||||
switch (status) {
|
||||
case 'online': return 'bg-green-400'
|
||||
case 'offline': return 'bg-red-400'
|
||||
case 'warning': return 'bg-yellow-400'
|
||||
default: return 'bg-gray-400'
|
||||
}
|
||||
}
|
||||
|
||||
const getStatusText = (status: FarmLocation['status']) => {
|
||||
switch (status) {
|
||||
case 'online': return '在线'
|
||||
case 'offline': return '离线'
|
||||
case 'warning': return '警告'
|
||||
default: return '未知'
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="bg-slate-800/50 border-slate-700 backdrop-blur-sm">
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center text-lg">
|
||||
<MapPin className="h-5 w-5 mr-2 text-blue-400" />
|
||||
养殖场地理分布
|
||||
</CardTitle>
|
||||
<CardDescription className="text-slate-400">
|
||||
全国农场分布及实时状态监控
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="relative h-96 bg-gradient-to-br from-blue-900/50 to-green-900/50 rounded-lg border border-slate-600/50 overflow-hidden">
|
||||
{/* Map Background */}
|
||||
<div className="absolute inset-0 bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAwIiBoZWlnaHQ9IjQwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjMEE0QjZDIi8+PHBhdGggZD0iTTAgMCBMNjAwIDAgTDYwMCA0MDAgTDAgNDAwIFoiIGZpbGw9Im5vbmUiIHN0cm9rZT0iIzFFNUI4QyIgc3Ryb2tlLXdpZHRoPSIwLjUiLz48L3N2Zz4=')] bg-cover bg-center opacity-30"></div>
|
||||
|
||||
{/* Grid Lines */}
|
||||
<div className="absolute inset-0 bg-grid-pattern opacity-20"></div>
|
||||
|
||||
{/* Farm Markers */}
|
||||
{/* 需要从props或状态管理中获取farmLocations数据 */}
|
||||
{([] as FarmLocation[]).map((farm) => (
|
||||
<div
|
||||
key={farm.id}
|
||||
className="absolute transform -translate-x-1/2 -translate-y-1/2 group cursor-pointer"
|
||||
style={{ left: farm.position.left, top: farm.position.top }}
|
||||
>
|
||||
<div className="relative">
|
||||
<div className={`w-4 h-4 rounded-full border-2 border-white ${getStatusColor(farm.status)} animate-pulse`}></div>
|
||||
<div className="absolute -top-6 left-1/2 transform -translate-x-1/2 bg-slate-800/90 backdrop-blur-sm text-white text-xs px-2 py-1 rounded border border-slate-600 opacity-0 group-hover:opacity-100 transition-opacity whitespace-nowrap">
|
||||
{farm.name}
|
||||
</div>
|
||||
|
||||
{/* Tooltip on hover */}
|
||||
<div className="absolute -top-32 left-1/2 transform -translate-x-1/2 bg-slate-800/95 backdrop-blur-sm text-white p-3 rounded-lg border border-slate-600 shadow-lg opacity-0 group-hover:opacity-100 transition-opacity w-48 z-50">
|
||||
<div className="text-sm font-semibold mb-2">{farm.name}</div>
|
||||
<div className="text-xs space-y-1 text-slate-300">
|
||||
<div>类型: {farm.type}</div>
|
||||
<div>地址: {farm.address}</div>
|
||||
<div>联系人: {farm.contact}</div>
|
||||
<div>电话: {farm.phone}</div>
|
||||
<div className={`inline-flex items-center px-2 py-1 rounded text-xs ${
|
||||
farm.status === 'online' ? 'bg-green-500/20 text-green-400' :
|
||||
farm.status === 'offline' ? 'bg-red-500/20 text-red-400' :
|
||||
'bg-yellow-500/20 text-yellow-400'
|
||||
}`}>
|
||||
<div className={`w-2 h-2 rounded-full mr-1 ${
|
||||
farm.status === 'online' ? 'bg-green-400' :
|
||||
farm.status === 'offline' ? 'bg-red-400' :
|
||||
'bg-yellow-400'
|
||||
}`}></div>
|
||||
{getStatusText(farm.status)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
{/* Map Controls */}
|
||||
<div className="absolute top-4 right-4 flex flex-col space-y-2">
|
||||
<button className="w-8 h-8 bg-slate-800/80 backdrop-blur-sm border border-slate-600 rounded text-white font-bold hover:bg-slate-700 transition-colors">
|
||||
+
|
||||
</button>
|
||||
<button className="w-8 h-8 bg-slate-800/80 backdrop-blur-sm border border-slate-600 rounded text-white font-bold hover:bg-slate-700 transition-colors">
|
||||
-
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="absolute bottom-4 left-4 bg-slate-800/80 backdrop-blur-sm border border-slate-600 rounded-lg p-3 text-xs text-white">
|
||||
<div className="font-semibold mb-2">图例</div>
|
||||
<div className="space-y-1">
|
||||
<div className="flex items-center">
|
||||
<div className="w-3 h-3 bg-green-400 rounded-full mr-2"></div>
|
||||
<span>在线</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="w-3 h-3 bg-red-400 rounded-full mr-2"></div>
|
||||
<span>离线</span>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="w-3 h-3 bg-yellow-400 rounded-full mr-2"></div>
|
||||
<span>警告</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user